Skip to content

Commit 9e7b022

Browse files
WIP: Squashed commit.
1 parent 86e2ad4 commit 9e7b022

11 files changed

+1109
-63
lines changed

include/pybind11/attr.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,9 @@ struct type_record {
226226
/// Function pointer to class_<..>::dealloc
227227
void (*dealloc)(detail::value_and_holder &) = nullptr;
228228

229+
/// See `type_info::has_cpp_release`.
230+
instance::type_release_info_t release_info;
231+
229232
/// List of base classes of the newly created type
230233
list bases;
231234

include/pybind11/cast.h

Lines changed: 349 additions & 53 deletions
Large diffs are not rendered by default.

include/pybind11/detail/common.h

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,8 @@ enum class return_value_policy : uint8_t {
354354
reference_internal
355355
};
356356

357+
class object;
358+
357359
NAMESPACE_BEGIN(detail)
358360

359361
inline static constexpr int log2(size_t n, int k = 0) { return (n <= 1) ? k : log2(n >> 1, k + 1); }
@@ -373,6 +375,83 @@ constexpr size_t instance_simple_holder_in_ptrs() {
373375
return size_in_ptrs(sizeof(std::shared_ptr<int>));
374376
}
375377

378+
enum class HolderTypeId {
379+
Unknown,
380+
UniquePtr,
381+
SharedPtr,
382+
};
383+
template <typename holder_type, typename SFINAE = void>
384+
struct get_holder_type_id {
385+
static constexpr HolderTypeId value = HolderTypeId::Unknown;
386+
};
387+
template <typename T>
388+
struct get_holder_type_id<std::shared_ptr<T>, void> {
389+
static constexpr HolderTypeId value = HolderTypeId::SharedPtr;
390+
};
391+
template <typename T, typename Deleter>
392+
struct get_holder_type_id<std::unique_ptr<T, Deleter>, void> {
393+
// TODO(eric.cousineau): Should this only specialize for `std::default_deleter`?
394+
static constexpr HolderTypeId value = HolderTypeId::UniquePtr;
395+
};
396+
397+
class holder_erased {
398+
public:
399+
holder_erased() = default;
400+
holder_erased(const holder_erased&) = default;
401+
holder_erased& operator=(const holder_erased&) = default;
402+
403+
template <typename holder_type>
404+
holder_erased(const holder_type* holder)
405+
: ptr_(const_cast<holder_type*>(holder)),
406+
type_id_(get_holder_type_id<holder_type>::value),
407+
is_const_(true) {}
408+
409+
template <typename holder_type>
410+
holder_erased(holder_type* holder)
411+
: holder_erased(static_cast<const holder_type*>(holder)) {
412+
is_const_ = false;
413+
}
414+
415+
holder_erased(const void* ptr, HolderTypeId type_id)
416+
: ptr_(const_cast<void*>(ptr)),
417+
type_id_(type_id),
418+
is_const_(true) {}
419+
420+
holder_erased(void* ptr, HolderTypeId type_id)
421+
: ptr_(ptr),
422+
type_id_(type_id),
423+
is_const_(false) {}
424+
425+
void* ptr() const { return ptr_; }
426+
HolderTypeId type_id() const { return type_id_; }
427+
428+
template <typename holder_type>
429+
holder_type& mutable_cast() const {
430+
if (is_const_)
431+
throw std::runtime_error("Trying to mutate const reference?");
432+
return do_cast<holder_type>();
433+
}
434+
435+
template <typename holder_type>
436+
const holder_type& cast() const {
437+
return do_cast<holder_type>();
438+
}
439+
440+
operator bool() const { return ptr_; }
441+
private:
442+
template <typename holder_type>
443+
holder_type& do_cast() const {
444+
if (type_id_ != get_holder_type_id<holder_type>::value) {
445+
throw std::runtime_error("Mismatch on holder type.");
446+
}
447+
return *reinterpret_cast<holder_type*>(ptr_);
448+
}
449+
450+
void* ptr_{};
451+
HolderTypeId type_id_{HolderTypeId::Unknown};
452+
bool is_const_{true};
453+
};
454+
376455
// Forward declarations
377456
struct type_info;
378457
struct value_and_holder;
@@ -423,6 +502,26 @@ struct instance {
423502
/// If true, get_internals().patients has an entry for this object
424503
bool has_patients : 1;
425504

505+
typedef void (*release_to_cpp_t)(instance* inst, holder_erased external_holder, object&& obj);
506+
typedef object (*reclaim_from_cpp_t)(instance* inst, holder_erased external_holder);
507+
508+
struct type_release_info_t {
509+
// Release an instance to C++ for pure C++ instances or Python-derived classes.
510+
release_to_cpp_t release_to_cpp = nullptr;
511+
512+
// For classes wrapped in `wrapper<>`. See `move_only_holder_caster` for more info.
513+
// Pure / direct C++ objects do not need any fancy releasing mechanisms. They are simply
514+
// unwrapped and passed back.
515+
bool can_derive_from_wrapper = false;
516+
517+
// The holder that is contained by this class.
518+
HolderTypeId holder_type_id = HolderTypeId::Unknown;
519+
};
520+
/// If the instance is a Python-derived type that is owned in C++, then this method
521+
/// will permit the instance to be reclaimed back by Python.
522+
// TODO(eric.cousineau): This may not be necessary. See note in `type_caster_generic::cast`.
523+
reclaim_from_cpp_t reclaim_from_cpp = nullptr;
524+
426525
/// Initializes all of the above type/values/holders data (but not the instance values themselves)
427526
void allocate_layout();
428527

include/pybind11/detail/internals.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ struct type_info {
108108
bool default_holder : 1;
109109
/* true if this is a type registered with py::module_local */
110110
bool module_local : 1;
111+
112+
instance::type_release_info_t release_info;
111113
};
112114

113115
/// Tracks the `internals` and `type_info` ABI version independent of the main library version

0 commit comments

Comments
 (0)