Skip to content

Commit

Permalink
New tests/core/smart_holder_poc_test.cpp, using Catch2.
Browse files Browse the repository at this point in the history
  • Loading branch information
Ralf W. Grosse-Kunstleve committed Jan 7, 2021
1 parent 41b87c8 commit 4b40a7c
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 9 deletions.
38 changes: 29 additions & 9 deletions include/pybind11/smart_holder_poc.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#pragma once

#include <memory>
#include <stdexcept>
#include <string>
#include <typeinfo>

namespace pybindit {
Expand Down Expand Up @@ -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 +
Expand All @@ -54,30 +58,45 @@ 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(
std::string("Incompatible unique_ptr deleter (") + context + ").");
}
}

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 + ").");
}
}

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;
Expand All @@ -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);
Expand All @@ -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());
Expand All @@ -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>
Expand Down Expand Up @@ -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);
Expand Down
99 changes: 99 additions & 0 deletions tests/core/smart_holder_poc_test.cpp
Original file line number Diff line number Diff line change
@@ -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);
}

0 comments on commit 4b40a7c

Please sign in to comment.