From e15da8451b5acf20777b354e348a6395eb75c832 Mon Sep 17 00:00:00 2001 From: Thomas Kunze Date: Sat, 14 Sep 2024 19:39:30 +0200 Subject: [PATCH] update pybind11 --- examples/knxPython/pybind11/.clang-tidy | 2 + .../pybind11/.github/workflows/ci.yml | 10 +- .../pybind11/.github/workflows/format.yml | 2 +- .../pybind11/.github/workflows/pip.yml | 9 +- .../pybind11/.pre-commit-config.yaml | 14 +- examples/knxPython/pybind11/CMakeLists.txt | 3 + .../pybind11/docs/advanced/cast/eigen.rst | 2 +- .../pybind11/docs/advanced/cast/stl.rst | 6 +- .../pybind11/docs/advanced/smart_ptrs.rst | 6 +- examples/knxPython/pybind11/docs/basics.rst | 7 + .../knxPython/pybind11/docs/changelog.rst | 164 + .../knxPython/pybind11/docs/compiling.rst | 6 +- examples/knxPython/pybind11/docs/faq.rst | 44 + .../knxPython/pybind11/docs/limitations.rst | 4 - .../knxPython/pybind11/docs/requirements.txt | 6 +- .../pybind11/include/pybind11/attr.h | 409 +- .../pybind11/include/pybind11/buffer_info.h | 310 +- .../pybind11/include/pybind11/cast.h | 2332 ++++----- .../pybind11/include/pybind11/chrono.h | 355 +- .../pybind11/include/pybind11/complex.h | 70 +- .../pybind11/include/pybind11/detail/class.h | 98 +- .../pybind11/include/pybind11/detail/common.h | 794 ++- .../pybind11/include/pybind11/detail/descr.h | 108 +- .../pybind11/include/pybind11/detail/init.h | 309 +- .../include/pybind11/detail/internals.h | 566 +-- .../pybind11/detail/type_caster_base.h | 1518 +++--- .../pybind11/include/pybind11/detail/typeid.h | 30 +- .../pybind11/include/pybind11/eigen/matrix.h | 867 ++-- .../pybind11/include/pybind11/eigen/tensor.h | 490 +- .../pybind11/include/pybind11/embed.h | 173 +- .../pybind11/include/pybind11/eval.h | 74 +- .../pybind11/include/pybind11/functional.h | 155 +- .../knxPython/pybind11/include/pybind11/gil.h | 321 +- .../include/pybind11/gil_safe_call_once.h | 89 +- .../pybind11/include/pybind11/iostream.h | 326 +- .../pybind11/include/pybind11/numpy.h | 3070 +++++------ .../pybind11/include/pybind11/operators.h | 28 +- .../pybind11/include/pybind11/options.h | 165 +- .../pybind11/include/pybind11/pybind11.h | 4470 +++++++---------- .../pybind11/include/pybind11/pytypes.h | 3961 ++++++--------- .../knxPython/pybind11/include/pybind11/stl.h | 525 +- .../include/pybind11/stl/filesystem.h | 165 +- .../pybind11/include/pybind11/stl_bind.h | 803 ++- .../pybind11/type_caster_pyobject_ptr.h | 91 +- .../pybind11/include/pybind11/typing.h | 158 +- .../knxPython/pybind11/pybind11/__main__.py | 29 +- .../knxPython/pybind11/pybind11/_version.py | 2 +- .../knxPython/pybind11/tests/CMakeLists.txt | 17 +- examples/knxPython/pybind11/tests/conftest.py | 6 +- .../pybind11/tests/constructor_stats.h | 342 +- .../pybind11/tests/cross_module_gil_utils.cpp | 129 +- ...s_module_interleaved_error_already_set.cpp | 64 +- .../tests/eigen_tensor_avoid_stl_array.cpp | 5 +- .../tests/extra_python_package/test_files.py | 3 + .../knxPython/pybind11/tests/local_bindings.h | 88 +- examples/knxPython/pybind11/tests/object.h | 366 +- .../tests/pybind11_cross_module_tests.cpp | 150 +- .../pybind11/tests/pybind11_tests.cpp | 87 +- .../knxPython/pybind11/tests/pybind11_tests.h | 107 +- .../knxPython/pybind11/tests/test_async.cpp | 20 +- .../knxPython/pybind11/tests/test_async.py | 7 +- .../knxPython/pybind11/tests/test_buffers.cpp | 429 +- .../knxPython/pybind11/tests/test_buffers.py | 7 + .../pybind11/tests/test_builtin_casters.cpp | 593 +-- .../pybind11/tests/test_builtin_casters.py | 2 + .../pybind11/tests/test_call_policies.cpp | 157 +- .../pybind11/tests/test_callbacks.cpp | 270 +- .../pybind11/tests/test_callbacks.py | 3 + .../knxPython/pybind11/tests/test_chrono.cpp | 58 +- .../knxPython/pybind11/tests/test_class.cpp | 602 +-- .../pybind11/tests/test_cmake_build/embed.cpp | 21 +- .../pybind11/tests/test_cmake_build/main.cpp | 8 +- .../pybind11/tests/test_const_name.cpp | 5 +- .../tests/test_constants_and_functions.cpp | 206 +- .../pybind11/tests/test_copy_move.cpp | 468 +- .../tests/test_custom_type_casters.cpp | 366 +- .../pybind11/tests/test_custom_type_setup.cpp | 44 +- .../pybind11/tests/test_custom_type_setup.py | 2 +- .../pybind11/tests/test_docstring_options.cpp | 52 +- .../pybind11/tests/test_eigen_matrix.cpp | 532 +- .../pybind11/tests/test_eigen_tensor.cpp | 2 +- .../pybind11/tests/test_eigen_tensor.inl | 16 +- .../pybind11/tests/test_embed/catch.cpp | 12 +- .../tests/test_embed/external_module.cpp | 17 +- .../tests/test_embed/test_interpreter.cpp | 228 +- .../knxPython/pybind11/tests/test_enum.cpp | 105 +- .../knxPython/pybind11/tests/test_eval.cpp | 52 +- .../pybind11/tests/test_exceptions.cpp | 462 +- .../pybind11/tests/test_exceptions.h | 14 +- .../pybind11/tests/test_exceptions.py | 2 +- .../tests/test_factory_constructors.cpp | 879 ++-- .../pybind11/tests/test_gil_scoped.cpp | 123 +- .../pybind11/tests/test_gil_scoped.py | 13 +- .../pybind11/tests/test_iostream.cpp | 74 +- .../knxPython/pybind11/tests/test_iostream.py | 4 + .../tests/test_kwargs_and_defaults.cpp | 366 +- .../pybind11/tests/test_local_bindings.cpp | 92 +- .../tests/test_methods_and_attributes.cpp | 929 ++-- .../knxPython/pybind11/tests/test_modules.cpp | 189 +- .../tests/test_multiple_inheritance.cpp | 478 +- .../pybind11/tests/test_numpy_array.cpp | 646 +-- .../pybind11/tests/test_numpy_array.py | 2 +- .../pybind11/tests/test_numpy_dtypes.cpp | 493 +- .../pybind11/tests/test_numpy_vectorize.cpp | 100 +- .../pybind11/tests/test_opaque_types.cpp | 91 +- .../tests/test_operator_overloading.cpp | 477 +- .../pybind11/tests/test_pickling.cpp | 290 +- .../test_python_multiple_inheritance.cpp | 78 +- .../knxPython/pybind11/tests/test_pytypes.cpp | 1047 ++-- .../knxPython/pybind11/tests/test_pytypes.py | 50 +- .../tests/test_sequences_and_iterators.cpp | 994 ++-- .../pybind11/tests/test_smart_ptr.cpp | 973 ++-- .../knxPython/pybind11/tests/test_stl.cpp | 649 +-- .../pybind11/tests/test_stl_binders.cpp | 266 +- .../tests/test_tagbased_polymorphic.cpp | 164 +- .../knxPython/pybind11/tests/test_thread.cpp | 52 +- .../knxPython/pybind11/tests/test_thread.py | 5 + .../tests/test_type_caster_pyobject_ptr.cpp | 182 +- .../knxPython/pybind11/tests/test_union.cpp | 12 +- .../tests/test_unnamed_namespace_a.cpp | 16 +- .../tests/test_unnamed_namespace_b.cpp | 15 +- .../tests/test_vector_unique_ptr_member.cpp | 81 +- .../pybind11/tests/test_virtual_functions.cpp | 854 ++-- .../pybind11/tests/test_virtual_functions.py | 3 + .../pybind11/tools/pybind11Common.cmake | 32 +- .../pybind11/tools/pybind11Config.cmake.in | 2 +- 126 files changed, 15800 insertions(+), 24193 deletions(-) diff --git a/examples/knxPython/pybind11/.clang-tidy b/examples/knxPython/pybind11/.clang-tidy index 23018386..96cb6f58 100644 --- a/examples/knxPython/pybind11/.clang-tidy +++ b/examples/knxPython/pybind11/.clang-tidy @@ -57,10 +57,12 @@ Checks: | readability-string-compare, readability-suspicious-call-argument, readability-uniqueptr-delete-release, + -bugprone-chained-comparison, -bugprone-easily-swappable-parameters, -bugprone-exception-escape, -bugprone-reserved-identifier, -bugprone-unused-raii, + -performance-enum-size, CheckOptions: - key: modernize-use-equals-default.IgnoreMacros diff --git a/examples/knxPython/pybind11/.github/workflows/ci.yml b/examples/knxPython/pybind11/.github/workflows/ci.yml index 3054d842..3f7e8a6c 100644 --- a/examples/knxPython/pybind11/.github/workflows/ci.yml +++ b/examples/knxPython/pybind11/.github/workflows/ci.yml @@ -243,7 +243,7 @@ jobs: - uses: actions/checkout@v4 - name: Setup Python ${{ matrix.python-version }} (deadsnakes) - uses: deadsnakes/action@v3.1.0 + uses: deadsnakes/action@v3.2.0 with: python-version: ${{ matrix.python-version }} debug: ${{ matrix.python-debug }} @@ -340,6 +340,12 @@ jobs: - clang: 16 std: 20 container_suffix: "-bullseye" + - clang: 17 + std: 20 + container_suffix: "-bookworm" + - clang: 18 + std: 20 + container_suffix: "-bookworm" name: "🐍 3 • Clang ${{ matrix.clang }} • C++${{ matrix.std }} • x64" container: "silkeh/clang:${{ matrix.clang }}${{ matrix.container_suffix }}" @@ -501,7 +507,9 @@ jobs: - { gcc: 7, std: 17 } - { gcc: 8, std: 14 } - { gcc: 8, std: 17 } + - { gcc: 9, std: 20 } - { gcc: 10, std: 17 } + - { gcc: 10, std: 20 } - { gcc: 11, std: 20 } - { gcc: 12, std: 20 } - { gcc: 13, std: 20 } diff --git a/examples/knxPython/pybind11/.github/workflows/format.yml b/examples/knxPython/pybind11/.github/workflows/format.yml index 1eaa56e1..e50dc0bb 100644 --- a/examples/knxPython/pybind11/.github/workflows/format.yml +++ b/examples/knxPython/pybind11/.github/workflows/format.yml @@ -41,7 +41,7 @@ jobs: # in .github/CONTRIBUTING.md and update as needed. name: Clang-Tidy runs-on: ubuntu-latest - container: silkeh/clang:15-bullseye + container: silkeh/clang:18-bookworm steps: - uses: actions/checkout@v4 diff --git a/examples/knxPython/pybind11/.github/workflows/pip.yml b/examples/knxPython/pybind11/.github/workflows/pip.yml index a054ce69..37135373 100644 --- a/examples/knxPython/pybind11/.github/workflows/pip.yml +++ b/examples/knxPython/pybind11/.github/workflows/pip.yml @@ -91,18 +91,19 @@ jobs: runs-on: ubuntu-latest if: github.event_name == 'release' && github.event.action == 'published' needs: [packaging] - environment: pypi + environment: + name: pypi + url: https://pypi.org/p/pybind11 permissions: id-token: write attestations: write - contents: read steps: # Downloads all to directories matching the artifact names - uses: actions/download-artifact@v4 - name: Generate artifact attestation for sdist and wheel - uses: actions/attest-build-provenance@173725a1209d09b31f9d30a3890cf2757ebbff0d # v1.1.2 + uses: actions/attest-build-provenance@1c608d11d69870c2092266b3f9a6f3abbf17002c # v1.4.3 with: subject-path: "*/pybind11*" @@ -110,8 +111,10 @@ jobs: uses: pypa/gh-action-pypi-publish@release/v1 with: packages-dir: standard/ + attestations: true - name: Publish global package uses: pypa/gh-action-pypi-publish@release/v1 with: packages-dir: global/ + attestations: true diff --git a/examples/knxPython/pybind11/.pre-commit-config.yaml b/examples/knxPython/pybind11/.pre-commit-config.yaml index 3cec1ebe..a8190df4 100644 --- a/examples/knxPython/pybind11/.pre-commit-config.yaml +++ b/examples/knxPython/pybind11/.pre-commit-config.yaml @@ -25,14 +25,14 @@ repos: # Clang format the codebase automatically - repo: https://github.com/pre-commit/mirrors-clang-format - rev: "v18.1.5" + rev: "v18.1.8" hooks: - id: clang-format types_or: [c++, c, cuda] # Ruff, the Python auto-correcting linter/formatter written in Rust - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.4.7 + rev: v0.6.3 hooks: - id: ruff args: ["--fix", "--show-fixes"] @@ -40,7 +40,7 @@ repos: # Check static types with mypy - repo: https://github.com/pre-commit/mirrors-mypy - rev: "v1.10.0" + rev: "v1.11.2" hooks: - id: mypy args: [] @@ -79,7 +79,7 @@ repos: # Also code format the docs - repo: https://github.com/adamchainz/blacken-docs - rev: "1.16.0" + rev: "1.18.0" hooks: - id: blacken-docs additional_dependencies: @@ -93,7 +93,7 @@ repos: # Avoid directional quotes - repo: https://github.com/sirosen/texthooks - rev: "0.6.6" + rev: "0.6.7" hooks: - id: fix-ligatures - id: fix-smartquotes @@ -142,14 +142,14 @@ repos: # PyLint has native support - not always usable, but works for us - repo: https://github.com/PyCQA/pylint - rev: "v3.2.2" + rev: "v3.2.7" hooks: - id: pylint files: ^pybind11 # Check schemas on some of our YAML files - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.28.4 + rev: 0.29.2 hooks: - id: check-readthedocs - id: check-github-workflows diff --git a/examples/knxPython/pybind11/CMakeLists.txt b/examples/knxPython/pybind11/CMakeLists.txt index 3526a1a6..f53aa209 100644 --- a/examples/knxPython/pybind11/CMakeLists.txt +++ b/examples/knxPython/pybind11/CMakeLists.txt @@ -149,11 +149,14 @@ endif() set(PYBIND11_HEADERS include/pybind11/detail/class.h include/pybind11/detail/common.h + include/pybind11/detail/cpp_conduit.h include/pybind11/detail/descr.h include/pybind11/detail/init.h include/pybind11/detail/internals.h include/pybind11/detail/type_caster_base.h include/pybind11/detail/typeid.h + include/pybind11/detail/value_and_holder.h + include/pybind11/detail/exception_translation.h include/pybind11/attr.h include/pybind11/buffer_info.h include/pybind11/cast.h diff --git a/examples/knxPython/pybind11/docs/advanced/cast/eigen.rst b/examples/knxPython/pybind11/docs/advanced/cast/eigen.rst index a5c11a3f..894ce97f 100644 --- a/examples/knxPython/pybind11/docs/advanced/cast/eigen.rst +++ b/examples/knxPython/pybind11/docs/advanced/cast/eigen.rst @@ -259,7 +259,7 @@ copying to take place: "small"_a // <- This one can be copied if needed ); -With the above binding code, attempting to call the the ``some_method(m)`` +With the above binding code, attempting to call the ``some_method(m)`` method on a ``MyClass`` object, or attempting to call ``some_function(m, m2)`` will raise a ``RuntimeError`` rather than making a temporary copy of the array. It will, however, allow the ``m2`` argument to be copied into a temporary if diff --git a/examples/knxPython/pybind11/docs/advanced/cast/stl.rst b/examples/knxPython/pybind11/docs/advanced/cast/stl.rst index 03d49b29..42b85532 100644 --- a/examples/knxPython/pybind11/docs/advanced/cast/stl.rst +++ b/examples/knxPython/pybind11/docs/advanced/cast/stl.rst @@ -162,7 +162,7 @@ the declaration .. code-block:: cpp - PYBIND11_MAKE_OPAQUE(std::vector); + PYBIND11_MAKE_OPAQUE(std::vector) 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 @@ -207,8 +207,8 @@ The following example showcases usage of :file:`pybind11/stl_bind.h`: // Don't forget this #include - PYBIND11_MAKE_OPAQUE(std::vector); - PYBIND11_MAKE_OPAQUE(std::map); + PYBIND11_MAKE_OPAQUE(std::vector) + PYBIND11_MAKE_OPAQUE(std::map) // ... diff --git a/examples/knxPython/pybind11/docs/advanced/smart_ptrs.rst b/examples/knxPython/pybind11/docs/advanced/smart_ptrs.rst index 3c40ce12..b9f100cf 100644 --- a/examples/knxPython/pybind11/docs/advanced/smart_ptrs.rst +++ b/examples/knxPython/pybind11/docs/advanced/smart_ptrs.rst @@ -124,7 +124,7 @@ top namespace level before any binding code: .. code-block:: cpp - PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr); + PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr) 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. @@ -136,7 +136,7 @@ by default. Specify .. code-block:: cpp - PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr, true); + PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr, true) if ``SmartPtr`` can always be initialized from a ``T*`` pointer without the risk of inconsistencies (such as multiple independent ``SmartPtr`` instances @@ -154,7 +154,7 @@ specialized: .. code-block:: cpp // Always needed for custom holder types - PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr); + PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr) // Only needed if the type's `.get()` goes by another name namespace PYBIND11_NAMESPACE { namespace detail { diff --git a/examples/knxPython/pybind11/docs/basics.rst b/examples/knxPython/pybind11/docs/basics.rst index e9b24c7f..cd97c100 100644 --- a/examples/knxPython/pybind11/docs/basics.rst +++ b/examples/knxPython/pybind11/docs/basics.rst @@ -78,6 +78,13 @@ For brevity, all code examples assume that the following two lines are present: 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. .. _simple_example: diff --git a/examples/knxPython/pybind11/docs/changelog.rst b/examples/knxPython/pybind11/docs/changelog.rst index ab6c713c..a9108211 100644 --- a/examples/knxPython/pybind11/docs/changelog.rst +++ b/examples/knxPython/pybind11/docs/changelog.rst @@ -15,6 +15,146 @@ IN DEVELOPMENT Changes will be summarized here periodically. +New Features: + +* Support for Python 3.7 was removed. (Official end-of-life: 2023-06-27). + `#5191 `_ + +* stl.h ``list|set|map_caster`` were made more user friendly: it is no longer + necessary to explicitly convert Python iterables to ``tuple()``, ``set()``, + or ``map()`` in many common situations. + `#4686 `_ + +* Support for CMake older than 3.15 removed. CMake 3.15-3.30 supported. + `#5304 `_ + +* The ``array_caster`` in pybind11/stl.h was enhanced to support value types that are not default-constructible. + `#5305 `_ + +* Added ``py::warnings`` namespace with ``py::warnings::warn`` and ``py::warnings::new_warning_type`` that provides the interface for Python warnings. + `#5291 `_ + +Version 2.13.6 (September 13, 2024) +----------------------------------- + +New Features: + +* A new ``self._pybind11_conduit_v1_()`` method is automatically added to all + ``py::class_``-wrapped types, to enable type-safe interoperability between + different independent Python/C++ bindings systems, including pybind11 + versions with different ``PYBIND11_INTERNALS_VERSION``'s. Supported on + pybind11 2.11.2, 2.12.1, and 2.13.6+. + `#5296 `_ + + +Bug fixes: + +* Using ``__cpp_nontype_template_args`` instead of ``__cpp_nontype_template_parameter_class``. + `#5330 `_ + +* Properly translate C++ exception to Python exception when creating Python buffer from wrapped object. + `#5324 `_ + + +Documentation: + +* Adds an answer (FAQ) for "What is a highly conclusive and simple way to find memory leaks?". + `#5340 `_ + + +Version 2.13.5 (August 22, 2024) +-------------------------------- + +Bug fixes: + +* Fix includes when using Windows long paths (``\\?\`` prefix). + `#5321 `_ + +* Support ``-Wpedantic`` in C++20 mode. + `#5322 `_ + +* Fix and test ```` support for ``py::tuple`` and ``py::list``. + `#5314 `_ + +Version 2.13.4 (August 14, 2024) +-------------------------------- + +Bug fixes: + +* Fix paths with spaces, including on Windows. + (Replaces regression from `#5302 `_) + `#4874 `_ + +Documentation: + +* Remove repetitive words. + `#5308 `_ + + +Version 2.13.3 (August 13, 2024) +-------------------------------- + +Bug fixes: + +* Quote paths from pybind11-config + `#5302 `_ + + +* Fix typo in Emscripten support when in config mode (CMake) + `#5301 `_ + + +Version 2.13.2 (August 13, 2024) +-------------------------------- + +New Features: + +* A ``pybind11::detail::type_caster_std_function_specializations`` feature was added, to support specializations for + ``std::function``'s with return types that require custom to-Python conversion behavior (to primary use case is to catch and + convert exceptions). + `#4597 `_ + + +Changes: + + +* Use ``PyMutex`` instead of ``std::mutex`` for internal locking in the free-threaded build. + `#5219 `_ + +* Add a special type annotation for C++ empty tuple. + `#5214 `_ + +* When compiling for WebAssembly, add the required exception flags (CMake 3.13+). + `#5298 `_ + +Bug fixes: + +* Make ``gil_safe_call_once_and_store`` thread-safe in free-threaded CPython. + `#5246 `_ + +* A missing ``#include `` in pybind11/typing.h was added to fix build errors (in case user code does not already depend + on that include). + `#5208 `_ + +* Fix regression introduced in #5201 for GCC<10.3 in C++20 mode. + `#5205 `_ + + +.. fix(cmake) + +* Remove extra = when assigning flto value in the case for Clang in CMake. + `#5207 `_ + + +Tests: + +* Adding WASM testing to our CI (Pyodide / Emscripten via scikit-build-core). + `#4745 `_ + +* clang-tidy (in GitHub Actions) was updated from clang 15 to clang 18. + `#5272 `_ + + Version 2.13.1 (June 26, 2024) ------------------------------ @@ -129,6 +269,18 @@ Other: * Update docs and noxfile. `#5071 `_ +Version 2.12.1 (September 13, 2024) +----------------------------------- + +New Features: + +* A new ``self._pybind11_conduit_v1_()`` method is automatically added to all + ``py::class_``-wrapped types, to enable type-safe interoperability between + different independent Python/C++ bindings systems, including pybind11 + versions with different ``PYBIND11_INTERNALS_VERSION``'s. Supported on + pybind11 2.11.2, 2.12.1, and 2.13.6+. + `#5296 `_ + Version 2.12.0 (March 27, 2024) ------------------------------- @@ -304,6 +456,18 @@ Other: * An ``assert()`` was added to help Coverty avoid generating a false positive. `#4817 `_ +Version 2.11.2 (September 13, 2024) +----------------------------------- + +New Features: + +* A new ``self._pybind11_conduit_v1_()`` method is automatically added to all + ``py::class_``-wrapped types, to enable type-safe interoperability between + different independent Python/C++ bindings systems, including pybind11 + versions with different ``PYBIND11_INTERNALS_VERSION``'s. Supported on + pybind11 2.11.2, 2.12.1, and 2.13.6+. + `#5296 `_ + Version 2.11.1 (July 17, 2023) ------------------------------ diff --git a/examples/knxPython/pybind11/docs/compiling.rst b/examples/knxPython/pybind11/docs/compiling.rst index 0b7c178b..448ea11c 100644 --- a/examples/knxPython/pybind11/docs/compiling.rst +++ b/examples/knxPython/pybind11/docs/compiling.rst @@ -25,7 +25,7 @@ A Python extension module can be created with just a few lines of code: find_package(pybind11 CONFIG REQUIRED) pybind11_add_module(example example.cpp) - install(TARGET example DESTINATION .) + install(TARGETS example DESTINATION .) (You use the ``add_subdirectory`` instead, see the example in :ref:`cmake`.) In this example, the code is located in a file named :file:`example.cpp`. Either @@ -388,7 +388,7 @@ that will be respected instead of the built-in flag search. The ``OPT_SIZE`` flag enables size-based optimization equivalent to the standard ``/Os`` or ``-Os`` compiler flags and the ``MinSizeRel`` build type, -which avoid optimizations that that can substantially increase the size of the +which avoid optimizations that can substantially increase the size of the resulting binary. This flag is particularly useful in projects that are split into performance-critical parts and associated bindings. In this case, we can compile the project in release mode (and hence, optimize performance globally), @@ -719,7 +719,7 @@ customizable pybind11-based wrappers by parsing C++ header files. [litgen]_ is an automatic python bindings generator with a focus on generating documented and discoverable bindings: bindings will nicely reproduce the documentation -found in headers. It is is based on srcML (srcml.org), a highly scalable, multi-language +found in headers. It is based on srcML (srcml.org), a highly scalable, multi-language parsing tool with a developer centric approach. The API that you want to expose to python must be C++14 compatible (but your implementation can use more modern constructs). diff --git a/examples/knxPython/pybind11/docs/faq.rst b/examples/knxPython/pybind11/docs/faq.rst index 1eb00efa..9b688b30 100644 --- a/examples/knxPython/pybind11/docs/faq.rst +++ b/examples/knxPython/pybind11/docs/faq.rst @@ -247,6 +247,50 @@ been received, you must either explicitly interrupt execution by throwing }); } +What is a highly conclusive and simple way to find memory leaks (e.g. in pybind11 bindings)? +============================================================================================ + +Use ``while True`` & ``top`` (Linux, macOS). + +For example, locally change tests/test_type_caster_pyobject_ptr.py like this: + +.. code-block:: diff + + def test_return_list_pyobject_ptr_reference(): + + while True: + vec_obj = m.return_list_pyobject_ptr_reference(ValueHolder) + assert [e.value for e in vec_obj] == [93, 186] + # Commenting out the next `assert` will leak the Python references. + # An easy way to see evidence of the leaks: + # Insert `while True:` as the first line of this function and monitor the + # process RES (Resident Memory Size) with the Unix top command. + - assert m.dec_ref_each_pyobject_ptr(vec_obj) == 2 + + # assert m.dec_ref_each_pyobject_ptr(vec_obj) == 2 + +Then run the test as you would normally do, which will go into the infinite loop. + +**In another shell, but on the same machine** run: + +.. code-block:: bash + + top + +This will show: + +.. code-block:: + + PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND + 1266095 rwgk 20 0 5207496 611372 45696 R 100.0 0.3 0:08.01 test_type_caste + +Look for the number under ``RES`` there. You'll see it going up very quickly. + +**Don't forget to Ctrl-C the test command** before your machine becomes +unresponsive due to swapping. + +This method only takes a couple minutes of effort and is very conclusive. +What you want to see is that the ``RES`` number is stable after a couple +seconds. + CMake doesn't detect the right Python version ============================================= diff --git a/examples/knxPython/pybind11/docs/limitations.rst b/examples/knxPython/pybind11/docs/limitations.rst index def5ad65..1b06ea87 100644 --- a/examples/knxPython/pybind11/docs/limitations.rst +++ b/examples/knxPython/pybind11/docs/limitations.rst @@ -50,10 +50,6 @@ clean, well written patch would likely be accepted to solve them. One consequence is that containers of ``char *`` are currently not supported. `#2245 `_ -- The ``cpptest`` does not run on Windows with Python 3.8 or newer, due to DLL - loader changes. User code that is correctly installed should not be affected. - `#2560 `_ - Python 3.9.0 warning ^^^^^^^^^^^^^^^^^^^^ diff --git a/examples/knxPython/pybind11/docs/requirements.txt b/examples/knxPython/pybind11/docs/requirements.txt index 293db6a0..4e53f035 100644 --- a/examples/knxPython/pybind11/docs/requirements.txt +++ b/examples/knxPython/pybind11/docs/requirements.txt @@ -16,9 +16,9 @@ breathe==4.35.0 \ --hash=sha256:5165541c3c67b6c7adde8b3ecfe895c6f7844783c4076b6d8d287e4f33d62386 \ --hash=sha256:52c581f42ca4310737f9e435e3851c3d1f15446205a85fbc272f1f97ed74f5be # via -r requirements.in -certifi==2024.2.2 \ - --hash=sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f \ - --hash=sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1 +certifi==2024.7.4 \ + --hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \ + --hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90 # via requests charset-normalizer==3.3.2 \ --hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \ diff --git a/examples/knxPython/pybind11/include/pybind11/attr.h b/examples/knxPython/pybind11/include/pybind11/attr.h index 041fcae2..1044db94 100644 --- a/examples/knxPython/pybind11/include/pybind11/attr.h +++ b/examples/knxPython/pybind11/include/pybind11/attr.h @@ -21,10 +21,9 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) /// @{ /// Annotation for methods -struct is_method -{ +struct is_method { handle class_; - explicit is_method(const handle& c) : class_(c) {} + explicit is_method(const handle &c) : class_(c) {} }; /// Annotation for setters @@ -37,37 +36,32 @@ struct is_operator {}; struct is_final {}; /// Annotation for parent scope -struct scope -{ +struct scope { handle value; - explicit scope(const handle& s) : value(s) {} + explicit scope(const handle &s) : value(s) {} }; /// Annotation for documentation -struct doc -{ - const char* value; - explicit doc(const char* value) : value(value) {} +struct doc { + const char *value; + explicit doc(const char *value) : value(value) {} }; /// Annotation for function names -struct name -{ - const char* value; - explicit name(const char* value) : value(value) {} +struct name { + const char *value; + explicit name(const char *value) : value(value) {} }; /// Annotation indicating that a function is an overload associated with a given "sibling" -struct sibling -{ +struct sibling { handle value; - explicit sibling(const handle& value) : value(value.ptr()) {} + explicit sibling(const handle &value) : value(value.ptr()) {} }; /// Annotation indicating that a class derives from another given type template -struct base -{ +struct base { PYBIND11_DEPRECATED( "base() was deprecated in favor of specifying 'T' as a template argument to class_") @@ -88,8 +82,7 @@ struct dynamic_attr {}; struct buffer_protocol {}; /// Annotation which requests that a special metaclass is created for a type -struct metaclass -{ +struct metaclass { handle value; PYBIND11_DEPRECATED("py::metaclass() is no longer required. It's turned on by default now.") @@ -108,9 +101,8 @@ struct metaclass /// work with later versions of pybind11. You may wish to consult the /// implementation of `make_new_python_type` in `detail/classes.h` to understand /// the context in which the callback will be run. -struct custom_type_setup -{ - using callback = std::function; +struct custom_type_setup { + using callback = std::function; explicit custom_type_setup(callback value) : value(std::move(value)) {} @@ -118,8 +110,7 @@ struct custom_type_setup }; /// Annotation that marks a class as local to the module: -struct module_local -{ +struct module_local { const bool value; constexpr explicit module_local(bool v = true) : value(v) {} }; @@ -152,14 +143,12 @@ template struct call_guard; template <> -struct call_guard<> -{ +struct call_guard<> { using type = detail::void_type; }; template -struct call_guard -{ +struct call_guard { static_assert(std::is_default_constructible::value, "The guard type must be default constructible"); @@ -167,10 +156,8 @@ struct call_guard }; template -struct call_guard -{ - struct type - { +struct call_guard { + struct type { T guard{}; // Compose multiple guard types with left-to-right default-constructor order typename call_guard::type next{}; }; @@ -185,50 +172,48 @@ enum op_type : int; struct undefined_t; template struct op_; -void keep_alive_impl(size_t Nurse, size_t Patient, function_call& call, handle ret); +void keep_alive_impl(size_t Nurse, size_t Patient, function_call &call, handle ret); /// Internal data structure which holds metadata about a keyword argument -struct argument_record -{ - const char* name; ///< Argument name - const char* descr; ///< Human-readable version of the argument value +struct argument_record { + const char *name; ///< Argument name + const char *descr; ///< Human-readable version of the argument value handle value; ///< Associated Python object bool convert : 1; ///< True if the argument is allowed to convert when loading bool none : 1; ///< True if None is allowed when loading - argument_record(const char* name, const char* descr, handle value, bool convert, bool none) + argument_record(const char *name, const char *descr, handle value, bool convert, bool none) : name(name), descr(descr), value(value), convert(convert), none(none) {} }; /// Internal data structure which holds metadata about a bound function (signature, overloads, /// etc.) -struct function_record -{ +struct function_record { function_record() : is_constructor(false), is_new_style_constructor(false), is_stateless(false), is_operator(false), is_method(false), is_setter(false), has_args(false), has_kwargs(false), prepend(false) {} /// Function name - char* name = nullptr; /* why no C++ strings? They generate heavier code.. */ + char *name = nullptr; /* why no C++ strings? They generate heavier code.. */ // User-specified documentation string - char* doc = nullptr; + char *doc = nullptr; /// Human-readable version of the function signature - char* signature = nullptr; + char *signature = nullptr; /// List of registered keyword arguments std::vector args; /// Pointer to lambda function which converts arguments and performs the actual call - handle (*impl)(function_call&) = nullptr; + handle (*impl)(function_call &) = nullptr; /// Storage for the wrapped function pointer and captured data, if any - void* data[3] = {}; + void *data[3] = {}; /// Pointer to custom destructor for 'data' (if needed) - void (*free_data)(function_record* ptr) = nullptr; + void (*free_data)(function_record *ptr) = nullptr; /// Return value policy associated with this function return_value_policy policy = return_value_policy::automatic; @@ -271,7 +256,7 @@ struct function_record std::uint16_t nargs_pos_only = 0; /// Python method object - PyMethodDef* def = nullptr; + PyMethodDef *def = nullptr; /// Python handle to the parent scope (a class or a module) handle scope; @@ -280,12 +265,11 @@ struct function_record handle sibling; /// Pointer to next overload - function_record* next = nullptr; + function_record *next = nullptr; }; /// Special data structure which (temporarily) holds metadata about a bound class -struct type_record -{ +struct type_record { PYBIND11_NOINLINE type_record() : multiple_inheritance(false), dynamic_attr(false), buffer_protocol(false), default_holder(true), module_local(false), is_final(false) {} @@ -294,10 +278,10 @@ struct type_record handle scope; /// Name of the class - const char* name = nullptr; + const char *name = nullptr; // Pointer to RTTI type_info data structure - const std::type_info* type = nullptr; + const std::type_info *type = nullptr; /// How large is the underlying C++ type? size_t type_size = 0; @@ -309,19 +293,19 @@ struct type_record size_t holder_size = 0; /// The global operator new can be overridden with a class-specific variant - void* (*operator_new)(size_t) = nullptr; + void *(*operator_new)(size_t) = nullptr; /// Function pointer to class_<..>::init_instance - void (*init_instance)(instance*, const void*) = nullptr; + void (*init_instance)(instance *, const void *) = nullptr; /// Function pointer to class_<..>::dealloc - void (*dealloc)(detail::value_and_holder&) = nullptr; + void (*dealloc)(detail::value_and_holder &) = nullptr; /// List of base classes of the newly created type list bases; /// Optional docstring - const char* doc = nullptr; + const char *doc = nullptr; /// Custom metaclass (optional) handle metaclass; @@ -347,20 +331,16 @@ struct type_record /// Is the class inheritable from python classes? bool is_final : 1; - PYBIND11_NOINLINE void add_base(const std::type_info& base, void* (*caster)(void*) ) - { - auto* base_info = detail::get_type_info(base, false); - - if (!base_info) - { + PYBIND11_NOINLINE void add_base(const std::type_info &base, void *(*caster)(void *) ) { + auto *base_info = detail::get_type_info(base, false); + if (!base_info) { std::string tname(base.name()); detail::clean_type_id(tname); pybind11_fail("generic_type: type \"" + std::string(name) + "\" referenced unknown base type \"" + tname + "\""); } - if (default_holder != base_info->default_holder) - { + if (default_holder != base_info->default_holder) { std::string tname(base.name()); detail::clean_type_id(tname); pybind11_fail("generic_type: type \"" + std::string(name) + "\" " @@ -369,7 +349,7 @@ struct type_record + (base_info->default_holder ? "does not" : "does")); } - bases.append((PyObject*) base_info->type); + bases.append((PyObject *) base_info->type); #if PY_VERSION_HEX < 0x030B0000 dynamic_attr |= base_info->type->tp_dictoffset != 0; @@ -377,15 +357,13 @@ struct type_record dynamic_attr |= (base_info->type->tp_flags & Py_TPFLAGS_MANAGED_DICT) != 0; #endif - if (caster) - { + if (caster) { base_info->implicit_casts.emplace_back(type, caster); } } }; -inline function_call::function_call(const function_record& f, handle p) : func(f), parent(p) -{ +inline function_call::function_call(const function_record &f, handle p) : func(f), parent(p) { args.reserve(f.nargs); args_convert.reserve(f.nargs); } @@ -403,78 +381,52 @@ template struct process_attribute; template -struct process_attribute_default -{ +struct process_attribute_default { /// Default implementation: do nothing - static void init(const T&, function_record*) {} - static void init(const T&, type_record*) {} - static void precall(function_call&) {} - static void postcall(function_call&, handle) {} + static void init(const T &, function_record *) {} + static void init(const T &, type_record *) {} + static void precall(function_call &) {} + static void postcall(function_call &, handle) {} }; /// Process an attribute specifying the function's name template <> -struct process_attribute : process_attribute_default -{ - static void init(const name& n, function_record* r) - { - r->name = const_cast(n.value); - } +struct process_attribute : process_attribute_default { + static void init(const name &n, function_record *r) { r->name = const_cast(n.value); } }; /// Process an attribute specifying the function's docstring template <> -struct process_attribute : process_attribute_default -{ - static void init(const doc& n, function_record* r) - { - r->doc = const_cast(n.value); - } +struct process_attribute : process_attribute_default { + static void init(const doc &n, function_record *r) { r->doc = const_cast(n.value); } }; /// Process an attribute specifying the function's docstring (provided as a C-style string) template <> -struct process_attribute : process_attribute_default -{ - static void init(const char* d, function_record* r) - { - r->doc = const_cast(d); - } - static void init(const char* d, type_record* r) - { - r->doc = d; - } +struct process_attribute : process_attribute_default { + static void init(const char *d, function_record *r) { r->doc = const_cast(d); } + static void init(const char *d, type_record *r) { r->doc = d; } }; template <> -struct process_attribute : process_attribute {}; +struct process_attribute : process_attribute {}; /// Process an attribute indicating the function's return value policy template <> -struct process_attribute : process_attribute_default -{ - static void init(const return_value_policy& p, function_record* r) - { - r->policy = p; - } +struct process_attribute : process_attribute_default { + static void init(const return_value_policy &p, function_record *r) { r->policy = p; } }; /// Process an attribute which indicates that this is an overloaded function associated with a /// given sibling template <> -struct process_attribute : process_attribute_default -{ - static void init(const sibling& s, function_record* r) - { - r->sibling = s.value; - } +struct process_attribute : process_attribute_default { + static void init(const sibling &s, function_record *r) { r->sibling = s.value; } }; /// Process an attribute which indicates that this function is a method template <> -struct process_attribute : process_attribute_default -{ - static void init(const is_method& s, function_record* r) - { +struct process_attribute : process_attribute_default { + static void init(const is_method &s, function_record *r) { r->is_method = true; r->scope = s.class_; } @@ -482,67 +434,47 @@ struct process_attribute : process_attribute_default /// Process an attribute which indicates that this function is a setter template <> -struct process_attribute : process_attribute_default -{ - static void init(const is_setter&, function_record* r) - { - r->is_setter = true; - } +struct process_attribute : process_attribute_default { + static void init(const is_setter &, function_record *r) { r->is_setter = true; } }; /// Process an attribute which indicates the parent scope of a method template <> -struct process_attribute : process_attribute_default -{ - static void init(const scope& s, function_record* r) - { - r->scope = s.value; - } +struct process_attribute : process_attribute_default { + static void init(const scope &s, function_record *r) { r->scope = s.value; } }; /// Process an attribute which indicates that this function is an operator template <> -struct process_attribute : process_attribute_default -{ - static void init(const is_operator&, function_record* r) - { - r->is_operator = true; - } +struct process_attribute : process_attribute_default { + static void init(const is_operator &, function_record *r) { r->is_operator = true; } }; template <> struct process_attribute - : process_attribute_default -{ - static void init(const is_new_style_constructor&, function_record* r) - { + : process_attribute_default { + static void init(const is_new_style_constructor &, function_record *r) { r->is_new_style_constructor = true; } }; -inline void check_kw_only_arg(const arg& a, function_record* r) -{ - if (r->args.size() > r->nargs_pos && (!a.name || a.name[0] == '\0')) - { +inline void check_kw_only_arg(const arg &a, function_record *r) { + if (r->args.size() > r->nargs_pos && (!a.name || a.name[0] == '\0')) { pybind11_fail("arg(): cannot specify an unnamed argument after a kw_only() annotation or " "args() argument"); } } -inline void append_self_arg_if_needed(function_record* r) -{ - if (r->is_method && r->args.empty()) - { +inline void append_self_arg_if_needed(function_record *r) { + if (r->is_method && r->args.empty()) { r->args.emplace_back("self", nullptr, handle(), /*convert=*/true, /*none=*/false); } } /// Process a keyword argument attribute (*without* a default value) template <> -struct process_attribute : process_attribute_default -{ - static void init(const arg& a, function_record* r) - { +struct process_attribute : process_attribute_default { + static void init(const arg &a, function_record *r) { append_self_arg_if_needed(r); r->args.emplace_back(a.name, nullptr, handle(), !a.flag_noconvert, a.flag_none); @@ -552,45 +484,30 @@ struct process_attribute : process_attribute_default /// Process a keyword argument attribute (*with* a default value) template <> -struct process_attribute : process_attribute_default -{ - static void init(const arg_v& a, function_record* r) - { - if (r->is_method && r->args.empty()) - { +struct process_attribute : process_attribute_default { + static void init(const arg_v &a, function_record *r) { + if (r->is_method && r->args.empty()) { r->args.emplace_back( "self", /*descr=*/nullptr, /*parent=*/handle(), /*convert=*/true, /*none=*/false); } - if (!a.value) - { + if (!a.value) { #if defined(PYBIND11_DETAILED_ERROR_MESSAGES) std::string descr("'"); - - if (a.name) - { + if (a.name) { descr += std::string(a.name) + ": "; } - descr += a.type + "'"; - - if (r->is_method) - { - if (r->name) - { + if (r->is_method) { + if (r->name) { descr += " in method '" + (std::string) str(r->scope) + "." + (std::string) r->name + "'"; - } - else - { + } else { descr += " in method of '" + (std::string) str(r->scope) + "'"; } - } - else if (r->name) - { + } else if (r->name) { descr += " in function '" + (std::string) r->name + "'"; } - pybind11_fail("arg(): could not convert default argument " + descr + " into a Python object (type not registered yet?)"); #else @@ -600,7 +517,6 @@ struct process_attribute : process_attribute_default "more information."); #endif } - r->args.emplace_back(a.name, a.descr, a.value.inc_ref(), !a.flag_noconvert, a.flag_none); check_kw_only_arg(a, r); @@ -609,36 +525,26 @@ struct process_attribute : process_attribute_default /// Process a keyword-only-arguments-follow pseudo argument template <> -struct process_attribute : process_attribute_default -{ - static void init(const kw_only&, function_record* r) - { +struct process_attribute : process_attribute_default { + static void init(const kw_only &, function_record *r) { append_self_arg_if_needed(r); - - if (r->has_args && r->nargs_pos != static_cast(r->args.size())) - { + if (r->has_args && r->nargs_pos != static_cast(r->args.size())) { pybind11_fail("Mismatched args() and kw_only(): they must occur at the same relative " "argument location (or omit kw_only() entirely)"); } - r->nargs_pos = static_cast(r->args.size()); } }; /// Process a positional-only-argument maker template <> -struct process_attribute : process_attribute_default -{ - static void init(const pos_only&, function_record* r) - { +struct process_attribute : process_attribute_default { + static void init(const pos_only &, function_record *r) { append_self_arg_if_needed(r); r->nargs_pos_only = static_cast(r->args.size()); - - if (r->nargs_pos_only > r->nargs_pos) - { + if (r->nargs_pos_only > r->nargs_pos) { pybind11_fail("pos_only(): cannot follow a py::args() argument"); } - // It also can't follow a kw_only, but a static_assert in pybind11.h checks that } }; @@ -647,96 +553,60 @@ struct process_attribute : process_attribute_default /// that) template struct process_attribute::value>> - : process_attribute_default -{ - static void init(const handle& h, type_record* r) - { - r->bases.append(h); - } + : process_attribute_default { + static void init(const handle &h, type_record *r) { r->bases.append(h); } }; /// Process a parent class attribute (deprecated, does not support multiple inheritance) template -struct process_attribute> : process_attribute_default> -{ - static void init(const base&, type_record* r) - { - r->add_base(typeid(T), nullptr); - } +struct process_attribute> : process_attribute_default> { + static void init(const base &, type_record *r) { r->add_base(typeid(T), nullptr); } }; /// Process a multiple inheritance attribute template <> -struct process_attribute : process_attribute_default -{ - static void init(const multiple_inheritance&, type_record* r) - { +struct process_attribute : process_attribute_default { + static void init(const multiple_inheritance &, type_record *r) { r->multiple_inheritance = true; } }; template <> -struct process_attribute : process_attribute_default -{ - static void init(const dynamic_attr&, type_record* r) - { - r->dynamic_attr = true; - } +struct process_attribute : process_attribute_default { + static void init(const dynamic_attr &, type_record *r) { r->dynamic_attr = true; } }; template <> -struct process_attribute -{ - static void init(const custom_type_setup& value, type_record* r) - { +struct process_attribute { + static void init(const custom_type_setup &value, type_record *r) { r->custom_type_setup_callback = value.value; } }; template <> -struct process_attribute : process_attribute_default -{ - static void init(const is_final&, type_record* r) - { - r->is_final = true; - } +struct process_attribute : process_attribute_default { + static void init(const is_final &, type_record *r) { r->is_final = true; } }; template <> -struct process_attribute : process_attribute_default -{ - static void init(const buffer_protocol&, type_record* r) - { - r->buffer_protocol = true; - } +struct process_attribute : process_attribute_default { + static void init(const buffer_protocol &, type_record *r) { r->buffer_protocol = true; } }; template <> -struct process_attribute : process_attribute_default -{ - static void init(const metaclass& m, type_record* r) - { - r->metaclass = m.value; - } +struct process_attribute : process_attribute_default { + static void init(const metaclass &m, type_record *r) { r->metaclass = m.value; } }; template <> -struct process_attribute : process_attribute_default -{ - static void init(const module_local& l, type_record* r) - { - r->module_local = l.value; - } +struct process_attribute : process_attribute_default { + static void init(const module_local &l, type_record *r) { r->module_local = l.value; } }; /// Process a 'prepend' attribute, putting this at the beginning of the overload chain template <> -struct process_attribute : process_attribute_default -{ - static void init(const prepend&, function_record* r) - { - r->prepend = true; - } +struct process_attribute : process_attribute_default { + static void init(const prepend &, function_record *r) { r->prepend = true; } }; /// Process an 'arithmetic' attribute for enums (does nothing here) @@ -753,59 +623,49 @@ struct process_attribute> : process_attribute_default struct process_attribute> - : public process_attribute_default> -{ - template < size_t N = Nurse, size_t P = Patient, enable_if_t < N != 0 && P != 0, int > = 0 > - static void precall(function_call& call) - { + : public process_attribute_default> { + template = 0> + static void precall(function_call &call) { keep_alive_impl(Nurse, Patient, call, handle()); } - template < size_t N = Nurse, size_t P = Patient, enable_if_t < N != 0 && P != 0, int > = 0 > - static void postcall(function_call&, handle) {} - template < size_t N = Nurse, size_t P = Patient, enable_if_t < N == 0 || P == 0, int > = 0 > - static void precall(function_call&) {} - template < size_t N = Nurse, size_t P = Patient, enable_if_t < N == 0 || P == 0, int > = 0 > - static void postcall(function_call& call, handle ret) - { + template = 0> + static void postcall(function_call &, handle) {} + template = 0> + static void precall(function_call &) {} + template = 0> + static void postcall(function_call &call, handle ret) { keep_alive_impl(Nurse, Patient, call, ret); } }; /// Recursively iterate over variadic template arguments template -struct process_attributes -{ - static void init(const Args& ...args, function_record* r) - { +struct process_attributes { + static void init(const Args &...args, function_record *r) { PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(r); PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(r); using expander = int[]; - (void) expander - { + (void) expander{ 0, ((void) process_attribute::type>::init(args, r), 0)...}; } - static void init(const Args& ...args, type_record* r) - { + static void init(const Args &...args, type_record *r) { PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(r); PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(r); using expander = int[]; (void) expander{0, (process_attribute::type>::init(args, r), 0)...}; } - static void precall(function_call& call) - { + static void precall(function_call &call) { PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(call); using expander = int[]; (void) expander{0, (process_attribute::type>::precall(call), 0)...}; } - static void postcall(function_call& call, handle fn_ret) - { + static void postcall(function_call &call, handle fn_ret) { PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(call, fn_ret); PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(fn_ret); using expander = int[]; - (void) expander - { + (void) expander{ 0, (process_attribute::type>::postcall(call, fn_ret), 0)...}; } }; @@ -821,8 +681,7 @@ using extract_guard_t = typename exactly_one_t, Extr template ::value...), size_t self = constexpr_sum(std::is_same::value...)> -constexpr bool expected_num_args(size_t nargs, bool has_args, bool has_kwargs) -{ +constexpr bool expected_num_args(size_t nargs, bool has_args, bool has_kwargs) { PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(nargs, has_args, has_kwargs); return named == 0 || (self + named + size_t(has_args) + size_t(has_kwargs)) == nargs; } diff --git a/examples/knxPython/pybind11/include/pybind11/buffer_info.h b/examples/knxPython/pybind11/include/pybind11/buffer_info.h index 5667d85c..75aec0ba 100644 --- a/examples/knxPython/pybind11/include/pybind11/buffer_info.h +++ b/examples/knxPython/pybind11/include/pybind11/buffer_info.h @@ -16,33 +16,24 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(detail) // Default, C-style strides -inline std::vector c_strides(const std::vector& shape, ssize_t itemsize) -{ +inline std::vector c_strides(const std::vector &shape, ssize_t itemsize) { auto ndim = shape.size(); std::vector strides(ndim, itemsize); - - if (ndim > 0) - { - for (size_t i = ndim - 1; i > 0; --i) - { + if (ndim > 0) { + for (size_t i = ndim - 1; i > 0; --i) { strides[i - 1] = strides[i] * shape[i]; } } - return strides; } // F-style strides; default when constructing an array_t with `ExtraFlags & f_style` -inline std::vector f_strides(const std::vector& shape, ssize_t itemsize) -{ +inline std::vector f_strides(const std::vector &shape, ssize_t itemsize) { auto ndim = shape.size(); std::vector strides(ndim, itemsize); - - for (size_t i = 1; i < ndim; ++i) - { + for (size_t i = 1; i < ndim; ++i) { strides[i] = strides[i - 1] * shape[i - 1]; } - return strides; } @@ -52,183 +43,158 @@ struct compare_buffer_info; PYBIND11_NAMESPACE_END(detail) /// Information record describing a Python buffer object -struct buffer_info -{ - void* ptr = nullptr; // Pointer to the underlying storage - ssize_t itemsize = 0; // Size of individual items in bytes - ssize_t size = 0; // Total number of entries - std::string format; // For homogeneous buffers, this should be set to - // format_descriptor::format() - ssize_t ndim = 0; // Number of dimensions - std::vector shape; // Shape of the tensor (1 entry per dimension) - std::vector strides; // Number of bytes between adjacent entries - // (for each per dimension) - bool readonly = false; // flag to indicate if the underlying storage may be written to - - buffer_info() = default; - - buffer_info(void* ptr, - ssize_t itemsize, - const std::string& format, - ssize_t ndim, - detail::any_container shape_in, - detail::any_container strides_in, - bool readonly = false) - : ptr(ptr), itemsize(itemsize), size(1), format(format), ndim(ndim), - shape(std::move(shape_in)), strides(std::move(strides_in)), readonly(readonly) - { - if (ndim != (ssize_t) shape.size() || ndim != (ssize_t) strides.size()) - { - pybind11_fail("buffer_info: ndim doesn't match shape and/or strides length"); - } - - for (size_t i = 0; i < (size_t) ndim; ++i) - { - size *= shape[i]; - } +struct buffer_info { + void *ptr = nullptr; // Pointer to the underlying storage + ssize_t itemsize = 0; // Size of individual items in bytes + ssize_t size = 0; // Total number of entries + std::string format; // For homogeneous buffers, this should be set to + // format_descriptor::format() + ssize_t ndim = 0; // Number of dimensions + std::vector shape; // Shape of the tensor (1 entry per dimension) + std::vector strides; // Number of bytes between adjacent entries + // (for each per dimension) + bool readonly = false; // flag to indicate if the underlying storage may be written to + + buffer_info() = default; + + buffer_info(void *ptr, + ssize_t itemsize, + const std::string &format, + ssize_t ndim, + detail::any_container shape_in, + detail::any_container strides_in, + bool readonly = false) + : ptr(ptr), itemsize(itemsize), size(1), format(format), ndim(ndim), + shape(std::move(shape_in)), strides(std::move(strides_in)), readonly(readonly) { + if (ndim != (ssize_t) shape.size() || ndim != (ssize_t) strides.size()) { + pybind11_fail("buffer_info: ndim doesn't match shape and/or strides length"); } - - template buffer_info(T* ptr, - detail::any_container shape_in, - detail::any_container strides_in, - bool readonly = false) - : buffer_info(private_ctr_tag(), - ptr, - sizeof(T), - format_descriptor::format(), - static_cast(shape_in->size()), - std::move(shape_in), - std::move(strides_in), - readonly) {} - - buffer_info(void* ptr, - ssize_t itemsize, - const std::string& format, - ssize_t size, - bool readonly = false) - : buffer_info(ptr, itemsize, format, 1, - { - size - }, {itemsize}, readonly) {} - - template buffer_info(T* ptr, ssize_t size, bool readonly = false) - : buffer_info(ptr, sizeof(T), format_descriptor::format(), size, readonly) {} - - template buffer_info(const T* ptr, ssize_t size, bool readonly = true) - : buffer_info( - const_cast(ptr), sizeof(T), format_descriptor::format(), size, readonly) {} - - explicit buffer_info(Py_buffer* view, bool ownview = true) - : buffer_info( - view->buf, - view->itemsize, - view->format, - view->ndim, - { - view->shape, view->shape + view->ndim - }, - /* Though buffer::request() requests PyBUF_STRIDES, ctypes objects - * ignore this flag and return a view with NULL strides. - * When strides are NULL, build them manually. */ - view->strides - ? std::vector(view->strides, view->strides + view->ndim) - : detail::c_strides({view->shape, view->shape + view->ndim}, view->itemsize), - (view->readonly != 0)) - { - // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) - this->m_view = view; - // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) - this->ownview = ownview; - } - - buffer_info(const buffer_info&) = delete; - buffer_info& operator=(const buffer_info&) = delete; - - buffer_info(buffer_info&& other) noexcept - { - (*this) = std::move(other); + for (size_t i = 0; i < (size_t) ndim; ++i) { + size *= shape[i]; } + } - buffer_info& operator=(buffer_info&& rhs) noexcept - { - ptr = rhs.ptr; - itemsize = rhs.itemsize; - size = rhs.size; - format = std::move(rhs.format); - ndim = rhs.ndim; - shape = std::move(rhs.shape); - strides = std::move(rhs.strides); - std::swap(m_view, rhs.m_view); - std::swap(ownview, rhs.ownview); - readonly = rhs.readonly; - return *this; - } + template + buffer_info(T *ptr, + detail::any_container shape_in, + detail::any_container strides_in, + bool readonly = false) + : buffer_info(private_ctr_tag(), + ptr, + sizeof(T), + format_descriptor::format(), + static_cast(shape_in->size()), + std::move(shape_in), + std::move(strides_in), + readonly) {} + + buffer_info(void *ptr, + ssize_t itemsize, + const std::string &format, + ssize_t size, + bool readonly = false) + : buffer_info(ptr, itemsize, format, 1, {size}, {itemsize}, readonly) {} + + template + buffer_info(T *ptr, ssize_t size, bool readonly = false) + : buffer_info(ptr, sizeof(T), format_descriptor::format(), size, readonly) {} + + template + buffer_info(const T *ptr, ssize_t size, bool readonly = true) + : buffer_info( + const_cast(ptr), sizeof(T), format_descriptor::format(), size, readonly) {} + + explicit buffer_info(Py_buffer *view, bool ownview = true) + : buffer_info( + view->buf, + view->itemsize, + view->format, + view->ndim, + {view->shape, view->shape + view->ndim}, + /* Though buffer::request() requests PyBUF_STRIDES, ctypes objects + * ignore this flag and return a view with NULL strides. + * When strides are NULL, build them manually. */ + view->strides + ? std::vector(view->strides, view->strides + view->ndim) + : detail::c_strides({view->shape, view->shape + view->ndim}, view->itemsize), + (view->readonly != 0)) { + // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) + this->m_view = view; + // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) + this->ownview = ownview; + } - ~buffer_info() - { - if (m_view && ownview) - { - PyBuffer_Release(m_view); - delete m_view; - } - } + buffer_info(const buffer_info &) = delete; + buffer_info &operator=(const buffer_info &) = delete; + + buffer_info(buffer_info &&other) noexcept { (*this) = std::move(other); } + + buffer_info &operator=(buffer_info &&rhs) noexcept { + ptr = rhs.ptr; + itemsize = rhs.itemsize; + size = rhs.size; + format = std::move(rhs.format); + ndim = rhs.ndim; + shape = std::move(rhs.shape); + strides = std::move(rhs.strides); + std::swap(m_view, rhs.m_view); + std::swap(ownview, rhs.ownview); + readonly = rhs.readonly; + return *this; + } - Py_buffer* view() const - { - return m_view; - } - Py_buffer*& view() - { - return m_view; + ~buffer_info() { + if (m_view && ownview) { + PyBuffer_Release(m_view); + delete m_view; } + } - /* True if the buffer item type is equivalent to `T`. */ - // To define "equivalent" by example: - // `buffer_info::item_type_is_equivalent_to(b)` and - // `buffer_info::item_type_is_equivalent_to(b)` may both be true - // on some platforms, but `int` and `unsigned` will never be equivalent. - // For the ground truth, please inspect `detail::compare_buffer_info<>`. - template - bool item_type_is_equivalent_to() const - { - return detail::compare_buffer_info::compare(*this); - } + Py_buffer *view() const { return m_view; } + Py_buffer *&view() { return m_view; } + + /* True if the buffer item type is equivalent to `T`. */ + // To define "equivalent" by example: + // `buffer_info::item_type_is_equivalent_to(b)` and + // `buffer_info::item_type_is_equivalent_to(b)` may both be true + // on some platforms, but `int` and `unsigned` will never be equivalent. + // For the ground truth, please inspect `detail::compare_buffer_info<>`. + template + bool item_type_is_equivalent_to() const { + return detail::compare_buffer_info::compare(*this); + } - private: - struct private_ctr_tag {}; - - buffer_info(private_ctr_tag, - void* ptr, - ssize_t itemsize, - const std::string& format, - ssize_t ndim, - detail::any_container&& shape_in, - detail::any_container&& strides_in, - bool readonly) - : buffer_info( - ptr, itemsize, format, ndim, std::move(shape_in), std::move(strides_in), readonly) {} - - Py_buffer* m_view = nullptr; - bool ownview = false; +private: + struct private_ctr_tag {}; + + buffer_info(private_ctr_tag, + void *ptr, + ssize_t itemsize, + const std::string &format, + ssize_t ndim, + detail::any_container &&shape_in, + detail::any_container &&strides_in, + bool readonly) + : buffer_info( + ptr, itemsize, format, ndim, std::move(shape_in), std::move(strides_in), readonly) {} + + Py_buffer *m_view = nullptr; + bool ownview = false; }; PYBIND11_NAMESPACE_BEGIN(detail) template -struct compare_buffer_info -{ - static bool compare(const buffer_info& b) - { +struct compare_buffer_info { + static bool compare(const buffer_info &b) { // NOLINTNEXTLINE(bugprone-sizeof-expression) Needed for `PyObject *` return b.format == format_descriptor::format() && b.itemsize == (ssize_t) sizeof(T); } }; template -struct compare_buffer_info::value>> -{ - static bool compare(const buffer_info& b) - { +struct compare_buffer_info::value>> { + static bool compare(const buffer_info &b) { return (size_t) b.itemsize == sizeof(T) && (b.format == format_descriptor::value || ((sizeof(T) == sizeof(long)) diff --git a/examples/knxPython/pybind11/include/pybind11/cast.h b/examples/knxPython/pybind11/include/pybind11/cast.h index 4c9327a2..0f3091f6 100644 --- a/examples/knxPython/pybind11/include/pybind11/cast.h +++ b/examples/knxPython/pybind11/include/pybind11/cast.h @@ -41,72 +41,62 @@ using make_caster = type_caster>; // Shortcut for calling a caster's `cast_op_type` cast operator for casting a type_caster to a T template -typename make_caster::template cast_op_type cast_op(make_caster& caster) -{ +typename make_caster::template cast_op_type cast_op(make_caster &caster) { using result_t = typename make_caster::template cast_op_type; // See PR #4893 return caster.operator result_t(); } template -typename make_caster::template cast_op_type::type> cast_op(make_caster&& caster) -{ - using result_t = typename make_caster::template cast_op_type < - typename std::add_rvalue_reference::type >; // See PR #4893 +typename make_caster::template cast_op_type::type> +cast_op(make_caster &&caster) { + using result_t = typename make_caster::template cast_op_type< + typename std::add_rvalue_reference::type>; // See PR #4893 return std::move(caster).operator result_t(); } template -class type_caster> -{ - private: - using caster_t = make_caster; - caster_t subcaster; - using reference_t = type &; - using subcaster_cast_op_type = typename caster_t::template cast_op_type; - - static_assert( - std::is_same::type&, subcaster_cast_op_type>::value +class type_caster> { +private: + using caster_t = make_caster; + caster_t subcaster; + using reference_t = type &; + using subcaster_cast_op_type = typename caster_t::template cast_op_type; + + static_assert( + std::is_same::type &, subcaster_cast_op_type>::value || std::is_same::value, - "std::reference_wrapper caster requires T to have a caster with an " - "`operator T &()` or `operator const T &()`"); - - public: - bool load(handle src, bool convert) - { - return subcaster.load(src, convert); - } - static constexpr auto name = caster_t::name; - static handle cast(const std::reference_wrapper& src, return_value_policy policy, handle parent) - { - // It is definitely wrong to take ownership of this pointer, so mask that rvp - if (policy == return_value_policy::take_ownership - || policy == return_value_policy::automatic) - { - policy = return_value_policy::automatic_reference; - } - - return caster_t::cast(&src.get(), policy, parent); - } - template - using cast_op_type = std::reference_wrapper; - explicit operator std::reference_wrapper() - { - return cast_op(subcaster); - } + "std::reference_wrapper caster requires T to have a caster with an " + "`operator T &()` or `operator const T &()`"); + +public: + bool load(handle src, bool convert) { return subcaster.load(src, convert); } + static constexpr auto name = caster_t::name; + static handle + cast(const std::reference_wrapper &src, return_value_policy policy, handle parent) { + // It is definitely wrong to take ownership of this pointer, so mask that rvp + if (policy == return_value_policy::take_ownership + || policy == return_value_policy::automatic) { + policy = return_value_policy::automatic_reference; + } + return caster_t::cast(&src.get(), policy, parent); + } + template + using cast_op_type = std::reference_wrapper; + explicit operator std::reference_wrapper() { return cast_op(subcaster); } }; #define PYBIND11_TYPE_CASTER(type, py_name) \ - protected: \ +protected: \ type value; \ - \ - public: \ + \ +public: \ static constexpr auto name = py_name; \ template >::value, \ - int> \ + std::is_same>::value, \ + int> \ = 0> \ static ::pybind11::handle cast( \ - T_ *src, ::pybind11::return_value_policy policy, ::pybind11::handle parent) { \ + T_ *src, ::pybind11::return_value_policy policy, ::pybind11::handle parent) { \ if (!src) \ return ::pybind11::none().release(); \ if (policy == ::pybind11::return_value_policy::take_ownership) { \ @@ -123,803 +113,625 @@ class type_caster> using cast_op_type = ::pybind11::detail::movable_cast_op_type template -using is_std_char_type = any_of < std::is_same, /* std::string */ +using is_std_char_type = any_of, /* std::string */ #if defined(PYBIND11_HAS_U8STRING) - std::is_same, /* std::u8string */ + std::is_same, /* std::u8string */ #endif - std::is_same, /* std::u16string */ - std::is_same, /* std::u32string */ - std::is_same /* std::wstring */ - >; + std::is_same, /* std::u16string */ + std::is_same, /* std::u32string */ + std::is_same /* std::wstring */ + >; template -struct type_caster < T, enable_if_t < std::is_arithmetic::value&& !is_std_char_type::value >> -{ - using _py_type_0 = conditional_t < sizeof(T) <= sizeof(long), long, long long >; - using _py_type_1 = conditional_t::value, - _py_type_0, - typename std::make_unsigned<_py_type_0>::type>; - using py_type = conditional_t::value, double, _py_type_1>; - - public: - bool load(handle src, bool convert) - { - py_type py_value; - - if (!src) - { - return false; - } +struct type_caster::value && !is_std_char_type::value>> { + using _py_type_0 = conditional_t; + using _py_type_1 = conditional_t::value, + _py_type_0, + typename std::make_unsigned<_py_type_0>::type>; + using py_type = conditional_t::value, double, _py_type_1>; + +public: + bool load(handle src, bool convert) { + py_type py_value; + + if (!src) { + return false; + } #if !defined(PYPY_VERSION) - auto index_check = [](PyObject * o) - { - return PyIndex_Check(o); - }; + auto index_check = [](PyObject *o) { return PyIndex_Check(o); }; #else - // In PyPy 7.3.3, `PyIndex_Check` is implemented by calling `__index__`, - // while CPython only considers the existence of `nb_index`/`__index__`. - auto index_check = [](PyObject * o) - { - return hasattr(o, "__index__"); - }; + // In PyPy 7.3.3, `PyIndex_Check` is implemented by calling `__index__`, + // while CPython only considers the existence of `nb_index`/`__index__`. + auto index_check = [](PyObject *o) { return hasattr(o, "__index__"); }; #endif - if (std::is_floating_point::value) - { - if (convert || PyFloat_Check(src.ptr())) - { - py_value = (py_type) PyFloat_AsDouble(src.ptr()); - } - else - { - return false; - } - } - else if (PyFloat_Check(src.ptr()) - || (!convert && !PYBIND11_LONG_CHECK(src.ptr()) && !index_check(src.ptr()))) - { + if (std::is_floating_point::value) { + if (convert || PyFloat_Check(src.ptr())) { + py_value = (py_type) PyFloat_AsDouble(src.ptr()); + } else { return false; } - else - { - handle src_or_index = src; - // PyPy: 7.3.7's 3.8 does not implement PyLong_*'s __index__ calls. + } else if (PyFloat_Check(src.ptr()) + || (!convert && !PYBIND11_LONG_CHECK(src.ptr()) && !index_check(src.ptr()))) { + return false; + } else { + handle src_or_index = src; + // PyPy: 7.3.7's 3.8 does not implement PyLong_*'s __index__ calls. #if PY_VERSION_HEX < 0x03080000 || defined(PYPY_VERSION) - object index; - - if (!PYBIND11_LONG_CHECK(src.ptr())) // So: index_check(src.ptr()) - { - index = reinterpret_steal(PyNumber_Index(src.ptr())); - - if (!index) - { - PyErr_Clear(); - - if (!convert) - return false; - } - else - { - src_or_index = index; - } + object index; + if (!PYBIND11_LONG_CHECK(src.ptr())) { // So: index_check(src.ptr()) + index = reinterpret_steal(PyNumber_Index(src.ptr())); + if (!index) { + PyErr_Clear(); + if (!convert) + return false; + } else { + src_or_index = index; } - + } #endif - - if (std::is_unsigned::value) - { - py_value = as_unsigned(src_or_index.ptr()); - } - else // signed integer: - { - py_value = sizeof(T) <= sizeof(long) + if (std::is_unsigned::value) { + py_value = as_unsigned(src_or_index.ptr()); + } else { // signed integer: + py_value = sizeof(T) <= sizeof(long) ? (py_type) PyLong_AsLong(src_or_index.ptr()) : (py_type) PYBIND11_LONG_AS_LONGLONG(src_or_index.ptr()); - } } + } - // Python API reported an error - bool py_err = py_value == (py_type) - 1 && PyErr_Occurred(); - - // Check to see if the conversion is valid (integers should match exactly) - // Signed/unsigned checks happen elsewhere - if (py_err - || (std::is_integral::value && sizeof(py_type) != sizeof(T) - && py_value != (py_type) (T) py_value)) - { - PyErr_Clear(); + // Python API reported an error + bool py_err = py_value == (py_type) -1 && PyErr_Occurred(); - if (py_err && convert && (PyNumber_Check(src.ptr()) != 0)) - { - auto tmp = reinterpret_steal(std::is_floating_point::value + // Check to see if the conversion is valid (integers should match exactly) + // Signed/unsigned checks happen elsewhere + if (py_err + || (std::is_integral::value && sizeof(py_type) != sizeof(T) + && py_value != (py_type) (T) py_value)) { + PyErr_Clear(); + if (py_err && convert && (PyNumber_Check(src.ptr()) != 0)) { + auto tmp = reinterpret_steal(std::is_floating_point::value ? PyNumber_Float(src.ptr()) : PyNumber_Long(src.ptr())); - PyErr_Clear(); - return load(tmp, false); - } - - return false; + PyErr_Clear(); + return load(tmp, false); } - - value = (T) py_value; - return true; + return false; } - template - static typename std::enable_if::value, handle>::type cast(U src, return_value_policy /* policy */, handle /* parent */) - { - return PyFloat_FromDouble((double) src); - } + value = (T) py_value; + return true; + } - template - static typename std::enable_if < !std::is_floating_point::value && std::is_signed::value - && (sizeof(U) <= sizeof(long)), - handle >::type - cast(U src, return_value_policy /* policy */, handle /* parent */) - { - return PYBIND11_LONG_FROM_SIGNED((long) src); - } + template + static typename std::enable_if::value, handle>::type + cast(U src, return_value_policy /* policy */, handle /* parent */) { + return PyFloat_FromDouble((double) src); + } - template - static typename std::enable_if < !std::is_floating_point::value && std::is_unsigned::value - && (sizeof(U) <= sizeof(unsigned long)), - handle >::type - cast(U src, return_value_policy /* policy */, handle /* parent */) - { - return PYBIND11_LONG_FROM_UNSIGNED((unsigned long) src); - } + template + static typename std::enable_if::value && std::is_signed::value + && (sizeof(U) <= sizeof(long)), + handle>::type + cast(U src, return_value_policy /* policy */, handle /* parent */) { + return PYBIND11_LONG_FROM_SIGNED((long) src); + } - template - static typename std::enable_if < !std::is_floating_point::value && std::is_signed::value - && (sizeof(U) > sizeof(long)), - handle >::type - cast(U src, return_value_policy /* policy */, handle /* parent */) - { - return PyLong_FromLongLong((long long) src); - } + template + static typename std::enable_if::value && std::is_unsigned::value + && (sizeof(U) <= sizeof(unsigned long)), + handle>::type + cast(U src, return_value_policy /* policy */, handle /* parent */) { + return PYBIND11_LONG_FROM_UNSIGNED((unsigned long) src); + } - template - static typename std::enable_if < !std::is_floating_point::value && std::is_unsigned::value - && (sizeof(U) > sizeof(unsigned long)), - handle >::type - cast(U src, return_value_policy /* policy */, handle /* parent */) - { - return PyLong_FromUnsignedLongLong((unsigned long long) src); - } + template + static typename std::enable_if::value && std::is_signed::value + && (sizeof(U) > sizeof(long)), + handle>::type + cast(U src, return_value_policy /* policy */, handle /* parent */) { + return PyLong_FromLongLong((long long) src); + } + + template + static typename std::enable_if::value && std::is_unsigned::value + && (sizeof(U) > sizeof(unsigned long)), + handle>::type + cast(U src, return_value_policy /* policy */, handle /* parent */) { + return PyLong_FromUnsignedLongLong((unsigned long long) src); + } - PYBIND11_TYPE_CASTER(T, const_name::value>("int", "float")); + PYBIND11_TYPE_CASTER(T, const_name::value>("int", "float")); }; template -struct void_caster -{ - public: - bool load(handle src, bool) - { - if (src && src.is_none()) - { - return true; - } - - return false; - } - static handle cast(T, return_value_policy /* policy */, handle /* parent */) - { - return none().release(); +struct void_caster { +public: + bool load(handle src, bool) { + if (src && src.is_none()) { + return true; } - PYBIND11_TYPE_CASTER(T, const_name("None")); + return false; + } + static handle cast(T, return_value_policy /* policy */, handle /* parent */) { + return none().release(); + } + PYBIND11_TYPE_CASTER(T, const_name("None")); }; template <> class type_caster : public void_caster {}; template <> -class type_caster : public type_caster -{ - public: - using type_caster::cast; - - bool load(handle h, bool) - { - if (!h) - { - return false; - } - - if (h.is_none()) - { - value = nullptr; - return true; - } - - /* Check if this is a capsule */ - if (isinstance(h)) - { - value = reinterpret_borrow(h); - return true; - } - - /* Check if this is a C++ type */ - const auto& bases = all_type_info((PyTypeObject*) type::handle_of(h).ptr()); +class type_caster : public type_caster { +public: + using type_caster::cast; - if (bases.size() == 1) // Only allowing loading from a single-value type - { - value = values_and_holders(reinterpret_cast(h.ptr())).begin()->value_ptr(); - return true; - } - - /* Fail */ + bool load(handle h, bool) { + if (!h) { return false; } + if (h.is_none()) { + value = nullptr; + return true; + } - static handle cast(const void* ptr, return_value_policy /* policy */, handle /* parent */) - { - if (ptr) - { - return capsule(ptr).release(); - } + /* Check if this is a capsule */ + if (isinstance(h)) { + value = reinterpret_borrow(h); + return true; + } - return none().release(); + /* Check if this is a C++ type */ + const auto &bases = all_type_info((PyTypeObject *) type::handle_of(h).ptr()); + if (bases.size() == 1) { // Only allowing loading from a single-value type + value = values_and_holders(reinterpret_cast(h.ptr())).begin()->value_ptr(); + return true; } - template - using cast_op_type = void* &; - explicit operator void*& () - { - return value; + /* Fail */ + return false; + } + + static handle cast(const void *ptr, return_value_policy /* policy */, handle /* parent */) { + if (ptr) { + return capsule(ptr).release(); } - static constexpr auto name = const_name("capsule"); + return none().release(); + } + + template + using cast_op_type = void *&; + explicit operator void *&() { return value; } + static constexpr auto name = const_name("capsule"); - private: - void* value = nullptr; +private: + void *value = nullptr; }; template <> class type_caster : public void_caster {}; template <> -class type_caster -{ - public: - bool load(handle src, bool convert) - { - if (!src) - { - return false; - } - - if (src.ptr() == Py_True) - { - value = true; - return true; - } +class type_caster { +public: + bool load(handle src, bool convert) { + if (!src) { + return false; + } + if (src.ptr() == Py_True) { + value = true; + return true; + } + if (src.ptr() == Py_False) { + value = false; + return true; + } + if (convert || is_numpy_bool(src)) { + // (allow non-implicit conversion for numpy booleans), use strncmp + // since NumPy 1.x had an additional trailing underscore. - if (src.ptr() == Py_False) - { - value = false; - return true; + Py_ssize_t res = -1; + if (src.is_none()) { + res = 0; // None is implicitly converted to False } - - if (convert || is_numpy_bool(src)) - { - // (allow non-implicit conversion for numpy booleans), use strncmp - // since NumPy 1.x had an additional trailing underscore. - - Py_ssize_t res = -1; - - if (src.is_none()) - { - res = 0; // None is implicitly converted to False - } - #if defined(PYPY_VERSION) - // On PyPy, check that "__bool__" attr exists - else if (hasattr(src, PYBIND11_BOOL_ATTR)) - { - res = PyObject_IsTrue(src.ptr()); - } - + // On PyPy, check that "__bool__" attr exists + else if (hasattr(src, PYBIND11_BOOL_ATTR)) { + res = PyObject_IsTrue(src.ptr()); + } #else - // Alternate approach for CPython: this does the same as the above, but optimized - // using the CPython API so as to avoid an unneeded attribute lookup. - else if (auto* tp_as_number = src.ptr()->ob_type->tp_as_number) - { - if (PYBIND11_NB_BOOL(tp_as_number)) - { - res = (*PYBIND11_NB_BOOL(tp_as_number))(src.ptr()); - } + // Alternate approach for CPython: this does the same as the above, but optimized + // using the CPython API so as to avoid an unneeded attribute lookup. + else if (auto *tp_as_number = src.ptr()->ob_type->tp_as_number) { + if (PYBIND11_NB_BOOL(tp_as_number)) { + res = (*PYBIND11_NB_BOOL(tp_as_number))(src.ptr()); } - + } #endif - - if (res == 0 || res == 1) - { - value = (res != 0); - return true; - } - - PyErr_Clear(); + if (res == 0 || res == 1) { + value = (res != 0); + return true; } - - return false; - } - static handle cast(bool src, return_value_policy /* policy */, handle /* parent */) - { - return handle(src ? Py_True : Py_False).inc_ref(); - } - PYBIND11_TYPE_CASTER(bool, const_name("bool")); - - private: - // Test if an object is a NumPy boolean (without fetching the type). - static inline bool is_numpy_bool(handle object) - { - const char* type_name = Py_TYPE(object.ptr())->tp_name; - // Name changed to `numpy.bool` in NumPy 2, `numpy.bool_` is needed for 1.x support - return std::strcmp("numpy.bool", type_name) == 0 - || std::strcmp("numpy.bool_", type_name) == 0; + PyErr_Clear(); } + return false; + } + static handle cast(bool src, return_value_policy /* policy */, handle /* parent */) { + return handle(src ? Py_True : Py_False).inc_ref(); + } + PYBIND11_TYPE_CASTER(bool, const_name("bool")); + +private: + // Test if an object is a NumPy boolean (without fetching the type). + static inline bool is_numpy_bool(handle object) { + const char *type_name = Py_TYPE(object.ptr())->tp_name; + // Name changed to `numpy.bool` in NumPy 2, `numpy.bool_` is needed for 1.x support + return std::strcmp("numpy.bool", type_name) == 0 + || std::strcmp("numpy.bool_", type_name) == 0; + } }; // Helper class for UTF-{8,16,32} C++ stl strings: template -struct string_caster -{ - using CharT = typename StringType::value_type; - - // Simplify life by being able to assume standard char sizes (the standard only guarantees - // minimums, but Python requires exact sizes) - static_assert(!std::is_same::value || sizeof(CharT) == 1, - "Unsupported char size != 1"); +struct string_caster { + using CharT = typename StringType::value_type; + + // Simplify life by being able to assume standard char sizes (the standard only guarantees + // minimums, but Python requires exact sizes) + static_assert(!std::is_same::value || sizeof(CharT) == 1, + "Unsupported char size != 1"); #if defined(PYBIND11_HAS_U8STRING) - static_assert(!std::is_same::value || sizeof(CharT) == 1, - "Unsupported char8_t size != 1"); + static_assert(!std::is_same::value || sizeof(CharT) == 1, + "Unsupported char8_t size != 1"); #endif - static_assert(!std::is_same::value || sizeof(CharT) == 2, - "Unsupported char16_t size != 2"); - static_assert(!std::is_same::value || sizeof(CharT) == 4, - "Unsupported char32_t size != 4"); - // wchar_t can be either 16 bits (Windows) or 32 (everywhere else) - static_assert(!std::is_same::value || sizeof(CharT) == 2 || sizeof(CharT) == 4, - "Unsupported wchar_t size != 2/4"); - static constexpr size_t UTF_N = 8 * sizeof(CharT); - - bool load(handle src, bool) - { - handle load_src = src; - - if (!src) - { - return false; - } - - if (!PyUnicode_Check(load_src.ptr())) - { - return load_raw(load_src); - } - - // For UTF-8 we avoid the need for a temporary `bytes` object by using - // `PyUnicode_AsUTF8AndSize`. - if (UTF_N == 8) - { - Py_ssize_t size = -1; - const auto* buffer - = reinterpret_cast(PyUnicode_AsUTF8AndSize(load_src.ptr(), &size)); - - if (!buffer) - { - PyErr_Clear(); - return false; - } - - value = StringType(buffer, static_cast(size)); - return true; - } - - auto utfNbytes - = reinterpret_steal(PyUnicode_AsEncodedString(load_src.ptr(), - UTF_N == 8 ? "utf-8" - : UTF_N == 16 ? "utf-16" - : "utf-32", - nullptr)); + static_assert(!std::is_same::value || sizeof(CharT) == 2, + "Unsupported char16_t size != 2"); + static_assert(!std::is_same::value || sizeof(CharT) == 4, + "Unsupported char32_t size != 4"); + // wchar_t can be either 16 bits (Windows) or 32 (everywhere else) + static_assert(!std::is_same::value || sizeof(CharT) == 2 || sizeof(CharT) == 4, + "Unsupported wchar_t size != 2/4"); + static constexpr size_t UTF_N = 8 * sizeof(CharT); + + bool load(handle src, bool) { + handle load_src = src; + if (!src) { + return false; + } + if (!PyUnicode_Check(load_src.ptr())) { + return load_raw(load_src); + } - if (!utfNbytes) - { + // For UTF-8 we avoid the need for a temporary `bytes` object by using + // `PyUnicode_AsUTF8AndSize`. + if (UTF_N == 8) { + Py_ssize_t size = -1; + const auto *buffer + = reinterpret_cast(PyUnicode_AsUTF8AndSize(load_src.ptr(), &size)); + if (!buffer) { PyErr_Clear(); return false; } + value = StringType(buffer, static_cast(size)); + return true; + } - const auto* buffer - = reinterpret_cast(PYBIND11_BYTES_AS_STRING(utfNbytes.ptr())); - size_t length = (size_t) PYBIND11_BYTES_SIZE(utfNbytes.ptr()) / sizeof(CharT); - - // Skip BOM for UTF-16/32 - if (UTF_N > 8) - { - buffer++; - length--; - } - - value = StringType(buffer, length); - - // If we're loading a string_view we need to keep the encoded Python object alive: - if (IsView) - { - loader_life_support::add_patient(utfNbytes); - } + auto utfNbytes + = reinterpret_steal(PyUnicode_AsEncodedString(load_src.ptr(), + UTF_N == 8 ? "utf-8" + : UTF_N == 16 ? "utf-16" + : "utf-32", + nullptr)); + if (!utfNbytes) { + PyErr_Clear(); + return false; + } - return true; + const auto *buffer + = reinterpret_cast(PYBIND11_BYTES_AS_STRING(utfNbytes.ptr())); + size_t length = (size_t) PYBIND11_BYTES_SIZE(utfNbytes.ptr()) / sizeof(CharT); + // Skip BOM for UTF-16/32 + if (UTF_N > 8) { + buffer++; + length--; } + value = StringType(buffer, length); - static handle cast(const StringType& src, return_value_policy /* policy */, handle /* parent */) - { - const char* buffer = reinterpret_cast(src.data()); - auto nbytes = ssize_t(src.size() * sizeof(CharT)); - handle s = decode_utfN(buffer, nbytes); + // If we're loading a string_view we need to keep the encoded Python object alive: + if (IsView) { + loader_life_support::add_patient(utfNbytes); + } - if (!s) - { - throw error_already_set(); - } + return true; + } - return s; + static handle + cast(const StringType &src, return_value_policy /* policy */, handle /* parent */) { + const char *buffer = reinterpret_cast(src.data()); + auto nbytes = ssize_t(src.size() * sizeof(CharT)); + handle s = decode_utfN(buffer, nbytes); + if (!s) { + throw error_already_set(); } + return s; + } - PYBIND11_TYPE_CASTER(StringType, const_name(PYBIND11_STRING_NAME)); + PYBIND11_TYPE_CASTER(StringType, const_name(PYBIND11_STRING_NAME)); - private: - static handle decode_utfN(const char* buffer, ssize_t nbytes) - { +private: + static handle decode_utfN(const char *buffer, ssize_t nbytes) { #if !defined(PYPY_VERSION) - return UTF_N == 8 ? PyUnicode_DecodeUTF8(buffer, nbytes, nullptr) - : UTF_N == 16 ? PyUnicode_DecodeUTF16(buffer, nbytes, nullptr, nullptr) - : PyUnicode_DecodeUTF32(buffer, nbytes, nullptr, nullptr); + return UTF_N == 8 ? PyUnicode_DecodeUTF8(buffer, nbytes, nullptr) + : UTF_N == 16 ? PyUnicode_DecodeUTF16(buffer, nbytes, nullptr, nullptr) + : PyUnicode_DecodeUTF32(buffer, nbytes, nullptr, nullptr); #else - // PyPy segfaults when on PyUnicode_DecodeUTF16 (and possibly on PyUnicode_DecodeUTF32 as - // well), so bypass the whole thing by just passing the encoding as a string value, which - // works properly: - return PyUnicode_Decode(buffer, - nbytes, - UTF_N == 8 ? "utf-8" - : UTF_N == 16 ? "utf-16" - : "utf-32", - nullptr); + // PyPy segfaults when on PyUnicode_DecodeUTF16 (and possibly on PyUnicode_DecodeUTF32 as + // well), so bypass the whole thing by just passing the encoding as a string value, which + // works properly: + return PyUnicode_Decode(buffer, + nbytes, + UTF_N == 8 ? "utf-8" + : UTF_N == 16 ? "utf-16" + : "utf-32", + nullptr); #endif - } - - // When loading into a std::string or char*, accept a bytes/bytearray object as-is (i.e. - // without any encoding/decoding attempt). For other C++ char sizes this is a no-op. - // which supports loading a unicode from a str, doesn't take this path. - template - bool load_raw(enable_if_t::value, handle> src) - { - if (PYBIND11_BYTES_CHECK(src.ptr())) - { - // We were passed raw bytes; accept it into a std::string or char* - // without any encoding attempt. - const char* bytes = PYBIND11_BYTES_AS_STRING(src.ptr()); - - if (!bytes) - { - pybind11_fail("Unexpected PYBIND11_BYTES_AS_STRING() failure."); - } + } - value = StringType(bytes, (size_t) PYBIND11_BYTES_SIZE(src.ptr())); - return true; + // When loading into a std::string or char*, accept a bytes/bytearray object as-is (i.e. + // without any encoding/decoding attempt). For other C++ char sizes this is a no-op. + // which supports loading a unicode from a str, doesn't take this path. + template + bool load_raw(enable_if_t::value, handle> src) { + if (PYBIND11_BYTES_CHECK(src.ptr())) { + // We were passed raw bytes; accept it into a std::string or char* + // without any encoding attempt. + const char *bytes = PYBIND11_BYTES_AS_STRING(src.ptr()); + if (!bytes) { + pybind11_fail("Unexpected PYBIND11_BYTES_AS_STRING() failure."); } - - if (PyByteArray_Check(src.ptr())) - { - // We were passed a bytearray; accept it into a std::string or char* - // without any encoding attempt. - const char* bytearray = PyByteArray_AsString(src.ptr()); - - if (!bytearray) - { - pybind11_fail("Unexpected PyByteArray_AsString() failure."); - } - - value = StringType(bytearray, (size_t) PyByteArray_Size(src.ptr())); - return true; + value = StringType(bytes, (size_t) PYBIND11_BYTES_SIZE(src.ptr())); + return true; + } + if (PyByteArray_Check(src.ptr())) { + // We were passed a bytearray; accept it into a std::string or char* + // without any encoding attempt. + const char *bytearray = PyByteArray_AsString(src.ptr()); + if (!bytearray) { + pybind11_fail("Unexpected PyByteArray_AsString() failure."); } - - return false; + value = StringType(bytearray, (size_t) PyByteArray_Size(src.ptr())); + return true; } - template - bool load_raw(enable_if_t < !std::is_same::value, handle > ) - { - return false; - } + return false; + } + + template + bool load_raw(enable_if_t::value, handle>) { + return false; + } }; template struct type_caster, - enable_if_t::value>> - : string_caster> {}; + enable_if_t::value>> + : string_caster> {}; #ifdef PYBIND11_HAS_STRING_VIEW template struct type_caster, - enable_if_t::value>> - : string_caster, true> {}; + enable_if_t::value>> + : string_caster, true> {}; #endif // Type caster for C-style strings. We basically use a std::string type caster, but also add the // ability to use None as a nullptr char* (which the string caster doesn't allow). template -struct type_caster::value>> -{ - using StringType = std::basic_string; - using StringCaster = make_caster; - StringCaster str_caster; - bool none = false; - CharT one_char = 0; - - public: - bool load(handle src, bool convert) - { - if (!src) - { +struct type_caster::value>> { + using StringType = std::basic_string; + using StringCaster = make_caster; + StringCaster str_caster; + bool none = false; + CharT one_char = 0; + +public: + bool load(handle src, bool convert) { + if (!src) { + return false; + } + if (src.is_none()) { + // Defer accepting None to other overloads (if we aren't in convert mode): + if (!convert) { return false; } - - if (src.is_none()) - { - // Defer accepting None to other overloads (if we aren't in convert mode): - if (!convert) - { - return false; - } - - none = true; - return true; - } - - return str_caster.load(src, convert); + none = true; + return true; } + return str_caster.load(src, convert); + } - static handle cast(const CharT* src, return_value_policy policy, handle parent) - { - if (src == nullptr) - { - return pybind11::none().release(); - } - - return StringCaster::cast(StringType(src), policy, parent); + static handle cast(const CharT *src, return_value_policy policy, handle parent) { + if (src == nullptr) { + return pybind11::none().release(); } + return StringCaster::cast(StringType(src), policy, parent); + } - static handle cast(CharT src, return_value_policy policy, handle parent) - { - if (std::is_same::value) - { - handle s = PyUnicode_DecodeLatin1((const char*) &src, 1, nullptr); - - if (!s) - { - throw error_already_set(); - } - - return s; + static handle cast(CharT src, return_value_policy policy, handle parent) { + if (std::is_same::value) { + handle s = PyUnicode_DecodeLatin1((const char *) &src, 1, nullptr); + if (!s) { + throw error_already_set(); } - - return StringCaster::cast(StringType(1, src), policy, parent); - } - - explicit operator CharT* () - { - return none ? nullptr : const_cast(static_cast(str_caster).c_str()); + return s; } - explicit operator CharT& () - { - if (none) - { - throw value_error("Cannot convert None to a character"); - } - - auto& value = static_cast(str_caster); - size_t str_len = value.size(); - - if (str_len == 0) - { - throw value_error("Cannot convert empty string to a character"); - } - - // If we're in UTF-8 mode, we have two possible failures: one for a unicode character that - // is too high, and one for multiple unicode characters (caught later), so we need to - // figure out how long the first encoded character is in bytes to distinguish between these - // two errors. We also allow want to allow unicode characters U+0080 through U+00FF, as - // those can fit into a single char value. - if (StringCaster::UTF_N == 8 && str_len > 1 && str_len <= 4) - { - auto v0 = static_cast(value[0]); - // low bits only: 0-127 - // 0b110xxxxx - start of 2-byte sequence - // 0b1110xxxx - start of 3-byte sequence - // 0b11110xxx - start of 4-byte sequence - size_t char0_bytes = (v0 & 0x80) == 0 ? 1 - : (v0 & 0xE0) == 0xC0 ? 2 - : (v0 & 0xF0) == 0xE0 ? 3 - : 4; - - if (char0_bytes == str_len) - { - // If we have a 128-255 value, we can decode it into a single char: - if (char0_bytes == 2 && (v0 & 0xFC) == 0xC0) // 0x110000xx 0x10xxxxxx - { - one_char = static_cast(((v0 & 3) << 6) - + (static_cast(value[1]) & 0x3F)); - return one_char; - } - - // Otherwise we have a single character, but it's > U+00FF - throw value_error("Character code point not in range(0x100)"); - } - } - - // UTF-16 is much easier: we can only have a surrogate pair for values above U+FFFF, thus a - // surrogate pair with total length 2 instantly indicates a range error (but not a "your - // string was too long" error). - else if (StringCaster::UTF_N == 16 && str_len == 2) - { - one_char = static_cast(value[0]); + return StringCaster::cast(StringType(1, src), policy, parent); + } - if (one_char >= 0xD800 && one_char < 0xE000) - { - throw value_error("Character code point not in range(0x10000)"); + explicit operator CharT *() { + return none ? nullptr : const_cast(static_cast(str_caster).c_str()); + } + explicit operator CharT &() { + if (none) { + throw value_error("Cannot convert None to a character"); + } + + auto &value = static_cast(str_caster); + size_t str_len = value.size(); + if (str_len == 0) { + throw value_error("Cannot convert empty string to a character"); + } + + // If we're in UTF-8 mode, we have two possible failures: one for a unicode character that + // is too high, and one for multiple unicode characters (caught later), so we need to + // figure out how long the first encoded character is in bytes to distinguish between these + // two errors. We also allow want to allow unicode characters U+0080 through U+00FF, as + // those can fit into a single char value. + if (StringCaster::UTF_N == 8 && str_len > 1 && str_len <= 4) { + auto v0 = static_cast(value[0]); + // low bits only: 0-127 + // 0b110xxxxx - start of 2-byte sequence + // 0b1110xxxx - start of 3-byte sequence + // 0b11110xxx - start of 4-byte sequence + size_t char0_bytes = (v0 & 0x80) == 0 ? 1 + : (v0 & 0xE0) == 0xC0 ? 2 + : (v0 & 0xF0) == 0xE0 ? 3 + : 4; + + if (char0_bytes == str_len) { + // If we have a 128-255 value, we can decode it into a single char: + if (char0_bytes == 2 && (v0 & 0xFC) == 0xC0) { // 0x110000xx 0x10xxxxxx + one_char = static_cast(((v0 & 3) << 6) + + (static_cast(value[1]) & 0x3F)); + return one_char; } + // Otherwise we have a single character, but it's > U+00FF + throw value_error("Character code point not in range(0x100)"); } + } - if (str_len != 1) - { - throw value_error("Expected a character, but multi-character string found"); + // UTF-16 is much easier: we can only have a surrogate pair for values above U+FFFF, thus a + // surrogate pair with total length 2 instantly indicates a range error (but not a "your + // string was too long" error). + else if (StringCaster::UTF_N == 16 && str_len == 2) { + one_char = static_cast(value[0]); + if (one_char >= 0xD800 && one_char < 0xE000) { + throw value_error("Character code point not in range(0x10000)"); } + } - one_char = value[0]; - return one_char; + if (str_len != 1) { + throw value_error("Expected a character, but multi-character string found"); } - static constexpr auto name = const_name(PYBIND11_STRING_NAME); - template - using cast_op_type = pybind11::detail::cast_op_type<_T>; + one_char = value[0]; + return one_char; + } + + static constexpr auto name = const_name(PYBIND11_STRING_NAME); + template + using cast_op_type = pybind11::detail::cast_op_type<_T>; }; // Base implementation for std::tuple and std::pair template