new test_variant_unique_shared with vptr_holder prototype

This commit is contained in:
Ralf W. Grosse-Kunstleve 2020-11-19 21:51:11 -08:00
parent 01e437a2da
commit d2c8e3ccde
2 changed files with 151 additions and 0 deletions

View File

@ -0,0 +1,101 @@
#include <memory>
#include <variant>
#include "pybind11_tests.h"
namespace pybind11_tests {
// Could this be a holder for a `class_`-like `vclass`?
// To enable passing of unique_ptr as in pure C++.
template <typename T> class vptr_holder {
public:
explicit vptr_holder(T *ptr = nullptr) : vptr_{std::unique_ptr<T>(ptr)} {}
explicit vptr_holder(std::unique_ptr<T> u) : vptr_{std::move(u)} {}
explicit vptr_holder(std::shared_ptr<T> s) : vptr_{s} {}
int ownership_type() const {
if (std::get_if<0>(&vptr_)) {
return 0;
}
if (std::get_if<1>(&vptr_)) {
return 1;
}
return -1;
}
T *get() {
auto u = std::get_if<0>(&vptr_);
if (u) {
return u->get();
}
auto s = std::get_if<1>(&vptr_);
if (s) {
return s->get();
}
return nullptr;
}
std::unique_ptr<T> get_unique() {
auto u = std::get_if<0>(&vptr_);
if (u) {
return std::move(*u);
}
throw std::runtime_error("get_unique failure.");
}
std::shared_ptr<T> get_shared() {
auto s = std::get_if<1>(&vptr_);
if (s) {
return *s;
}
auto u = std::get_if<0>(&vptr_);
if (u) {
auto result = std::shared_ptr<T>(std::move(*u));
vptr_ = result;
return result;
}
throw std::runtime_error("get_shared failure.");
}
private:
std::variant<std::unique_ptr<T>, std::shared_ptr<T>> vptr_;
};
vptr_holder<double> from_raw() { return vptr_holder<double>{new double{3}}; }
vptr_holder<double> from_unique() {
return vptr_holder<double>{std::unique_ptr<double>(new double{5})};
}
vptr_holder<double> from_shared() {
return vptr_holder<double>{std::shared_ptr<double>(new double{7})};
}
TEST_SUBMODULE(variant_unique_shared, m) {
m.def("from_raw", from_raw);
m.def("from_unique", from_unique);
m.def("from_shared", from_shared);
py::class_<vptr_holder<double>>(m, "vptr_holder_double")
.def(py::init<>())
.def("ownership_type", &vptr_holder<double>::ownership_type)
.def("get_value",
[](vptr_holder<double> &v) {
auto p = v.get();
if (p)
return *p;
return -1.;
})
.def("get_unique",
[](vptr_holder<double> &v) {
v.get_unique();
return;
})
.def("get_shared", [](vptr_holder<double> &v) {
v.get_shared();
return;
});
}
} // namespace pybind11_tests

View File

@ -0,0 +1,50 @@
# -*- coding: utf-8 -*-
import pytest
from pybind11_tests import variant_unique_shared as m
def test_default_constructed():
v = m.vptr_holder_double()
assert v.ownership_type() == 0
assert v.get_value() == -1
def test_from_raw():
v = m.from_raw()
assert v.ownership_type() == 0
assert v.get_value() == 3
def test_from_unique():
v = m.from_unique()
assert v.ownership_type() == 0
assert v.get_value() == 5
def test_from_shared():
v = m.from_shared()
assert v.ownership_type() == 1
assert v.get_value() == 7
def test_promotion_to_shared():
v = m.from_raw()
v.get_unique()
assert v.ownership_type() == 0
v.get_shared() # Promotion to shared_ptr.
assert v.ownership_type() == 1
v.get_shared() # Existing shared_ptr.
with pytest.raises(RuntimeError) as exc_info:
v.get_unique()
assert str(exc_info.value) == "get_unique failure."
v.get_shared() # Still works.
def test_shared_from_birth():
v = m.from_shared()
assert v.ownership_type() == 1
with pytest.raises(RuntimeError) as exc_info:
v.get_unique()
assert str(exc_info.value) == "get_unique failure."
v.get_shared() # Still works.