Merge branch 'smart_holder' into pr2621_patched_sh

This commit is contained in:
Ralf W. Grosse-Kunstleve 2024-08-22 20:42:26 -07:00
commit 62c7a35aba
27 changed files with 220 additions and 56 deletions

View File

@ -162,7 +162,7 @@ the declaration
.. code-block:: cpp .. code-block:: cpp
PYBIND11_MAKE_OPAQUE(std::vector<int>); PYBIND11_MAKE_OPAQUE(std::vector<int>)
before any binding code (e.g. invocations to ``class_::def()``, etc.). This before any binding code (e.g. invocations to ``class_::def()``, etc.). This
macro must be specified at the top level (and outside of any namespaces), since macro must be specified at the top level (and outside of any namespaces), since
@ -207,8 +207,8 @@ The following example showcases usage of :file:`pybind11/stl_bind.h`:
// Don't forget this // Don't forget this
#include <pybind11/stl_bind.h> #include <pybind11/stl_bind.h>
PYBIND11_MAKE_OPAQUE(std::vector<int>); PYBIND11_MAKE_OPAQUE(std::vector<int>)
PYBIND11_MAKE_OPAQUE(std::map<std::string, double>); PYBIND11_MAKE_OPAQUE(std::map<std::string, double>)
// ... // ...

View File

@ -131,7 +131,7 @@ top namespace level before any binding code:
.. code-block:: cpp .. code-block:: cpp
PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr<T>); PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr<T>)
The first argument of :func:`PYBIND11_DECLARE_HOLDER_TYPE` should be a The first argument of :func:`PYBIND11_DECLARE_HOLDER_TYPE` should be a
placeholder name that is used as a template parameter of the second argument. placeholder name that is used as a template parameter of the second argument.
@ -143,7 +143,7 @@ by default. Specify
.. code-block:: cpp .. code-block:: cpp
PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr<T>, true); PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr<T>, true)
if ``SmartPtr<T>`` can always be initialized from a ``T*`` pointer without the if ``SmartPtr<T>`` can always be initialized from a ``T*`` pointer without the
risk of inconsistencies (such as multiple independent ``SmartPtr`` instances risk of inconsistencies (such as multiple independent ``SmartPtr`` instances
@ -161,7 +161,7 @@ specialized:
.. code-block:: cpp .. code-block:: cpp
// Always needed for custom holder types // Always needed for custom holder types
PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr<T>); PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr<T>)
// Only needed if the type's `.get()` goes by another name // Only needed if the type's `.get()` goes by another name
namespace PYBIND11_NAMESPACE { namespace detail { namespace PYBIND11_NAMESPACE { namespace detail {

View File

@ -78,6 +78,13 @@ For brevity, all code examples assume that the following two lines are present:
namespace py = pybind11; namespace py = pybind11;
.. note::
``pybind11/pybind11.h`` includes ``Python.h``, as such it must be the first file
included in any source file or header for `the same reasons as Python.h`_.
.. _`the same reasons as Python.h`: https://docs.python.org/3/extending/extending.html#a-simple-example
Some features may require additional headers, but those will be specified as needed. Some features may require additional headers, but those will be specified as needed.
.. _simple_example: .. _simple_example:

View File

@ -28,6 +28,23 @@ New Features:
* Support for CMake older than 3.15 removed. CMake 3.15-3.30 supported. * Support for CMake older than 3.15 removed. CMake 3.15-3.30 supported.
`#5304 <https://github.com/pybind/pybind11/pull/5304>`_ `#5304 <https://github.com/pybind/pybind11/pull/5304>`_
* The ``array_caster`` in pybind11/stl.h was enhanced to support value types that are not default-constructible.
`#5305 <https://github.com/pybind/pybind11/pull/5305>`_
Version 2.13.5 (August 22, 2024)
--------------------------------
Bug fixes:
* Fix includes when using Windows long paths (``\\?\`` prefix).
`#5321 <https://github.com/pybind/pybind11/pull/5321>`_
* Support ``-Wpedantic`` in C++20 mode.
`#5322 <https://github.com/pybind/pybind11/pull/5322>`_
* Fix and test ``<ranges>`` support for ``py::tuple`` and ``py::list``.
`#5314 <https://github.com/pybind/pybind11/pull/5314>`_
Version 2.13.4 (August 14, 2024) Version 2.13.4 (August 14, 2024)
-------------------------------- --------------------------------

View File

@ -858,8 +858,12 @@ public:
using base::value; using base::value;
bool load(handle src, bool convert) { bool load(handle src, bool convert) {
return base::template load_impl<copyable_holder_caster<type, std::shared_ptr<type>>>( if (base::template load_impl<copyable_holder_caster<type, std::shared_ptr<type>>>(
src, convert); src, convert)) {
sh_load_helper.maybe_set_python_instance_is_alias(src);
return true;
}
return false;
} }
explicit operator std::shared_ptr<type> *() { explicit operator std::shared_ptr<type> *() {
@ -914,6 +918,7 @@ protected:
void load_value(value_and_holder &&v_h) { void load_value(value_and_holder &&v_h) {
if (typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder) { if (typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder) {
sh_load_helper.loaded_v_h = v_h; sh_load_helper.loaded_v_h = v_h;
sh_load_helper.was_populated = true;
value = sh_load_helper.get_void_ptr_or_nullptr(); value = sh_load_helper.get_void_ptr_or_nullptr();
return; return;
} }
@ -1041,14 +1046,19 @@ public:
} }
bool load(handle src, bool convert) { bool load(handle src, bool convert) {
return base::template load_impl< if (base::template load_impl<
move_only_holder_caster<type, std::unique_ptr<type, deleter>>>(src, convert); move_only_holder_caster<type, std::unique_ptr<type, deleter>>>(src, convert)) {
sh_load_helper.maybe_set_python_instance_is_alias(src);
return true;
}
return false;
} }
void load_value(value_and_holder &&v_h) { void load_value(value_and_holder &&v_h) {
if (typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder) { if (typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder) {
sh_load_helper.loaded_v_h = v_h; sh_load_helper.loaded_v_h = v_h;
sh_load_helper.loaded_v_h.type = typeinfo; sh_load_helper.loaded_v_h.type = typeinfo;
sh_load_helper.was_populated = true;
value = sh_load_helper.get_void_ptr_or_nullptr(); value = sh_load_helper.get_void_ptr_or_nullptr();
return; return;
} }

View File

@ -9,8 +9,8 @@
#pragma once #pragma once
#include "../attr.h" #include <pybind11/attr.h>
#include "../options.h" #include <pybind11/options.h>
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail) PYBIND11_NAMESPACE_BEGIN(detail)

View File

@ -479,6 +479,8 @@ PYBIND11_WARNING_POP
} }
\endrst */ \endrst */
PYBIND11_WARNING_PUSH
PYBIND11_WARNING_DISABLE_CLANG("-Wgnu-zero-variadic-macro-arguments")
#define PYBIND11_MODULE(name, variable, ...) \ #define PYBIND11_MODULE(name, variable, ...) \
static ::pybind11::module_::module_def PYBIND11_CONCAT(pybind11_module_def_, name) \ static ::pybind11::module_::module_def PYBIND11_CONCAT(pybind11_module_def_, name) \
PYBIND11_MAYBE_UNUSED; \ PYBIND11_MAYBE_UNUSED; \
@ -499,6 +501,7 @@ PYBIND11_WARNING_POP
PYBIND11_CATCH_INIT_EXCEPTIONS \ PYBIND11_CATCH_INIT_EXCEPTIONS \
} \ } \
void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ & (variable)) void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ & (variable))
PYBIND11_WARNING_POP
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
@ -637,6 +640,11 @@ struct instance {
bool simple_instance_registered : 1; bool simple_instance_registered : 1;
/// If true, get_internals().patients has an entry for this object /// If true, get_internals().patients has an entry for this object
bool has_patients : 1; bool has_patients : 1;
// Cannot use PYBIND11_INTERNALS_VERSION >= 6 here without refactoring.
#if PYBIND11_VERSION_MAJOR >= 3
/// If true, this Python object needs to be kept alive for the lifetime of the C++ value.
bool is_alias : 1;
#endif
/// Initializes all of the above type/values/holders data (but not the instance values /// Initializes all of the above type/values/holders data (but not the instance values
/// themselves) /// themselves)

View File

@ -12,10 +12,10 @@
#include "common.h" #include "common.h"
#if defined(PYBIND11_SIMPLE_GIL_MANAGEMENT) #if defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
# include "../gil.h" # include <pybind11/gil.h>
#endif #endif
#include "../pytypes.h" #include <pybind11/pytypes.h>
#include <exception> #include <exception>
#include <mutex> #include <mutex>

View File

@ -136,7 +136,6 @@ struct smart_holder {
bool vptr_is_external_shared_ptr : 1; bool vptr_is_external_shared_ptr : 1;
bool is_populated : 1; bool is_populated : 1;
bool is_disowned : 1; bool is_disowned : 1;
bool pointee_depends_on_holder_owner : 1; // SMART_HOLDER_WIP: See PR #2839.
// Design choice: smart_holder is movable but not copyable. // Design choice: smart_holder is movable but not copyable.
smart_holder(smart_holder &&) = default; smart_holder(smart_holder &&) = default;
@ -146,8 +145,7 @@ struct smart_holder {
smart_holder() smart_holder()
: vptr_is_using_noop_deleter{false}, vptr_is_using_builtin_delete{false}, : vptr_is_using_noop_deleter{false}, vptr_is_using_builtin_delete{false},
vptr_is_external_shared_ptr{false}, is_populated{false}, is_disowned{false}, vptr_is_external_shared_ptr{false}, is_populated{false}, is_disowned{false} {}
pointee_depends_on_holder_owner{false} {}
bool has_pointee() const { return vptr != nullptr; } bool has_pointee() const { return vptr != nullptr; }

View File

@ -9,9 +9,10 @@
#pragma once #pragma once
#include "../gil.h" #include <pybind11/gil.h>
#include "../pytypes.h" #include <pybind11/pytypes.h>
#include "../trampoline_self_life_support.h" #include <pybind11/trampoline_self_life_support.h>
#include "common.h" #include "common.h"
#include "descr.h" #include "descr.h"
#include "dynamic_raw_ptr_cast_if_possible.h" #include "dynamic_raw_ptr_cast_if_possible.h"
@ -704,6 +705,15 @@ inline std::unique_ptr<T, D> unique_with_deleter(T *raw_ptr, std::unique_ptr<D>
template <typename T> template <typename T>
struct load_helper : value_and_holder_helper { struct load_helper : value_and_holder_helper {
bool was_populated = false;
bool python_instance_is_alias = false;
void maybe_set_python_instance_is_alias(handle src) {
if (was_populated) {
python_instance_is_alias = reinterpret_cast<instance *>(src.ptr())->is_alias;
}
}
static std::shared_ptr<T> make_shared_ptr_with_responsible_parent(T *raw_ptr, handle parent) { static std::shared_ptr<T> make_shared_ptr_with_responsible_parent(T *raw_ptr, handle parent) {
return std::shared_ptr<T>(raw_ptr, shared_ptr_parent_life_support(parent.ptr())); return std::shared_ptr<T>(raw_ptr, shared_ptr_parent_life_support(parent.ptr()));
} }
@ -724,7 +734,7 @@ struct load_helper : value_and_holder_helper {
throw std::runtime_error("Non-owning holder (load_as_shared_ptr)."); throw std::runtime_error("Non-owning holder (load_as_shared_ptr).");
} }
auto *type_raw_ptr = static_cast<T *>(void_raw_ptr); auto *type_raw_ptr = static_cast<T *>(void_raw_ptr);
if (hld.pointee_depends_on_holder_owner) { if (python_instance_is_alias) {
auto *vptr_gd_ptr = std::get_deleter<pybindit::memory::guarded_delete>(hld.vptr); auto *vptr_gd_ptr = std::get_deleter<pybindit::memory::guarded_delete>(hld.vptr);
if (vptr_gd_ptr != nullptr) { if (vptr_gd_ptr != nullptr) {
std::shared_ptr<void> released_ptr = vptr_gd_ptr->released_ptr.lock(); std::shared_ptr<void> released_ptr = vptr_gd_ptr->released_ptr.lock();
@ -778,7 +788,7 @@ struct load_helper : value_and_holder_helper {
auto *self_life_support auto *self_life_support
= dynamic_raw_ptr_cast_if_possible<trampoline_self_life_support>(raw_type_ptr); = dynamic_raw_ptr_cast_if_possible<trampoline_self_life_support>(raw_type_ptr);
if (self_life_support == nullptr && holder().pointee_depends_on_holder_owner) { if (self_life_support == nullptr && python_instance_is_alias) {
throw value_error("Alias class (also known as trampoline) does not inherit from " throw value_error("Alias class (also known as trampoline) does not inherit from "
"py::trampoline_self_life_support, therefore the ownership of this " "py::trampoline_self_life_support, therefore the ownership of this "
"instance cannot safely be transferred to C++."); "instance cannot safely be transferred to C++.");

View File

@ -9,7 +9,8 @@
#pragma once #pragma once
#include "../numpy.h" #include <pybind11/numpy.h>
#include "common.h" #include "common.h"
/* HINT: To suppress warnings originating from the Eigen headers, use -isystem. /* HINT: To suppress warnings originating from the Eigen headers, use -isystem.

View File

@ -7,7 +7,8 @@
#pragma once #pragma once
#include "../numpy.h" #include <pybind11/numpy.h>
#include "common.h" #include "common.h"
#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) #if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER)

View File

@ -2271,7 +2271,8 @@ private:
} }
auto *uninitialized_location = std::addressof(v_h.holder<holder_type>()); auto *uninitialized_location = std::addressof(v_h.holder<holder_type>());
auto *value_ptr_w_t = v_h.value_ptr<type>(); auto *value_ptr_w_t = v_h.value_ptr<type>();
bool pointee_depends_on_holder_owner // Try downcast from `type` to `type_alias`:
inst->is_alias
= detail::dynamic_raw_ptr_cast_if_possible<type_alias>(value_ptr_w_t) != nullptr; = detail::dynamic_raw_ptr_cast_if_possible<type_alias>(value_ptr_w_t) != nullptr;
if (holder_void_ptr) { if (holder_void_ptr) {
// Note: inst->owned ignored. // Note: inst->owned ignored.
@ -2281,14 +2282,12 @@ private:
uninitialized_location, value_ptr_w_t, value_ptr_w_t)) { uninitialized_location, value_ptr_w_t, value_ptr_w_t)) {
if (inst->owned) { if (inst->owned) {
new (uninitialized_location) holder_type(holder_type::from_raw_ptr_take_ownership( new (uninitialized_location) holder_type(holder_type::from_raw_ptr_take_ownership(
value_ptr_w_t, /*void_cast_raw_ptr*/ pointee_depends_on_holder_owner)); value_ptr_w_t, /*void_cast_raw_ptr*/ inst->is_alias));
} else { } else {
new (uninitialized_location) new (uninitialized_location)
holder_type(holder_type::from_raw_ptr_unowned(value_ptr_w_t)); holder_type(holder_type::from_raw_ptr_unowned(value_ptr_w_t));
} }
} }
v_h.holder<holder_type>().pointee_depends_on_holder_owner
= pointee_depends_on_holder_owner;
v_h.set_holder_constructed(); v_h.set_holder_constructed();
} }

View File

@ -1259,6 +1259,7 @@ protected:
using pointer = arrow_proxy<const handle>; using pointer = arrow_proxy<const handle>;
sequence_fast_readonly(handle obj, ssize_t n) : ptr(PySequence_Fast_ITEMS(obj.ptr()) + n) {} sequence_fast_readonly(handle obj, ssize_t n) : ptr(PySequence_Fast_ITEMS(obj.ptr()) + n) {}
sequence_fast_readonly() = default;
// NOLINTNEXTLINE(readability-const-return-type) // PR #3263 // NOLINTNEXTLINE(readability-const-return-type) // PR #3263
reference dereference() const { return *ptr; } reference dereference() const { return *ptr; }
@ -1281,6 +1282,7 @@ protected:
using pointer = arrow_proxy<const sequence_accessor>; using pointer = arrow_proxy<const sequence_accessor>;
sequence_slow_readwrite(handle obj, ssize_t index) : obj(obj), index(index) {} sequence_slow_readwrite(handle obj, ssize_t index) : obj(obj), index(index) {}
sequence_slow_readwrite() = default;
reference dereference() const { return {obj, static_cast<size_t>(index)}; } reference dereference() const { return {obj, static_cast<size_t>(index)}; }
void increment() { ++index; } void increment() { ++index; }

View File

@ -4,11 +4,11 @@
#pragma once #pragma once
#include "../pybind11.h" #include <pybind11/cast.h>
#include "../detail/common.h" #include <pybind11/detail/common.h>
#include "../detail/descr.h" #include <pybind11/detail/descr.h>
#include "../cast.h" #include <pybind11/pybind11.h>
#include "../pytypes.h" #include <pybind11/pytypes.h>
#include <string> #include <string>

View File

@ -400,6 +400,9 @@ function(pybind11_enable_warnings target_name)
-Wdeprecated -Wdeprecated
-Wundef -Wundef
-Wnon-virtual-dtor) -Wnon-virtual-dtor)
if(DEFINED CMAKE_CXX_STANDARD AND NOT CMAKE_CXX_STANDARD VERSION_LESS 20)
target_compile_options(${target_name} PRIVATE -Wpedantic)
endif()
endif() endif()
if(PYBIND11_WERROR) if(PYBIND11_WERROR)

View File

@ -56,13 +56,13 @@ private:
std::string message = ""; std::string message = "";
}; };
PYBIND11_MAKE_OPAQUE(LocalVec); PYBIND11_MAKE_OPAQUE(LocalVec)
PYBIND11_MAKE_OPAQUE(LocalVec2); PYBIND11_MAKE_OPAQUE(LocalVec2)
PYBIND11_MAKE_OPAQUE(LocalMap); PYBIND11_MAKE_OPAQUE(LocalMap)
PYBIND11_MAKE_OPAQUE(NonLocalVec); PYBIND11_MAKE_OPAQUE(NonLocalVec)
// PYBIND11_MAKE_OPAQUE(NonLocalVec2); // same type as LocalVec2 // PYBIND11_MAKE_OPAQUE(NonLocalVec2) // same type as LocalVec2
PYBIND11_MAKE_OPAQUE(NonLocalMap); PYBIND11_MAKE_OPAQUE(NonLocalMap)
PYBIND11_MAKE_OPAQUE(NonLocalMap2); PYBIND11_MAKE_OPAQUE(NonLocalMap2)
// Simple bindings (used with the above): // Simple bindings (used with the above):
template <typename T, int Adjust = 0, typename... Args> template <typename T, int Adjust = 0, typename... Args>
@ -70,7 +70,7 @@ py::class_<T> bind_local(Args &&...args) {
return py::class_<T>(std::forward<Args>(args)...).def(py::init<int>()).def("get", [](T &i) { return py::class_<T>(std::forward<Args>(args)...).def(py::init<int>()).def("get", [](T &i) {
return i.i + Adjust; return i.i + Adjust;
}); });
}; }
// Simulate a foreign library base class (to match the example in the docs): // Simulate a foreign library base class (to match the example in the docs):
namespace pets { namespace pets {

View File

@ -148,7 +148,7 @@ TEST_SUBMODULE(callbacks, m) {
m.def("dummy_function2", [](int i, int j) { return i + j; }); m.def("dummy_function2", [](int i, int j) { return i + j; });
m.def( m.def(
"roundtrip", "roundtrip",
[](std::function<int(int)> f, bool expect_none = false) { [](std::function<int(int)> f, bool expect_none) {
if (expect_none && f) { if (expect_none && f) {
throw std::runtime_error("Expected None to be converted to empty std::function"); throw std::runtime_error("Expected None to be converted to empty std::function");
} }

View File

@ -55,7 +55,7 @@ void reset_refs() {
} }
// Returns element 2,1 from a matrix (used to test copy/nocopy) // Returns element 2,1 from a matrix (used to test copy/nocopy)
double get_elem(const Eigen::Ref<const Eigen::MatrixXd> &m) { return m(2, 1); }; double get_elem(const Eigen::Ref<const Eigen::MatrixXd> &m) { return m(2, 1); }
// Returns a matrix with 10*r + 100*c added to each matrix element (to help test that the matrix // Returns a matrix with 10*r + 100*c added to each matrix element (to help test that the matrix
// reference is referencing rows/columns correctly). // reference is referencing rows/columns correctly).
@ -76,7 +76,7 @@ struct CustomOperatorNew {
Eigen::Matrix4d a = Eigen::Matrix4d::Zero(); Eigen::Matrix4d a = Eigen::Matrix4d::Zero();
Eigen::Matrix4d b = Eigen::Matrix4d::Identity(); Eigen::Matrix4d b = Eigen::Matrix4d::Identity();
EIGEN_MAKE_ALIGNED_OPERATOR_NEW; EIGEN_MAKE_ALIGNED_OPERATOR_NEW
}; };
TEST_SUBMODULE(eigen_matrix, m) { TEST_SUBMODULE(eigen_matrix, m) {

View File

@ -18,7 +18,7 @@
// This also deliberately doesn't use the below StringList type alias to test // This also deliberately doesn't use the below StringList type alias to test
// that MAKE_OPAQUE can handle a type containing a `,`. (The `std::allocator` // that MAKE_OPAQUE can handle a type containing a `,`. (The `std::allocator`
// bit is just the default `std::vector` allocator). // bit is just the default `std::vector` allocator).
PYBIND11_MAKE_OPAQUE(std::vector<std::string, std::allocator<std::string>>); PYBIND11_MAKE_OPAQUE(std::vector<std::string, std::allocator<std::string>>)
using StringList = std::vector<std::string, std::allocator<std::string>>; using StringList = std::vector<std::string, std::allocator<std::string>>;

View File

@ -13,6 +13,14 @@
#include <utility> #include <utility>
//__has_include has been part of C++17, no need to check it
#if defined(PYBIND11_CPP20) && __has_include(<ranges>)
# if !defined(PYBIND11_COMPILER_CLANG) || __clang_major__ >= 16 // llvm/llvm-project#52696
# define PYBIND11_TEST_PYTYPES_HAS_RANGES
# include <ranges>
# endif
#endif
namespace external { namespace external {
namespace detail { namespace detail {
bool check(PyObject *o) { return PyFloat_Check(o) != 0; } bool check(PyObject *o) { return PyFloat_Check(o) != 0; }
@ -923,4 +931,59 @@ TEST_SUBMODULE(pytypes, m) {
#else #else
m.attr("defined_PYBIND11_TYPING_H_HAS_STRING_LITERAL") = false; m.attr("defined_PYBIND11_TYPING_H_HAS_STRING_LITERAL") = false;
#endif #endif
#if defined(PYBIND11_TEST_PYTYPES_HAS_RANGES)
// test_tuple_ranges
m.def("tuple_iterator_default_initialization", []() {
using TupleIterator = decltype(std::declval<py::tuple>().begin());
static_assert(std::random_access_iterator<TupleIterator>);
return TupleIterator{} == TupleIterator{};
});
m.def("transform_tuple_plus_one", [](py::tuple &tpl) {
py::list ret{};
for (auto it : tpl | std::views::transform([](auto &o) { return py::cast<int>(o) + 1; })) {
ret.append(py::int_(it));
}
return ret;
});
// test_list_ranges
m.def("list_iterator_default_initialization", []() {
using ListIterator = decltype(std::declval<py::list>().begin());
static_assert(std::random_access_iterator<ListIterator>);
return ListIterator{} == ListIterator{};
});
m.def("transform_list_plus_one", [](py::list &lst) {
py::list ret{};
for (auto it : lst | std::views::transform([](auto &o) { return py::cast<int>(o) + 1; })) {
ret.append(py::int_(it));
}
return ret;
});
// test_dict_ranges
m.def("dict_iterator_default_initialization", []() {
using DictIterator = decltype(std::declval<py::dict>().begin());
static_assert(std::forward_iterator<DictIterator>);
return DictIterator{} == DictIterator{};
});
m.def("transform_dict_plus_one", [](py::dict &dct) {
py::list ret{};
for (auto it : dct | std::views::transform([](auto &o) {
return std::pair{py::cast<int>(o.first) + 1,
py::cast<int>(o.second) + 1};
})) {
ret.append(py::make_tuple(py::int_(it.first), py::int_(it.second)));
}
return ret;
});
m.attr("defined_PYBIND11_TEST_PYTYPES_HAS_RANGES") = true;
#else
m.attr("defined_PYBIND11_TEST_PYTYPES_HAS_RANGES") = false;
#endif
} }

View File

@ -1048,3 +1048,45 @@ def test_typevar(doc):
assert doc(m.annotate_listT_to_T) == "annotate_listT_to_T(arg0: list[T]) -> T" assert doc(m.annotate_listT_to_T) == "annotate_listT_to_T(arg0: list[T]) -> T"
assert doc(m.annotate_object_to_T) == "annotate_object_to_T(arg0: object) -> T" assert doc(m.annotate_object_to_T) == "annotate_object_to_T(arg0: object) -> T"
@pytest.mark.skipif(
not m.defined_PYBIND11_TEST_PYTYPES_HAS_RANGES,
reason="<ranges> not available.",
)
@pytest.mark.parametrize(
("tested_tuple", "expected"),
[((1,), [2]), ((3, 4), [4, 5]), ((7, 8, 9), [8, 9, 10])],
)
def test_tuple_ranges(tested_tuple, expected):
assert m.tuple_iterator_default_initialization()
assert m.transform_tuple_plus_one(tested_tuple) == expected
@pytest.mark.skipif(
not m.defined_PYBIND11_TEST_PYTYPES_HAS_RANGES,
reason="<ranges> not available.",
)
@pytest.mark.parametrize(
("tested_list", "expected"), [([1], [2]), ([3, 4], [4, 5]), ([7, 8, 9], [8, 9, 10])]
)
def test_list_ranges(tested_list, expected):
assert m.list_iterator_default_initialization()
assert m.transform_list_plus_one(tested_list) == expected
@pytest.mark.skipif(
not m.defined_PYBIND11_TEST_PYTYPES_HAS_RANGES,
reason="<ranges> not available.",
)
@pytest.mark.parametrize(
("tested_dict", "expected"),
[
({1: 2}, [(2, 3)]),
({3: 4, 5: 6}, [(4, 5), (6, 7)]),
({7: 8, 9: 10, 11: 12}, [(8, 9), (10, 11), (12, 13)]),
],
)
def test_dict_ranges(tested_dict, expected):
assert m.dict_iterator_default_initialization()
assert m.transform_dict_plus_one(tested_dict) == expected

View File

@ -86,8 +86,8 @@ private:
}; };
using NonCopyableIntPair = std::pair<NonCopyableInt, NonCopyableInt>; using NonCopyableIntPair = std::pair<NonCopyableInt, NonCopyableInt>;
PYBIND11_MAKE_OPAQUE(std::vector<NonCopyableInt>); PYBIND11_MAKE_OPAQUE(std::vector<NonCopyableInt>)
PYBIND11_MAKE_OPAQUE(std::vector<NonCopyableIntPair>); PYBIND11_MAKE_OPAQUE(std::vector<NonCopyableIntPair>)
template <typename PythonType> template <typename PythonType>
py::list test_random_access_iterator(PythonType x) { py::list test_random_access_iterator(PythonType x) {

View File

@ -11,6 +11,9 @@
#include "object.h" #include "object.h"
#include "pybind11_tests.h" #include "pybind11_tests.h"
// This breaks on PYBIND11_DECLARE_HOLDER_TYPE
PYBIND11_WARNING_DISABLE_GCC("-Wpedantic")
namespace { namespace {
// This is just a wrapper around unique_ptr, but with extra fields to deliberately bloat up the // This is just a wrapper around unique_ptr, but with extra fields to deliberately bloat up the
@ -279,13 +282,13 @@ struct holder_helper<ref<T>> {
} // namespace PYBIND11_NAMESPACE } // namespace PYBIND11_NAMESPACE
// Make pybind aware of the ref-counted wrapper type (s): // Make pybind aware of the ref-counted wrapper type (s):
PYBIND11_DECLARE_HOLDER_TYPE(T, ref<T>, true); PYBIND11_DECLARE_HOLDER_TYPE(T, ref<T>, true)
// The following is not required anymore for std::shared_ptr, but it should compile without error: // The following is not required anymore for std::shared_ptr, but it should compile without error:
PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>); PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>)
PYBIND11_DECLARE_HOLDER_TYPE(T, huge_unique_ptr<T>); PYBIND11_DECLARE_HOLDER_TYPE(T, huge_unique_ptr<T>)
PYBIND11_DECLARE_HOLDER_TYPE(T, custom_unique_ptr<T>); PYBIND11_DECLARE_HOLDER_TYPE(T, custom_unique_ptr<T>)
PYBIND11_DECLARE_HOLDER_TYPE(T, shared_ptr_with_addressof_operator<T>); PYBIND11_DECLARE_HOLDER_TYPE(T, shared_ptr_with_addressof_operator<T>)
PYBIND11_DECLARE_HOLDER_TYPE(T, unique_ptr_with_addressof_operator<T>); PYBIND11_DECLARE_HOLDER_TYPE(T, unique_ptr_with_addressof_operator<T>)
TEST_SUBMODULE(smart_ptr, m) { TEST_SUBMODULE(smart_ptr, m) {
// Please do not interleave `struct` and `class` definitions with bindings code, // Please do not interleave `struct` and `class` definitions with bindings code,

View File

@ -59,7 +59,7 @@ struct visit_helper<boost::variant> {
} // namespace PYBIND11_NAMESPACE } // namespace PYBIND11_NAMESPACE
#endif #endif
PYBIND11_MAKE_OPAQUE(std::vector<std::string, std::allocator<std::string>>); PYBIND11_MAKE_OPAQUE(std::vector<std::string, std::allocator<std::string>>)
/// Issue #528: templated constructor /// Issue #528: templated constructor
struct TplCtorClass { struct TplCtorClass {

View File

@ -145,4 +145,4 @@ TEST_SUBMODULE(tagbased_polymorphic, m) {
.def(py::init<std::string>()) .def(py::init<std::string>())
.def("purr", &Panther::purr); .def("purr", &Panther::purr);
m.def("create_zoo", &create_zoo); m.def("create_zoo", &create_zoo);
}; }

View File

@ -589,4 +589,4 @@ void initialize_inherited_virtuals(py::module_ &m) {
// Fix issue #1454 (crash when acquiring/releasing GIL on another thread in Python 2.7) // Fix issue #1454 (crash when acquiring/releasing GIL on another thread in Python 2.7)
m.def("test_gil", &test_gil); m.def("test_gil", &test_gil);
m.def("test_gil_from_thread", &test_gil_from_thread); m.def("test_gil_from_thread", &test_gil_from_thread);
}; }