RDKit
Open-source cheminformatics and machine learning.
Toggle main menu visibility
Loading...
Searching...
No Matches
boost_shared_ptr.h
Go to the documentation of this file.
1
/*
2
RDBoost/boost_shared_ptr.h: Type caster for boost::shared_ptr<T>
3
adapted from nanobind's type caster for std::shared_ptr<T>
4
https://github.com/wjakob/nanobind/blob/master/include/nanobind/stl/shared_ptr.h
5
6
Copyright (c) 2022 Wenzel Jakob
7
8
All rights reserved. Use of this source code is governed by a
9
BSD-style license that can be found in the LICENSE file.
10
*/
11
12
#pragma once
13
14
#include <nanobind/nanobind.h>
15
#include <boost/shared_ptr.hpp>
16
17
NAMESPACE_BEGIN(NB_NAMESPACE)
18
NAMESPACE_BEGIN(detail)
19
20
// shared_ptr deleter that reduces the reference count of a Python object
21
struct
boost_py_deleter
{
22
void
operator()
(
void
*)
noexcept
{
23
// Don't run the deleter if the interpreter has been shut down
24
if
(!is_alive())
return
;
25
gil_scoped_acquire guard;
26
Py_DECREF(
o
);
27
}
28
29
PyObject *
o
;
30
};
31
32
/**
33
* Create a std::shared_ptr for `ptr` that owns a reference to the Python
34
* object `h`; if `ptr` is non-null, then the refcount of `h` is incremented
35
* before creating the shared_ptr and decremented by its deleter.
36
*
37
* Usually this is instantiated with T = void, to reduce template bloat.
38
* But if the pointee type uses enable_shared_from_this, we instantiate
39
* with T = that type, in order to allow its internal weak_ptr to share
40
* ownership with the shared_ptr we're creating.
41
*
42
* The next two functions are simultaneously marked as 'inline' (to avoid
43
* linker errors) and 'NB_NOINLINE' (to avoid them being inlined into every
44
* single shared_ptr type_caster, which would enlarge the binding size)
45
*/
46
template
<
typename
T>
47
inline
NB_NOINLINE boost::shared_ptr<T>
boost_shared_from_python
(
48
T *ptr, handle h)
noexcept
{
49
if
(ptr)
50
return
boost::shared_ptr<T>(ptr,
boost_py_deleter
{h.inc_ref().ptr()});
51
else
52
return
boost::shared_ptr<T>(
nullptr
);
53
}
54
55
inline
NB_NOINLINE
void
boost_shared_from_cpp
(boost::shared_ptr<void> &&ptr,
56
PyObject *o)
noexcept
{
57
keep_alive(o,
new
boost::shared_ptr<void>(std::move(ptr)),
58
[](
void
*p)
noexcept
{
delete
(boost::shared_ptr<void> *)p; });
59
}
60
61
template
<
typename
T>
62
struct
type_caster<
boost
::shared_ptr<T>> {
63
static
constexpr
bool
IsClass
=
true
;
64
using
Caster
= make_caster<T>;
65
using
Td
= std::decay_t<T>;
66
67
NB_TYPE_CASTER(boost::shared_ptr<T>, Caster::Name)
68
69
static_assert
(is_base_caster_v<Caster>,
70
"Conversion of ``shared_ptr<T>`` requires that ``T`` is "
71
"handled by nanobind's regular class binding mechanism. "
72
"However, a type caster was registered to intercept this "
73
"particular type, which is not allowed."
);
74
75
bool
from_python
(handle src, uint8_t flags, cleanup_list *cleanup)
noexcept
{
76
Caster
caster;
77
if
(!caster.from_python(src, flags, cleanup))
return
false
;
78
79
Td
*ptr = caster.operator
Td
*();
80
if
constexpr
(has_shared_from_this_v<T>) {
81
if
(ptr) {
82
if
(
auto
sp = ptr->weak_from_this().lock()) {
83
// There is already a C++ shared_ptr for this object. Use it.
84
value = boost::static_pointer_cast<T>(std::move(sp));
85
return
true
;
86
}
87
}
88
// Otherwise create a new one. Use boost_shared_from_python<T>(...)
89
// so that future calls to ptr->shared_from_this() can share
90
// ownership with it.
91
value =
boost_shared_from_python
(ptr, src);
92
}
else
{
93
value = boost::static_pointer_cast<T>(
94
boost_shared_from_python
(
static_cast<
void
*
>
(ptr), src));
95
}
96
return
true
;
97
}
98
99
static
handle
from_cpp
(
const
Value &value, rv_policy,
100
cleanup_list *cleanup)
noexcept
{
101
bool
is_new =
false
;
102
handle result;
103
104
Td
*ptr = (
Td
*)value.get();
105
const
std::type_info *type = &
typeid
(
Td
);
106
107
constexpr
bool
has_type_hook =
108
!std::is_base_of_v<std::false_type, type_hook<Td>>;
109
if
constexpr
(has_type_hook) type = type_hook<Td>::get(ptr);
110
111
if
constexpr
(!std::is_polymorphic_v<Td>) {
112
result = nb_type_put(type, ptr, rv_policy::reference, cleanup, &is_new);
113
}
else
{
114
const
std::type_info *type_p =
115
(!has_type_hook && ptr) ? &
typeid
(*ptr) :
nullptr
;
116
117
result = nb_type_put_p(type, type_p, ptr, rv_policy::reference, cleanup,
118
&is_new);
119
}
120
121
if
(is_new) {
122
boost::shared_ptr<void> pp;
123
if
constexpr
(std::is_const_v<T>)
124
pp = boost::static_pointer_cast<void>(
125
boost::const_pointer_cast<Td>(value));
126
else
127
pp = boost::static_pointer_cast<void>(value);
128
boost_shared_from_cpp
(std::move(pp), result.ptr());
129
}
130
131
return
result;
132
}
133
};
134
135
NAMESPACE_END(detail)
136
NAMESPACE_END(NB_NAMESPACE)
boost_shared_from_cpp
NB_NOINLINE void boost_shared_from_cpp(boost::shared_ptr< void > &&ptr, PyObject *o) noexcept
Definition
boost_shared_ptr.h:55
boost_shared_from_python
NB_NOINLINE boost::shared_ptr< T > boost_shared_from_python(T *ptr, handle h) noexcept
Definition
boost_shared_ptr.h:47
boost
Definition
ShapeInput.h:39
boost_py_deleter
Definition
boost_shared_ptr.h:21
boost_py_deleter::o
PyObject * o
Definition
boost_shared_ptr.h:29
boost_py_deleter::operator()
void operator()(void *) noexcept
Definition
boost_shared_ptr.h:22
type_caster< boost::shared_ptr< T > >::from_cpp
static handle from_cpp(const Value &value, rv_policy, cleanup_list *cleanup) noexcept
Definition
boost_shared_ptr.h:99
type_caster< boost::shared_ptr< T > >::Caster
make_caster< T > Caster
Definition
boost_shared_ptr.h:64
type_caster< boost::shared_ptr< T > >::from_python
bool from_python(handle src, uint8_t flags, cleanup_list *cleanup) noexcept
Definition
boost_shared_ptr.h:75
type_caster< boost::shared_ptr< T > >::Td
std::decay_t< T > Td
Definition
boost_shared_ptr.h:65
type_caster< boost::shared_ptr< T > >::IsClass
static constexpr bool IsClass
Definition
boost_shared_ptr.h:63
RDBoost
boost_shared_ptr.h
Generated on
for RDKit by
1.17.0