New tests/core/smart_holder_poc_test.cpp, using Catch2.

This commit is contained in:
Ralf W. Grosse-Kunstleve 2021-01-06 16:45:49 -08:00
parent 84bdaebf57
commit 5ab34305ae
2 changed files with 128 additions and 9 deletions

View File

@ -1,6 +1,8 @@
#pragma once
#include <memory>
#include <stdexcept>
#include <string>
#include <typeinfo>
namespace pybindit {
@ -44,8 +46,10 @@ struct smart_holder {
rtti_uqp_del{nullptr},
vptr_deleter_guard_flag{false} {}
bool has_pointee() const { return vptr.get() != nullptr; }
template <typename T>
void ensure_compatible_rtti_held(const char* context) {
void ensure_compatible_rtti_held(const char* context) const {
const std::type_info* rtti_requested = &typeid(T);
if (!(*rtti_requested == *rtti_held)) {
throw std::runtime_error(std::string("Incompatible RTTI (") + context +
@ -54,7 +58,7 @@ struct smart_holder {
}
template <typename D>
void ensure_compatible_rtti_uqp_del(const char* context) {
void ensure_compatible_rtti_uqp_del(const char* context) const {
const std::type_info* rtti_requested = &typeid(D);
if (!(*rtti_requested == *rtti_uqp_del)) {
throw std::runtime_error(
@ -62,14 +66,21 @@ struct smart_holder {
}
}
void ensure_vptr_deleter_guard_flag_true(const char* context) {
void ensure_has_pointee(const char* context) const {
if (!has_pointee()) {
throw std::runtime_error(std::string("Disowned holder (") + context +
").");
}
}
void ensure_vptr_deleter_guard_flag_true(const char* context) const {
if (rtti_uqp_del != nullptr) {
throw std::runtime_error(std::string("Cannot disown this shared_ptr (") +
context + ").");
}
}
void ensure_use_count_1(const char* context) {
void ensure_use_count_1(const char* context) const {
if (vptr.use_count() != 1) {
throw std::runtime_error(std::string("Cannot disown use_count != 1 (") +
context + ").");
@ -77,7 +88,15 @@ struct smart_holder {
}
template <typename T>
void from_raw_ptr_owned(T* raw_ptr) {
const T& const_value_ref() const {
static const char* context = "const_value_ref";
ensure_compatible_rtti_held<T>(context);
ensure_has_pointee(context);
return *static_cast<T*>(vptr.get());
}
template <typename T>
void from_raw_ptr_take_ownership(T* raw_ptr) {
clear();
rtti_held = &typeid(T);
vptr_deleter_guard_flag = true;
@ -93,7 +112,8 @@ struct smart_holder {
}
template <typename T>
T* as_raw_ptr_owned(const char* context = "as_raw_ptr_owned") {
T* as_raw_ptr_release_ownership(
const char* context = "as_raw_ptr_release_ownership") {
ensure_compatible_rtti_held<T>(context);
ensure_vptr_deleter_guard_flag_true(context);
ensure_use_count_1(context);
@ -104,7 +124,7 @@ struct smart_holder {
}
template <typename T>
T* as_raw_ptr_unowned() {
T* as_raw_ptr_unowned() const {
static const char* context = "as_raw_ptr_unowned";
ensure_compatible_rtti_held<T>(context);
return static_cast<T*>(vptr.get());
@ -122,7 +142,7 @@ struct smart_holder {
template <typename T>
std::unique_ptr<T> as_unique_ptr() {
return std::unique_ptr<T>(as_raw_ptr_owned<T>("as_unique_ptr"));
return std::unique_ptr<T>(as_raw_ptr_release_ownership<T>("as_unique_ptr"));
}
template <typename T, typename D>
@ -156,7 +176,7 @@ struct smart_holder {
}
template <typename T>
std::shared_ptr<T> as_shared_ptr() {
std::shared_ptr<T> as_shared_ptr() const {
static const char* context = "as_shared_ptr";
ensure_compatible_rtti_held<T>(context);
return std::static_pointer_cast<T>(vptr);

View File

@ -0,0 +1,99 @@
#include "pybind11/smart_holder_poc.h"
#define CATCH_CONFIG_MAIN
#include "catch.hpp"
using pybindit::memory::smart_holder;
namespace helpers {
template <typename T>
struct functor_builtin_delete {
void operator()(T* ptr) { delete ptr; }
};
} // namespace helpers
TEST_CASE("from_raw_ptr_take_ownership=const_value_ref") {
smart_holder hld;
REQUIRE(!hld.has_pointee());
hld.from_raw_ptr_take_ownership(new int(19));
REQUIRE(hld.has_pointee());
REQUIRE(hld.const_value_ref<int>() == 19);
}
TEST_CASE("from_raw_ptr_unowned=const_value_ref") {
static int value = 19;
smart_holder hld;
hld.from_raw_ptr_unowned(&value);
REQUIRE(hld.const_value_ref<int>() == 19);
}
TEST_CASE("as_raw_ptr_release_ownership") {
smart_holder hld;
hld.from_raw_ptr_take_ownership(new int(19));
auto new_owner =
std::unique_ptr<int>(hld.as_raw_ptr_release_ownership<int>());
REQUIRE(!hld.has_pointee());
}
TEST_CASE("as_raw_ptr_unowned") {
smart_holder hld;
hld.from_raw_ptr_take_ownership(new int(19));
int* raw_ptr = hld.as_raw_ptr_unowned<int>();
REQUIRE(hld.has_pointee());
REQUIRE(*raw_ptr == 19);
}
TEST_CASE("from_unique_ptr=const_value_ref") {
std::unique_ptr<int> orig_owner(new int(19));
smart_holder hld;
hld.from_unique_ptr(std::move(orig_owner));
REQUIRE(orig_owner.get() == nullptr);
REQUIRE(hld.const_value_ref<int>() == 19);
}
TEST_CASE("as_unique_ptr") {
smart_holder hld;
hld.from_raw_ptr_take_ownership(new int(19));
auto new_owner = hld.as_unique_ptr<int>();
REQUIRE(!hld.has_pointee());
REQUIRE(*new_owner == 19);
}
TEST_CASE("from_unique_ptr_with_deleter=const_value_ref") {
std::unique_ptr<int, helpers::functor_builtin_delete<int>> orig_owner(
new int(19));
smart_holder hld;
hld.from_unique_ptr_with_deleter(std::move(orig_owner));
REQUIRE(orig_owner.get() == nullptr);
REQUIRE(hld.const_value_ref<int>() == 19);
}
TEST_CASE("as_unique_ptr_with_deleter") {
std::unique_ptr<int, helpers::functor_builtin_delete<int>> orig_owner(
new int(19));
smart_holder hld;
hld.from_unique_ptr_with_deleter(std::move(orig_owner));
auto new_owner =
hld.as_unique_ptr_with_deleter<int,
helpers::functor_builtin_delete<int>>();
REQUIRE(!hld.has_pointee());
REQUIRE(*new_owner == 19);
}
TEST_CASE("from_shared_ptr=const_value_ref") {
std::shared_ptr<int> orig_owner(new int(19));
smart_holder hld;
hld.from_shared_ptr(orig_owner);
REQUIRE(orig_owner.get() != nullptr);
REQUIRE(hld.const_value_ref<int>() == 19);
}
TEST_CASE("as_shared_ptr") {
smart_holder hld;
hld.from_raw_ptr_take_ownership(new int(19));
auto new_owner = hld.as_shared_ptr<int>();
REQUIRE(hld.has_pointee());
REQUIRE(*new_owner == 19);
}