Skip to content

Commit 4b40a7c

Browse files
committed
New tests/core/smart_holder_poc_test.cpp, using Catch2.
1 parent 41b87c8 commit 4b40a7c

File tree

2 files changed

+128
-9
lines changed

2 files changed

+128
-9
lines changed

include/pybind11/smart_holder_poc.h

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#pragma once
22

33
#include <memory>
4+
#include <stdexcept>
5+
#include <string>
46
#include <typeinfo>
57

68
namespace pybindit {
@@ -44,8 +46,10 @@ struct smart_holder {
4446
rtti_uqp_del{nullptr},
4547
vptr_deleter_guard_flag{false} {}
4648

49+
bool has_pointee() const { return vptr.get() != nullptr; }
50+
4751
template <typename T>
48-
void ensure_compatible_rtti_held(const char* context) {
52+
void ensure_compatible_rtti_held(const char* context) const {
4953
const std::type_info* rtti_requested = &typeid(T);
5054
if (!(*rtti_requested == *rtti_held)) {
5155
throw std::runtime_error(std::string("Incompatible RTTI (") + context +
@@ -54,30 +58,45 @@ struct smart_holder {
5458
}
5559

5660
template <typename D>
57-
void ensure_compatible_rtti_uqp_del(const char* context) {
61+
void ensure_compatible_rtti_uqp_del(const char* context) const {
5862
const std::type_info* rtti_requested = &typeid(D);
5963
if (!(*rtti_requested == *rtti_uqp_del)) {
6064
throw std::runtime_error(
6165
std::string("Incompatible unique_ptr deleter (") + context + ").");
6266
}
6367
}
6468

65-
void ensure_vptr_deleter_guard_flag_true(const char* context) {
69+
void ensure_has_pointee(const char* context) const {
70+
if (!has_pointee()) {
71+
throw std::runtime_error(std::string("Disowned holder (") + context +
72+
").");
73+
}
74+
}
75+
76+
void ensure_vptr_deleter_guard_flag_true(const char* context) const {
6677
if (rtti_uqp_del != nullptr) {
6778
throw std::runtime_error(std::string("Cannot disown this shared_ptr (") +
6879
context + ").");
6980
}
7081
}
7182

72-
void ensure_use_count_1(const char* context) {
83+
void ensure_use_count_1(const char* context) const {
7384
if (vptr.use_count() != 1) {
7485
throw std::runtime_error(std::string("Cannot disown use_count != 1 (") +
7586
context + ").");
7687
}
7788
}
7889

7990
template <typename T>
80-
void from_raw_ptr_owned(T* raw_ptr) {
91+
const T& const_value_ref() const {
92+
static const char* context = "const_value_ref";
93+
ensure_compatible_rtti_held<T>(context);
94+
ensure_has_pointee(context);
95+
return *static_cast<T*>(vptr.get());
96+
}
97+
98+
template <typename T>
99+
void from_raw_ptr_take_ownership(T* raw_ptr) {
81100
clear();
82101
rtti_held = &typeid(T);
83102
vptr_deleter_guard_flag = true;
@@ -93,7 +112,8 @@ struct smart_holder {
93112
}
94113

95114
template <typename T>
96-
T* as_raw_ptr_owned(const char* context = "as_raw_ptr_owned") {
115+
T* as_raw_ptr_release_ownership(
116+
const char* context = "as_raw_ptr_release_ownership") {
97117
ensure_compatible_rtti_held<T>(context);
98118
ensure_vptr_deleter_guard_flag_true(context);
99119
ensure_use_count_1(context);
@@ -104,7 +124,7 @@ struct smart_holder {
104124
}
105125

106126
template <typename T>
107-
T* as_raw_ptr_unowned() {
127+
T* as_raw_ptr_unowned() const {
108128
static const char* context = "as_raw_ptr_unowned";
109129
ensure_compatible_rtti_held<T>(context);
110130
return static_cast<T*>(vptr.get());
@@ -122,7 +142,7 @@ struct smart_holder {
122142

123143
template <typename T>
124144
std::unique_ptr<T> as_unique_ptr() {
125-
return std::unique_ptr<T>(as_raw_ptr_owned<T>("as_unique_ptr"));
145+
return std::unique_ptr<T>(as_raw_ptr_release_ownership<T>("as_unique_ptr"));
126146
}
127147

128148
template <typename T, typename D>
@@ -156,7 +176,7 @@ struct smart_holder {
156176
}
157177

158178
template <typename T>
159-
std::shared_ptr<T> as_shared_ptr() {
179+
std::shared_ptr<T> as_shared_ptr() const {
160180
static const char* context = "as_shared_ptr";
161181
ensure_compatible_rtti_held<T>(context);
162182
return std::static_pointer_cast<T>(vptr);

tests/core/smart_holder_poc_test.cpp

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
#include "pybind11/smart_holder_poc.h"
2+
3+
#define CATCH_CONFIG_MAIN
4+
#include "catch.hpp"
5+
6+
using pybindit::memory::smart_holder;
7+
8+
namespace helpers {
9+
10+
template <typename T>
11+
struct functor_builtin_delete {
12+
void operator()(T* ptr) { delete ptr; }
13+
};
14+
15+
} // namespace helpers
16+
17+
TEST_CASE("from_raw_ptr_take_ownership=const_value_ref") {
18+
smart_holder hld;
19+
REQUIRE(!hld.has_pointee());
20+
hld.from_raw_ptr_take_ownership(new int(19));
21+
REQUIRE(hld.has_pointee());
22+
REQUIRE(hld.const_value_ref<int>() == 19);
23+
}
24+
25+
TEST_CASE("from_raw_ptr_unowned=const_value_ref") {
26+
static int value = 19;
27+
smart_holder hld;
28+
hld.from_raw_ptr_unowned(&value);
29+
REQUIRE(hld.const_value_ref<int>() == 19);
30+
}
31+
32+
TEST_CASE("as_raw_ptr_release_ownership") {
33+
smart_holder hld;
34+
hld.from_raw_ptr_take_ownership(new int(19));
35+
auto new_owner =
36+
std::unique_ptr<int>(hld.as_raw_ptr_release_ownership<int>());
37+
REQUIRE(!hld.has_pointee());
38+
}
39+
40+
TEST_CASE("as_raw_ptr_unowned") {
41+
smart_holder hld;
42+
hld.from_raw_ptr_take_ownership(new int(19));
43+
int* raw_ptr = hld.as_raw_ptr_unowned<int>();
44+
REQUIRE(hld.has_pointee());
45+
REQUIRE(*raw_ptr == 19);
46+
}
47+
48+
TEST_CASE("from_unique_ptr=const_value_ref") {
49+
std::unique_ptr<int> orig_owner(new int(19));
50+
smart_holder hld;
51+
hld.from_unique_ptr(std::move(orig_owner));
52+
REQUIRE(orig_owner.get() == nullptr);
53+
REQUIRE(hld.const_value_ref<int>() == 19);
54+
}
55+
56+
TEST_CASE("as_unique_ptr") {
57+
smart_holder hld;
58+
hld.from_raw_ptr_take_ownership(new int(19));
59+
auto new_owner = hld.as_unique_ptr<int>();
60+
REQUIRE(!hld.has_pointee());
61+
REQUIRE(*new_owner == 19);
62+
}
63+
64+
TEST_CASE("from_unique_ptr_with_deleter=const_value_ref") {
65+
std::unique_ptr<int, helpers::functor_builtin_delete<int>> orig_owner(
66+
new int(19));
67+
smart_holder hld;
68+
hld.from_unique_ptr_with_deleter(std::move(orig_owner));
69+
REQUIRE(orig_owner.get() == nullptr);
70+
REQUIRE(hld.const_value_ref<int>() == 19);
71+
}
72+
73+
TEST_CASE("as_unique_ptr_with_deleter") {
74+
std::unique_ptr<int, helpers::functor_builtin_delete<int>> orig_owner(
75+
new int(19));
76+
smart_holder hld;
77+
hld.from_unique_ptr_with_deleter(std::move(orig_owner));
78+
auto new_owner =
79+
hld.as_unique_ptr_with_deleter<int,
80+
helpers::functor_builtin_delete<int>>();
81+
REQUIRE(!hld.has_pointee());
82+
REQUIRE(*new_owner == 19);
83+
}
84+
85+
TEST_CASE("from_shared_ptr=const_value_ref") {
86+
std::shared_ptr<int> orig_owner(new int(19));
87+
smart_holder hld;
88+
hld.from_shared_ptr(orig_owner);
89+
REQUIRE(orig_owner.get() != nullptr);
90+
REQUIRE(hld.const_value_ref<int>() == 19);
91+
}
92+
93+
TEST_CASE("as_shared_ptr") {
94+
smart_holder hld;
95+
hld.from_raw_ptr_take_ownership(new int(19));
96+
auto new_owner = hld.as_shared_ptr<int>();
97+
REQUIRE(hld.has_pointee());
98+
REQUIRE(*new_owner == 19);
99+
}

0 commit comments

Comments
 (0)