From fbdf8404867c36579565151d54f9547c8c8e27e3 Mon Sep 17 00:00:00 2001 From: PyBind11 Upstream Date: Mon, 28 Mar 2022 17:24:59 -0400 Subject: [PATCH] pybind11 2022-03-28 (42d8593a) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Code extracted from: https://github.com/pybind/pybind11.git at commit 42d8593ad4225a634b481cd573f7aeb94de72418 (master). Upstream Shortlog ----------------- Aaron Gokaslan (45): cd4b49a2 Update py::kwargs examples to pass by reference (#3038) b4b67f02 Fix typos (#3044) af6218ff fix(clang-tidy): Apply performance fixes from clang-tidy (#3046) e0b5cbd4 chore(clang-tidy): add more modernize clang-tidy checks (#3049) 3b30b0a5 fix(clang-tidy): clang-tidy readability and misc fixes, like adding const (#3052) dac74ebd fix(clang-tidy): performance fixes applied in tests and CI (#3051) b5357d1f fix(clang-tidy): Enable clang-tidy else-after-return and redundant void checks (#3080) 25e470c5 fix(clang-tidy): Add cppcoreguidelines-init-vars,slicing, and throw-by-value-catch-by-reference checks (#3094) c4b0dc7c Add shellcheck style checking (#3114) 9beaa925 maint(clang-tidy): Improve code readability with explicit boolean casts (#3148) 0ac4c8af maint(clang-tidy): Improve code readability with explicit boolean casts (#3148) c0756ccd fix: func_handle for rule of two (#3169) 9f204a18 fix: func_handle for rule of two (#3169) 3893f37b maint(clang-tidy): Bugprone enable checks (#3166) ff590c12 maint(perf): Optimize Numpy constructor to remove copies by value. (#3183) 9df2f1ff maint(precommit): Apply isort (#3195) 617cb653 [Bugfix] Fix errant const methods (#3194) 6cbabc4b maint(clang-tidy): Enable cpp-coreguideline slicing checks (#3210) d71ba0cb (perf): Add a missing noexcept to a pytype constructor (#3236) 4c6bee35 fix: Set __file__ constant when using eval_file (#1300) (#3233) ae07d4c6 maint(Clang-Tidy): readability-const-return (#3254) 9978ed58 Fix capsule bug (#3261) d0f3c51f Enable defining custom __new__ (#3265) 6e6975e2 Fix test case with __new__ (#3285) 0fb981b2 Add blacken-docs and pycln pre-commit hooks (#3292) ad966556 fix: replace free() with std::free() (#3321) f4c81e08 maint: Add additional linter-related pre-commit hooks (#3337) 78ee782b feat: Add C++ binding to throw AttributeError (#3387) ef070f77 Add additional info to TypeError when C++->Python casting fails (#3605) d434b5f3 (chore): Remove deprecated c-headers (#3610) f8d4aa47 Add clang-tidy readability checks for sus args (#3611) d2ec8367 Add support for nested C++11 exceptions (#3608) 3a8d9230 Fix caster optimization regression introduced in #3650 (#3659) 978617f6 fix issue 3668 by removing bool casts in numpy.h (#3669) ce18721d Ensure TypeError use raise_from for C++->Python overload res. (#3671) 1b841883 Minor change to improve readability (#3695) 7f975816 chore(clang-tidy): Enable static downcast and decl naming check (#3709) dc9803ce Add missing clang-tidy fixes (#3715) d6c66d25 chore(clang-tidy): Add clang-tidy rules: prefer-member-initializer and optin.performance.Padding (#3716) 42a8e312 Improve Python 3.11 support (#3694) af08a95b fix: potential memory leak in pypy (#3774) 2dd52544 fix: missing move in eval.h (#3775) 47079b9e (perf): Add missing move in sp matrix caster and microopt char concats (#3823) 146695a9 fix: better exception and error handling for capsules (#3825) 3a183d4b fix: improve str exceptions and consistency with python (#3826) Akira Kawata (1): 417fd120 Fix: fix typo of WITHOUT_SOABI (#2992) Andy Maloney (3): 14b37512 docs: fix example code in Exceptions section (match vs. matches) (#2781) df8494dc fix: a clang warning [-Wshadow-field-in-constructor-modified] (#2780) 40931961 docs: fix spelling in some comments/docs (#2777) Antony Lee (6): d068ab28 docs: pybind11/numpy.h does not require numpy at build time. (#2720) 6b4297fd fix: don't trigger -Wunused-parameter in flagcheck.cpp. (#2735) e8c4f543 fix: prepend Pybind11Extension flags rather than appending them. (#2808) 5bcaaa04 Add a std::filesystem::path <-> os.PathLike caster. (#2730) 1be0a0a6 Add helper to build in-tree extensions. (#2831) b11ff912 fix(setup =_helpers): don't add -g0 CFLAGS sets -g (#3436) Axel Huebl (5): 0b3df7f9 ci: Intel icc/icpc via oneAPI (#2573) c78dfb69 MSVC but not Clang: /MP (#2824) 55f6f6e9 Fix: RTD Docutils Build (#3119) d75b3536 CI: MSVC Debug Build (#3784) a7e7a6e8 Docs: No Strip in Debug (#3779) Bertrand MICHEL (1): 74a767d4 Dtype kind vs char (#2864) Bjorn (1): 32d11c96 fix typo in pickle example (#2669) Bobby Impollonia (1): 75168113 fix(setup_helpers): ensure ThreadPool is closed (#3548) Boris Rasin (2): 01f938e7 fix: add missing std::forward calls (#3443) a224d0cc fix: vs2022 compilation, issue #3477 (#3497) Boris Staletic (4): 06b673a0 Allow NULL value in pybind11_meta_setattro (#2629) 8adef2c7 fix: workaround for #2682 and #2422 by simply clearing the TypeError (#2685) f110889d Use correct duration representation when casting from datetime.timdelta to std::chrono::duration (#2870) 5cd37507 Enable -Wstrict-aliasing warning (#2816) Bruce Merry (4): ee0c5ee4 Add make_value_iterator (#3271) b3573ac9 feat: add `.keys` and `.values` to bind_map (#3310) 47ed124f Fix some formatting in the v2.8.0 changelog (#3339) 8a7c266d Fix make_key_iterator/make_value_iterator for prvalue iterators (#3348) Chad B. Hovey (1): dd2d1272 Correct "which" versus "that" error. (#3430) Changming Sun (1): 210c8c21 fix: a warning found by static code analyzer (#2783) Chris Ohk (1): 1a432b42 docs: Correct minor typos (#3721) Cris Luengo (1): 93e69191 fix: enable py::implicitly_convertible for py::class_-wrapped types (#3059) Dan (1): 930bb16c Call PySys_SetArgv when initializing interpreter. (#2341) David Hewitt (2): a0b97596 Allow python builtins to be used as callbacks (#1413) fd71bd48 Allow python builtins to be used as callbacks (#1413) Dmitry Yershov (1): 076c89fc tests: test recursive dispatch using visitor pattern (#3365) Dustin Spicuzza (4): c0fbb02c Extract gil management functions to separate header (#2845) 6d440946 Check dict item accesses where it isn't already checked (#2863) ec81e8e7 Propagate py::multiple_inheritance to all children (#3650) 17792884 Document how to bind templates (#3665) Edward Lockhart (1): 23c3edcf When determining if a shared_ptr already exists, use a test on the we… (#2819) Eric Cousineau (6): 635e3fc9 CONTRIBUTING: Add suggestion about passing pytest flags (#2738) 2110d2d8 enum: add missing Enum.value property (#2739) f676782b env: Add surrogate for pytest.deprecated_call for ptyest<3.9 (#2923) b6ec0e95 functions: Add doc on incorrect argument index (#2979) 6ac8efe5 test_eval: Show example of working closure (#2743) f495dfc4 cast: Qualify symbol usage in PYBIND11_TYPE_CASTER (#3758) Frank (1): f8b8107b fix: make FindPython2 and FindPython3 work (#2662) Geoffrey Gunter (1): 2d6014e4 docs: fix minor typo (#3390) Guillaume Jacquenot (2): e450eb62 Removed duplicated word in docs/advanced/cast/eigen.rst (#3458) 1eb59963 Removed duplicated word in docs/advanced/exceptions.rst (#3476) Henry Fredrick Schreiner (5): 5b43ac42 docs: fix missing line from #2310 dff9b3b4 chore: add pytest-timeout, mypy 732bf88d fix: avoid changing class outside of GIL 4a5b81b1 chore: get back to work 87954e7a fix: corrected dev versioning Henry Schreiner (111): b8dc60ec fix: Python include directory was missing from DIRS (#2636) 6cc233cc ci: label PRs when merged only for now 6d4854a5 ci: correct types statement 3e4d54bc fix: match new extension discovery with changes to classic discovery (#2640) ebd5c5b4 feat: way to only recompile changed files (#2643) f1abf5d9 docs: changelog update (#2652) b7c741b5 docs: back to work after 2.6.1 02746cb6 docs: add a little more information for releases de78bddd docs: better badges (#2656) 17c22b9e docs: mention branch update in checklist (#2670) 499fcd54 ci: drop pypy2 linux, PGI 20.7, add Python 10 dev (#2724) ffb113d1 fix: regression with installed pybind11 overriding local one (#2716) d5af536f ci: update cmake action (#2734) 5bd766bf docs: update changelog and add script to help generate it (#2733) 79b0e2c0 docs: fix pdf build, simpler start page (#2736) b7dfe5cc chore: changelog update (#2750) 5abce7fc ci: use fixed action (#2791) 230fa53f fix: Don't override global settings for VISIBILITY if set (#2793) 0df11d85 docs: update build description slightly (#2794) 87f5aff4 ci: update to setup-cmake v1.6 (#2805) eb83feef style: avoid using unintialized variables (#2806) 130c9954 fix: support basic dual includes (#2804) 2db0264a style: add clang-format file (#2310) 44105ca1 docs: mention that the changelog block in PR is special 08bca374 docs: update changelog, nicer output for script (#2811) 8e5d3d23 docs: prepare for 2.6.2 (#2820) 8de7772c chore: prepare for the 2.6.2 release (#2821) 721834b4 chore: get PyPy 3.7 wheels using NumPy 1.20 (#2837) e0c1dadb chore: add myself to CODEOWNERS (#2940) 114be7f4 docs: remove recommonmark (#2955) 5e4804bb tests: use master commit for pytest on 3.10 (#2967) 54430436 ci: install Boost for boost checks (#2968) 7a64b8ad docs: fix script issues for changelog compilation (#3100) f0a65c89 docs(fix): spelling mistake in recent commit ddf0efb9 chore: add nox support (#3101) 84fdadfb chore: update pre-commit hooks 11e12fe4 chore: move some config to pyproject.toml 0e2e0035 style: add pyupgrade check, 2.7+ 6a644c8f docs: update changelog (#3099) cd061aee style: pre-commit cleanup (#3111) 31843d45 docs: reduce visibility of 3.9.0 warning (#3105) 2415c094 feat(package): support pipx run (#3117) 1b10292c chore: support PDF from nox (#3121) 6642f389 docs: update changelog (#3122) 65e95ea8 chore: bump to 2.7.0 (#3123) 74935f8d chore: post-release (#3128) 7cc0ebb4 fix: the CMake config in Python package had a hard coded path (#3144) c14b1933 chore: increase CMake upper limit (#3124) 5c6bdb72 fix: the CMake config in Python package had a hard coded path (#3144) b1fdbe69 chore: add discussions link (#3159) a2b78a8c chore: changelog update (#3163) 90959848 chore: changelog update (#3163) 078c1167 chore: bump to version 2.7.1 5f34c42d chore: bump to version 2.7.1 82adacb3 fix: include hex version in bump 787d2c88 fix: include hex version in bump c30f57d2 chore: start development for 2.8.0 5f4d7259 fix: version number hex 1fafd1b4 fix: apply simpler expression with fewer workarounds 089328f7 Revert "fix: apply simpler expression with fewer workarounds" fdac5fbf chore: support targeting different Python versions with nox (#3214) db44afa3 tests: fix pytest usage on Python 3.10 (#3221) 04dd3262 docs: update CHANGELOG (#3276) b06a6f4f feat: Slice allowing None with py::object or std::optional (#1101) 2fa3fcfd Revert "Add make_value_iterator (#3271)" 5f46e47d tests: check simple iteration of pairs (#3296) 21282e64 feat: reapply fixed version of #3271 (#3293) 6ad3f874 fix(build): avoid a possible warning about shadowed variables and changing behaviors (#3220) d58699c9 fix(cmake): reduce chance for variable collision (#3302) 6bce3bd7 docs: update CHANGELOG (#3304) a1830d5e docs: mention title conventions in PR template (#3313) d7a7edc1 tests: support Eigen configuration 591db0b9 docs: update CHANGELOG for 2.8 20aae3e6 ci: disable Eigen due to Cert issue on CentOS c9a319c6 chore: version 2.8.0 final 3747dc2c Revert "All `-DDOWNLOAD_EIGEN=OFF` (to work around gitlab eigen outage)." (#3326) ba9f919b chore: get back to work after 2.8.0 931f6644 ci: cancel in-progress on repeated pushes (#3370) f791dc86 fix: deprecate make_simple_namespace, fix Python 3.11 (#3374) 606f81a9 style: drop pycln (#3397) 9379b399 fix: MSVC 2017 C++17 on Python 3 regression (#3407) e7e2c79f fix: improve support for Python 3.11-dev (#3368) 90707b46 fix(build): support conan's multiple includes of all files (#3420) f1594cb9 docs: changelog update for 2.8.1 (#3416) a61e354e docs: touch up manual release suggestion (#3422) aebd21b5 docs: rework CI a bit, more modern skipping (#3424) 270b11d5 Revert "style: drop pycln" (#3466) 72282f75 ci: support development releases of Python (#3419) ff51fcb7 docs: fix broken link (again) 15f8d7c1 fix(build): cleaner CMake printouts & IDE folders (#3479) cd176cee chore: update changelog with recent PRs (#3524) 39fbc799 fix: avoiding usage of _ if already defined (#3423) e50f841d fix: do not use LTS on mips64 and ppc64le (#3557) d4b9f347 docs: update changelog (#3556) cb302305 fix: restore full range of _ functions (#3571) 45f792ef chore: prepare for 2.9 9b4f71d1 docs: remove duplication in changelog for 2.9.0 bf7e5f92 fix(setup): support overriding CMake args (#3577) 21e10945 ci: move centos 8 to stream (#3675) 0f6ad910 docs: update changelog for 2.9.1 (#3670) ffa34686 chore: bump to 2.9.1 36813cfa chore: back to work af056b65 fix: __index__ on Enum should always be present. (#3700) 46dcd9bc fix: minor CMake warning fix for unused variable (#3718) 522c59ce chore: drop Python 3.5 (#3719) a25d40c7 tests: use 'build' in tests instead of running setup.py (#3734) 4b42c371 style: pylint (#3720) 5f9b090a ci: fix PyPy (#3768) 461937d3 ci: test pypy 3.9 (#3789) 7742be02 Revert "ci: test pypy 3.9" (#3828) 42d8593a style: bump black (#3831) Ivor Wanders (1): 21911e12 A way to register additional test targets and support .py only tests. (#3590) JYX (1): 3df0ee6f docs: typo in classes.rst (#2926) Jack S. Hale (1): 4c7697db Add const T to docstring generation. (#3020) James Foster (1): d57c1fab docs: update installing.rst (#2691) Jan Iwaszkiewicz (1): cf006af2 Fix typos and docs style (#3088) Jason Rhinelander (3): e7c9753f feat: allow kw-only args after a py::args (#3402) 673b4be3 Fix py::kw_only when used before the first arg of a method (#3488) b4939fcb Expand std::string_view support to str, bytes, memoryview (#3521) Jean-Baptiste Lespiau (1): af8849f4 docs: list all pybind11 exceptions (#2671) Jeremy Maitin-Shepard (4): 4d5ad03e Avoid use of temporary `bytes` object in string_caster for UTF-8 (#3257) 14976c85 Eliminate duplicate TLS keys for loader_life_support stack (#3275) 2a78abff Ensure PYBIND11_TLS_REPLACE_VALUE evaluates its arguments only once (#3290) 62c4909c Add `custom_type_setup` attribute (#3287) Jerome Robert (4): 1259db6f Fix Pybind11Extension on mingw64 (#2921) 9e8a741b fix: Mingw64 corrected and add a CI job to test it (#3132) c80e0593 fix: Mingw64 corrected and add a CI job to test it (#3132) 56b49c2b ci: fix mingw checks by pinning (#3375) JonTriebenbach (1): 8b1944d3 Remove idioms in code comments (#3809) Jouke Witteveen (1): 031a700d Add make_simple_namespace function and tests (#2840) Karthik Nishanth (1): e791ec4e fix: add null pointer check with std::localtime (#2846) Kumar Aditya (1): 948d09d6 test: Test against Python 3.10 (#2848) Laramie Leavitt (4): 5469c238 Adjusting `type_caster>` to support const/non-const propagation in `cast_op`. (#2705) 0e599589 Fix thread safety for pybind11 loader_life_support (#3237) b3a43d13 Use rvalue reference for std::variant cast_op (#3811) b22ee64c Add type_caster (#3818) Liam Keegan (2): 4f29b8a4 ci: extend msys2 mingw CI (#3207) bcb6d63c fix msys ci python issue (#3651) Lishen1 (1): 5d067e87 fix: remove redundant copy operation to fix warning (#3486) Matthias Köppe (1): e0031bfc include/pybind11/numpy.h: gcc 4.8.4 does not have is_trivially_copyable (#3270) Mattia Basaglia (2): 07103d65 Remove extra semicolon (#3666) dc4717ba fix: module extension detection for python 3.10 (#3663) Michael Kuron (1): 48534089 fix: Intel ICC C++17 compatibility (#2729) Michał Górny (2): 1d3b04e8 test: Strip whitespace when comparing numpy dtypes for 1.22 compat (#3682) 96b943be tests: update catch to 2.13.5 to fix glibc 2.34 failures (#3679) NaDDu (1): 750e38dc Update eval.h (#3344) Nick Cullen (2): 59ad1e7d reshape for numpy arrays (#984) 503ff2a6 view for numpy arrays (#987) Nikita Shulga (1): 79cb013f fix: allow users to avoid thread termination in scoped_released (#2657) Nimrod (1): 9ec1128c Fix typo in doc (#3628) Oleksandr Pavlyk (1): 91a6e129 PYBIND11_OBJECT_CVT should use namespace for error_already_set() (#3797) OnlineCop (1): cbae6d55 docs: fix CMake status for DOWNLOAD_EIGEN (#2857) Peter Hawkins (1): 44596bc4 Fix exception handling when pybind11::weakref() fails. (#3739) Philipp Bucher (3): 62976cfc fix: using -Werror-all for Intel (#2948) 71fd5241 docs: fix minor typo (#3311) c9bbf8d2 docs: fix minor typo (#3311) Pieter P (1): 0c93a0f3 Fix Unicode support for ostream redirects (#2982) Qifan Lu (1): d587a2fd fix: do not set docstring for function when empty (#2745) Ralf W. Grosse-Kunstleve (78): cecdfadc minor cleanup: fixing or silencing flake8 errors (#2731) 9b7bfef8 Factoring out find_registered_python_instance() from type_caster_generic::cast. (#2822) 0432ae7c Changing pybind11::str to exclusively hold PyUnicodeObject (#2409) 932769b0 Adding holder_caster `typename SFINAE = void` hooks to help work around the current lack of smart-pointer interoperability (#2833) 0c42250a Splitting out detail/type_caster_base.h from cast.h, with iwyu cleanup. (#2841) e2e819b2 Shuffling code in test_smart_ptr.cpp to separate struct/class definitions from bindings code. Back-porting from smart_holder branch, to minimize diffs and potential for merge conflicts. (#2875) 44678e54 Shuffling code in test_multiple_inheritance.cpp to separate struct/class definitions from bindings code. (#2890) 0e01c243 Generalizing suppression for pypocketfft. (#2896) ad6bf5cd Adding PyGILState_Check() in object_api<>::operator(). (#2919) e25b1505 Adjusting valgrind suppression for pypocketfft to resolve systematic failures that started to appear on 2020-05-27. (#3022) 19d99a87 Working around Centos 8 failure. (#3030) 484b0f04 Updating and slightly enhancing instructions for running clang-tidy. (#3055) fbae8f31 pickle setstate: setattr __dict__ only if not empty (#2972) cad79c11 tests: remove very minor oversight in PR #3059. (#3066) 795e3c4c Removing `AlignConsecutiveAssignments: true`. (#3067) 0ad116d3 Adding codespell to .pre-commit-config.yaml (follow-on to PR #3075). (#3076) 6d1b197b Splitting out pybind11/stl/filesystem.h. (#3077) bac5a0c3 Go all the way fixing clang-tidy issues to avoid the NOLINTNEXTLINE clutter and clang-format issues. This was really meant to be part of PR #3051 but was held back either out of an abundance of caution, or because of confusion caused by stray semicolons. (#3086) 0f4761b4 Rollback of DOWNLOAD_CATCH=OFF change merged via PR #3059. (#3092) 2d468697 NOLINT reduction (#3096) 7472d37a Adding iostream.h thread-safety documentation. (#2995) 9f11951b Fixing spelling errors that went undetected because the pre-commit spell check was added after the CI for PR #2995 last ran. (#3103) 75090647 More precise return_value_policy::automatic documentation. (#2920) aca6c3ba * Removing stray semicolons (discovered by running clang-format v12 followed by tools/check-style.sh). (#3087) 4359e00b Introducing PYBIND11_VERSION_HEX (#3120) 34f587dd Removing all warning pragmas that have not effect. (#3127) ff97f101 Removing MSVC C4996 from pragma block at the top of pybind11.h (#3129) 7904ba1a Adding pragma warning(disable: 4522) for MSVC <= 2017. (#3142) a0f862d4 Removing MSVC C4800 from pragma block at the top of pybind11.h (#3141) 2164c2e0 Removing __INTEL_COMPILER section from pragma block at the top of pybind11.h (#3135) f4721a7b Accommodating environments that define __STDC_WANT_LIB_EXT1__ even if __STDC_LIB_EXT1__ is not defined by the implementation. (#3151) b72ca7d1 Removing MSVC C4100 from pragma block at the top of pybind11.h (#3150) b193d42c Removing MSVC C4996 from pragma block at the top of pybind11.h (#3129) 85b38c69 Adding pragma warning(disable: 4522) for MSVC <= 2017. (#3142) e93d9459 Removing MSVC C4800 from pragma block at the top of pybind11.h (#3141) ed5fb66b Removing __INTEL_COMPILER section from pragma block at the top of pybind11.h (#3135) 05852fb6 Accommodating environments that define __STDC_WANT_LIB_EXT1__ even if __STDC_LIB_EXT1__ is not defined by the implementation. (#3151) b4259729 Limiting pragma for ignoring GCC 7 -Wnoexcept-type to the scope of pybind11.h. (#3161) e2573dc9 Moving pragma for MSVC warning C4505 from pybind11.h to existing list in detail/common.h (#3160) 46c51fc0 Limiting pragma for ignoring GCC 7 -Wnoexcept-type to the scope of pybind11.h. (#3161) b961ac64 Moving pragma for MSVC warning C4505 from pybind11.h to existing list in detail/common.h (#3160) dcbda8d7 Removing MSVC C4127 from pragma block at the top of pybind11.h (#3152) af700733 Removing GCC -Wunused-but-set-parameter from pragma block at the top of pybind11.h (#3164) 61ee923b Consistent step name "Python tests". (#3180) 4c7e509f PYBIND11_NOINLINE-related cleanup. (#3179) 7d3b0571 Improved workaround for Centos 8 failure (follow-on to PR #3030). (#3193) 1bcd94c4 Removing last remnants of pragma block at the top of pybind11.h (#3186) 774b5ff9 Removing obsolete eigen.h warning suppression pragmas. (#3198) 998d45e4 Cleanup of file-scoped and globally-scoped warning suppression pragmas across pybind11 header files. (#3201) c8ce4b8d Clone of @virtuald's PR #2112 with minor enhancements. (#3215) 777352fc Adding `ssize_t_cast` to support passing `size_t` or `ssize_t` values where `ssize_t` is needed. (#3219) a46f6237 Minor tweaks. (#3230) 49173e47 Minor follow-on to PR #1334 (Fix enum value's __int__ returning non-int when underlying type is bool or of char type) (#3232) 6abf2baa CodeHealth: Enabling clang-tidy google-explicit-constructor (#3250) 121b91f9 Fixing NOLINT mishap (#3260) 6c65ab59 Follow-on to PR #3254, to address user code breakages. (#3263) 9f146a56 All `-DDOWNLOAD_EIGEN=OFF` (to work around gitlab eigen outage). 7c580586 Correct options on Eigen::MappedSparseMatrix & adding MSVC C4127 suppression around Eigen includes. (#3352) f7b49961 [skip ci] Tweaks in preparation for the 2.8.1 release. (#3421) a80b2237 chore: get back to work after 2.8.1 9281faf4 Fixing `stict` vs `strict` typo. (#3493) b3d9c354 vi: replacing currently broken ICC Latest C++17 with C++14. (#3551) 1bbaeb34 Adding dedicated test_const_name. (#3578) f5888108 Replacing ICC C++14 with C++17 (#3570) 7e7c5585 Fixing obvious minor typo (missing `D` in `-DOWNLOAD_EIGEN=ON`). 3899dc65 Documenting missing unit test coverage. (#3673) 8581584e Manual fix-ups in preparation for clang-tidy readability-braces-around-statements. ddbc74c6 Adding .clang-tidy readability-braces-around-statements option. b4f5350d chore: use member initializer (#3704) 7769e771 clang-tidy readability-qualified-auto (#3702) abc38690 Manually applying two clang-format changes that need fix-ups for clang-tidy. (#3705) e96221be Final manual curation in preparation for global `clang-format`ing (#3712) ec24786e Fully-automatic clang-format with include reordering (#3713) 6493f496 Python 2 removal part 1: tests (C++ code is intentionally ~untouched) (#3688) 44156477 Adding MSVC 2022 C++20 GitHub Action (#3732) a97e9d8c Dropping MSVC 2015 (#3722) c14170a7 Removing `// clang-format off` - `on` directives from test_pickling.cpp (#3738) 009ffc33 MSVC C++20 test_eigen (#3741) Rasmus Munk Larsen (1): 70a58c57 Replace usage of deprecated Eigen class MappedSparseMatrix. (#3499) Robert Haschke (4): b72cebeb style: clang-tidy: modernize-use-using (#2645) d9fa7056 style: remove redundant instance->owned = true (#2723) c2db53da fix: catch missing self argument in overloads constructor (#2914) c090c8c4 Unify cast_error message thrown by [simple|unpacking]_collector (#3013) Robert Schütz (1): d00fc629 use CMAKE_INSTALL_FULL_INCLUDEDIR (#3005) Ryan Cahoon (1): c2d3e220 fix: the types for return_value_policy_override in optional_caster (#3376) Sebastian Koslowski (1): 94a94872 docs: fix imported target name (#3689) Sergei Izmailov (1): 51948559 Render `py::bool_` and `py::float_` without `_` in docstrings (#3622) Sergiu Deitsch (1): d2b21316 cmake: report version type in the version string (#3472) Shane Loretz (1): 7331d381 Raise codec errors when casting to std::string (#2903) StarQTius (1): 9aa676d3 fix: clear local internals after finalizing interpreter #2101 (#3744) Stefano Rivera (1): 465b2e0b Use sysconfig in Python >= 3.10 (#3764) Steve Siano (1): 6f66e760 docs: add a note about compiling the example (#2737) Tailing Yuan (1): d6474ed7 fix: memory leak in cpp_function (#3228) (#3229) Tamaki Nishino (1): 6709abba Allow function pointer extraction from overloaded functions (#2944) Thomas Ballinger (1): 39a0aac8 docs fix to avoid nonexistent SmartCompile (#3241) Tobias Leibner (1): 7bd4b397 fix: define PYBIND11_CPP14 for recent intel compilers (#2679) Tom de Geus (1): 9c0aa699 Pointing out namespace in docs (#2874) Trigve (1): afdc09de [master] Wrong caching of overrides (#3465) Vikram Pal (1): 417067ee Add pybind11::bytearray (#2799) Weiming Zhao (1): 4f0727f2 Fix the enabling of default extension handling (#2938) Wenzel Jakob (1): 409be833 CMake: react to python version changes Yannick Jadoul (19): 7d6713a4 Use weakref to clean up captured function object in def_buffer (#2634) c58758d0 fix: add reasonable argument names to enum_ methods (#2637) 028812ae docs: add warning about FindPython's Development component when libraries don't exist (e.g. on manylinux) (#2689) 91a69720 docs: Update warning about Python 3.9.0 UB, now that 3.9.1 has been released (#2719) 30eb39ed fix: also throw in the move-constructor added by the PYBIND11_OBJECT macro, after the argument has been moved-out (if necessary) (#2701) 830f8eda tests: update pytest 6.2.1 and fix test_python_alreadyset_in_destructor (#2741) e612043d Fix invalid access when reinterpret_casting a non-pybind11 PyObject* to instance* (found by Valgrind in #2746) (#2755) e57dd471 Fix various minor memory leaks in the tests (found by Valgrind in #2746) (#2758) 98f1bbb8 Ignore deprecation warnings about old-style __init__/__setstate__ constructors in the tests (originally done in #2746) (#2759) 7b7ec664 ci: pin CMake to 3.19.2, fixes issues with 3.19.3 on Linux (aarch64) and macOS (universal) (#2790) f243450e ci: disable builds for 3.10.0a4, and enable a nightly 3.10-dev build (#2792) 1faf4a8a docs: the order of alternatives for variant types matters, and follows the same rules as overload resolution (#2784) 08551463 Plug leaking function_records in cpp_function initialization in case of exceptions (found by Valgrind in #2746) (#2756) 0f8d5f2e Add a Valgrind build on debug Python 3.9 (#2746) 8449a808 fix: only allow integer type_caster to call __int__ method when conversion is allowed; always call __index__ (#2698) 0bb8ca26 Always call PyNumber_Index when casting from Python to a C++ integral type, also pre-3.8 (#2801) 587d5f84 Update breathe to 4.26.1, add make_tuple, make_iterator, and make_key_iterator (#2828) 6cf6bf20 Fix confusing weakref constructor overload (#2832) fe845878 Make sure all warnings in pytest get turned into errors (#2838) Ye Zhihao (1): cb60ed49 Fix enum value's __int__ returning non-int when underlying type is bool or of char type (#1334) Yichen (1): 3ac690b8 Explicitly export exception types. (#2999) albanD (1): 087b07c8 Remove workaround code that is not needed since #1211 (#2683) blacktea (1): 6d5d4e73 Move object in pop method of List. (#3116) crimsoncor (1): 9ea39dc3 Force the builtin module key to be the correct type. (#2814) cyy (1): f067deb5 avoid unnecessary strlen (#3058) dependabot[bot] (14): 42e73807 chore(deps): bump jwlawson/actions-setup-cmake from v1.6 to v1.7 (#2818) c2362393 chore(deps): bump pypa/gh-action-pypi-publish from v1.4.1 to v1.4.2 (#2851) 59f8d7f1 chore(deps): bump jwlawson/actions-setup-cmake from v1.7 to v1.8 (#2865) 16c23fef chore(deps): bump pre-commit/action from v2.0.0 to v2.0.2 (#2935) bca4b36b chore(deps): bump pre-commit/action from v2.0.2 to v2.0.3 (#2964) bc7cf6ef chore(deps): bump jwlawson/actions-setup-cmake from 1.8 to 1.9 (#3000) f61855b9 chore(deps): bump ilammy/msvc-dev-cmd from 1 to 1.8.0 (#3001) 14023c9c chore(deps): bump ilammy/msvc-dev-cmd from 1.8.0 to 1.8.1 (#3021) 9b3b3577 chore(deps): bump ilammy/msvc-dev-cmd from 1.8.1 to 1.9.0 (#3027) d6841f60 chore(deps): bump jwlawson/actions-setup-cmake from 1.9 to 1.10 (#3196) 1dc9a23c chore(deps): bump jwlawson/actions-setup-cmake from 1.10 to 1.11 (#3294) ed09664f chore(deps): bump ilammy/msvc-dev-cmd from 1.9.0 to 1.10.0 (#3338) fb9a222d chore(deps): bump pypa/gh-action-pypi-publish from 1.4.2 to 1.5.0 (#3606) 3a1eddab chore(deps): bump jwlawson/actions-setup-cmake from 1.11 to 1.12 (#3625) heyer2 (1): 76a16007 fix: STATIC and SHARED flags not being detected (#2796) jakobjw (1): 98f9a33c Correct typo in FAQ (#2868) jbarlow83 (2): 79178e71 fix(setup_helpers): try import multiprocessing.synchronize too (#3043) 2b7985e5 Improve documentation of discard_as_unraisable() API (#2697) jesse-sony (1): d65edfb0 Feature/local exception translator (#2650) jonathan-conder-sm (1): 733f8de2 Avoid string copy if possible when passing a Python object to std::ostream (#3042) ka-bo (2): e58c6897 Specified encoding in setup.py calls of open() (#3137) ee3ecb8a Specified encoding in setup.py calls of open() (#3137) kururu002 (1): da15bb20 Cast bytearray to string (#3707) luzpaz (1): 8bee61b6 docs: fix various typos (#3075) mvoelkle-cern (1): e08a5811 Fix compilation with gcc < 5 (#2956) ngc92 (1): 56322daf fixed include for filesystem::path (#3482) nickbridgechess (1): 2fa4747c pythonbuf fix (#2675) pre-commit-ci[bot] (28): 9626483c [pre-commit.ci] pre-commit autoupdate (#3134) 7f76d795 [pre-commit.ci] pre-commit autoupdate (#3143) c973660d [pre-commit.ci] pre-commit autoupdate (#3143) f4f4632e [pre-commit.ci] pre-commit autoupdate (#3167) ada6b791 [pre-commit.ci] pre-commit autoupdate (#3167) 0be2ea06 [pre-commit.ci] pre-commit autoupdate (#3185) b3d18f38 [pre-commit.ci] pre-commit autoupdate (#3213) 76d939de [pre-commit.ci] pre-commit autoupdate (#3231) 3ed31e92 [pre-commit.ci] pre-commit autoupdate (#3266) 077a16e9 [pre-commit.ci] pre-commit autoupdate (#3286) 6be64304 [pre-commit.ci] pre-commit autoupdate (#3312) 97976c16 [pre-commit.ci] pre-commit autoupdate (#3325) 02c05573 [pre-commit.ci] pre-commit autoupdate (#3353) d45a8810 [pre-commit.ci] pre-commit autoupdate (#3409) 6de30d31 [pre-commit.ci] pre-commit autoupdate (#3432) b322018e [pre-commit.ci] pre-commit autoupdate (#3449) 9422d98f [pre-commit.ci] pre-commit autoupdate (#3473) fe65693c [pre-commit.ci] pre-commit autoupdate (#3500) 59aa9986 [pre-commit.ci] pre-commit autoupdate (#3533) d0406c74 [pre-commit.ci] pre-commit autoupdate (#3563) 89769e6e [pre-commit.ci] pre-commit autoupdate (#3574) 2cd32e5d [pre-commit.ci] pre-commit autoupdate (#3589) b66328b0 [pre-commit.ci] pre-commit autoupdate (#3609) 0986af61 [pre-commit.ci] pre-commit autoupdate (#3672) 91f597be [pre-commit.ci] pre-commit autoupdate (#3754) 061c6177 [pre-commit.ci] pre-commit autoupdate (#3765) f8a532a7 [pre-commit.ci] pre-commit autoupdate (#3800) 67089cd3 [pre-commit.ci] pre-commit autoupdate (#3817) xaedes (1): b4e1ab8c Docs: Demonstrate non-enum internal types in example (#3314) yangliz5 (1): dedda228 Fix a typo in class.rst (#3648) --- include/pybind11/attr.h | 345 ++- include/pybind11/buffer_info.h | 131 +- include/pybind11/cast.h | 2139 +++++++----------- include/pybind11/chrono.h | 174 +- include/pybind11/complex.h | 31 +- include/pybind11/detail/class.h | 292 +-- include/pybind11/detail/common.h | 1012 ++++++--- include/pybind11/detail/descr.h | 108 +- include/pybind11/detail/init.h | 288 ++- include/pybind11/detail/internals.h | 446 ++-- include/pybind11/detail/type_caster_base.h | 1073 +++++++++ include/pybind11/detail/typeid.h | 18 +- include/pybind11/eigen.h | 543 +++-- include/pybind11/embed.h | 154 +- include/pybind11/eval.h | 112 +- include/pybind11/functional.h | 70 +- include/pybind11/gil.h | 202 ++ include/pybind11/iostream.h | 141 +- include/pybind11/numpy.h | 1330 ++++++----- include/pybind11/operators.h | 246 ++- include/pybind11/options.h | 41 +- include/pybind11/pybind11.h | 2307 ++++++++++++-------- include/pybind11/pytypes.h | 1357 ++++++++---- include/pybind11/stl.h | 271 ++- include/pybind11/stl/filesystem.h | 102 + include/pybind11/stl_bind.h | 670 +++--- 26 files changed, 8451 insertions(+), 5152 deletions(-) create mode 100644 include/pybind11/detail/type_caster_base.h create mode 100644 include/pybind11/gil.h create mode 100644 include/pybind11/stl/filesystem.h diff --git a/include/pybind11/attr.h b/include/pybind11/attr.h index 0c41670926..38139afa32 100644 --- a/include/pybind11/attr.h +++ b/include/pybind11/attr.h @@ -12,70 +12,110 @@ #include "cast.h" +#include + PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) /// \addtogroup annotations /// @{ /// Annotation for methods -struct is_method { handle class_; is_method(const handle &c) : class_(c) { } }; +struct is_method { + handle class_; + explicit is_method(const handle &c) : class_(c) {} +}; /// Annotation for operators -struct is_operator { }; +struct is_operator {}; /// Annotation for classes that cannot be subclassed -struct is_final { }; +struct is_final {}; /// Annotation for parent scope -struct scope { handle value; scope(const handle &s) : value(s) { } }; +struct scope { + handle value; + explicit scope(const handle &s) : value(s) {} +}; /// Annotation for documentation -struct doc { const char *value; 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; 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 { handle value; sibling(const handle &value) : value(value.ptr()) { } }; +struct sibling { + handle value; + explicit sibling(const handle &value) : value(value.ptr()) {} +}; /// Annotation indicating that a class derives from another given type -template struct base { +template +struct base { - PYBIND11_DEPRECATED("base() was deprecated in favor of specifying 'T' as a template argument to class_") - base() { } // NOLINT(modernize-use-equals-default): breaks MSVC 2015 when adding an attribute + PYBIND11_DEPRECATED( + "base() was deprecated in favor of specifying 'T' as a template argument to class_") + base() = default; }; /// Keep patient alive while nurse lives -template struct keep_alive { }; +template +struct keep_alive {}; /// Annotation indicating that a class is involved in a multiple inheritance relationship -struct multiple_inheritance { }; +struct multiple_inheritance {}; /// Annotation which enables dynamic attributes, i.e. adds `__dict__` to a class -struct dynamic_attr { }; +struct dynamic_attr {}; /// Annotation which enables the buffer protocol for a type -struct buffer_protocol { }; +struct buffer_protocol {}; /// Annotation which requests that a special metaclass is created for a type struct metaclass { handle value; PYBIND11_DEPRECATED("py::metaclass() is no longer required. It's turned on by default now.") - metaclass() { } // NOLINT(modernize-use-equals-default): breaks MSVC 2015 when adding an attribute + metaclass() = default; /// Override pybind11's default metaclass - explicit metaclass(handle value) : value(value) { } + explicit metaclass(handle value) : value(value) {} +}; + +/// Specifies a custom callback with signature `void (PyHeapTypeObject*)` that +/// may be used to customize the Python type. +/// +/// The callback is invoked immediately before `PyType_Ready`. +/// +/// Note: This is an advanced interface, and uses of it may require changes to +/// 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; + + explicit custom_type_setup(callback value) : value(std::move(value)) {} + + callback value; }; /// Annotation that marks a class as local to the module: -struct module_local { const bool value; constexpr module_local(bool v = true) : value(v) { } }; +struct module_local { + const bool value; + constexpr explicit module_local(bool v = true) : value(v) {} +}; /// Annotation to mark enums as an arithmetic type -struct arithmetic { }; +struct arithmetic {}; /// Mark a function for addition at the beginning of the existing overload chain instead of the end -struct prepend { }; +struct prepend {}; /** \rst A call policy which places one or more guard variables (``Ts...``) around the function call. @@ -95,9 +135,13 @@ struct prepend { }; return foo(args...); // forwarded arguments }); \endrst */ -template struct call_guard; +template +struct call_guard; -template <> struct call_guard<> { using type = detail::void_type; }; +template <> +struct call_guard<> { + using type = detail::void_type; +}; template struct call_guard { @@ -122,8 +166,9 @@ PYBIND11_NAMESPACE_BEGIN(detail) enum op_id : int; enum op_type : int; struct undefined_t; -template struct op_; -inline void keep_alive_impl(size_t Nurse, size_t Patient, function_call &call, handle ret); +template +struct op_; +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 { @@ -134,15 +179,16 @@ struct argument_record { bool none : 1; ///< True if None is allowed when loading argument_record(const char *name, const char *descr, handle value, bool convert, bool none) - : name(name), descr(descr), value(value), convert(convert), none(none) { } + : name(name), descr(descr), value(value), convert(convert), none(none) {} }; -/// Internal data structure which holds metadata about a bound function (signature, overloads, etc.) +/// Internal data structure which holds metadata about a bound function (signature, overloads, +/// etc.) struct function_record { function_record() : is_constructor(false), is_new_style_constructor(false), is_stateless(false), - is_operator(false), is_method(false), has_args(false), - has_kwargs(false), has_kw_only_args(false), prepend(false) { } + is_operator(false), is_method(false), has_args(false), has_kwargs(false), + prepend(false) {} /// Function name char *name = nullptr; /* why no C++ strings? They generate heavier code.. */ @@ -157,13 +203,13 @@ struct function_record { 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; @@ -189,17 +235,15 @@ struct function_record { /// True if the function has a '**kwargs' argument bool has_kwargs : 1; - /// True once a 'py::kw_only' is encountered (any following args are keyword-only) - bool has_kw_only_args : 1; - /// True if this function is to be inserted at the beginning of the overload resolution chain bool prepend : 1; /// Number of arguments (including py::args and/or py::kwargs, if present) std::uint16_t nargs; - /// Number of trailing arguments (counted in `nargs`) that are keyword-only - std::uint16_t nargs_kw_only = 0; + /// Number of leading positional arguments, which are terminated by a py::args or py::kwargs + /// argument or by a py::kw_only annotation. + std::uint16_t nargs_pos = 0; /// Number of leading arguments (counted in `nargs`) that are positional-only std::uint16_t nargs_pos_only = 0; @@ -221,7 +265,7 @@ struct function_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) { } + default_holder(true), module_local(false), is_final(false) {} /// Handle to the parent scope handle scope; @@ -259,6 +303,9 @@ struct type_record { /// Custom metaclass (optional) handle metaclass; + /// Custom type setup. + custom_type_setup::callback custom_type_setup_callback; + /// Multiple inheritance marker bool multiple_inheritance : 1; @@ -277,42 +324,43 @@ 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); + 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 + "\""); + pybind11_fail("generic_type: type \"" + std::string(name) + + "\" referenced unknown base type \"" + tname + "\""); } 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) + "\" " + - (default_holder ? "does not have" : "has") + - " a non-default holder type while its base \"" + tname + "\" " + - (base_info->default_holder ? "does not" : "does")); + pybind11_fail("generic_type: type \"" + std::string(name) + "\" " + + (default_holder ? "does not have" : "has") + + " a non-default holder type while its base \"" + tname + "\" " + + (base_info->default_holder ? "does not" : "does")); } bases.append((PyObject *) base_info->type); - if (base_info->type->tp_dictoffset != 0) + if (base_info->type->tp_dictoffset != 0) { dynamic_attr = true; + } - 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); } /// Tag for a new-style `__init__` defined in `detail/init.h` -struct is_new_style_constructor { }; +struct is_new_style_constructor {}; /** * Partial template specializations to process custom attributes provided to @@ -320,100 +368,133 @@ struct is_new_style_constructor { }; * fields in the type_record and function_record data structures or executed at * runtime to deal with custom call policies (e.g. keep_alive). */ -template struct process_attribute; +template +struct process_attribute; -template struct process_attribute_default { +template +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 { +template <> +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 { +template <> +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 { +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 = const_cast(d); } }; -template <> struct process_attribute : process_attribute { }; +template <> +struct process_attribute : process_attribute {}; /// Process an attribute indicating the function's return value policy -template <> struct process_attribute : process_attribute_default { +template <> +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 { +/// 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; } }; /// 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) { r->is_method = true; r->scope = s.class_; } +template <> +struct process_attribute : process_attribute_default { + static void init(const is_method &s, function_record *r) { + r->is_method = true; + r->scope = s.class_; + } }; /// Process an attribute which indicates the parent scope of a method -template <> struct process_attribute : process_attribute_default { +template <> +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 { +template <> +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) { r->is_new_style_constructor = true; } +template <> +struct process_attribute + : process_attribute_default { + static void init(const is_new_style_constructor &, function_record *r) { + r->is_new_style_constructor = true; + } }; -inline void process_kw_only_arg(const arg &a, function_record *r) { - if (!a.name || strlen(a.name) == 0) - pybind11_fail("arg(): cannot specify an unnamed argument after an kw_only() annotation"); - ++r->nargs_kw_only; +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()) { + 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 { +template <> +struct process_attribute : process_attribute_default { static void init(const arg &a, function_record *r) { - if (r->is_method && r->args.empty()) - r->args.emplace_back("self", nullptr, handle(), true /*convert*/, false /*none not allowed*/); + append_self_arg_if_needed(r); r->args.emplace_back(a.name, nullptr, handle(), !a.flag_noconvert, a.flag_none); - if (r->has_kw_only_args) process_kw_only_arg(a, r); + check_kw_only_arg(a, r); } }; /// Process a keyword argument attribute (*with* a default value) -template <> struct process_attribute : process_attribute_default { +template <> +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", nullptr /*descr*/, handle() /*parent*/, true /*convert*/, false /*none not allowed*/); + if (r->is_method && r->args.empty()) { + r->args.emplace_back( + "self", /*descr=*/nullptr, /*parent=*/handle(), /*convert=*/true, /*none=*/false); + } if (!a.value) { #if !defined(NDEBUG) std::string descr("'"); - if (a.name) descr += std::string(a.name) + ": "; + if (a.name) { + descr += std::string(a.name) + ": "; + } descr += a.type + "'"; if (r->is_method) { - if (r->name) - descr += " in method '" + (std::string) str(r->scope) + "." + (std::string) r->name + "'"; - else + if (r->name) { + descr += " in method '" + (std::string) str(r->scope) + "." + + (std::string) r->name + "'"; + } else { descr += " in method of '" + (std::string) str(r->scope) + "'"; + } } 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?)"); + pybind11_fail("arg(): could not convert default argument " + descr + + " into a Python object (type not registered yet?)"); #else pybind11_fail("arg(): could not convert default argument " "into a Python object (type not registered yet?). " @@ -422,27 +503,41 @@ template <> struct process_attribute : process_attribute_default { } r->args.emplace_back(a.name, a.descr, a.value.inc_ref(), !a.flag_noconvert, a.flag_none); - if (r->has_kw_only_args) process_kw_only_arg(a, r); + check_kw_only_arg(a, r); } }; /// Process a keyword-only-arguments-follow pseudo argument -template <> struct process_attribute : process_attribute_default { +template <> +struct process_attribute : process_attribute_default { static void init(const kw_only &, function_record *r) { - r->has_kw_only_args = true; + append_self_arg_if_needed(r); + 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 { +template <> +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) { + 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 } }; -/// Process a parent class attribute. Single inheritance only (class_ itself already guarantees that) +/// Process a parent class attribute. Single inheritance only (class_ itself already guarantees +/// that) template -struct process_attribute::value>> : process_attribute_default { +struct process_attribute::value>> + : process_attribute_default { static void init(const handle &h, type_record *r) { r->bases.append(h); } }; @@ -455,7 +550,9 @@ struct process_attribute> : process_attribute_default> { /// Process a multiple inheritance attribute template <> struct process_attribute : process_attribute_default { - static void init(const multiple_inheritance &, type_record *r) { r->multiple_inheritance = true; } + static void init(const multiple_inheritance &, type_record *r) { + r->multiple_inheritance = true; + } }; template <> @@ -463,6 +560,13 @@ 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) { + 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; } @@ -494,41 +598,59 @@ template <> struct process_attribute : process_attribute_default {}; template -struct process_attribute> : process_attribute_default> { }; +struct process_attribute> : process_attribute_default> {}; /** * Process a keep_alive call policy -- invokes keep_alive_impl during the * pre-call handler if both Nurse, Patient != 0 and use the post-call handler * otherwise */ -template struct process_attribute> : public process_attribute_default> { +template +struct process_attribute> + : public process_attribute_default> { template = 0> - static void precall(function_call &call) { keep_alive_impl(Nurse, Patient, call, handle()); } + static void precall(function_call &call) { + keep_alive_impl(Nurse, Patient, call, handle()); + } template = 0> - static void postcall(function_call &, handle) { } + static void postcall(function_call &, handle) {} template = 0> - static void precall(function_call &) { } + static void precall(function_call &) {} template = 0> - static void postcall(function_call &call, handle ret) { keep_alive_impl(Nurse, Patient, call, ret); } + 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) { - int unused[] = { 0, (process_attribute::type>::init(args, r), 0) ... }; - ignore_unused(unused); +template +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{ + 0, ((void) process_attribute::type>::init(args, r), 0)...}; } - static void init(const Args&... args, type_record *r) { - int unused[] = { 0, (process_attribute::type>::init(args, r), 0) ... }; - ignore_unused(unused); + 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) { - int unused[] = { 0, (process_attribute::type>::precall(call), 0) ... }; - ignore_unused(unused); + 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) { - int unused[] = { 0, (process_attribute::type>::postcall(call, fn_ret), 0) ... }; - ignore_unused(unused); + PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(call, fn_ret); + PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(fn_ret); + using expander = int[]; + (void) expander{ + 0, (process_attribute::type>::postcall(call, fn_ret), 0)...}; } }; @@ -542,9 +664,10 @@ using extract_guard_t = typename exactly_one_t, Extr /// Check the number of named arguments at compile time template ::value...), - size_t self = constexpr_sum(std::is_same::value...)> + size_t self = constexpr_sum(std::is_same::value...)> constexpr bool expected_num_args(size_t nargs, bool has_args, bool has_kwargs) { - return named == 0 || (self + named + has_args + has_kwargs) == nargs; + PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(nargs, has_args, has_kwargs); + return named == 0 || (self + named + size_t(has_args) + size_t(has_kwargs)) == nargs; } PYBIND11_NAMESPACE_END(detail) diff --git a/include/pybind11/buffer_info.h b/include/pybind11/buffer_info.h index d803004a10..06120d5563 100644 --- a/include/pybind11/buffer_info.h +++ b/include/pybind11/buffer_info.h @@ -19,9 +19,11 @@ PYBIND11_NAMESPACE_BEGIN(detail) 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; } @@ -29,8 +31,9 @@ inline std::vector c_strides(const std::vector &shape, ssize_t 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; } @@ -41,61 +44,89 @@ 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() + 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) + 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()) + 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) + } + for (size_t i = 0; i < (size_t) ndim; ++i) { size *= shape[i]; + } } 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) { } + 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) { } + 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) { } + 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, + : 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) { + ? 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 &operator=(const buffer_info &) = delete; - buffer_info(buffer_info &&other) { - (*this) = std::move(other); - } + buffer_info(buffer_info &&other) noexcept { (*this) = std::move(other); } - buffer_info& operator=(buffer_info &&rhs) { + buffer_info &operator=(buffer_info &&rhs) noexcept { ptr = rhs.ptr; itemsize = rhs.itemsize; size = rhs.size; @@ -110,17 +141,28 @@ struct buffer_info { } ~buffer_info() { - if (m_view && ownview) { PyBuffer_Release(m_view); delete m_view; } + if (m_view && ownview) { + PyBuffer_Release(m_view); + delete m_view; + } } Py_buffer *view() const { return m_view; } Py_buffer *&view() { return m_view; } -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) { } +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; @@ -128,17 +170,22 @@ struct buffer_info { PYBIND11_NAMESPACE_BEGIN(detail) -template struct compare_buffer_info { - static bool compare(const buffer_info& b) { +template +struct compare_buffer_info { + static bool compare(const buffer_info &b) { 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) { - return (size_t) b.itemsize == sizeof(T) && (b.format == format_descriptor::value || - ((sizeof(T) == sizeof(long)) && b.format == (std::is_unsigned::value ? "L" : "l")) || - ((sizeof(T) == sizeof(size_t)) && b.format == (std::is_unsigned::value ? "N" : "n"))); +template +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)) + && b.format == (std::is_unsigned::value ? "L" : "l")) + || ((sizeof(T) == sizeof(size_t)) + && b.format == (std::is_unsigned::value ? "N" : "n"))); } }; diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index d6e440f787..d45b49c52e 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -10,1029 +10,168 @@ #pragma once -#include "pytypes.h" -#include "detail/typeid.h" +#include "detail/common.h" #include "detail/descr.h" -#include "detail/internals.h" +#include "detail/type_caster_base.h" +#include "detail/typeid.h" +#include "pytypes.h" + #include -#include +#include +#include +#include +#include +#include +#include #include #include - -#if defined(PYBIND11_CPP17) -# if defined(__has_include) -# if __has_include() -# define PYBIND11_HAS_STRING_VIEW -# endif -# elif defined(_MSC_VER) -# define PYBIND11_HAS_STRING_VIEW -# endif -#endif -#ifdef PYBIND11_HAS_STRING_VIEW -#include -#endif - -#if defined(__cpp_lib_char8_t) && __cpp_lib_char8_t >= 201811L -# define PYBIND11_HAS_U8STRING -#endif +#include +#include PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(detail) -/// A life support system for temporary objects created by `type_caster::load()`. -/// Adding a patient will keep it alive up until the enclosing function returns. -class loader_life_support { -public: - /// A new patient frame is created when a function is entered - loader_life_support() { - get_internals().loader_patient_stack.push_back(nullptr); - } - - /// ... and destroyed after it returns - ~loader_life_support() { - auto &stack = get_internals().loader_patient_stack; - if (stack.empty()) - pybind11_fail("loader_life_support: internal error"); - - auto ptr = stack.back(); - stack.pop_back(); - Py_CLEAR(ptr); - - // A heuristic to reduce the stack's capacity (e.g. after long recursive calls) - if (stack.capacity() > 16 && !stack.empty() && stack.capacity() / stack.size() > 2) - stack.shrink_to_fit(); - } - - /// This can only be used inside a pybind11-bound function, either by `argument_loader` - /// at argument preparation time or by `py::cast()` at execution time. - PYBIND11_NOINLINE static void add_patient(handle h) { - auto &stack = get_internals().loader_patient_stack; - if (stack.empty()) - throw cast_error("When called outside a bound function, py::cast() cannot " - "do Python -> C++ conversions which require the creation " - "of temporary values"); - - auto &list_ptr = stack.back(); - if (list_ptr == nullptr) { - list_ptr = PyList_New(1); - if (!list_ptr) - pybind11_fail("loader_life_support: error allocating list"); - PyList_SET_ITEM(list_ptr, 0, h.inc_ref().ptr()); - } else { - auto result = PyList_Append(list_ptr, h.ptr()); - if (result == -1) - pybind11_fail("loader_life_support: error adding patient"); - } - } -}; - -// Gets the cache entry for the given type, creating it if necessary. The return value is the pair -// returned by emplace, i.e. an iterator for the entry and a bool set to `true` if the entry was -// just created. -inline std::pair all_type_info_get_cache(PyTypeObject *type); - -// Populates a just-created cache entry. -PYBIND11_NOINLINE inline void all_type_info_populate(PyTypeObject *t, std::vector &bases) { - std::vector check; - for (handle parent : reinterpret_borrow(t->tp_bases)) - check.push_back((PyTypeObject *) parent.ptr()); - - auto const &type_dict = get_internals().registered_types_py; - for (size_t i = 0; i < check.size(); i++) { - auto type = check[i]; - // Ignore Python2 old-style class super type: - if (!PyType_Check((PyObject *) type)) continue; - - // Check `type` in the current set of registered python types: - auto it = type_dict.find(type); - if (it != type_dict.end()) { - // We found a cache entry for it, so it's either pybind-registered or has pre-computed - // pybind bases, but we have to make sure we haven't already seen the type(s) before: we - // want to follow Python/virtual C++ rules that there should only be one instance of a - // common base. - for (auto *tinfo : it->second) { - // NB: Could use a second set here, rather than doing a linear search, but since - // having a large number of immediate pybind11-registered types seems fairly - // unlikely, that probably isn't worthwhile. - bool found = false; - for (auto *known : bases) { - if (known == tinfo) { found = true; break; } - } - if (!found) bases.push_back(tinfo); - } - } - else if (type->tp_bases) { - // It's some python type, so keep follow its bases classes to look for one or more - // registered types - if (i + 1 == check.size()) { - // When we're at the end, we can pop off the current element to avoid growing - // `check` when adding just one base (which is typical--i.e. when there is no - // multiple inheritance) - check.pop_back(); - i--; - } - for (handle parent : reinterpret_borrow(type->tp_bases)) - check.push_back((PyTypeObject *) parent.ptr()); - } - } -} - -/** - * Extracts vector of type_info pointers of pybind-registered roots of the given Python type. Will - * be just 1 pybind type for the Python type of a pybind-registered class, or for any Python-side - * derived class that uses single inheritance. Will contain as many types as required for a Python - * class that uses multiple inheritance to inherit (directly or indirectly) from multiple - * pybind-registered classes. Will be empty if neither the type nor any base classes are - * pybind-registered. - * - * The value is cached for the lifetime of the Python type. - */ -inline const std::vector &all_type_info(PyTypeObject *type) { - auto ins = all_type_info_get_cache(type); - if (ins.second) - // New cache entry: populate it - all_type_info_populate(type, ins.first->second); - - return ins.first->second; -} - -/** - * Gets a single pybind11 type info for a python type. Returns nullptr if neither the type nor any - * ancestors are pybind11-registered. Throws an exception if there are multiple bases--use - * `all_type_info` instead if you want to support multiple bases. - */ -PYBIND11_NOINLINE inline detail::type_info* get_type_info(PyTypeObject *type) { - auto &bases = all_type_info(type); - if (bases.empty()) - return nullptr; - if (bases.size() > 1) - pybind11_fail("pybind11::detail::get_type_info: type has multiple pybind11-registered bases"); - return bases.front(); -} - -inline detail::type_info *get_local_type_info(const std::type_index &tp) { - auto &locals = registered_local_types_cpp(); - auto it = locals.find(tp); - if (it != locals.end()) - return it->second; - return nullptr; -} - -inline detail::type_info *get_global_type_info(const std::type_index &tp) { - auto &types = get_internals().registered_types_cpp; - auto it = types.find(tp); - if (it != types.end()) - return it->second; - return nullptr; -} - -/// Return the type info for a given C++ type; on lookup failure can either throw or return nullptr. -PYBIND11_NOINLINE inline detail::type_info *get_type_info(const std::type_index &tp, - bool throw_if_missing = false) { - if (auto ltype = get_local_type_info(tp)) - return ltype; - if (auto gtype = get_global_type_info(tp)) - return gtype; - - if (throw_if_missing) { - std::string tname = tp.name(); - detail::clean_type_id(tname); - pybind11_fail("pybind11::detail::get_type_info: unable to find type info for \"" + tname + "\""); - } - return nullptr; -} - -PYBIND11_NOINLINE inline handle get_type_handle(const std::type_info &tp, bool throw_if_missing) { - detail::type_info *type_info = get_type_info(tp, throw_if_missing); - return handle(type_info ? ((PyObject *) type_info->type) : nullptr); -} - -struct value_and_holder { - instance *inst = nullptr; - size_t index = 0u; - const detail::type_info *type = nullptr; - void **vh = nullptr; - - // Main constructor for a found value/holder: - value_and_holder(instance *i, const detail::type_info *type, size_t vpos, size_t index) : - inst{i}, index{index}, type{type}, - vh{inst->simple_layout ? inst->simple_value_holder : &inst->nonsimple.values_and_holders[vpos]} - {} - - // Default constructor (used to signal a value-and-holder not found by get_value_and_holder()) - value_and_holder() = default; - - // Used for past-the-end iterator - value_and_holder(size_t index) : index{index} {} - - template V *&value_ptr() const { - return reinterpret_cast(vh[0]); - } - // True if this `value_and_holder` has a non-null value pointer - explicit operator bool() const { return value_ptr(); } - - template H &holder() const { - return reinterpret_cast(vh[1]); - } - bool holder_constructed() const { - return inst->simple_layout - ? inst->simple_holder_constructed - : inst->nonsimple.status[index] & instance::status_holder_constructed; - } - void set_holder_constructed(bool v = true) { - if (inst->simple_layout) - inst->simple_holder_constructed = v; - else if (v) - inst->nonsimple.status[index] |= instance::status_holder_constructed; - else - inst->nonsimple.status[index] &= (uint8_t) ~instance::status_holder_constructed; - } - bool instance_registered() const { - return inst->simple_layout - ? inst->simple_instance_registered - : inst->nonsimple.status[index] & instance::status_instance_registered; - } - void set_instance_registered(bool v = true) { - if (inst->simple_layout) - inst->simple_instance_registered = v; - else if (v) - inst->nonsimple.status[index] |= instance::status_instance_registered; - else - inst->nonsimple.status[index] &= (uint8_t) ~instance::status_instance_registered; - } -}; - -// Container for accessing and iterating over an instance's values/holders -struct values_and_holders { -private: - instance *inst; - using type_vec = std::vector; - const type_vec &tinfo; - -public: - values_and_holders(instance *inst) : inst{inst}, tinfo(all_type_info(Py_TYPE(inst))) {} - - struct iterator { - private: - instance *inst = nullptr; - const type_vec *types = nullptr; - value_and_holder curr; - friend struct values_and_holders; - iterator(instance *inst, const type_vec *tinfo) - : inst{inst}, types{tinfo}, - curr(inst /* instance */, - types->empty() ? nullptr : (*types)[0] /* type info */, - 0, /* vpos: (non-simple types only): the first vptr comes first */ - 0 /* index */) - {} - // Past-the-end iterator: - iterator(size_t end) : curr(end) {} - public: - bool operator==(const iterator &other) const { return curr.index == other.curr.index; } - bool operator!=(const iterator &other) const { return curr.index != other.curr.index; } - iterator &operator++() { - if (!inst->simple_layout) - curr.vh += 1 + (*types)[curr.index]->holder_size_in_ptrs; - ++curr.index; - curr.type = curr.index < types->size() ? (*types)[curr.index] : nullptr; - return *this; - } - value_and_holder &operator*() { return curr; } - value_and_holder *operator->() { return &curr; } - }; - - iterator begin() { return iterator(inst, &tinfo); } - iterator end() { return iterator(tinfo.size()); } - - iterator find(const type_info *find_type) { - auto it = begin(), endit = end(); - while (it != endit && it->type != find_type) ++it; - return it; - } - - size_t size() { return tinfo.size(); } -}; - -/** - * Extracts C++ value and holder pointer references from an instance (which may contain multiple - * values/holders for python-side multiple inheritance) that match the given type. Throws an error - * if the given type (or ValueType, if omitted) is not a pybind11 base of the given instance. If - * `find_type` is omitted (or explicitly specified as nullptr) the first value/holder are returned, - * regardless of type (and the resulting .type will be nullptr). - * - * The returned object should be short-lived: in particular, it must not outlive the called-upon - * instance. - */ -PYBIND11_NOINLINE inline value_and_holder instance::get_value_and_holder(const type_info *find_type /*= nullptr default in common.h*/, bool throw_if_missing /*= true in common.h*/) { - // Optimize common case: - if (!find_type || Py_TYPE(this) == find_type->type) - return value_and_holder(this, find_type, 0, 0); - - detail::values_and_holders vhs(this); - auto it = vhs.find(find_type); - if (it != vhs.end()) - return *it; - - if (!throw_if_missing) - return value_and_holder(); - -#if defined(NDEBUG) - pybind11_fail("pybind11::detail::instance::get_value_and_holder: " - "type is not a pybind11 base of the given instance " - "(compile in debug mode for type details)"); -#else - pybind11_fail("pybind11::detail::instance::get_value_and_holder: `" + - get_fully_qualified_tp_name(find_type->type) + "' is not a pybind11 base of the given `" + - get_fully_qualified_tp_name(Py_TYPE(this)) + "' instance"); -#endif -} - -PYBIND11_NOINLINE inline void instance::allocate_layout() { - auto &tinfo = all_type_info(Py_TYPE(this)); - - const size_t n_types = tinfo.size(); - - if (n_types == 0) - pybind11_fail("instance allocation failed: new instance has no pybind11-registered base types"); - - simple_layout = - n_types == 1 && tinfo.front()->holder_size_in_ptrs <= instance_simple_holder_in_ptrs(); - - // Simple path: no python-side multiple inheritance, and a small-enough holder - if (simple_layout) { - simple_value_holder[0] = nullptr; - simple_holder_constructed = false; - simple_instance_registered = false; - } - else { // multiple base types or a too-large holder - // Allocate space to hold: [v1*][h1][v2*][h2]...[bb...] where [vN*] is a value pointer, - // [hN] is the (uninitialized) holder instance for value N, and [bb...] is a set of bool - // values that tracks whether each associated holder has been initialized. Each [block] is - // padded, if necessary, to an integer multiple of sizeof(void *). - size_t space = 0; - for (auto t : tinfo) { - space += 1; // value pointer - space += t->holder_size_in_ptrs; // holder instance - } - size_t flags_at = space; - space += size_in_ptrs(n_types); // status bytes (holder_constructed and instance_registered) - - // Allocate space for flags, values, and holders, and initialize it to 0 (flags and values, - // in particular, need to be 0). Use Python's memory allocation functions: in Python 3.6 - // they default to using pymalloc, which is designed to be efficient for small allocations - // like the one we're doing here; in earlier versions (and for larger allocations) they are - // just wrappers around malloc. -#if PY_VERSION_HEX >= 0x03050000 - nonsimple.values_and_holders = (void **) PyMem_Calloc(space, sizeof(void *)); - if (!nonsimple.values_and_holders) throw std::bad_alloc(); -#else - nonsimple.values_and_holders = (void **) PyMem_New(void *, space); - if (!nonsimple.values_and_holders) throw std::bad_alloc(); - std::memset(nonsimple.values_and_holders, 0, space * sizeof(void *)); -#endif - nonsimple.status = reinterpret_cast(&nonsimple.values_and_holders[flags_at]); - } - owned = true; -} - -PYBIND11_NOINLINE inline void instance::deallocate_layout() { - if (!simple_layout) - PyMem_Free(nonsimple.values_and_holders); -} - -PYBIND11_NOINLINE inline bool isinstance_generic(handle obj, const std::type_info &tp) { - handle type = detail::get_type_handle(tp, false); - if (!type) - return false; - return isinstance(obj, type); -} - -PYBIND11_NOINLINE inline std::string error_string() { - if (!PyErr_Occurred()) { - PyErr_SetString(PyExc_RuntimeError, "Unknown internal error occurred"); - return "Unknown internal error occurred"; - } - - error_scope scope; // Preserve error state - - std::string errorString; - if (scope.type) { - errorString += handle(scope.type).attr("__name__").cast(); - errorString += ": "; - } - if (scope.value) - errorString += (std::string) str(scope.value); - - PyErr_NormalizeException(&scope.type, &scope.value, &scope.trace); - -#if PY_MAJOR_VERSION >= 3 - if (scope.trace != nullptr) - PyException_SetTraceback(scope.value, scope.trace); -#endif - -#if !defined(PYPY_VERSION) - if (scope.trace) { - auto *trace = (PyTracebackObject *) scope.trace; - - /* Get the deepest trace possible */ - while (trace->tb_next) - trace = trace->tb_next; - - PyFrameObject *frame = trace->tb_frame; - errorString += "\n\nAt:\n"; - while (frame) { - int lineno = PyFrame_GetLineNumber(frame); - errorString += - " " + handle(frame->f_code->co_filename).cast() + - "(" + std::to_string(lineno) + "): " + - handle(frame->f_code->co_name).cast() + "\n"; - frame = frame->f_back; - } - } -#endif - - return errorString; -} - -PYBIND11_NOINLINE inline handle get_object_handle(const void *ptr, const detail::type_info *type ) { - auto &instances = get_internals().registered_instances; - auto range = instances.equal_range(ptr); - for (auto it = range.first; it != range.second; ++it) { - for (const auto &vh : values_and_holders(it->second)) { - if (vh.type == type) - return handle((PyObject *) it->second); - } - } - return handle(); -} - -inline PyThreadState *get_thread_state_unchecked() { -#if defined(PYPY_VERSION) - return PyThreadState_GET(); -#elif PY_VERSION_HEX < 0x03000000 - return _PyThreadState_Current; -#elif PY_VERSION_HEX < 0x03050000 - return (PyThreadState*) _Py_atomic_load_relaxed(&_PyThreadState_Current); -#elif PY_VERSION_HEX < 0x03050200 - return (PyThreadState*) _PyThreadState_Current.value; -#else - return _PyThreadState_UncheckedGet(); -#endif -} - -// Forward declarations -inline void keep_alive_impl(handle nurse, handle patient); -inline PyObject *make_new_instance(PyTypeObject *type); - -class type_caster_generic { -public: - PYBIND11_NOINLINE type_caster_generic(const std::type_info &type_info) - : typeinfo(get_type_info(type_info)), cpptype(&type_info) { } - - type_caster_generic(const type_info *typeinfo) - : typeinfo(typeinfo), cpptype(typeinfo ? typeinfo->cpptype : nullptr) { } - - bool load(handle src, bool convert) { - return load_impl(src, convert); - } - - PYBIND11_NOINLINE static handle cast(const void *_src, return_value_policy policy, handle parent, - const detail::type_info *tinfo, - void *(*copy_constructor)(const void *), - void *(*move_constructor)(const void *), - const void *existing_holder = nullptr) { - if (!tinfo) // no type info: error will be set already - return handle(); - - void *src = const_cast(_src); - if (src == nullptr) - return none().release(); - - auto it_instances = get_internals().registered_instances.equal_range(src); - for (auto it_i = it_instances.first; it_i != it_instances.second; ++it_i) { - for (auto instance_type : detail::all_type_info(Py_TYPE(it_i->second))) { - if (instance_type && same_type(*instance_type->cpptype, *tinfo->cpptype)) - return handle((PyObject *) it_i->second).inc_ref(); - } - } - - auto inst = reinterpret_steal(make_new_instance(tinfo->type)); - auto wrapper = reinterpret_cast(inst.ptr()); - wrapper->owned = false; - void *&valueptr = values_and_holders(wrapper).begin()->value_ptr(); - - switch (policy) { - case return_value_policy::automatic: - case return_value_policy::take_ownership: - valueptr = src; - wrapper->owned = true; - break; - - case return_value_policy::automatic_reference: - case return_value_policy::reference: - valueptr = src; - wrapper->owned = false; - break; - - case return_value_policy::copy: - if (copy_constructor) - valueptr = copy_constructor(src); - else { -#if defined(NDEBUG) - throw cast_error("return_value_policy = copy, but type is " - "non-copyable! (compile in debug mode for details)"); -#else - std::string type_name(tinfo->cpptype->name()); - detail::clean_type_id(type_name); - throw cast_error("return_value_policy = copy, but type " + - type_name + " is non-copyable!"); -#endif - } - wrapper->owned = true; - break; - - case return_value_policy::move: - if (move_constructor) - valueptr = move_constructor(src); - else if (copy_constructor) - valueptr = copy_constructor(src); - else { -#if defined(NDEBUG) - throw cast_error("return_value_policy = move, but type is neither " - "movable nor copyable! " - "(compile in debug mode for details)"); -#else - std::string type_name(tinfo->cpptype->name()); - detail::clean_type_id(type_name); - throw cast_error("return_value_policy = move, but type " + - type_name + " is neither movable nor copyable!"); -#endif - } - wrapper->owned = true; - break; - - case return_value_policy::reference_internal: - valueptr = src; - wrapper->owned = false; - keep_alive_impl(inst, parent); - break; - - default: - throw cast_error("unhandled return_value_policy: should not happen!"); - } - - tinfo->init_instance(wrapper, existing_holder); - - return inst.release(); - } - - // Base methods for generic caster; there are overridden in copyable_holder_caster - void load_value(value_and_holder &&v_h) { - auto *&vptr = v_h.value_ptr(); - // Lazy allocation for unallocated values: - if (vptr == nullptr) { - auto *type = v_h.type ? v_h.type : typeinfo; - if (type->operator_new) { - vptr = type->operator_new(type->type_size); - } else { - #if defined(__cpp_aligned_new) && (!defined(_MSC_VER) || _MSC_VER >= 1912) - if (type->type_align > __STDCPP_DEFAULT_NEW_ALIGNMENT__) - vptr = ::operator new(type->type_size, - std::align_val_t(type->type_align)); - else - #endif - vptr = ::operator new(type->type_size); - } - } - value = vptr; - } - bool try_implicit_casts(handle src, bool convert) { - for (auto &cast : typeinfo->implicit_casts) { - type_caster_generic sub_caster(*cast.first); - if (sub_caster.load(src, convert)) { - value = cast.second(sub_caster.value); - return true; - } - } - return false; - } - bool try_direct_conversions(handle src) { - for (auto &converter : *typeinfo->direct_conversions) { - if (converter(src.ptr(), value)) - return true; - } - return false; - } - void check_holder_compat() {} - - PYBIND11_NOINLINE static void *local_load(PyObject *src, const type_info *ti) { - auto caster = type_caster_generic(ti); - if (caster.load(src, false)) - return caster.value; - return nullptr; - } - - /// Try to load with foreign typeinfo, if available. Used when there is no - /// native typeinfo, or when the native one wasn't able to produce a value. - PYBIND11_NOINLINE bool try_load_foreign_module_local(handle src) { - constexpr auto *local_key = PYBIND11_MODULE_LOCAL_ID; - const auto pytype = type::handle_of(src); - if (!hasattr(pytype, local_key)) - return false; - - type_info *foreign_typeinfo = reinterpret_borrow(getattr(pytype, local_key)); - // Only consider this foreign loader if actually foreign and is a loader of the correct cpp type - if (foreign_typeinfo->module_local_load == &local_load - || (cpptype && !same_type(*cpptype, *foreign_typeinfo->cpptype))) - return false; - - if (auto result = foreign_typeinfo->module_local_load(src.ptr(), foreign_typeinfo)) { - value = result; - return true; - } - return false; - } - - // Implementation of `load`; this takes the type of `this` so that it can dispatch the relevant - // bits of code between here and copyable_holder_caster where the two classes need different - // logic (without having to resort to virtual inheritance). - template - PYBIND11_NOINLINE bool load_impl(handle src, bool convert) { - if (!src) return false; - if (!typeinfo) return try_load_foreign_module_local(src); - if (src.is_none()) { - // Defer accepting None to other overloads (if we aren't in convert mode): - if (!convert) return false; - value = nullptr; - return true; - } - - auto &this_ = static_cast(*this); - this_.check_holder_compat(); - - PyTypeObject *srctype = Py_TYPE(src.ptr()); - - // Case 1: If src is an exact type match for the target type then we can reinterpret_cast - // the instance's value pointer to the target type: - if (srctype == typeinfo->type) { - this_.load_value(reinterpret_cast(src.ptr())->get_value_and_holder()); - return true; - } - // Case 2: We have a derived class - else if (PyType_IsSubtype(srctype, typeinfo->type)) { - auto &bases = all_type_info(srctype); - bool no_cpp_mi = typeinfo->simple_type; - - // Case 2a: the python type is a Python-inherited derived class that inherits from just - // one simple (no MI) pybind11 class, or is an exact match, so the C++ instance is of - // the right type and we can use reinterpret_cast. - // (This is essentially the same as case 2b, but because not using multiple inheritance - // is extremely common, we handle it specially to avoid the loop iterator and type - // pointer lookup overhead) - if (bases.size() == 1 && (no_cpp_mi || bases.front()->type == typeinfo->type)) { - this_.load_value(reinterpret_cast(src.ptr())->get_value_and_holder()); - return true; - } - // Case 2b: the python type inherits from multiple C++ bases. Check the bases to see if - // we can find an exact match (or, for a simple C++ type, an inherited match); if so, we - // can safely reinterpret_cast to the relevant pointer. - else if (bases.size() > 1) { - for (auto base : bases) { - if (no_cpp_mi ? PyType_IsSubtype(base->type, typeinfo->type) : base->type == typeinfo->type) { - this_.load_value(reinterpret_cast(src.ptr())->get_value_and_holder(base)); - return true; - } - } - } - - // Case 2c: C++ multiple inheritance is involved and we couldn't find an exact type match - // in the registered bases, above, so try implicit casting (needed for proper C++ casting - // when MI is involved). - if (this_.try_implicit_casts(src, convert)) - return true; - } - - // Perform an implicit conversion - if (convert) { - for (auto &converter : typeinfo->implicit_conversions) { - auto temp = reinterpret_steal(converter(src.ptr(), typeinfo->type)); - if (load_impl(temp, false)) { - loader_life_support::add_patient(temp); - return true; - } - } - if (this_.try_direct_conversions(src)) - return true; - } - - // Failed to match local typeinfo. Try again with global. - if (typeinfo->module_local) { - if (auto gtype = get_global_type_info(*typeinfo->cpptype)) { - typeinfo = gtype; - return load(src, false); - } - } - - // Global typeinfo has precedence over foreign module_local - return try_load_foreign_module_local(src); - } - - - // Called to do type lookup and wrap the pointer and type in a pair when a dynamic_cast - // isn't needed or can't be used. If the type is unknown, sets the error and returns a pair - // with .second = nullptr. (p.first = nullptr is not an error: it becomes None). - PYBIND11_NOINLINE static std::pair src_and_type( - const void *src, const std::type_info &cast_type, const std::type_info *rtti_type = nullptr) { - if (auto *tpi = get_type_info(cast_type)) - return {src, const_cast(tpi)}; - - // Not found, set error: - std::string tname = rtti_type ? rtti_type->name() : cast_type.name(); - detail::clean_type_id(tname); - std::string msg = "Unregistered type : " + tname; - PyErr_SetString(PyExc_TypeError, msg.c_str()); - return {nullptr, nullptr}; - } - - const type_info *typeinfo = nullptr; - const std::type_info *cpptype = nullptr; - void *value = nullptr; -}; - -/** - * Determine suitable casting operator for pointer-or-lvalue-casting type casters. The type caster - * needs to provide `operator T*()` and `operator T&()` operators. - * - * If the type supports moving the value away via an `operator T&&() &&` method, it should use - * `movable_cast_op_type` instead. - */ -template -using cast_op_type = - conditional_t>::value, - typename std::add_pointer>::type, - typename std::add_lvalue_reference>::type>; - -/** - * Determine suitable casting operator for a type caster with a movable value. Such a type caster - * needs to provide `operator T*()`, `operator T&()`, and `operator T&&() &&`. The latter will be - * called in appropriate contexts where the value can be moved rather than copied. - * - * These operator are automatically provided when using the PYBIND11_TYPE_CASTER macro. - */ -template -using movable_cast_op_type = - conditional_t::type>::value, - typename std::add_pointer>::type, - conditional_t::value, - typename std::add_rvalue_reference>::type, - typename std::add_lvalue_reference>::type>>; - -// std::is_copy_constructible isn't quite enough: it lets std::vector (and similar) through when -// T is non-copyable, but code containing such a copy constructor fails to actually compile. -template struct is_copy_constructible : std::is_copy_constructible {}; - -// Specialization for types that appear to be copy constructible but also look like stl containers -// (we specifically check for: has `value_type` and `reference` with `reference = value_type&`): if -// so, copy constructability depends on whether the value_type is copy constructible. -template struct is_copy_constructible, - std::is_same, - // Avoid infinite recursion - negation> - >::value>> : is_copy_constructible {}; - -// Likewise for std::pair -// (after C++17 it is mandatory that the copy constructor not exist when the two types aren't themselves -// copy constructible, but this can not be relied upon when T1 or T2 are themselves containers). -template struct is_copy_constructible> - : all_of, is_copy_constructible> {}; - -// The same problems arise with std::is_copy_assignable, so we use the same workaround. -template struct is_copy_assignable : std::is_copy_assignable {}; -template struct is_copy_assignable, - std::is_same - >::value>> : is_copy_assignable {}; -template struct is_copy_assignable> - : all_of, is_copy_assignable> {}; - -PYBIND11_NAMESPACE_END(detail) - -// polymorphic_type_hook::get(src, tinfo) determines whether the object pointed -// to by `src` actually is an instance of some class derived from `itype`. -// If so, it sets `tinfo` to point to the std::type_info representing that derived -// type, and returns a pointer to the start of the most-derived object of that type -// (in which `src` is a subobject; this will be the same address as `src` in most -// single inheritance cases). If not, or if `src` is nullptr, it simply returns `src` -// and leaves `tinfo` at its default value of nullptr. -// -// The default polymorphic_type_hook just returns src. A specialization for polymorphic -// types determines the runtime type of the passed object and adjusts the this-pointer -// appropriately via dynamic_cast. This is what enables a C++ Animal* to appear -// to Python as a Dog (if Dog inherits from Animal, Animal is polymorphic, Dog is -// registered with pybind11, and this Animal is in fact a Dog). -// -// You may specialize polymorphic_type_hook yourself for types that want to appear -// polymorphic to Python but do not use C++ RTTI. (This is a not uncommon pattern -// in performance-sensitive applications, used most notably in LLVM.) -// -// polymorphic_type_hook_base allows users to specialize polymorphic_type_hook with -// std::enable_if. User provided specializations will always have higher priority than -// the default implementation and specialization provided in polymorphic_type_hook_base. -template -struct polymorphic_type_hook_base -{ - static const void *get(const itype *src, const std::type_info*&) { return src; } -}; -template -struct polymorphic_type_hook_base::value>> -{ - static const void *get(const itype *src, const std::type_info*& type) { - type = src ? &typeid(*src) : nullptr; - return dynamic_cast(src); - } -}; -template -struct polymorphic_type_hook : public polymorphic_type_hook_base {}; - -PYBIND11_NAMESPACE_BEGIN(detail) - -/// Generic type caster for objects stored on the heap -template class type_caster_base : public type_caster_generic { - using itype = intrinsic_t; - -public: - static constexpr auto name = _(); - - type_caster_base() : type_caster_base(typeid(type)) { } - explicit type_caster_base(const std::type_info &info) : type_caster_generic(info) { } - - static handle cast(const itype &src, return_value_policy policy, handle parent) { - if (policy == return_value_policy::automatic || policy == return_value_policy::automatic_reference) - policy = return_value_policy::copy; - return cast(&src, policy, parent); - } - - static handle cast(itype &&src, return_value_policy, handle parent) { - return cast(&src, return_value_policy::move, parent); - } - - // Returns a (pointer, type_info) pair taking care of necessary type lookup for a - // polymorphic type (using RTTI by default, but can be overridden by specializing - // polymorphic_type_hook). If the instance isn't derived, returns the base version. - static std::pair src_and_type(const itype *src) { - auto &cast_type = typeid(itype); - const std::type_info *instance_type = nullptr; - const void *vsrc = polymorphic_type_hook::get(src, instance_type); - if (instance_type && !same_type(cast_type, *instance_type)) { - // This is a base pointer to a derived type. If the derived type is registered - // with pybind11, we want to make the full derived object available. - // In the typical case where itype is polymorphic, we get the correct - // derived pointer (which may be != base pointer) by a dynamic_cast to - // most derived type. If itype is not polymorphic, we won't get here - // except via a user-provided specialization of polymorphic_type_hook, - // and the user has promised that no this-pointer adjustment is - // required in that case, so it's OK to use static_cast. - if (const auto *tpi = get_type_info(*instance_type)) - return {vsrc, tpi}; - } - // Otherwise we have either a nullptr, an `itype` pointer, or an unknown derived pointer, so - // don't do a cast - return type_caster_generic::src_and_type(src, cast_type, instance_type); - } - - static handle cast(const itype *src, return_value_policy policy, handle parent) { - auto st = src_and_type(src); - return type_caster_generic::cast( - st.first, policy, parent, st.second, - make_copy_constructor(src), make_move_constructor(src)); - } - - static handle cast_holder(const itype *src, const void *holder) { - auto st = src_and_type(src); - return type_caster_generic::cast( - st.first, return_value_policy::take_ownership, {}, st.second, - nullptr, nullptr, holder); - } - - template using cast_op_type = detail::cast_op_type; - - operator itype*() { return (type *) value; } - operator itype&() { if (!value) throw reference_cast_error(); return *((itype *) value); } - -protected: - using Constructor = void *(*)(const void *); - - /* Only enabled when the types are {copy,move}-constructible *and* when the type - does not have a private operator new implementation. */ - template ::value>> - static auto make_copy_constructor(const T *x) -> decltype(new T(*x), Constructor{}) { - return [](const void *arg) -> void * { - return new T(*reinterpret_cast(arg)); - }; - } - - template ::value>> - static auto make_move_constructor(const T *x) -> decltype(new T(std::move(*const_cast(x))), Constructor{}) { - return [](const void *arg) -> void * { - return new T(std::move(*const_cast(reinterpret_cast(arg)))); - }; - } - - static Constructor make_copy_constructor(...) { return nullptr; } - static Constructor make_move_constructor(...) { return nullptr; } -}; - -template class type_caster : public type_caster_base { }; -template using make_caster = type_caster>; +template +class type_caster : public type_caster_base {}; +template +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) { +template +typename make_caster::template cast_op_type cast_op(make_caster &caster) { return caster.operator typename make_caster::template cast_op_type(); } -template typename make_caster::template cast_op_type::type> +template +typename make_caster::template cast_op_type::type> cast_op(make_caster &&caster) { - return std::move(caster).operator - typename make_caster::template cast_op_type::type>(); + return std::move(caster).operator typename make_caster:: + template cast_op_type::type>(); } -template class type_caster> { +template +class type_caster> { private: using caster_t = make_caster; caster_t subcaster; - using subcaster_cast_op_type = typename caster_t::template cast_op_type; - static_assert(std::is_same::type &, subcaster_cast_op_type>::value, - "std::reference_wrapper caster requires T to have a caster with an `T &` operator"); + 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) { + 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) + 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; - operator std::reference_wrapper() { return subcaster.operator subcaster_cast_op_type&(); } + 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: \ - type value; \ - public: \ - static constexpr auto name = py_name; \ - template >::value, int> = 0> \ - static handle cast(T_ *src, return_value_policy policy, handle parent) { \ - if (!src) return none().release(); \ - if (policy == return_value_policy::take_ownership) { \ - auto h = cast(std::move(*src), policy, parent); delete src; return h; \ - } else { \ - return cast(*src, policy, parent); \ - } \ - } \ - operator type*() { return &value; } \ - operator type&() { return value; } \ - operator type&&() && { return std::move(value); } \ - template using cast_op_type = pybind11::detail::movable_cast_op_type - - -template using is_std_char_type = any_of< - std::is_same, /* std::string */ +#define PYBIND11_TYPE_CASTER(type, py_name) \ +protected: \ + type value; \ + \ +public: \ + static constexpr auto name = py_name; \ + template >::value, \ + int> = 0> \ + static ::pybind11::handle cast( \ + T_ *src, ::pybind11::return_value_policy policy, ::pybind11::handle parent) { \ + if (!src) \ + return ::pybind11::none().release(); \ + if (policy == ::pybind11::return_value_policy::take_ownership) { \ + auto h = cast(std::move(*src), policy, parent); \ + delete src; \ + return h; \ + } \ + return cast(*src, policy, parent); \ + } \ + operator type *() { return &value; } /* NOLINT(bugprone-macro-parentheses) */ \ + operator type &() { return value; } /* NOLINT(bugprone-macro-parentheses) */ \ + operator type &&() && { return std::move(value); } /* NOLINT(bugprone-macro-parentheses) */ \ + template \ + using cast_op_type = ::pybind11::detail::movable_cast_op_type + +template +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::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_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: +public: bool load(handle src, bool convert) { py_type py_value; - if (!src) + if (!src) { return false; + } + +#if !defined(PYPY_VERSION) + 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__"); }; +#endif if (std::is_floating_point::value) { - if (convert || PyFloat_Check(src.ptr())) + if (convert || PyFloat_Check(src.ptr())) { py_value = (py_type) PyFloat_AsDouble(src.ptr()); - else + } else { return false; - } else if (PyFloat_Check(src.ptr())) { + } + } else if (PyFloat_Check(src.ptr()) + || (!convert && !PYBIND11_LONG_CHECK(src.ptr()) && !index_check(src.ptr()))) { return false; - } else if (std::is_unsigned::value) { - py_value = as_unsigned(src.ptr()); - } else { // signed integer: - py_value = sizeof(T) <= sizeof(long) - ? (py_type) PyLong_AsLong(src.ptr()) - : (py_type) PYBIND11_LONG_AS_LONGLONG(src.ptr()); + } 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; + } + } +#endif + 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 @@ -1040,19 +179,14 @@ struct type_caster::value && !is_std_char_t // 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)) { - bool type_error = py_err && PyErr_ExceptionMatches( -#if PY_VERSION_HEX < 0x03000000 && !defined(PYPY_VERSION) - PyExc_SystemError -#else - PyExc_TypeError -#endif - ); + if (py_err + || (std::is_integral::value && sizeof(py_type) != sizeof(T) + && py_value != (py_type) (T) py_value)) { PyErr_Clear(); - if (type_error && convert && PyNumber_Check(src.ptr())) { + 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())); + ? PyNumber_Float(src.ptr()) + : PyNumber_Long(src.ptr())); PyErr_Clear(); return load(tmp, false); } @@ -1063,62 +197,75 @@ struct type_caster::value && !is_std_char_t return true; } - template + 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::value && std::is_signed::value && (sizeof(U) <= sizeof(long)), handle>::type + 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::value && std::is_unsigned::value && (sizeof(U) <= sizeof(unsigned long)), handle>::type + 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::value && std::is_signed::value && (sizeof(U) > sizeof(long)), handle>::type + 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 + 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, _::value>("int", "float")); + PYBIND11_TYPE_CASTER(T, const_name::value>("int", "float")); }; -template struct void_caster { +template +struct void_caster { public: bool load(handle src, bool) { - if (src && src.is_none()) + if (src && src.is_none()) { return true; + } return false; } static handle cast(T, return_value_policy /* policy */, handle /* parent */) { return none().inc_ref(); } - PYBIND11_TYPE_CASTER(T, _("None")); + PYBIND11_TYPE_CASTER(T, const_name("None")); }; -template <> class type_caster : public void_caster {}; +template <> +class type_caster : public void_caster {}; -template <> class type_caster : public type_caster { +template <> +class type_caster : public type_caster { public: using type_caster::cast; bool load(handle h, bool) { if (!h) { return false; - } else if (h.is_none()) { + } + if (h.is_none()) { value = nullptr; return true; } @@ -1130,7 +277,7 @@ template <> class type_caster : public type_caster { } /* Check if this is a C++ type */ - auto &bases = all_type_info((PyTypeObject *) type::handle_of(h).ptr()); + 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; @@ -1141,191 +288,247 @@ template <> class type_caster : public type_caster { } static handle cast(const void *ptr, return_value_policy /* policy */, handle /* parent */) { - if (ptr) + if (ptr) { return capsule(ptr).release(); - else - return none().inc_ref(); + } + return none().inc_ref(); } - template using cast_op_type = void*&; - operator void *&() { return value; } - static constexpr auto name = _("capsule"); + template + using cast_op_type = void *&; + explicit operator void *&() { return value; } + static constexpr auto name = const_name("capsule"); + private: void *value = nullptr; }; -template <> class type_caster : public void_caster { }; +template <> +class type_caster : public void_caster {}; -template <> class type_caster { +template <> +class type_caster { public: bool load(handle src, bool convert) { - if (!src) return false; - else if (src.ptr() == Py_True) { value = true; return true; } - else if (src.ptr() == Py_False) { value = false; return true; } - else if (convert || !strcmp("numpy.bool_", Py_TYPE(src.ptr())->tp_name)) { + if (!src) { + return false; + } + if (src.ptr() == Py_True) { + value = true; + return true; + } + if (src.ptr() == Py_False) { + value = false; + return true; + } + if (convert || (std::strcmp("numpy.bool_", Py_TYPE(src.ptr())->tp_name) == 0)) { // (allow non-implicit conversion for numpy booleans) Py_ssize_t res = -1; if (src.is_none()) { - res = 0; // None is implicitly converted to False + res = 0; // None is implicitly converted to False } - #if defined(PYPY_VERSION) - // On PyPy, check that "__bool__" (or "__nonzero__" on Python 2.7) attr exists +#if defined(PYPY_VERSION) + // On PyPy, check that "__bool__" attr exists else if (hasattr(src, PYBIND11_BOOL_ATTR)) { res = PyObject_IsTrue(src.ptr()); } - #else +#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) { + 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 +#endif if (res == 0 || res == 1) { - value = (bool) res; + value = (res != 0); return true; - } else { - PyErr_Clear(); } + 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, _("bool")); + PYBIND11_TYPE_CASTER(bool, const_name("bool")); }; // Helper class for UTF-{8,16,32} C++ stl strings: -template struct string_caster { +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"); + 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"); + 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"); + "Unsupported wchar_t size != 2/4"); static constexpr size_t UTF_N = 8 * sizeof(CharT); bool load(handle src, bool) { -#if PY_MAJOR_VERSION < 3 - object temp; -#endif handle load_src = src; if (!src) { return false; - } else if (!PyUnicode_Check(load_src.ptr())) { -#if PY_MAJOR_VERSION >= 3 - return load_bytes(load_src); -#else - if (std::is_same::value) { - return load_bytes(load_src); - } + } + if (!PyUnicode_Check(load_src.ptr())) { + return load_raw(load_src); + } - // The below is a guaranteed failure in Python 3 when PyUnicode_Check returns false - if (!PYBIND11_BYTES_CHECK(load_src.ptr())) + // For UTF-8 we avoid the need for a temporary `bytes` object by using + // `PyUnicode_AsUTF8AndSize`. + if (PYBIND11_SILENCE_MSVC_C4127(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; - - temp = reinterpret_steal(PyUnicode_FromObject(load_src.ptr())); - if (!temp) { PyErr_Clear(); return false; } - load_src = temp; -#endif + } + value = StringType(buffer, static_cast(size)); + return true; } - object 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; } + 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; + } - const auto *buffer = reinterpret_cast(PYBIND11_BYTES_AS_STRING(utfNbytes.ptr())); + const auto *buffer + = reinterpret_cast(PYBIND11_BYTES_AS_STRING(utfNbytes.ptr())); size_t length = (size_t) PYBIND11_BYTES_SIZE(utfNbytes.ptr()) / sizeof(CharT); - if (UTF_N > 8) { buffer++; length--; } // Skip BOM for UTF-16/32 + // Skip BOM for UTF-16/32 + if (PYBIND11_SILENCE_MSVC_C4127(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) + if (IsView) { loader_life_support::add_patient(utfNbytes); + } return true; } - static handle cast(const StringType &src, return_value_policy /* policy */, handle /* parent */) { + 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(); + if (!s) { + throw error_already_set(); + } return s; } - PYBIND11_TYPE_CASTER(StringType, _(PYBIND11_STRING_NAME)); + PYBIND11_TYPE_CASTER(StringType, const_name(PYBIND11_STRING_NAME)); 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 object as-is (i.e. + // 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_bytes(enable_if_t::value, handle> src) { + bool load_raw(enable_if_t::value, handle> src) { if (PYBIND11_BYTES_CHECK(src.ptr())) { - // We were passed a Python 3 raw bytes; accept it into a std::string or char* + // 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) { - value = StringType(bytes, (size_t) PYBIND11_BYTES_SIZE(src.ptr())); - return true; + if (!bytes) { + pybind11_fail("Unexpected PYBIND11_BYTES_AS_STRING() failure."); } + 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."); + } + value = StringType(bytearray, (size_t) PyByteArray_Size(src.ptr())); + return true; } return false; } template - bool load_bytes(enable_if_t::value, handle>) { return false; } + bool load_raw(enable_if_t::value, handle>) { + return false; + } }; template -struct type_caster, enable_if_t::value>> +struct type_caster, + enable_if_t::value>> : string_caster> {}; #ifdef PYBIND11_HAS_STRING_VIEW template -struct type_caster, enable_if_t::value>> +struct type_caster, + 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>> { +template +struct type_caster::value>> { using StringType = std::basic_string; using StringCaster = type_caster; StringCaster str_caster; bool none = false; CharT one_char = 0; + public: bool load(handle src, bool convert) { - if (!src) return false; + 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 (!convert) { + return false; + } none = true; return true; } @@ -1333,45 +536,58 @@ template struct type_caster::value) { handle s = PyUnicode_DecodeLatin1((const char *) &src, 1, nullptr); - if (!s) throw error_already_set(); + if (!s) { + throw error_already_set(); + } return s; } return StringCaster::cast(StringType(1, src), policy, parent); } - operator CharT*() { return none ? nullptr : const_cast(static_cast(str_caster).c_str()); } - operator CharT&() { - if (none) + 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) + 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) { + // 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 (PYBIND11_SILENCE_MSVC_C4127(StringCaster::UTF_N == 8) && str_len > 1 && str_len <= 4) { auto v0 = static_cast(value[0]); - size_t char0_bytes = !(v0 & 0x80) ? 1 : // low bits only: 0-127 - (v0 & 0xE0) == 0xC0 ? 2 : // 0b110xxxxx - start of 2-byte sequence - (v0 & 0xF0) == 0xE0 ? 3 : // 0b1110xxxx - start of 3-byte sequence - 4; // 0b11110xxx - start of 4-byte sequence + // 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)); + 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 @@ -1382,36 +598,42 @@ template struct type_caster(value[0]); - if (one_char >= 0xD800 && one_char < 0xE000) + if (one_char >= 0xD800 && one_char < 0xE000) { throw value_error("Character code point not in range(0x10000)"); + } } - if (str_len != 1) + if (str_len != 1) { throw value_error("Expected a character, but multi-character string found"); + } one_char = value[0]; return one_char; } - static constexpr auto name = _(PYBIND11_STRING_NAME); - template using cast_op_type = pybind11::detail::cast_op_type<_T>; + 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 class Tuple, typename... Ts> class tuple_caster { +template