@@ -20,6 +20,7 @@ NAMESPACE_BEGIN(pybind11)
20
20
NAMESPACE_BEGIN(detail)
21
21
inline PyTypeObject *make_static_property_type();
22
22
inline PyTypeObject *make_default_metaclass ();
23
+ inline PyObject *make_object_base_type (PyTypeObject *metaclass);
23
24
24
25
// / Additional type information which does not fit into the PyTypeObject
25
26
struct type_info {
@@ -78,20 +79,55 @@ PYBIND11_NOINLINE inline internals &get_internals() {
78
79
);
79
80
internals_ptr->static_property_type = make_static_property_type ();
80
81
internals_ptr->default_metaclass = make_default_metaclass ();
82
+ internals_ptr->instance_base = make_object_base_type (internals_ptr->default_metaclass );
81
83
}
82
84
return *internals_ptr;
83
85
}
84
86
85
- PYBIND11_NOINLINE inline detail::type_info* get_type_info (PyTypeObject *type) {
87
+ /* * Takes a Python type and returns the pybind11 type_info for it (if it is a pybind11-registered
88
+ * type). If it is not (i.e. it is a python type) this walks the type's inheritance tree to any
89
+ * inherited pybind11-registered types, which are returned in a vector. (There can be multiple if
90
+ * an involved python type inherits from multiple pybind11-registered types). */
91
+ PYBIND11_NOINLINE inline std::vector<detail::type_info *> get_all_type_info (PyTypeObject *type) {
92
+ std::vector<PyTypeObject *> check (1 , type);
93
+ std::vector<detail::type_info *> all_type_info;
86
94
auto const &type_dict = get_internals ().registered_types_py ;
87
- do {
95
+ for (size_t i = 0 ; i < check.size (); i++) {
96
+ type = check[i];
97
+ if (!PyType_Check ((PyObject *) type)) continue ;
88
98
auto it = type_dict.find (type);
89
- if (it != type_dict.end ())
90
- return (detail::type_info *) it->second ;
91
- type = type->tp_base ;
92
- if (!type)
93
- return nullptr ;
94
- } while (true );
99
+ if (it != type_dict.end ()) {
100
+ // Make sure we haven't already seen this type (so that we follow Python/virtual C++
101
+ // rules that there should only be one instance of a common base).
102
+ //
103
+ // NB: Could use an set here, rather than a linear search, but since having a large
104
+ // number of immediate pybind11-registered types seems fairly unlikely, that probably
105
+ // isn't worthwhile).
106
+ auto *tinfo = (detail::type_info *) it->second ;
107
+ bool found = false ;
108
+ for (auto &known : all_type_info) {
109
+ if (known == tinfo) { found = true ; break ; }
110
+ }
111
+ if (!found) all_type_info.push_back (tinfo);
112
+ } else if (type->tp_bases ) {
113
+ for (handle parent : reinterpret_borrow<tuple>(type->tp_bases ))
114
+ check.push_back ((PyTypeObject *) parent.ptr ());
115
+ }
116
+ }
117
+ return all_type_info;
118
+ }
119
+
120
+ /* * Gets a single pybind11 type info for a python type. Returns nullptr if neither the type nor any
121
+ * ancestors are pybind11-registered. Throws an exception if there are multiple bases--get
122
+ * `get_all_type_info` directly if you want to support multiple bases.
123
+ */
124
+ PYBIND11_NOINLINE inline detail::type_info* get_type_info (PyTypeObject *type) {
125
+ auto all = get_all_type_info (type);
126
+ if (all.size () == 0 )
127
+ return nullptr ;
128
+ if (all.size () != 1 )
129
+ pybind11_fail (" pybind11::detail::get_type_info: type has multiple pybind11-registered bases" );
130
+ return all[0 ];
95
131
}
96
132
97
133
PYBIND11_NOINLINE inline detail::type_info *get_type_info (const std::type_info &tp,
@@ -114,6 +150,46 @@ PYBIND11_NOINLINE inline handle get_type_handle(const std::type_info &tp, bool t
114
150
return handle (type_info ? ((PyObject *) type_info->type ) : nullptr );
115
151
}
116
152
153
+ struct value_and_holder {
154
+ void *&value, *&holder;
155
+ value_and_holder (void *&v, void *&h) : value{v}, holder{h} {}
156
+ template <typename V> enable_if_t <std::is_pointer<V>::value, V> value_as () const { return reinterpret_cast <V>(value); }
157
+ template <typename H> enable_if_t <std::is_pointer<H>::value, H> holder_as () const { return reinterpret_cast <H>(holder); }
158
+ };
159
+
160
+ /* * Extracts C++ value and holder pointer references from an instance (which may contain multiple
161
+ * values/holders for python-side multiple inheritance) that match the given type. Throws an error
162
+ * if the given type (or ValueType, if omitted) is not a pybind11 base of the given instance.
163
+ *
164
+ * Takes the instance pointer, a vector returned by `get_all_type_info()`, and the desired type.
165
+ * See also the version below, which doesn't require the vector.
166
+ */
167
+ PYBIND11_NOINLINE inline value_and_holder get_value_and_holder (
168
+ instance *inst, const std::vector<type_info *> &all_type_info,
169
+ const type_info *find_type) {
170
+ size_t i = 0 ;
171
+ for (auto tinfo : all_type_info) {
172
+ if (tinfo == find_type) {
173
+ return value_and_holder (inst->values_and_holders [i], inst->values_and_holders [i+1 ]);
174
+ }
175
+ i += 2 ;
176
+ }
177
+ #if defined(NDEBUG)
178
+ pybind11_fail (" pybind11::detail::get_value_and_holder: "
179
+ " type is not a pybind11 base of the given instance "
180
+ " (compile in debug mode for type details)" );
181
+ #else
182
+ pybind11_fail (" pybind11::detail::get_value_and_holder: `" +
183
+ std::string (find_type->type ->tp_name ) + " ' is not a pybind11 base of the given `" +
184
+ std::string (Py_TYPE (inst)->tp_name ) + " ' instance" );
185
+ #endif
186
+ }
187
+
188
+ // / Shortcut for get_value_and_holder that gets the get_all_type_info vector when called.
189
+ inline value_and_holder get_value_and_holder (instance *inst, const type_info *find_type) {
190
+ return get_value_and_holder (inst, get_all_type_info (Py_TYPE (inst)), find_type);
191
+ }
192
+
117
193
PYBIND11_NOINLINE inline bool isinstance_generic (handle obj, const std::type_info &tp) {
118
194
handle type = detail::get_type_handle (tp, false );
119
195
if (!type)
@@ -203,51 +279,31 @@ class type_caster_generic {
203
279
: typeinfo(get_type_info(type_info)) { }
204
280
205
281
PYBIND11_NOINLINE bool load (handle src, bool convert) {
206
- if (!src)
207
- return false ;
208
- return load (src, convert, Py_TYPE (src.ptr ()));
209
- }
210
-
211
- bool load (handle src, bool convert, PyTypeObject *tobj) {
212
282
if (!src || !typeinfo)
213
283
return false ;
214
284
if (src.is_none ()) {
215
285
value = nullptr ;
216
286
return true ;
217
287
}
218
288
219
- if (typeinfo->simple_type ) { /* Case 1: no multiple inheritance etc. involved */
220
- /* Check if we can safely perform a reinterpret-style cast */
221
- if (PyType_IsSubtype (tobj, typeinfo->type )) {
222
- value = reinterpret_cast <instance<void > *>(src.ptr ())->value ;
223
- return true ;
224
- }
225
- } else { /* Case 2: multiple inheritance */
226
- /* Check if we can safely perform a reinterpret-style cast */
227
- if (tobj == typeinfo->type ) {
228
- value = reinterpret_cast <instance<void > *>(src.ptr ())->value ;
289
+ PyTypeObject *pytype = Py_TYPE (src.ptr ());
290
+ // First check to see if we can safely perform a reinterpret-style cast: allowed if one of
291
+ // the pybind bases of `src` (i.e. following non-pybind inheritance) is the desired type
292
+ auto registered_bases = get_all_type_info (pytype);
293
+ for (auto base : registered_bases) {
294
+ if (base == typeinfo ||
295
+ (typeinfo->simple_type && PyType_IsSubtype (base->type , typeinfo->type ))) {
296
+ value = get_value_and_holder (reinterpret_cast <instance *>(src.ptr ()), registered_bases, base).value ;
229
297
return true ;
230
298
}
299
+ }
231
300
232
- /* If this is a python class, also check the parents recursively */
233
- auto const &type_dict = get_internals ().registered_types_py ;
234
- bool new_style_class = PyType_Check ((PyObject *) tobj);
235
- if (type_dict.find (tobj) == type_dict.end () && new_style_class && tobj->tp_bases ) {
236
- auto parents = reinterpret_borrow<tuple>(tobj->tp_bases );
237
- for (handle parent : parents) {
238
- bool result = load (src, convert, (PyTypeObject *) parent.ptr ());
239
- if (result)
240
- return true ;
241
- }
242
- }
243
-
244
- /* Try implicit casts */
245
- for (auto &cast : typeinfo->implicit_casts ) {
246
- type_caster_generic sub_caster (*cast.first );
247
- if (sub_caster.load (src, convert)) {
248
- value = cast.second (sub_caster.value );
249
- return true ;
250
- }
301
+ /* Try implicit casts */
302
+ for (auto &cast : typeinfo->implicit_casts ) {
303
+ type_caster_generic sub_caster (*cast.first );
304
+ if (sub_caster.load (src, convert)) {
305
+ value = cast.second (sub_caster.value );
306
+ return true ;
251
307
}
252
308
}
253
309
@@ -301,29 +357,34 @@ class type_caster_generic {
301
357
return handle ((PyObject *) it_i->second ).inc_ref ();
302
358
}
303
359
360
+ // Set up the object manually (rather than calling new): we don't want value pointer
361
+ // initialized because we want to set it to our `src` pointer below.
304
362
auto inst = reinterpret_steal<object>(PyType_GenericAlloc (tinfo->type , 0 ));
363
+ auto wrapper = (instance *) inst.ptr ();
364
+ // Since we are a registered type, we know there will only be one value/holder pair:
365
+ wrapper->values_and_holders = (void **) ::operator new (2 * sizeof (void *));
366
+ void *&valueptr = wrapper->values_and_holders [0 ];
367
+ valueptr = nullptr ;
368
+ wrapper->values_and_holders [1 ] = nullptr ;
305
369
306
- auto wrapper = (instance<void > *) inst.ptr ();
307
-
308
- wrapper->value = nullptr ;
309
370
wrapper->owned = false ;
310
371
311
372
switch (policy) {
312
373
case return_value_policy::automatic:
313
374
case return_value_policy::take_ownership:
314
- wrapper-> value = src;
375
+ valueptr = src;
315
376
wrapper->owned = true ;
316
377
break ;
317
378
318
379
case return_value_policy::automatic_reference:
319
380
case return_value_policy::reference:
320
- wrapper-> value = src;
381
+ valueptr = src;
321
382
wrapper->owned = false ;
322
383
break ;
323
384
324
385
case return_value_policy::copy:
325
386
if (copy_constructor)
326
- wrapper-> value = copy_constructor (src);
387
+ valueptr = copy_constructor (src);
327
388
else
328
389
throw cast_error (" return_value_policy = copy, but the "
329
390
" object is non-copyable!" );
@@ -332,17 +393,17 @@ class type_caster_generic {
332
393
333
394
case return_value_policy::move:
334
395
if (move_constructor)
335
- wrapper-> value = move_constructor (src);
396
+ valueptr = move_constructor (src);
336
397
else if (copy_constructor)
337
- wrapper-> value = copy_constructor (src);
398
+ valueptr = copy_constructor (src);
338
399
else
339
400
throw cast_error (" return_value_policy = move, but the "
340
401
" object is neither movable nor copyable!" );
341
402
wrapper->owned = true ;
342
403
break ;
343
404
344
405
case return_value_policy::reference_internal:
345
- wrapper-> value = src;
406
+ valueptr = src;
346
407
wrapper->owned = false ;
347
408
detail::keep_alive_impl (inst, parent);
348
409
break ;
@@ -353,7 +414,7 @@ class type_caster_generic {
353
414
354
415
tinfo->init_holder (inst.ptr (), existing_holder);
355
416
356
- internals.registered_instances .emplace (wrapper-> value , inst.ptr ());
417
+ internals.registered_instances .emplace (valueptr , inst.ptr ());
357
418
358
419
return inst.release ();
359
420
}
@@ -590,8 +651,9 @@ template <> class type_caster<void> : public type_caster<void_type> {
590
651
}
591
652
592
653
/* Check if this is a C++ type */
593
- if (get_type_info ((PyTypeObject *) h.get_type ().ptr ())) {
594
- value = ((instance<void > *) h.ptr ())->value ;
654
+ type_info *tinfo = get_type_info ((PyTypeObject *) h.get_type ().ptr ());
655
+ if (tinfo) {
656
+ value = get_value_and_holder (reinterpret_cast <instance *>(h.ptr ()), tinfo).value ;
595
657
return true ;
596
658
}
597
659
@@ -890,42 +952,28 @@ struct copyable_holder_caster : public type_caster_base<type> {
890
952
using base::temp;
891
953
892
954
PYBIND11_NOINLINE bool load (handle src, bool convert) {
893
- return load (src, convert, Py_TYPE (src.ptr ()));
894
- }
895
-
896
- bool load (handle src, bool convert, PyTypeObject *tobj) {
897
955
if (!src || !typeinfo)
898
956
return false ;
899
957
if (src.is_none ()) {
900
958
value = nullptr ;
901
959
return true ;
902
960
}
903
961
904
- if (typeinfo->simple_type ) { /* Case 1: no multiple inheritance etc. involved */
905
- /* Check if we can safely perform a reinterpret-style cast */
906
- if (PyType_IsSubtype (tobj, typeinfo->type ))
907
- return load_value_and_holder (src);
908
- } else { /* Case 2: multiple inheritance */
909
- /* Check if we can safely perform a reinterpret-style cast */
910
- if (tobj == typeinfo->type )
911
- return load_value_and_holder (src);
912
-
913
- /* If this is a python class, also check the parents recursively */
914
- auto const &type_dict = get_internals ().registered_types_py ;
915
- bool new_style_class = PyType_Check ((PyObject *) tobj);
916
- if (type_dict.find (tobj) == type_dict.end () && new_style_class && tobj->tp_bases ) {
917
- auto parents = reinterpret_borrow<tuple>(tobj->tp_bases );
918
- for (handle parent : parents) {
919
- bool result = load (src, convert, (PyTypeObject *) parent.ptr ());
920
- if (result)
921
- return true ;
922
- }
962
+ PyTypeObject *pytype = Py_TYPE (src.ptr ());
963
+ // First check to see if we can safely perform a reinterpret-style cast: allowed if one of
964
+ // the pybind bases of `src` (i.e. following non-pybind inheritance) is the desired type
965
+ auto registered_bases = get_all_type_info (pytype);
966
+ for (auto base : registered_bases) {
967
+ if (base == typeinfo ||
968
+ (typeinfo->simple_type && PyType_IsSubtype (base->type , typeinfo->type ))) {
969
+ return load_value_and_holder (get_value_and_holder (
970
+ reinterpret_cast <instance *>(src.ptr ()), registered_bases, base));
923
971
}
924
-
925
- if (try_implicit_casts (src, convert))
926
- return true ;
927
972
}
928
973
974
+ if (try_implicit_casts (src, convert))
975
+ return true ;
976
+
929
977
if (convert) {
930
978
for (auto &converter : typeinfo->implicit_conversions ) {
931
979
temp = reinterpret_steal<object>(converter (src.ptr (), typeinfo->type ));
@@ -937,11 +985,10 @@ struct copyable_holder_caster : public type_caster_base<type> {
937
985
return false ;
938
986
}
939
987
940
- bool load_value_and_holder (handle src) {
941
- auto inst = (instance<type, holder_type> *) src.ptr ();
942
- value = (void *) inst->value ;
943
- if (inst->holder_constructed ) {
944
- holder = inst->holder ;
988
+ bool load_value_and_holder (const value_and_holder &v_h) {
989
+ if (v_h.holder ) {
990
+ value = v_h.value ;
991
+ holder = *v_h.holder_as <holder_type *>();
945
992
return true ;
946
993
} else {
947
994
throw cast_error (" Unable to cast from non-held to held instance (T& to Holder<T>) "
0 commit comments