From 23f424c6605b8b9fbb8e1187a17a7821a317fa57 Mon Sep 17 00:00:00 2001 From: Shintaro Iwasaki Date: Thu, 22 Sep 2022 17:53:42 -0700 Subject: [PATCH] [Triton-MLIR][pybind11] Update pybind11 to 2.10.0 (#694) This PR applies #691 to the Triton-MLIR branch. --- .github/workflows/integration-tests.yml | 4 +- .gitmodules | 3 + CMakeLists.txt | 3 + python/setup.py | 15 + python/src/pybind11/attr.h | 601 ------ python/src/pybind11/buffer_info.h | 127 -- python/src/pybind11/cast.h | 2465 ----------------------- python/src/pybind11/chrono.h | 187 -- python/src/pybind11/common.h | 3 - python/src/pybind11/complex.h | 72 - python/src/pybind11/detail/class.h | 668 ------ python/src/pybind11/detail/common.h | 945 --------- python/src/pybind11/detail/descr.h | 118 -- python/src/pybind11/detail/init.h | 415 ---- python/src/pybind11/detail/internals.h | 340 ---- python/src/pybind11/detail/typeid.h | 56 - python/src/pybind11/eigen.h | 724 ------- python/src/pybind11/embed.h | 206 -- python/src/pybind11/eval.h | 134 -- python/src/pybind11/functional.h | 116 -- python/src/pybind11/iostream.h | 201 -- python/src/pybind11/numpy.h | 1789 ---------------- python/src/pybind11/operators.h | 228 --- python/src/pybind11/options.h | 79 - python/src/pybind11/pybind11.h | 2438 ---------------------- python/src/pybind11/pytypes.h | 1733 ---------------- python/src/pybind11/stl.h | 424 ---- python/src/pybind11/stl_bind.h | 669 ------ third-party/pybind11 | 1 + 29 files changed, 24 insertions(+), 14740 deletions(-) delete mode 100644 python/src/pybind11/attr.h delete mode 100644 python/src/pybind11/buffer_info.h delete mode 100644 python/src/pybind11/cast.h delete mode 100644 python/src/pybind11/chrono.h delete mode 100644 python/src/pybind11/common.h delete mode 100644 python/src/pybind11/complex.h delete mode 100644 python/src/pybind11/detail/class.h delete mode 100644 python/src/pybind11/detail/common.h delete mode 100644 python/src/pybind11/detail/descr.h delete mode 100644 python/src/pybind11/detail/init.h delete mode 100644 python/src/pybind11/detail/internals.h delete mode 100644 python/src/pybind11/detail/typeid.h delete mode 100644 python/src/pybind11/eigen.h delete mode 100644 python/src/pybind11/embed.h delete mode 100644 python/src/pybind11/eval.h delete mode 100644 python/src/pybind11/functional.h delete mode 100644 python/src/pybind11/iostream.h delete mode 100644 python/src/pybind11/numpy.h delete mode 100644 python/src/pybind11/operators.h delete mode 100644 python/src/pybind11/options.h delete mode 100644 python/src/pybind11/pybind11.h delete mode 100644 python/src/pybind11/pytypes.h delete mode 100644 python/src/pybind11/stl.h delete mode 100644 python/src/pybind11/stl_bind.h create mode 160000 third-party/pybind11 diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index d61848742..ed63e6513 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -57,8 +57,8 @@ jobs: if: ${{ matrix.runner != 'macos-latest' }} run: | pip install clang-format - find . -regex '.*\.\(cpp\|hpp\|h\|cc\)' -not -path "./python/build/*" -not -path "./include/triton/external/*" -print0 | xargs -0 -n1 clang-format -style=file --dry-run -Werror -i || - (echo '::error title=Style issues:: Please run `find . -regex ".*\.\(cpp\|hpp\|h\|cc\)" -not -path "./python/build/*" -not -path "./include/triton/external/*" -print0 | xargs -0 -n1 clang-format -style=file -i`' ; exit 1) + find . -regex '.*\.\(cpp\|hpp\|h\|cc\)' -not -path "./python/build/*" -not -path "./include/triton/external/*" -not -path "./third-party/*" -print0 | xargs -0 -n1 clang-format -style=file --dry-run -Werror -i || + (echo '::error title=Style issues:: Please run `find . -regex ".*\.\(cpp\|hpp\|h\|cc\)" -not -path "./python/build/*" -not -path "./include/triton/external/*" -not -path "./third-party/*" -print0 | xargs -0 -n1 clang-format -style=file -i`' ; exit 1) - name: Flake8 if: ${{ matrix.runner != 'macos-latest' }} diff --git a/.gitmodules b/.gitmodules index 2754cffc4..a9faf3b82 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "deps/dlfcn-win32"] path = deps/dlfcn-win32 url = https://github.com/dlfcn-win32/dlfcn-win32.git +[submodule "third-party/pybind11"] + path = third-party/pybind11 + url = https://github.com/pybind/pybind11.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 2fb182135..dd6311a9c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,6 +31,9 @@ endif() # Compiler flags include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) +# Third-party +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/third-party/pybind11/include) + if(WIN32) SET(BUILD_SHARED_LIBS OFF) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/deps/dlfcn-win32/src) diff --git a/python/setup.py b/python/setup.py index 305de5520..242069d09 100644 --- a/python/setup.py +++ b/python/setup.py @@ -20,6 +20,20 @@ def check_env_flag(name: str, default: str = "") -> bool: return os.getenv(name, default).upper() in ["ON", "1", "YES", "TRUE", "Y"] +def check_submodule(): + submodule_paths = ["third-party/pybind11/include/pybind11"] + if not all([os.path.exists(p) for p in submodule_paths]): + print("initializing submodules ...") + try: + cwd = os.path.abspath(os.path.dirname(__file__)) + subprocess.check_call(["git", "submodule", "update", "--init", "--recursive"], cwd=cwd) + print("submodule initialization succeeded") + except Exception: + print("submodule initialization failed") + print(" Please run:\n\tgit submodule update --init --recursive") + exit(-1) + + def get_llvm(): # download if nothing is installed system = platform.system() @@ -81,6 +95,7 @@ class CMakeBuild(build_ext): self.build_extension(ext) def build_extension(self, ext): + check_submodule() llvm_include_dir, llvm_library_dir = get_llvm() # lit is used by the test suite lit_dir = shutil.which('lit') diff --git a/python/src/pybind11/attr.h b/python/src/pybind11/attr.h deleted file mode 100644 index 3d4c54091..000000000 --- a/python/src/pybind11/attr.h +++ /dev/null @@ -1,601 +0,0 @@ -/* - pybind11/attr.h: Infrastructure for processing custom - type and function attributes - - Copyright (c) 2016 Wenzel Jakob - - All rights reserved. Use of this source code is governed by a - BSD-style license that can be found in the LICENSE file. -*/ - -#pragma once - -#include "cast.h" - -NAMESPACE_BEGIN(PYBIND11_NAMESPACE) - -/// \addtogroup annotations -/// @{ - -/// Annotation for methods -struct is_method { - handle class_; - is_method(const handle &c) : class_(c) {} -}; - -/// Annotation for operators -struct is_operator {}; - -/// Annotation for parent scope -struct scope { - handle value; - scope(const handle &s) : value(s) {} -}; - -/// Annotation for documentation -struct doc { - const char *value; - doc(const char *value) : value(value) {} -}; - -/// Annotation for function names -struct name { - const char *value; - 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()) {} -}; - -/// Annotation indicating that a class derives from another given type -template struct base { - PYBIND11_DEPRECATED("base() was deprecated in favor of specifying 'T' as " - "a template argument to class_") - base() {} -}; - -/// Keep patient alive while nurse lives -template struct keep_alive {}; - -/// Annotation indicating that a class is involved in a multiple inheritance -/// relationship -struct multiple_inheritance {}; - -/// Annotation which enables dynamic attributes, i.e. adds `__dict__` to a class -struct dynamic_attr {}; - -/// Annotation which enables the buffer protocol for a type -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() {} - - /// Override pybind11's default metaclass - explicit metaclass(handle value) : value(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) {} -}; - -/// Annotation to mark enums as an arithmetic type -struct arithmetic {}; - -/** \rst - A call policy which places one or more guard variables (``Ts...``) around - the function call. - - For example, this definition: - - .. code-block:: cpp - - m.def("foo", foo, py::call_guard()); - - is equivalent to the following pseudocode: - - .. code-block:: cpp - - m.def("foo", [](args...) { - T scope_guard; - return foo(args...); // forwarded arguments - }); - \endrst */ -template struct call_guard; - -template <> struct call_guard<> { using type = detail::void_type; }; - -template struct call_guard { - static_assert(std::is_default_constructible::value, - "The guard type must be default constructible"); - - using type = T; -}; - -template struct call_guard { - struct type { - T guard{}; // Compose multiple guard types with left-to-right - // default-constructor order - typename call_guard::type next{}; - }; -}; - -/// @} annotations - -NAMESPACE_BEGIN(detail) -/* Forward declarations */ -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); - -/// Internal data structure which holds metadata about a keyword argument -struct argument_record { - const char *name; ///< Argument name - const char *descr; ///< Human-readable version of the argument value - handle value; ///< Associated Python object - bool convert : 1; ///< True if the argument is allowed to convert when loading - bool none : 1; ///< True if None is allowed when loading - - argument_record(const char *name, const char *descr, handle value, - bool convert, bool none) - : name(name), descr(descr), value(value), convert(convert), none(none) {} -}; - -/// Internal data structure which holds metadata about a bound function -/// (signature, overloads, etc.) -struct function_record { - function_record() - : is_constructor(false), is_new_style_constructor(false), - is_stateless(false), is_operator(false), has_args(false), - has_kwargs(false), is_method(false) {} - - /// Function name - char *name = nullptr; /* why no C++ strings? They generate heavier code.. */ - - // User-specified documentation string - char *doc = nullptr; - - /// Human-readable version of the function signature - char *signature = nullptr; - - /// List of registered keyword arguments - std::vector args; - - /// Pointer to lambda function which converts arguments and performs the - /// actual call - handle (*impl)(function_call &) = nullptr; - - /// Storage for the wrapped function pointer and captured data, if any - void *data[3] = {}; - - /// Pointer to custom destructor for 'data' (if needed) - void (*free_data)(function_record *ptr) = nullptr; - - /// Return value policy associated with this function - return_value_policy policy = return_value_policy::automatic; - - /// True if name == '__init__' - bool is_constructor : 1; - - /// True if this is a new-style `__init__` defined in `detail/init.h` - bool is_new_style_constructor : 1; - - /// True if this is a stateless function pointer - bool is_stateless : 1; - - /// True if this is an operator (__add__), etc. - bool is_operator : 1; - - /// True if the function has a '*args' argument - bool has_args : 1; - - /// True if the function has a '**kwargs' argument - bool has_kwargs : 1; - - /// True if this is a method - bool is_method : 1; - - /// Number of arguments (including py::args and/or py::kwargs, if present) - std::uint16_t nargs; - - /// Python method object - PyMethodDef *def = nullptr; - - /// Python handle to the parent scope (a class or a module) - handle scope; - - /// Python handle to the sibling function representing an overload chain - handle sibling; - - /// Pointer to next overload - function_record *next = nullptr; -}; - -/// Special data structure which (temporarily) holds metadata about a bound -/// class -struct type_record { - PYBIND11_NOINLINE type_record() - : multiple_inheritance(false), dynamic_attr(false), - buffer_protocol(false), default_holder(true), module_local(false) {} - - /// Handle to the parent scope - handle scope; - - /// Name of the class - const char *name = nullptr; - - // Pointer to RTTI type_info data structure - const std::type_info *type = nullptr; - - /// How large is the underlying C++ type? - size_t type_size = 0; - - /// What is the alignment of the underlying C++ type? - size_t type_align = 0; - - /// How large is the type's holder? - size_t holder_size = 0; - - /// The global operator new can be overridden with a class-specific variant - void *(*operator_new)(size_t) = nullptr; - - /// Function pointer to class_<..>::init_instance - void (*init_instance)(instance *, const void *) = nullptr; - - /// Function pointer to class_<..>::dealloc - void (*dealloc)(detail::value_and_holder &) = nullptr; - - /// List of base classes of the newly created type - list bases; - - /// Optional docstring - const char *doc = nullptr; - - /// Custom metaclass (optional) - handle metaclass; - - /// Multiple inheritance marker - bool multiple_inheritance : 1; - - /// Does the class manage a __dict__? - bool dynamic_attr : 1; - - /// Does the class implement the buffer protocol? - bool buffer_protocol : 1; - - /// Is the default (unique_ptr) holder type used? - bool default_holder : 1; - - /// Is the class definition local to the module shared object? - bool module_local : 1; - - PYBIND11_NOINLINE void add_base(const std::type_info &base, - void *(*caster)(void *)) { - auto base_info = detail::get_type_info(base, false); - if (!base_info) { - std::string tname(base.name()); - detail::clean_type_id(tname); - pybind11_fail("generic_type: type \"" + std::string(name) + - "\" referenced unknown base type \"" + tname + "\""); - } - - if (default_holder != base_info->default_holder) { - 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")); - } - - bases.append((PyObject *)base_info->type); - - if (base_info->type->tp_dictoffset != 0) - dynamic_attr = true; - - 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) { - 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 {}; - -/** - * Partial template specializations to process custom attributes provided to - * cpp_function_ and class_. These are either used to initialize the respective - * 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_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) {} -}; - -/// Process an attribute specifying the function's name -template <> struct process_attribute : process_attribute_default { - static void init(const name &n, function_record *r) { - r->name = const_cast(n.value); - } -}; - -/// Process an attribute specifying the function's docstring -template <> struct process_attribute : process_attribute_default { - static void init(const doc &n, function_record *r) { - r->doc = const_cast(n.value); - } -}; - -/// Process an attribute specifying the function's docstring (provided as a -/// C-style string) -template <> -struct process_attribute - : process_attribute_default { - static void init(const char *d, function_record *r) { - r->doc = const_cast(d); - } - static void init(const char *d, type_record *r) { - r->doc = const_cast(d); - } -}; -template <> -struct process_attribute : process_attribute {}; - -/// Process an attribute indicating the function's return value policy -template <> -struct process_attribute - : process_attribute_default { - static void init(const return_value_policy &p, function_record *r) { - r->policy = p; - } -}; - -/// 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_; - } -}; - -/// Process an attribute which indicates the parent scope of a method -template <> struct process_attribute : process_attribute_default { - static void init(const scope &s, function_record *r) { r->scope = s.value; } -}; - -/// Process an attribute which indicates that this function is an operator -template <> -struct process_attribute : process_attribute_default { - static void init(const is_operator &, function_record *r) { - r->is_operator = true; - } -}; - -template <> -struct process_attribute - : process_attribute_default { - static void init(const is_new_style_constructor &, function_record *r) { - r->is_new_style_constructor = true; - } -}; - -/// Process a keyword argument attribute (*without* a default value) -template <> struct process_attribute : process_attribute_default { - static void init(const arg &a, function_record *r) { - if (r->is_method && r->args.empty()) - r->args.emplace_back("self", nullptr, handle(), true /*convert*/, - false /*none not allowed*/); - r->args.emplace_back(a.name, nullptr, handle(), !a.flag_noconvert, - a.flag_none); - } -}; - -/// Process a keyword argument attribute (*with* a default value) -template <> struct process_attribute : process_attribute_default { - static void init(const arg_v &a, function_record *r) { - if (r->is_method && r->args.empty()) - r->args.emplace_back("self", nullptr /*descr*/, handle() /*parent*/, - true /*convert*/, false /*none not allowed*/); - - if (!a.value) { -#if !defined(NDEBUG) - std::string descr("'"); - 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 - 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?)"); -#else - pybind11_fail("arg(): could not convert default argument " - "into a Python object (type not registered yet?). " - "Compile in debug mode for more information."); -#endif - } - r->args.emplace_back(a.name, a.descr, a.value.inc_ref(), !a.flag_noconvert, - a.flag_none); - } -}; - -/// Process a parent class attribute. Single inheritance only (class_ itself -/// already guarantees that) -template -struct process_attribute::value>> - : process_attribute_default { - static void init(const handle &h, type_record *r) { r->bases.append(h); } -}; - -/// Process a parent class attribute (deprecated, does not support multiple -/// inheritance) -template -struct process_attribute> : process_attribute_default> { - static void init(const base &, type_record *r) { - r->add_base(typeid(T), nullptr); - } -}; - -/// 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; - } -}; - -template <> -struct process_attribute - : process_attribute_default { - static void init(const dynamic_attr &, type_record *r) { - r->dynamic_attr = true; - } -}; - -template <> -struct process_attribute - : process_attribute_default { - static void init(const buffer_protocol &, type_record *r) { - r->buffer_protocol = true; - } -}; - -template <> -struct process_attribute : process_attribute_default { - static void init(const metaclass &m, type_record *r) { - r->metaclass = m.value; - } -}; - -template <> -struct process_attribute - : process_attribute_default { - static void init(const module_local &l, type_record *r) { - r->module_local = l.value; - } -}; - -/// Process an 'arithmetic' attribute for enums (does nothing here) -template <> -struct process_attribute : process_attribute_default {}; - -template -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 = 0> - static void precall(function_call &call) { - keep_alive_impl(Nurse, Patient, call, handle()); - } - template = 0> - static void postcall(function_call &, handle) {} - template = 0> - static void precall(function_call &) {} - template = 0> - static void postcall(function_call &call, handle ret) { - keep_alive_impl(Nurse, Patient, call, ret); - } -}; - -/// Recursively iterate over variadic template arguments -template struct process_attributes { - static void init(const Args &...args, function_record *r) { - int unused[] = { - 0, (process_attribute::type>::init(args, r), - 0)...}; - ignore_unused(unused); - } - static void init(const Args &...args, type_record *r) { - int unused[] = { - 0, (process_attribute::type>::init(args, r), - 0)...}; - ignore_unused(unused); - } - static void precall(function_call &call) { - int unused[] = { - 0, (process_attribute::type>::precall(call), - 0)...}; - ignore_unused(unused); - } - static void postcall(function_call &call, handle fn_ret) { - int unused[] = { - 0, (process_attribute::type>::postcall( - call, fn_ret), - 0)...}; - ignore_unused(unused); - } -}; - -template using is_call_guard = is_instantiation; - -/// Extract the ``type`` from the first `call_guard` in `Extras...` (or -/// `void_type` if none found) -template -using extract_guard_t = - typename exactly_one_t, Extra...>::type; - -/// Check the number of named arguments at compile time -template ::value...), - size_t self = constexpr_sum(std::is_same::value...)> -constexpr bool expected_num_args(size_t nargs, bool has_args, bool has_kwargs) { - return named == 0 || (self + named + has_args + has_kwargs) == nargs; -} - -NAMESPACE_END(detail) -NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/python/src/pybind11/buffer_info.h b/python/src/pybind11/buffer_info.h deleted file mode 100644 index 3c080140c..000000000 --- a/python/src/pybind11/buffer_info.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - pybind11/buffer_info.h: Python buffer object interface - - Copyright (c) 2016 Wenzel Jakob - - All rights reserved. Use of this source code is governed by a - BSD-style license that can be found in the LICENSE file. -*/ - -#pragma once - -#include "detail/common.h" - -NAMESPACE_BEGIN(PYBIND11_NAMESPACE) - -/// Information record describing a Python buffer object -struct buffer_info { - void *ptr = nullptr; // Pointer to the underlying storage - ssize_t itemsize = 0; // Size of individual items in bytes - ssize_t size = 0; // Total number of entries - std::string format; // For homogeneous buffers, this should be set to - // format_descriptor::format() - ssize_t ndim = 0; // Number of dimensions - std::vector shape; // Shape of the tensor (1 entry per dimension) - std::vector strides; // Number of entries between adjacent entries - // (for each per dimension) - - buffer_info() {} - - buffer_info(void *ptr, ssize_t itemsize, const std::string &format, - ssize_t ndim, detail::any_container shape_in, - detail::any_container strides_in) - : ptr(ptr), itemsize(itemsize), size(1), format(format), ndim(ndim), - shape(std::move(shape_in)), strides(std::move(strides_in)) { - if (ndim != (ssize_t)shape.size() || ndim != (ssize_t)strides.size()) - pybind11_fail( - "buffer_info: ndim doesn't match shape and/or strides length"); - for (size_t i = 0; i < (size_t)ndim; ++i) - size *= shape[i]; - } - - template - buffer_info(T *ptr, detail::any_container shape_in, - detail::any_container strides_in) - : buffer_info(private_ctr_tag(), ptr, sizeof(T), - format_descriptor::format(), - static_cast(shape_in->size()), std::move(shape_in), - std::move(strides_in)) {} - - buffer_info(void *ptr, ssize_t itemsize, const std::string &format, - ssize_t size) - : buffer_info(ptr, itemsize, format, 1, {size}, {itemsize}) {} - - template - buffer_info(T *ptr, ssize_t size) - : buffer_info(ptr, sizeof(T), format_descriptor::format(), size) {} - - explicit buffer_info(Py_buffer *view, bool ownview = true) - : buffer_info(view->buf, view->itemsize, view->format, view->ndim, - {view->shape, view->shape + view->ndim}, - {view->strides, view->strides + view->ndim}) { - this->view = view; - this->ownview = ownview; - } - - buffer_info(const buffer_info &) = delete; - buffer_info &operator=(const buffer_info &) = delete; - - buffer_info(buffer_info &&other) { (*this) = std::move(other); } - - buffer_info &operator=(buffer_info &&rhs) { - ptr = rhs.ptr; - itemsize = rhs.itemsize; - size = rhs.size; - format = std::move(rhs.format); - ndim = rhs.ndim; - shape = std::move(rhs.shape); - strides = std::move(rhs.strides); - std::swap(view, rhs.view); - std::swap(ownview, rhs.ownview); - return *this; - } - - ~buffer_info() { - if (view && ownview) { - PyBuffer_Release(view); - delete 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) - : buffer_info(ptr, itemsize, format, ndim, std::move(shape_in), - std::move(strides_in)) {} - - Py_buffer *view = nullptr; - bool ownview = false; -}; - -NAMESPACE_BEGIN(detail) - -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"))); - } -}; - -NAMESPACE_END(detail) -NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/python/src/pybind11/cast.h b/python/src/pybind11/cast.h deleted file mode 100644 index 5e7c6648e..000000000 --- a/python/src/pybind11/cast.h +++ /dev/null @@ -1,2465 +0,0 @@ -/* - pybind11/cast.h: Partial template specializations to cast between - C++ and Python types - - Copyright (c) 2016 Wenzel Jakob - - All rights reserved. Use of this source code is governed by a - BSD-style license that can be found in the LICENSE file. -*/ - -#pragma once - -#include "detail/descr.h" -#include "detail/internals.h" -#include "detail/typeid.h" -#include "pytypes.h" -#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 - -NAMESPACE_BEGIN(PYBIND11_NAMESPACE) -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.size() != 0 && - 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.size() == 0) - 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() {} - - // 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) { - return curr.index == other.curr.index; - } - bool operator!=(const iterator &other) { - 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: `" + - std::string(find_type->type->tp_name) + - "' is not a pybind11 base of the given `" + - std::string(Py_TYPE(this)->tp_name) + "' 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) { - PyTracebackObject *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 (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 - throw cast_error("return_value_policy = copy, but the " - "object is non-copyable!"); - 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 - throw cast_error("return_value_policy = move, but the " - "object is neither movable nor copyable!"); - 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(PYBIND11_CPP17) - 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 = src.get_type(); - 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< - std::is_pointer::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< - Container, - enable_if_t, - std::is_same>::value>> - : is_copy_constructible {}; - -#if !defined(PYBIND11_CPP17) -// Likewise for std::pair before C++17 (which mandates that the copy constructor -// not exist when the two types aren't themselves copy constructible). -template -struct is_copy_constructible> - : all_of, is_copy_constructible> {}; -#endif - -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.) -template struct polymorphic_type_hook { - static const void *get(const itype *src, const std::type_info *&) { - return src; - } -}; -template -struct polymorphic_type_hook< - itype, detail::enable_if_t::value>> { - static const void *get(const itype *src, const std::type_info *&type) { - type = src ? &typeid(*src) : nullptr; - return dynamic_cast(src); - } -}; - -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>; - -// 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) { - return caster.operator typename make_caster::template cast_op_type(); -} -template -typename make_caster::template cast_op_type< - typename std::add_rvalue_reference::type> -cast_op(make_caster &&caster) { - return std::move(caster).operator typename make_caster:: - template cast_op_type::type>(); -} - -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"); - -public: - bool load(handle src, bool convert) { return subcaster.load(src, convert); } - static constexpr auto name = caster_t::name; - static handle cast(const std::reference_wrapper &src, - return_value_policy policy, handle parent) { - // It is definitely wrong to take ownership of this pointer, so mask that - // rvp - if (policy == return_value_policy::take_ownership || - policy == return_value_policy::automatic) - policy = return_value_policy::automatic_reference; - return caster_t::cast(&src.get(), policy, parent); - } - template using cast_op_type = std::reference_wrapper; - operator std::reference_wrapper() { - return subcaster.operator subcaster_cast_op_type &(); - } -}; - -#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::string */ - 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 = - conditional_t::value, double, _py_type_1>; - -public: - bool load(handle src, bool convert) { - py_type py_value; - - if (!src) - return false; - - if (std::is_floating_point::value) { - if (convert || PyFloat_Check(src.ptr())) - py_value = (py_type)PyFloat_AsDouble(src.ptr()); - else - return false; - } else if (PyFloat_Check(src.ptr())) { - 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()); - } - - bool py_err = py_value == (py_type)-1 && PyErr_Occurred(); - if (py_err || (std::is_integral::value && sizeof(py_type) != sizeof(T) && - (py_value < (py_type)std::numeric_limits::min() || - py_value > (py_type)std::numeric_limits::max()))) { - bool type_error = py_err && PyErr_ExceptionMatches( -#if PY_VERSION_HEX < 0x03000000 && !defined(PYPY_VERSION) - PyExc_SystemError -#else - PyExc_TypeError -#endif - ); - PyErr_Clear(); - if (type_error && convert && PyNumber_Check(src.ptr())) { - auto tmp = reinterpret_steal(std::is_floating_point::value - ? PyNumber_Float(src.ptr()) - : PyNumber_Long(src.ptr())); - PyErr_Clear(); - return load(tmp, false); - } - return false; - } - - value = (T)py_value; - return true; - } - - 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 - 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 - cast(U src, return_value_policy /* policy */, handle /* parent */) { - return PYBIND11_LONG_FROM_UNSIGNED((unsigned long)src); - } - - template - static typename std::enable_if::value && - std::is_signed::value && - (sizeof(U) > sizeof(long)), - handle>::type - cast(U src, return_value_policy /* policy */, handle /* parent */) { - return PyLong_FromLongLong((long long)src); - } - - template - static typename std::enable_if::value && - std::is_unsigned::value && - (sizeof(U) > sizeof(unsigned long)), - handle>::type - cast(U src, return_value_policy /* policy */, handle /* parent */) { - return PyLong_FromUnsignedLongLong((unsigned long long)src); - } - - PYBIND11_TYPE_CASTER(T, _::value>("int", "float")); -}; - -template struct void_caster { -public: - bool load(handle src, bool) { - if (src && src.is_none()) - return true; - return false; - } - static handle cast(T, return_value_policy /* policy */, handle /* parent */) { - return none().inc_ref(); - } - PYBIND11_TYPE_CASTER(T, _("None")); -}; - -template <> class type_caster : public void_caster {}; - -template <> class type_caster : public type_caster { -public: - using type_caster::cast; - - bool load(handle h, bool) { - if (!h) { - return false; - } else if (h.is_none()) { - value = nullptr; - return true; - } - - /* Check if this is a capsule */ - if (isinstance(h)) { - value = reinterpret_borrow(h); - return true; - } - - /* Check if this is a C++ type */ - auto &bases = all_type_info((PyTypeObject *)h.get_type().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; - } - - /* Fail */ - return false; - } - - static handle cast(const void *ptr, return_value_policy /* policy */, - handle /* parent */) { - if (ptr) - return capsule(ptr).release(); - else - return none().inc_ref(); - } - - template using cast_op_type = void *&; - operator void *&() { return value; } - static constexpr auto name = _("capsule"); - -private: - void *value = nullptr; -}; - -template <> -class type_caster : public void_caster {}; - -template <> class type_caster { -public: - bool load(handle src, bool convert) { - if (!src) - return false; - 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)) { - // (allow non-implicit conversion for numpy booleans) - - Py_ssize_t res = -1; - if (src.is_none()) { - res = 0; // None is implicitly converted to False - } -#if defined(PYPY_VERSION) - // On PyPy, check that "__bool__" (or "__nonzero__" on Python 2.7) attr - // exists - else if (hasattr(src, PYBIND11_BOOL_ATTR)) { - res = PyObject_IsTrue(src.ptr()); - } -#else - // Alternate approach for CPython: this does the same as the above, but - // optimized using the CPython API so as to avoid an unneeded attribute - // lookup. - else if (auto tp_as_number = src.ptr()->ob_type->tp_as_number) { - if (PYBIND11_NB_BOOL(tp_as_number)) { - res = (*PYBIND11_NB_BOOL(tp_as_number))(src.ptr()); - } - } -#endif - if (res == 0 || res == 1) { - value = (bool)res; - return true; - } - } - return false; - } - static handle cast(bool src, return_value_policy /* policy */, - handle /* parent */) { - return handle(src ? Py_True : Py_False).inc_ref(); - } - PYBIND11_TYPE_CASTER(bool, _("bool")); -}; - -// Helper class for UTF-{8,16,32} C++ stl strings: -template struct string_caster { - using CharT = typename StringType::value_type; - - // Simplify life by being able to assume standard char sizes (the standard - // only guarantees minimums, but Python requires exact sizes) - static_assert(!std::is_same::value || sizeof(CharT) == 1, - "Unsupported char size != 1"); - static_assert(!std::is_same::value || sizeof(CharT) == 2, - "Unsupported char16_t size != 2"); - static_assert(!std::is_same::value || sizeof(CharT) == 4, - "Unsupported char32_t size != 4"); - // wchar_t can be either 16 bits (Windows) or 32 (everywhere else) - static_assert(!std::is_same::value || sizeof(CharT) == 2 || - sizeof(CharT) == 4, - "Unsupported wchar_t size != 2/4"); - static constexpr size_t UTF_N = 8 * sizeof(CharT); - - bool load(handle src, bool) { -#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 (sizeof(CharT) == 1) { - return load_bytes(load_src); - } - - // The below is a guaranteed failure in Python 3 when PyUnicode_Check - // returns false - if (!PYBIND11_BYTES_CHECK(load_src.ptr())) - return false; - - temp = reinterpret_steal(PyUnicode_FromObject(load_src.ptr())); - if (!temp) { - PyErr_Clear(); - return false; - } - load_src = temp; -#endif - } - - 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; - } - - const CharT *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 - value = StringType(buffer, length); - - // If we're loading a string_view we need to keep the encoded Python object - // alive: - if (IsView) - loader_life_support::add_patient(utfNbytes); - - return true; - } - - static handle cast(const StringType &src, return_value_policy /* policy */, - handle /* parent */) { - const char *buffer = reinterpret_cast(src.data()); - ssize_t nbytes = ssize_t(src.size() * sizeof(CharT)); - handle s = decode_utfN(buffer, nbytes); - if (!s) - throw error_already_set(); - return s; - } - - PYBIND11_TYPE_CASTER(StringType, _(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); -#else - // PyPy seems to have multiple problems related to PyUnicode_UTF*: the UTF8 - // version sometimes segfaults for unknown reasons, while the UTF16 and 32 - // versions require a non-const char * arguments, which is also a nuisance, - // 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. - // 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 src) { - if (PYBIND11_BYTES_CHECK(src.ptr())) { - // We were passed a Python 3 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; - } - } - - return false; - } - - template - bool load_bytes(enable_if_t) { - return false; - } -}; - -template -struct type_caster, - enable_if_t::value>> - : string_caster> {}; - -#ifdef PYBIND11_HAS_STRING_VIEW -template -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>> { - 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.is_none()) { - // Defer accepting None to other overloads (if we aren't in convert mode): - if (!convert) - return false; - none = true; - return true; - } - return str_caster.load(src, convert); - } - - static handle cast(const CharT *src, return_value_policy policy, - handle parent) { - if (src == nullptr) - return pybind11::none().inc_ref(); - return StringCaster::cast(StringType(src), policy, parent); - } - - static handle cast(CharT src, return_value_policy policy, handle parent) { - if (std::is_same::value) { - handle s = PyUnicode_DecodeLatin1((const char *)&src, 1, nullptr); - if (!s) - throw error_already_set(); - return s; - } - 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) - throw value_error("Cannot convert None to a character"); - - auto &value = static_cast(str_caster); - size_t str_len = value.size(); - if (str_len == 0) - throw value_error("Cannot convert empty string to a character"); - - // If we're in UTF-8 mode, we have two possible failures: one for a unicode - // character that is too high, and one for multiple unicode characters - // (caught later), so we need to figure out how long the first encoded - // character is in bytes to distinguish between these two errors. We also - // allow want to allow unicode characters U+0080 through U+00FF, as those - // can fit into a single char value. - if (StringCaster::UTF_N == 8 && str_len > 1 && str_len <= 4) { - unsigned char 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 - - if (char0_bytes == str_len) { - // If we have a 128-255 value, we can decode it into a single char: - if (char0_bytes == 2 && (v0 & 0xFC) == 0xC0) { // 0x110000xx 0x10xxxxxx - one_char = static_cast( - ((v0 & 3) << 6) + (static_cast(value[1]) & 0x3F)); - return one_char; - } - // Otherwise we have a single character, but it's > U+00FF - throw value_error("Character code point not in range(0x100)"); - } - } - - // UTF-16 is much easier: we can only have a surrogate pair for values above - // U+FFFF, thus a surrogate pair with total length 2 instantly indicates a - // range error (but not a "your string was too long" error). - else if (StringCaster::UTF_N == 16 && str_len == 2) { - one_char = static_cast(value[0]); - if (one_char >= 0xD800 && one_char < 0xE000) - throw value_error("Character code point not in range(0x10000)"); - } - - 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>; -}; - -// Base implementation for std::tuple and std::pair -template