Skip to content

Commit 48f2527

Browse files
authored
[smart_holder] Bake smart_holder functionality into class_ and type_caster_base (#5257)
* Put bakein branch @ 18b72c0 on top of smart_holder branch: Commands used: ``` git checkout bakein git diff smart_holder > ~/zd git checkout smart_holder git checkout -b bakein_sh patch -p 1 < ~/zd git checkout smart_holder \ MANIFEST.in \ README.rst \ README_smart_holder.rst \ docs/advanced/smart_ptrs.rst \ ubench/holder_comparison.cpp \ ubench/holder_comparison.py \ ubench/holder_comparison_extract_sheet_data.py \ ubench/number_bucket.h \ ubench/python/number_bucket.clif git add -A ``` * Add back README_smart_holder.rst in tests/extra_python_package/test_files.py * Restore smart_holder_poc.h as-is on smart_holder branch (i.e. undo `PYBIND11_SMART_HOLDER_PADDING`, which was meant for stress-testing only). * Insert `std::move()` as suggested by @laramiel * `property_cpp_function_sh_*` named specializations, as suggested by @laramiel (#5257 (comment)) * Call `property_cpp_function_classic` member functions, rather than inlining the implementations. * Use `PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT` in holder_comparison.cpp (holder_comparison.py is NOT changed accordingly in this commit, i.e. can still only be run if the smart_holder functionality is available). * Systematically rename `loaded_as` to `load_as` (`shared_ptr`, `unique_ptr`) as suggested by @laramiel * Make change as suggested by @laramiel. This makes it much more obvious that the latest implementation of `smart_holder_from_unique_ptr()` accepts all existing `return_value_policy` enum values except `copy`. * Resolve `BAKEIN_WIP: Rewrite comment.` for `property_cpp_function_*` specializations. * Resolve `BAKEIN_WIP: Add comment to explain: This is meant for stress-testing only.` * Resolve all remaining BAKEIN_WIP (in pybind11/cast.h). Leave only two pairs of SMART_HOLDER_BAKEIN_FOLLOW_ON comments: refactoring of copyable_holder_caster, move_only_holder_caster. This is best left until after the smart_holder branch is merged into the master branch. * Remove obsolete `using holder_type = smart_holder;` in `load_helper` * Add SMART_HOLDER_BAKEIN_FOLLOW_ON comment for `internals::default_holder` * README_smart_holder.rst update (line count reduced from 356 to 123).
1 parent 6765d4e commit 48f2527

File tree

68 files changed

+1334
-1768
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+1334
-1768
lines changed

CMakeLists.txt

+1-2
Original file line numberDiff line numberDiff line change
@@ -154,10 +154,9 @@ set(PYBIND11_HEADERS
154154
include/pybind11/detail/init.h
155155
include/pybind11/detail/internals.h
156156
include/pybind11/detail/smart_holder_poc.h
157-
include/pybind11/detail/smart_holder_sfinae_hooks_only.h
158-
include/pybind11/detail/smart_holder_type_casters.h
159157
include/pybind11/detail/type_caster_base.h
160158
include/pybind11/detail/typeid.h
159+
include/pybind11/detail/using_smart_holder.h
161160
include/pybind11/detail/value_and_holder.h
162161
include/pybind11/attr.h
163162
include/pybind11/buffer_info.h

README_smart_holder.rst

+54-287
Large diffs are not rendered by default.

include/pybind11/attr.h

+4
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,10 @@ struct type_record {
331331
/// Is the class inheritable from python classes?
332332
bool is_final : 1;
333333

334+
#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT
335+
holder_enum_t holder_enum_v = holder_enum_t::undefined;
336+
#endif
337+
334338
PYBIND11_NOINLINE void add_base(const std::type_info &base, void *(*caster)(void *) ) {
335339
auto *base_info = detail::get_type_info(base, false);
336340
if (!base_info) {

include/pybind11/cast.h

+249-32
Large diffs are not rendered by default.

include/pybind11/detail/common.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@
99

1010
#pragma once
1111

12-
#define PYBIND11_VERSION_MAJOR 2
13-
#define PYBIND11_VERSION_MINOR 14
12+
#define PYBIND11_VERSION_MAJOR 3
13+
#define PYBIND11_VERSION_MINOR 0
1414
#define PYBIND11_VERSION_PATCH 0.dev1
1515

1616
// Similar to Python's convention: https://docs.python.org/3/c-api/apiabiversion.html
1717
// Additional convention: 0xD = dev
18-
#define PYBIND11_VERSION_HEX 0x020E00D1
18+
#define PYBIND11_VERSION_HEX 0x030000D1
1919

2020
// Define some generic pybind11 helper macros for warning management.
2121
//

include/pybind11/detail/init.h

+22-19
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#pragma once
1111

1212
#include "class.h"
13-
#include "smart_holder_sfinae_hooks_only.h"
13+
#include "using_smart_holder.h"
1414

1515
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
1616

@@ -156,9 +156,7 @@ void construct(value_and_holder &v_h, Alias<Class> *alias_ptr, bool) {
156156
// holder. This also handles types like std::shared_ptr<T> and std::unique_ptr<T> where T is a
157157
// derived type (through those holder's implicit conversion from derived class holder
158158
// constructors).
159-
template <typename Class,
160-
detail::enable_if_t<!detail::type_uses_smart_holder_type_caster<Cpp<Class>>::value, int>
161-
= 0>
159+
template <typename Class, detail::enable_if_t<!is_smart_holder<Holder<Class>>::value, int> = 0>
162160
void construct(value_and_holder &v_h, Holder<Class> holder, bool need_alias) {
163161
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias);
164162
auto *ptr = holder_helper<Holder<Class>>::get(holder);
@@ -200,10 +198,18 @@ void construct(value_and_holder &v_h, Alias<Class> &&result, bool) {
200198
v_h.value_ptr() = new Alias<Class>(std::move(result));
201199
}
202200

201+
#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT
202+
203+
template <typename T, typename D>
204+
smart_holder init_smart_holder_from_unique_ptr(std::unique_ptr<T, D> &&unq_ptr,
205+
bool void_cast_raw_ptr) {
206+
void *void_ptr = void_cast_raw_ptr ? static_cast<void *>(unq_ptr.get()) : nullptr;
207+
return smart_holder::from_unique_ptr(std::move(unq_ptr), void_ptr);
208+
}
209+
203210
template <typename Class,
204211
typename D = std::default_delete<Cpp<Class>>,
205-
detail::enable_if_t<detail::type_uses_smart_holder_type_caster<Cpp<Class>>::value, int>
206-
= 0>
212+
detail::enable_if_t<is_smart_holder<Holder<Class>>::value, int> = 0>
207213
void construct(value_and_holder &v_h, std::unique_ptr<Cpp<Class>, D> &&unq_ptr, bool need_alias) {
208214
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias);
209215
auto *ptr = unq_ptr.get();
@@ -217,30 +223,27 @@ void construct(value_and_holder &v_h, std::unique_ptr<Cpp<Class>, D> &&unq_ptr,
217223
// trampoline Python object alive. For types that don't inherit from enable_shared_from_this
218224
// it does not matter if void_cast_raw_ptr is true or false, therefore it's not necessary
219225
// to also inspect the type.
220-
auto smhldr = type_caster<Cpp<Class>>::smart_holder_from_unique_ptr(
226+
auto smhldr = init_smart_holder_from_unique_ptr(
221227
std::move(unq_ptr), /*void_cast_raw_ptr*/ Class::has_alias && is_alias<Class>(ptr));
222228
v_h.value_ptr() = ptr;
223229
v_h.type->init_instance(v_h.inst, &smhldr);
224230
}
225231

226232
template <typename Class,
227233
typename D = std::default_delete<Alias<Class>>,
228-
detail::enable_if_t<detail::type_uses_smart_holder_type_caster<Alias<Class>>::value, int>
229-
= 0>
234+
detail::enable_if_t<is_smart_holder<Holder<Class>>::value, int> = 0>
230235
void construct(value_and_holder &v_h,
231236
std::unique_ptr<Alias<Class>, D> &&unq_ptr,
232237
bool /*need_alias*/) {
233238
auto *ptr = unq_ptr.get();
234239
no_nullptr(ptr);
235-
auto smhldr = type_caster<Alias<Class>>::smart_holder_from_unique_ptr(
236-
std::move(unq_ptr), /*void_cast_raw_ptr*/ true);
240+
auto smhldr
241+
= init_smart_holder_from_unique_ptr(std::move(unq_ptr), /*void_cast_raw_ptr*/ true);
237242
v_h.value_ptr() = ptr;
238243
v_h.type->init_instance(v_h.inst, &smhldr);
239244
}
240245

241-
template <typename Class,
242-
detail::enable_if_t<detail::type_uses_smart_holder_type_caster<Cpp<Class>>::value, int>
243-
= 0>
246+
template <typename Class, detail::enable_if_t<is_smart_holder<Holder<Class>>::value, int> = 0>
244247
void construct(value_and_holder &v_h, std::shared_ptr<Cpp<Class>> &&shd_ptr, bool need_alias) {
245248
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias);
246249
auto *ptr = shd_ptr.get();
@@ -249,24 +252,24 @@ void construct(value_and_holder &v_h, std::shared_ptr<Cpp<Class>> &&shd_ptr, boo
249252
throw type_error("pybind11::init(): construction failed: returned std::shared_ptr pointee "
250253
"is not an alias instance");
251254
}
252-
auto smhldr = type_caster<Cpp<Class>>::smart_holder_from_shared_ptr(shd_ptr);
255+
auto smhldr = smart_holder::from_shared_ptr(shd_ptr);
253256
v_h.value_ptr() = ptr;
254257
v_h.type->init_instance(v_h.inst, &smhldr);
255258
}
256259

257-
template <typename Class,
258-
detail::enable_if_t<detail::type_uses_smart_holder_type_caster<Alias<Class>>::value, int>
259-
= 0>
260+
template <typename Class, detail::enable_if_t<is_smart_holder<Holder<Class>>::value, int> = 0>
260261
void construct(value_and_holder &v_h,
261262
std::shared_ptr<Alias<Class>> &&shd_ptr,
262263
bool /*need_alias*/) {
263264
auto *ptr = shd_ptr.get();
264265
no_nullptr(ptr);
265-
auto smhldr = type_caster<Alias<Class>>::smart_holder_from_shared_ptr(shd_ptr);
266+
auto smhldr = smart_holder::from_shared_ptr(shd_ptr);
266267
v_h.value_ptr() = ptr;
267268
v_h.type->init_instance(v_h.inst, &smhldr);
268269
}
269270

271+
#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT
272+
270273
// Implementing class for py::init<...>()
271274
template <typename... Args>
272275
struct constructor {

include/pybind11/detail/internals.h

+26-16
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
#endif
1717

1818
#include "../pytypes.h"
19-
#include "smart_holder_sfinae_hooks_only.h"
2019

2120
#include <exception>
2221
#include <mutex>
@@ -37,7 +36,9 @@
3736
/// further ABI-incompatible changes may be made before the ABI is officially
3837
/// changed to the new version.
3938
#ifndef PYBIND11_INTERNALS_VERSION
40-
# if PY_VERSION_HEX >= 0x030C0000 || defined(_MSC_VER)
39+
# if PYBIND11_VERSION_MAJOR >= 3
40+
# define PYBIND11_INTERNALS_VERSION 6
41+
# elif PY_VERSION_HEX >= 0x030C0000 || defined(_MSC_VER)
4142
// Version bump for Python 3.12+, before first 3.12 beta release.
4243
// Version bump for MSVC piggy-backed on PR #4779. See comments there.
4344
# define PYBIND11_INTERNALS_VERSION 5
@@ -237,6 +238,20 @@ struct internals {
237238
}
238239
};
239240

241+
#if PYBIND11_INTERNALS_VERSION >= 6
242+
243+
# define PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT
244+
245+
enum class holder_enum_t : uint8_t {
246+
undefined,
247+
std_unique_ptr, // Default, lacking interop with std::shared_ptr.
248+
std_shared_ptr, // Lacking interop with std::unique_ptr.
249+
smart_holder, // Full std::unique_ptr / std::shared_ptr interop.
250+
custom_holder,
251+
};
252+
253+
#endif
254+
240255
/// Additional type information which does not fit into the PyTypeObject.
241256
/// Changes to this struct also require bumping `PYBIND11_INTERNALS_VERSION`.
242257
struct type_info {
@@ -260,9 +275,14 @@ struct type_info {
260275
/* True if there is no multiple inheritance in this type's inheritance tree */
261276
bool simple_ancestors : 1;
262277
/* for base vs derived holder_type checks */
278+
// SMART_HOLDER_BAKEIN_FOLLOW_ON: Remove default_holder member here and
279+
// produce better error messages in the places where it is currently used.
263280
bool default_holder : 1;
264281
/* true if this is a type registered with py::module_local */
265282
bool module_local : 1;
283+
#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT
284+
holder_enum_t holder_enum_v = holder_enum_t::undefined;
285+
#endif
266286
};
267287

268288
/// On MSVC, debug and release builds are not ABI-compatible!
@@ -322,25 +342,15 @@ struct type_info {
322342
# define PYBIND11_INTERNALS_KIND ""
323343
#endif
324344

325-
/// See README_smart_holder.rst:
326-
/// Classic / Conservative / Progressive cross-module compatibility
327-
#ifndef PYBIND11_INTERNALS_SH_DEF
328-
# if defined(PYBIND11_USE_SMART_HOLDER_AS_DEFAULT)
329-
# define PYBIND11_INTERNALS_SH_DEF "_sh_def"
330-
# else
331-
# define PYBIND11_INTERNALS_SH_DEF ""
332-
# endif
333-
#endif
334-
335345
#define PYBIND11_INTERNALS_ID \
336346
"__pybind11_internals_v" PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) \
337-
PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI \
338-
PYBIND11_BUILD_TYPE PYBIND11_INTERNALS_SH_DEF "__"
347+
PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB \
348+
PYBIND11_BUILD_ABI PYBIND11_BUILD_TYPE "__"
339349

340350
#define PYBIND11_MODULE_LOCAL_ID \
341351
"__pybind11_module_local_v" PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) \
342-
PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI \
343-
PYBIND11_BUILD_TYPE PYBIND11_INTERNALS_SH_DEF "__"
352+
PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB \
353+
PYBIND11_BUILD_ABI PYBIND11_BUILD_TYPE "__"
344354

345355
/// Each module locally stores a pointer to the `internals` data. The data
346356
/// itself is shared among modules with the same `PYBIND11_INTERNALS_ID`.

include/pybind11/detail/smart_holder_sfinae_hooks_only.h

-46
This file was deleted.

0 commit comments

Comments
 (0)