diff options
Diffstat (limited to 'ext/pybind11/include/pybind11/pybind11.h')
-rw-r--r-- | ext/pybind11/include/pybind11/pybind11.h | 858 |
1 files changed, 432 insertions, 426 deletions
diff --git a/ext/pybind11/include/pybind11/pybind11.h b/ext/pybind11/include/pybind11/pybind11.h index 1db9efb8c..5976a36d8 100644 --- a/ext/pybind11/include/pybind11/pybind11.h +++ b/ext/pybind11/include/pybind11/pybind11.h @@ -35,6 +35,7 @@ #include "attr.h" #include "options.h" +#include "class_support.h" NAMESPACE_BEGIN(pybind11) @@ -50,10 +51,16 @@ public: } /// Construct a cpp_function from a lambda function (possibly with internal state) - template <typename Func, typename... Extra> cpp_function(Func &&f, const Extra&... extra) { + template <typename Func, typename... Extra, typename = detail::enable_if_t< + detail::satisfies_none_of< + typename std::remove_reference<Func>::type, + std::is_function, std::is_pointer, std::is_member_pointer + >::value> + > + cpp_function(Func &&f, const Extra&... extra) { + using FuncType = typename detail::remove_class<decltype(&std::remove_reference<Func>::type::operator())>::type; initialize(std::forward<Func>(f), - (typename detail::remove_class<decltype( - &std::remove_reference<Func>::type::operator())>::type *) nullptr, extra...); + (FuncType *) nullptr, extra...); } /// Construct a cpp_function from a class method (non-const) @@ -82,8 +89,6 @@ protected: /// Special internal constructor for functors, lambda functions, etc. template <typename Func, typename Return, typename... Args, typename... Extra> void initialize(Func &&f, Return (*)(Args...), const Extra&... extra) { - static_assert(detail::expected_num_args<Extra...>(sizeof...(Args)), - "The number of named arguments does not match the function signature"); struct capture { typename std::remove_reference<Func>::type f; }; @@ -116,32 +121,34 @@ protected: detail::conditional_t<std::is_void<Return>::value, detail::void_type, Return> >; + static_assert(detail::expected_num_args<Extra...>(sizeof...(Args), cast_in::has_args, cast_in::has_kwargs), + "The number of argument annotations does not match the number of function arguments"); + /* Dispatch code which converts function arguments and performs the actual function call */ - rec->impl = [](detail::function_record *rec, handle args, handle kwargs, handle parent) -> handle { + rec->impl = [](detail::function_call &call) -> handle { cast_in args_converter; /* Try to cast the function arguments into the C++ domain */ - if (!args_converter.load_args(args, kwargs, true)) + if (!args_converter.load_args(call)) return PYBIND11_TRY_NEXT_OVERLOAD; /* Invoke call policy pre-call hook */ - detail::process_attributes<Extra...>::precall(args); + detail::process_attributes<Extra...>::precall(call); /* Get a pointer to the capture object */ - capture *cap = (capture *) (sizeof(capture) <= sizeof(rec->data) - ? &rec->data : rec->data[0]); + auto data = (sizeof(capture) <= sizeof(call.func.data) + ? &call.func.data : call.func.data[0]); + capture *cap = const_cast<capture *>(reinterpret_cast<const capture *>(data)); - /* Override policy for rvalues -- always move */ - constexpr auto is_rvalue = !std::is_pointer<Return>::value - && !std::is_lvalue_reference<Return>::value; - const auto policy = is_rvalue ? return_value_policy::move : rec->policy; + /* Override policy for rvalues -- usually to enforce rvp::move on an rvalue */ + const auto policy = detail::return_value_policy_override<Return>::policy(call.func.policy); /* Perform the function call */ handle result = cast_out::cast(args_converter.template call<Return>(cap->f), - policy, parent); + policy, call.parent); /* Invoke call policy post-call hook */ - detail::process_attributes<Extra...>::postcall(args, result); + detail::process_attributes<Extra...>::postcall(call, result); return result; }; @@ -166,7 +173,7 @@ protected: sizeof(capture) == sizeof(void *); if (is_function_ptr) { rec->is_stateless = true; - rec->data[1] = (void *) &typeid(FunctionType); + rec->data[1] = const_cast<void *>(reinterpret_cast<const void *>(&typeid(FunctionType))); } } @@ -197,7 +204,7 @@ protected: if (c == '{') { // Write arg name for everything except *args, **kwargs and return type. if (type_depth == 0 && text[char_index] != '*' && arg_index < args) { - if (!rec->args.empty()) { + if (!rec->args.empty() && rec->args[arg_index].name) { signature += rec->args[arg_index].name; } else if (arg_index == 0 && rec->is_method) { signature += "self"; @@ -221,6 +228,11 @@ protected: if (!t) pybind11_fail("Internal error while parsing type signature (1)"); if (auto tinfo = detail::get_type_info(*t)) { +#if defined(PYPY_VERSION) + signature += handle((PyObject *) tinfo->type) + .attr("__module__") + .cast<std::string>() + "."; +#endif signature += tinfo->type->tp_name; } else { std::string tname(t->name()); @@ -251,7 +263,7 @@ protected: rec->signature = strdup(signature.c_str()); rec->args.shrink_to_fit(); rec->is_constructor = !strcmp(rec->name, "__init__") || !strcmp(rec->name, "__setstate__"); - rec->nargs = (uint16_t) args; + rec->nargs = (std::uint16_t) args; #if PY_MAJOR_VERSION < 3 if (rec->sibling && PyMethod_Check(rec->sibling.ptr())) @@ -261,7 +273,7 @@ protected: detail::function_record *chain = nullptr, *chain_start = rec; if (rec->sibling) { if (PyCFunction_Check(rec->sibling.ptr())) { - auto rec_capsule = reinterpret_borrow<capsule>(PyCFunction_GetSelf(rec->sibling.ptr())); + auto rec_capsule = reinterpret_borrow<capsule>(PyCFunction_GET_SELF(rec->sibling.ptr())); chain = (detail::function_record *) rec_capsule; /* Never append a method to an overload chain of a parent class; instead, hide the parent's overloads in this case */ @@ -282,8 +294,8 @@ protected: rec->def->ml_meth = reinterpret_cast<PyCFunction>(*dispatcher); rec->def->ml_flags = METH_VARARGS | METH_KEYWORDS; - capsule rec_capsule(rec, [](PyObject *o) { - destruct((detail::function_record *) PyCapsule_GetPointer(o, nullptr)); + capsule rec_capsule(rec, [](void *ptr) { + destruct((detail::function_record *) ptr); }); object scope_module; @@ -319,8 +331,10 @@ protected: signatures += "Overloaded function.\n\n"; } // Then specific overload signatures + bool first_user_def = true; for (auto it = chain_start; it != nullptr; it = it->next) { if (options::show_function_signatures()) { + if (index > 0) signatures += "\n"; if (chain) signatures += std::to_string(++index) + ". "; signatures += rec->name; @@ -328,18 +342,22 @@ protected: signatures += "\n"; } if (it->doc && strlen(it->doc) > 0 && options::show_user_defined_docstrings()) { + // If we're appending another docstring, and aren't printing function signatures, we + // need to append a newline first: + if (!options::show_function_signatures()) { + if (first_user_def) first_user_def = false; + else signatures += "\n"; + } if (options::show_function_signatures()) signatures += "\n"; signatures += it->doc; if (options::show_function_signatures()) signatures += "\n"; } - if (it->next) - signatures += "\n"; } /* Install docstring */ PyCFunctionObject *func = (PyCFunctionObject *) m_ptr; if (func->m_ml->ml_doc) - std::free((char *) func->m_ml->ml_doc); + std::free(const_cast<char *>(func->m_ml->ml_doc)); func->m_ml->ml_doc = strdup(signatures.c_str()); if (rec->is_method) { @@ -360,12 +378,12 @@ protected: std::free((char *) rec->doc); std::free((char *) rec->signature); for (auto &arg: rec->args) { - std::free((char *) arg.name); - std::free((char *) arg.descr); + std::free(const_cast<char *>(arg.name)); + std::free(const_cast<char *>(arg.descr)); arg.value.dec_ref(); } if (rec->def) { - std::free((char *) rec->def->ml_doc); + std::free(const_cast<char *>(rec->def->ml_doc)); delete rec->def; } delete rec; @@ -374,72 +392,205 @@ protected: } /// Main dispatch logic for calls to functions bound using pybind11 - static PyObject *dispatcher(PyObject *self, PyObject *args, PyObject *kwargs) { + static PyObject *dispatcher(PyObject *self, PyObject *args_in, PyObject *kwargs_in) { + using namespace detail; + /* Iterator over the list of potentially admissible overloads */ - detail::function_record *overloads = (detail::function_record *) PyCapsule_GetPointer(self, nullptr), - *it = overloads; + function_record *overloads = (function_record *) PyCapsule_GetPointer(self, nullptr), + *it = overloads; /* Need to know how many arguments + keyword arguments there are to pick the right overload */ - size_t nargs = (size_t) PyTuple_GET_SIZE(args), - nkwargs = kwargs ? (size_t) PyDict_Size(kwargs) : 0; + const size_t n_args_in = (size_t) PyTuple_GET_SIZE(args_in); - handle parent = nargs > 0 ? PyTuple_GET_ITEM(args, 0) : nullptr, + handle parent = n_args_in > 0 ? PyTuple_GET_ITEM(args_in, 0) : nullptr, result = PYBIND11_TRY_NEXT_OVERLOAD; + try { + // We do this in two passes: in the first pass, we load arguments with `convert=false`; + // in the second, we allow conversion (except for arguments with an explicit + // py::arg().noconvert()). This lets us prefer calls without conversion, with + // conversion as a fallback. + std::vector<function_call> second_pass; + + // However, if there are no overloads, we can just skip the no-convert pass entirely + const bool overloaded = it != nullptr && it->next != nullptr; + for (; it != nullptr; it = it->next) { - auto args_ = reinterpret_borrow<tuple>(args); - size_t kwargs_consumed = 0; /* For each overload: - 1. If the required list of arguments is longer than the - actually provided amount, create a copy of the argument - list and fill in any available keyword/default arguments. - 2. Ensure that all keyword arguments were "consumed" - 3. Call the function call dispatcher (function_record::impl) + 1. Copy all positional arguments we were given, also checking to make sure that + named positional arguments weren't *also* specified via kwarg. + 2. If we weren't given enough, try to make up the omitted ones by checking + whether they were provided by a kwarg matching the `py::arg("name")` name. If + so, use it (and remove it from kwargs; if not, see if the function binding + provided a default that we can use. + 3. Ensure that either all keyword arguments were "consumed", or that the function + takes a kwargs argument to accept unconsumed kwargs. + 4. Any positional arguments still left get put into a tuple (for args), and any + leftover kwargs get put into a dict. + 5. Pack everything into a vector; if we have py::args or py::kwargs, they are an + extra tuple or dict at the end of the positional arguments. + 6. Call the function call dispatcher (function_record::impl) + + If one of these fail, move on to the next overload and keep trying until we get a + result other than PYBIND11_TRY_NEXT_OVERLOAD. */ - size_t nargs_ = nargs; - if (nargs < it->args.size()) { - nargs_ = it->args.size(); - args_ = tuple(nargs_); - for (size_t i = 0; i < nargs; ++i) { - handle item = PyTuple_GET_ITEM(args, i); - PyTuple_SET_ITEM(args_.ptr(), i, item.inc_ref().ptr()); + + function_record &func = *it; + size_t pos_args = func.nargs; // Number of positional arguments that we need + if (func.has_args) --pos_args; // (but don't count py::args + if (func.has_kwargs) --pos_args; // or py::kwargs) + + if (!func.has_args && n_args_in > pos_args) + continue; // Too many arguments for this overload + + if (n_args_in < pos_args && func.args.size() < pos_args) + continue; // Not enough arguments given, and not enough defaults to fill in the blanks + + function_call call(func, parent); + + size_t args_to_copy = std::min(pos_args, n_args_in); + size_t args_copied = 0; + + // 1. Copy any position arguments given. + bool bad_kwarg = false; + for (; args_copied < args_to_copy; ++args_copied) { + if (kwargs_in && args_copied < func.args.size() && func.args[args_copied].name + && PyDict_GetItemString(kwargs_in, func.args[args_copied].name)) { + bad_kwarg = true; + break; } - int arg_ctr = 0; - for (auto const &it2 : it->args) { - int index = arg_ctr++; - if (PyTuple_GET_ITEM(args_.ptr(), index)) - continue; + call.args.push_back(PyTuple_GET_ITEM(args_in, args_copied)); + call.args_convert.push_back(args_copied < func.args.size() ? func.args[args_copied].convert : true); + } + if (bad_kwarg) + continue; // Maybe it was meant for another overload (issue #688) + + // We'll need to copy this if we steal some kwargs for defaults + dict kwargs = reinterpret_borrow<dict>(kwargs_in); + + // 2. Check kwargs and, failing that, defaults that may help complete the list + if (args_copied < pos_args) { + bool copied_kwargs = false; + + for (; args_copied < pos_args; ++args_copied) { + const auto &arg = func.args[args_copied]; handle value; - if (kwargs) - value = PyDict_GetItemString(kwargs, it2.name); + if (kwargs_in && arg.name) + value = PyDict_GetItemString(kwargs.ptr(), arg.name); - if (value) - kwargs_consumed++; - else if (it2.value) - value = it2.value; + if (value) { + // Consume a kwargs value + if (!copied_kwargs) { + kwargs = reinterpret_steal<dict>(PyDict_Copy(kwargs.ptr())); + copied_kwargs = true; + } + PyDict_DelItemString(kwargs.ptr(), arg.name); + } else if (arg.value) { + value = arg.value; + } if (value) { - PyTuple_SET_ITEM(args_.ptr(), index, value.inc_ref().ptr()); - } else { - kwargs_consumed = (size_t) -1; /* definite failure */ + call.args.push_back(value); + call.args_convert.push_back(arg.convert); + } + else break; + } + + if (args_copied < pos_args) + continue; // Not enough arguments, defaults, or kwargs to fill the positional arguments + } + + // 3. Check everything was consumed (unless we have a kwargs arg) + if (kwargs && kwargs.size() > 0 && !func.has_kwargs) + continue; // Unconsumed kwargs, but no py::kwargs argument to accept them + + // 4a. If we have a py::args argument, create a new tuple with leftovers + tuple extra_args; + if (func.has_args) { + if (args_to_copy == 0) { + // We didn't copy out any position arguments from the args_in tuple, so we + // can reuse it directly without copying: + extra_args = reinterpret_borrow<tuple>(args_in); + } else if (args_copied >= n_args_in) { + extra_args = tuple(0); + } else { + size_t args_size = n_args_in - args_copied; + extra_args = tuple(args_size); + for (size_t i = 0; i < args_size; ++i) { + handle item = PyTuple_GET_ITEM(args_in, args_copied + i); + extra_args[i] = item.inc_ref().ptr(); } } + call.args.push_back(extra_args); + call.args_convert.push_back(false); } + // 4b. If we have a py::kwargs, pass on any remaining kwargs + if (func.has_kwargs) { + if (!kwargs.ptr()) + kwargs = dict(); // If we didn't get one, send an empty one + call.args.push_back(kwargs); + call.args_convert.push_back(false); + } + + // 5. Put everything in a vector. Not technically step 5, we've been building it + // in `call.args` all along. + #if !defined(NDEBUG) + if (call.args.size() != func.nargs || call.args_convert.size() != func.nargs) + pybind11_fail("Internal error: function call dispatcher inserted wrong number of arguments!"); + #endif + + std::vector<bool> second_pass_convert; + if (overloaded) { + // We're in the first no-convert pass, so swap out the conversion flags for a + // set of all-false flags. If the call fails, we'll swap the flags back in for + // the conversion-allowed call below. + second_pass_convert.resize(func.nargs, false); + call.args_convert.swap(second_pass_convert); + } + + // 6. Call the function. try { - if ((kwargs_consumed == nkwargs || it->has_kwargs) && - (nargs_ == it->nargs || it->has_args)) - result = it->impl(it, args_, kwargs, parent); + result = func.impl(call); } catch (reference_cast_error &) { result = PYBIND11_TRY_NEXT_OVERLOAD; } if (result.ptr() != PYBIND11_TRY_NEXT_OVERLOAD) break; + + if (overloaded) { + // The (overloaded) call failed; if the call has at least one argument that + // permits conversion (i.e. it hasn't been explicitly specified `.noconvert()`) + // then add this call to the list of second pass overloads to try. + for (size_t i = func.is_method ? 1 : 0; i < pos_args; i++) { + if (second_pass_convert[i]) { + // Found one: swap the converting flags back in and store the call for + // the second pass. + call.args_convert.swap(second_pass_convert); + second_pass.push_back(std::move(call)); + break; + } + } + } + } + + if (overloaded && !second_pass.empty() && result.ptr() == PYBIND11_TRY_NEXT_OVERLOAD) { + // The no-conversion pass finished without success, try again with conversion allowed + for (auto &call : second_pass) { + try { + result = call.func.impl(call); + } catch (reference_cast_error &) { + result = PYBIND11_TRY_NEXT_OVERLOAD; + } + + if (result.ptr() != PYBIND11_TRY_NEXT_OVERLOAD) + break; + } } } catch (error_already_set &e) { e.restore(); @@ -457,7 +608,7 @@ protected: - delegate translation to the next translator by throwing a new type of exception. */ auto last_exception = std::current_exception(); - auto ®istered_exception_translators = pybind11::detail::get_internals().registered_exception_translators; + auto ®istered_exception_translators = get_internals().registered_exception_translators; for (auto& translator : registered_exception_translators) { try { translator(last_exception); @@ -480,7 +631,7 @@ protected: " arguments. The following argument types are supported:\n"; int ctr = 0; - for (detail::function_record *it2 = overloads; it2 != nullptr; it2 = it2->next) { + for (function_record *it2 = overloads; it2 != nullptr; it2 = it2->next) { msg += " "+ std::to_string(++ctr) + ". "; bool wrote_sig = false; @@ -507,12 +658,27 @@ protected: msg += "\n"; } msg += "\nInvoked with: "; - auto args_ = reinterpret_borrow<tuple>(args); + auto args_ = reinterpret_borrow<tuple>(args_in); + bool some_args = false; for (size_t ti = overloads->is_constructor ? 1 : 0; ti < args_.size(); ++ti) { + if (!some_args) some_args = true; + else msg += ", "; msg += pybind11::repr(args_[ti]); - if ((ti + 1) != args_.size() ) - msg += ", "; } + if (kwargs_in) { + auto kwargs = reinterpret_borrow<dict>(kwargs_in); + if (kwargs.size() > 0) { + if (some_args) msg += "; "; + msg += "kwargs: "; + bool first = true; + for (auto kwarg : kwargs) { + if (first) first = false; + else msg += ", "; + msg += pybind11::str("{}={!r}").format(kwarg.first, kwarg.second); + } + } + } + PyErr_SetString(PyExc_TypeError, msg.c_str()); return nullptr; } else if (!result) { @@ -525,9 +691,8 @@ protected: if (overloads->is_constructor) { /* When a constructor ran successfully, the corresponding holder type (e.g. std::unique_ptr) must still be initialized. */ - PyObject *inst = PyTuple_GET_ITEM(args, 0); - auto tinfo = detail::get_type_info(Py_TYPE(inst)); - tinfo->init_holder(inst, nullptr); + auto tinfo = get_type_info(Py_TYPE(parent.ptr())); + tinfo->init_holder(parent.ptr(), nullptr); } return result.ptr(); } @@ -539,6 +704,7 @@ class module : public object { public: PYBIND11_OBJECT_DEFAULT(module, object, PyModule_Check) + /// Create a new top-level Python module with the given name and docstring explicit module(const char *name, const char *doc = nullptr) { if (!options::show_user_defined_docstrings()) doc = nullptr; #if PY_MAJOR_VERSION >= 3 @@ -557,6 +723,11 @@ public: inc_ref(); } + /** \rst + Create Python binding for a new function within the module scope. ``Func`` + can be a plain C++ function, a function pointer, or a lambda function. For + details on the ``Extra&& ... extra`` argument, see section :ref:`extras`. + \endrst */ template <typename Func, typename... Extra> module &def(const char *name_, Func &&f, const Extra& ... extra) { cpp_function func(std::forward<Func>(f), name(name_), scope(*this), @@ -567,6 +738,16 @@ public: return *this; } + /** \rst + Create and return a new Python submodule with the given name and docstring. + This also works recursively, i.e. + + .. code-block:: cpp + + py::module m("example", "pybind11 example plugin"); + py::module m2 = m.def_submodule("sub", "A submodule of 'example'"); + py::module m3 = m2.def_submodule("subsub", "A submodule of 'example.sub'"); + \endrst */ module def_submodule(const char *name, const char *doc = nullptr) { std::string full_name = std::string(PyModule_GetName(m_ptr)) + std::string(".") + std::string(name); @@ -577,6 +758,7 @@ public: return result; } + /// Import and return a module or throws `error_already_set`. static module import(const char *name) { PyObject *obj = PyImport_ImportModule(name); if (!obj) @@ -600,175 +782,40 @@ public: }; NAMESPACE_BEGIN(detail) -extern "C" inline PyObject *get_dict(PyObject *op, void *) { - PyObject *&dict = *_PyObject_GetDictPtr(op); - if (!dict) { - dict = PyDict_New(); - } - Py_XINCREF(dict); - return dict; -} - -extern "C" inline int set_dict(PyObject *op, PyObject *new_dict, void *) { - if (!PyDict_Check(new_dict)) { - PyErr_Format(PyExc_TypeError, "__dict__ must be set to a dictionary, not a '%.200s'", - Py_TYPE(new_dict)->tp_name); - return -1; - } - PyObject *&dict = *_PyObject_GetDictPtr(op); - Py_INCREF(new_dict); - Py_CLEAR(dict); - dict = new_dict; - return 0; -} - -static PyGetSetDef generic_getset[] = { - {const_cast<char*>("__dict__"), get_dict, set_dict, nullptr, nullptr}, - {nullptr, nullptr, nullptr, nullptr, nullptr} -}; - /// Generic support for creating new Python heap types class generic_type : public object { template <typename...> friend class class_; public: PYBIND11_OBJECT_DEFAULT(generic_type, object, PyType_Check) protected: - void initialize(type_record *rec) { - auto &internals = get_internals(); - auto tindex = std::type_index(*(rec->type)); + void initialize(const type_record &rec) { + if (rec.scope && hasattr(rec.scope, rec.name)) + pybind11_fail("generic_type: cannot initialize type \"" + std::string(rec.name) + + "\": an object with that name is already defined"); - if (get_type_info(*(rec->type))) - pybind11_fail("generic_type: type \"" + std::string(rec->name) + + if (get_type_info(*rec.type)) + pybind11_fail("generic_type: type \"" + std::string(rec.name) + "\" is already registered!"); - auto name = reinterpret_steal<object>(PYBIND11_FROM_STRING(rec->name)); - object scope_module; - if (rec->scope) { - if (hasattr(rec->scope, rec->name)) - pybind11_fail("generic_type: cannot initialize type \"" + std::string(rec->name) + - "\": an object with that name is already defined"); - - if (hasattr(rec->scope, "__module__")) { - scope_module = rec->scope.attr("__module__"); - } else if (hasattr(rec->scope, "__name__")) { - scope_module = rec->scope.attr("__name__"); - } - } - -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3 - /* Qualified names for Python >= 3.3 */ - object scope_qualname; - if (rec->scope && hasattr(rec->scope, "__qualname__")) - scope_qualname = rec->scope.attr("__qualname__"); - object ht_qualname; - if (scope_qualname) { - ht_qualname = reinterpret_steal<object>(PyUnicode_FromFormat( - "%U.%U", scope_qualname.ptr(), name.ptr())); - } else { - ht_qualname = name; - } -#endif - - size_t num_bases = rec->bases.size(); - auto bases = tuple(rec->bases); - - std::string full_name = (scope_module ? ((std::string) pybind11::str(scope_module) + "." + rec->name) - : std::string(rec->name)); - - char *tp_doc = nullptr; - if (rec->doc && options::show_user_defined_docstrings()) { - /* Allocate memory for docstring (using PyObject_MALLOC, since - Python will free this later on) */ - size_t size = strlen(rec->doc) + 1; - tp_doc = (char *) PyObject_MALLOC(size); - memcpy((void *) tp_doc, rec->doc, size); - } - - /* Danger zone: from now (and until PyType_Ready), make sure to - issue no Python C API calls which could potentially invoke the - garbage collector (the GC will call type_traverse(), which will in - turn find the newly constructed type in an invalid state) */ - - auto type_holder = reinterpret_steal<object>(PyType_Type.tp_alloc(&PyType_Type, 0)); - auto type = (PyHeapTypeObject*) type_holder.ptr(); - - if (!type_holder || !name) - pybind11_fail(std::string(rec->name) + ": Unable to create type object!"); + m_ptr = make_new_python_type(rec); /* Register supplemental type information in C++ dict */ - detail::type_info *tinfo = new detail::type_info(); - tinfo->type = (PyTypeObject *) type; - tinfo->type_size = rec->type_size; - tinfo->init_holder = rec->init_holder; + auto *tinfo = new detail::type_info(); + tinfo->type = (PyTypeObject *) m_ptr; + tinfo->type_size = rec.type_size; + tinfo->operator_new = rec.operator_new; + tinfo->init_holder = rec.init_holder; + tinfo->dealloc = rec.dealloc; + + auto &internals = get_internals(); + auto tindex = std::type_index(*rec.type); tinfo->direct_conversions = &internals.direct_conversions[tindex]; + tinfo->default_holder = rec.default_holder; internals.registered_types_cpp[tindex] = tinfo; - internals.registered_types_py[type] = tinfo; - - /* Basic type attributes */ - type->ht_type.tp_name = strdup(full_name.c_str()); - type->ht_type.tp_basicsize = (ssize_t) rec->instance_size; - - if (num_bases > 0) { - type->ht_type.tp_base = (PyTypeObject *) ((object) bases[0]).inc_ref().ptr(); - type->ht_type.tp_bases = bases.release().ptr(); - rec->multiple_inheritance |= num_bases > 1; - } - - type->ht_name = name.release().ptr(); - -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3 - type->ht_qualname = ht_qualname.release().ptr(); -#endif + internals.registered_types_py[m_ptr] = tinfo; - /* Supported protocols */ - type->ht_type.tp_as_number = &type->as_number; - type->ht_type.tp_as_sequence = &type->as_sequence; - type->ht_type.tp_as_mapping = &type->as_mapping; - - /* Supported elementary operations */ - type->ht_type.tp_init = (initproc) init; - type->ht_type.tp_new = (newfunc) new_instance; - type->ht_type.tp_dealloc = rec->dealloc; - - /* Support weak references (needed for the keep_alive feature) */ - type->ht_type.tp_weaklistoffset = offsetof(instance_essentials<void>, weakrefs); - - /* Flags */ - type->ht_type.tp_flags |= Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE; -#if PY_MAJOR_VERSION < 3 - type->ht_type.tp_flags |= Py_TPFLAGS_CHECKTYPES; -#endif - type->ht_type.tp_flags &= ~Py_TPFLAGS_HAVE_GC; - - /* Support dynamic attributes */ - if (rec->dynamic_attr) { - type->ht_type.tp_flags |= Py_TPFLAGS_HAVE_GC; - type->ht_type.tp_dictoffset = type->ht_type.tp_basicsize; // place the dict at the end - type->ht_type.tp_basicsize += sizeof(PyObject *); // and allocate enough space for it - type->ht_type.tp_getset = generic_getset; - type->ht_type.tp_traverse = traverse; - type->ht_type.tp_clear = clear; - } - - type->ht_type.tp_doc = tp_doc; - - if (PyType_Ready(&type->ht_type) < 0) - pybind11_fail(std::string(rec->name) + ": PyType_Ready failed (" + - detail::error_string() + ")!"); - - m_ptr = type_holder.ptr(); - - if (scope_module) // Needed by pydoc - attr("__module__") = scope_module; - - /* Register type with the parent scope */ - if (rec->scope) - rec->scope.attr(handle(type->ht_name)) = *this; - - if (rec->multiple_inheritance) - mark_parents_nonsimple(&type->ht_type); - - type_holder.release(); + if (rec.bases.size() > 1 || rec.multiple_inheritance) + mark_parents_nonsimple(tinfo->type); } /// Helper function which tags all parents of a type using mult. inheritance @@ -782,141 +829,50 @@ protected: } } - /// Allocate a metaclass on demand (for static properties) - handle metaclass() { - auto &ht_type = ((PyHeapTypeObject *) m_ptr)->ht_type; - auto &ob_type = PYBIND11_OB_TYPE(ht_type); - - if (ob_type == &PyType_Type) { - std::string name_ = std::string(ht_type.tp_name) + "__Meta"; -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3 - auto ht_qualname = reinterpret_steal<object>(PyUnicode_FromFormat("%U__Meta", attr("__qualname__").ptr())); -#endif - auto name = reinterpret_steal<object>(PYBIND11_FROM_STRING(name_.c_str())); - auto type_holder = reinterpret_steal<object>(PyType_Type.tp_alloc(&PyType_Type, 0)); - if (!type_holder || !name) - pybind11_fail("generic_type::metaclass(): unable to create type object!"); - - auto type = (PyHeapTypeObject*) type_holder.ptr(); - type->ht_name = name.release().ptr(); - -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3 - /* Qualified names for Python >= 3.3 */ - type->ht_qualname = ht_qualname.release().ptr(); -#endif - type->ht_type.tp_name = strdup(name_.c_str()); - type->ht_type.tp_base = ob_type; - type->ht_type.tp_flags |= (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE) & - ~Py_TPFLAGS_HAVE_GC; - - if (PyType_Ready(&type->ht_type) < 0) - pybind11_fail("generic_type::metaclass(): PyType_Ready failed!"); - - ob_type = (PyTypeObject *) type_holder.release().ptr(); - } - return handle((PyObject *) ob_type); - } - - static int init(void *self, PyObject *, PyObject *) { - std::string msg = std::string(Py_TYPE(self)->tp_name) + ": No constructor defined!"; - PyErr_SetString(PyExc_TypeError, msg.c_str()); - return -1; - } - - static PyObject *new_instance(PyTypeObject *type, PyObject *, PyObject *) { - instance<void> *self = (instance<void> *) PyType_GenericAlloc((PyTypeObject *) type, 0); - auto tinfo = detail::get_type_info(type); - self->value = ::operator new(tinfo->type_size); - self->owned = true; - self->holder_constructed = false; - detail::get_internals().registered_instances.emplace(self->value, (PyObject *) self); - return (PyObject *) self; - } - - static void dealloc(instance<void> *self) { - if (self->value) { - auto instance_type = Py_TYPE(self); - auto ®istered_instances = detail::get_internals().registered_instances; - auto range = registered_instances.equal_range(self->value); - bool found = false; - for (auto it = range.first; it != range.second; ++it) { - if (instance_type == Py_TYPE(it->second)) { - registered_instances.erase(it); - found = true; - break; - } - } - if (!found) - pybind11_fail("generic_type::dealloc(): Tried to deallocate unregistered instance!"); - - if (self->weakrefs) - PyObject_ClearWeakRefs((PyObject *) self); - - PyObject **dict_ptr = _PyObject_GetDictPtr((PyObject *) self); - if (dict_ptr) { - Py_CLEAR(*dict_ptr); - } - } - Py_TYPE(self)->tp_free((PyObject*) self); - } - - static int traverse(PyObject *op, visitproc visit, void *arg) { - PyObject *&dict = *_PyObject_GetDictPtr(op); - Py_VISIT(dict); - return 0; - } - - static int clear(PyObject *op) { - PyObject *&dict = *_PyObject_GetDictPtr(op); - Py_CLEAR(dict); - return 0; - } - void install_buffer_funcs( buffer_info *(*get_buffer)(PyObject *, void *), void *get_buffer_data) { PyHeapTypeObject *type = (PyHeapTypeObject*) m_ptr; - type->ht_type.tp_as_buffer = &type->as_buffer; -#if PY_MAJOR_VERSION < 3 - type->ht_type.tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER; -#endif - type->as_buffer.bf_getbuffer = getbuffer; - type->as_buffer.bf_releasebuffer = releasebuffer; auto tinfo = detail::get_type_info(&type->ht_type); + + if (!type->ht_type.tp_as_buffer) + pybind11_fail( + "To be able to register buffer protocol support for the type '" + + std::string(tinfo->type->tp_name) + + "' the associated class<>(..) invocation must " + "include the pybind11::buffer_protocol() annotation!"); + tinfo->get_buffer = get_buffer; tinfo->get_buffer_data = get_buffer_data; } - static int getbuffer(PyObject *obj, Py_buffer *view, int flags) { - auto tinfo = detail::get_type_info(Py_TYPE(obj)); - if (view == nullptr || obj == nullptr || !tinfo || !tinfo->get_buffer) { - PyErr_SetString(PyExc_BufferError, "generic_type::getbuffer(): Internal error"); - return -1; - } - memset(view, 0, sizeof(Py_buffer)); - buffer_info *info = tinfo->get_buffer(obj, tinfo->get_buffer_data); - view->obj = obj; - view->ndim = 1; - view->internal = info; - view->buf = info->ptr; - view->itemsize = (ssize_t) info->itemsize; - view->len = view->itemsize; - for (auto s : info->shape) - view->len *= s; - if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) - view->format = const_cast<char *>(info->format.c_str()); - if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) { - view->ndim = (int) info->ndim; - view->strides = (ssize_t *) &info->strides[0]; - view->shape = (ssize_t *) &info->shape[0]; - } - Py_INCREF(view->obj); - return 0; - } + void def_property_static_impl(const char *name, + handle fget, handle fset, + detail::function_record *rec_fget) { + const auto is_static = !(rec_fget->is_method && rec_fget->scope); + const auto has_doc = rec_fget->doc && pybind11::options::show_user_defined_docstrings(); - static void releasebuffer(PyObject *, Py_buffer *view) { delete (buffer_info *) view->internal; } + auto property = handle((PyObject *) (is_static ? get_internals().static_property_type + : &PyProperty_Type)); + attr(name) = property(fget.ptr() ? fget : none(), + fset.ptr() ? fset : none(), + /*deleter*/none(), + pybind11::str(has_doc ? rec_fget->doc : "")); + } }; +/// Set the pointer to operator new if it exists. The cast is needed because it can be overloaded. +template <typename T, typename = void_t<decltype(static_cast<void *(*)(size_t)>(T::operator new))>> +void set_operator_new(type_record *r) { r->operator_new = &T::operator new; } + +template <typename> void set_operator_new(...) { } + +/// Call class-specific delete if it exists or global otherwise. Can also be an overload set. +template <typename T, typename = void_t<decltype(static_cast<void (*)(void *)>(T::operator delete))>> +void call_operator_delete(T *p) { T::operator delete(p); } + +inline void call_operator_delete(void *p) { ::operator delete(p); } + NAMESPACE_END(detail) template <typename type_, typename... options> @@ -924,12 +880,9 @@ class class_ : public detail::generic_type { template <typename T> using is_holder = detail::is_holder_type<type_, T>; template <typename T> using is_subtype = detail::bool_constant<std::is_base_of<type_, T>::value && !std::is_same<T, type_>::value>; template <typename T> using is_base = detail::bool_constant<std::is_base_of<T, type_>::value && !std::is_same<T, type_>::value>; - template <typename T> using is_valid_class_option = - detail::bool_constant< - is_holder<T>::value || - is_subtype<T>::value || - is_base<T>::value - >; + // struct instead of using here to help MSVC: + template <typename T> struct is_valid_class_option : + detail::any_of<is_holder<T>, is_subtype<T>, is_base<T>> {}; public: using type = type_; @@ -938,33 +891,46 @@ public: using holder_type = detail::first_of_t<is_holder, std::unique_ptr<type>, options...>; using instance_type = detail::instance<type, holder_type>; - static_assert(detail::all_of_t<is_valid_class_option, options...>::value, + static_assert(detail::all_of<is_valid_class_option<options>...>::value, "Unknown/invalid class_ template parameters provided"); PYBIND11_OBJECT(class_, generic_type, PyType_Check) template <typename... Extra> class_(handle scope, const char *name, const Extra &... extra) { - detail::type_record record; + using namespace detail; + + // MI can only be specified via class_ template options, not constructor parameters + static_assert( + none_of<is_pyobject<Extra>...>::value || // no base class arguments, or: + ( constexpr_sum(is_pyobject<Extra>::value...) == 1 && // Exactly one base + constexpr_sum(is_base<options>::value...) == 0 && // no template option bases + none_of<std::is_same<multiple_inheritance, Extra>...>::value), // no multiple_inheritance attr + "Error: multiple inheritance bases must be specified via class_ template options"); + + type_record record; record.scope = scope; record.name = name; record.type = &typeid(type); - record.type_size = sizeof(detail::conditional_t<has_alias, type_alias, type>); + record.type_size = sizeof(conditional_t<has_alias, type_alias, type>); record.instance_size = sizeof(instance_type); record.init_holder = init_holder; record.dealloc = dealloc; + record.default_holder = std::is_same<holder_type, std::unique_ptr<type>>::value; + + set_operator_new<type>(&record); /* Register base classes specified via template arguments to class_, if any */ bool unused[] = { (add_base<options>(record), false)..., false }; (void) unused; /* Process optional arguments, if any */ - detail::process_attributes<Extra...>::init(extra..., &record); + process_attributes<Extra...>::init(extra..., &record); - detail::generic_type::initialize(&record); + generic_type::initialize(record); if (has_alias) { - auto &instances = pybind11::detail::get_internals().registered_types_cpp; + auto &instances = get_internals().registered_types_cpp; instances[std::type_index(typeid(type_alias))] = instances[std::type_index(typeid(type))]; } } @@ -988,7 +954,9 @@ public: } template <typename Func, typename... Extra> class_ & - def_static(const char *name_, Func f, const Extra&... extra) { + def_static(const char *name_, Func &&f, const Extra&... extra) { + static_assert(!std::is_member_function_pointer<Func>::value, + "def_static(...) called with a non-static member function pointer"); cpp_function cf(std::forward<Func>(f), name(name_), scope(*this), sibling(getattr(*this, name_, none())), extra...); attr(cf.name()) = cf; @@ -1023,7 +991,7 @@ public: struct capture { Func func; }; capture *ptr = new capture { std::forward<Func>(func) }; install_buffer_funcs([](PyObject *obj, void *ptr) -> buffer_info* { - detail::type_caster<type> caster; + detail::make_caster<type> caster; if (!caster.load(obj, false)) return nullptr; return new buffer_info(((capture *) ptr)->func(caster)); @@ -1121,14 +1089,7 @@ public: rec_fset->doc = strdup(rec_fset->doc); } } - pybind11::str doc_obj = pybind11::str((rec_fget->doc && pybind11::options::show_user_defined_docstrings()) ? rec_fget->doc : ""); - const auto property = reinterpret_steal<object>( - PyObject_CallFunctionObjArgs((PyObject *) &PyProperty_Type, fget.ptr() ? fget.ptr() : Py_None, - fset.ptr() ? fset.ptr() : Py_None, Py_None, doc_obj.ptr(), nullptr)); - if (rec_fget->is_method && rec_fget->scope) - attr(name) = property; - else - metaclass().attr(name) = property; + def_property_static_impl(name, fget, fset, rec_fget); return *this; } @@ -1147,24 +1108,22 @@ private: } } + static void init_holder_from_existing(instance_type *inst, const holder_type *holder_ptr, + std::true_type /*is_copy_constructible*/) { + new (&inst->holder) holder_type(*holder_ptr); + } + + static void init_holder_from_existing(instance_type *inst, const holder_type *holder_ptr, + std::false_type /*is_copy_constructible*/) { + new (&inst->holder) holder_type(std::move(*const_cast<holder_type *>(holder_ptr))); + } + /// Initialize holder object, variant 2: try to construct from existing holder object, if possible - template <typename T = holder_type, - detail::enable_if_t<std::is_copy_constructible<T>::value, int> = 0> static void init_holder_helper(instance_type *inst, const holder_type *holder_ptr, const void * /* dummy */) { if (holder_ptr) { - new (&inst->holder) holder_type(*holder_ptr); + init_holder_from_existing(inst, holder_ptr, std::is_copy_constructible<holder_type>()); inst->holder_constructed = true; - } else if (inst->owned) { - new (&inst->holder) holder_type(inst->value); - inst->holder_constructed = true; - } - } - - /// Initialize holder object, variant 3: holder is not copy constructible (e.g. unique_ptr), always initialize from raw pointer - template <typename T = holder_type, - detail::enable_if_t<!std::is_copy_constructible<T>::value, int> = 0> - static void init_holder_helper(instance_type *inst, const holder_type * /* unused */, const void * /* dummy */) { - if (inst->owned) { + } else if (inst->owned || detail::always_construct_holder<holder_type>::value) { new (&inst->holder) holder_type(inst->value); inst->holder_constructed = true; } @@ -1181,14 +1140,12 @@ private: if (inst->holder_constructed) inst->holder.~holder_type(); else if (inst->owned) - ::operator delete(inst->value); - - generic_type::dealloc((detail::instance<void> *) inst); + detail::call_operator_delete(inst->value); } static detail::function_record *get_function_record(handle h) { h = detail::get_function(h); - return h ? (detail::function_record *) reinterpret_borrow<capsule>(PyCFunction_GetSelf(h.ptr())) + return h ? (detail::function_record *) reinterpret_borrow<capsule>(PyCFunction_GET_SELF(h.ptr())) : nullptr; } }; @@ -1197,26 +1154,33 @@ private: template <typename Type> class enum_ : public class_<Type> { public: using class_<Type>::def; + using class_<Type>::def_property_readonly_static; using Scalar = typename std::underlying_type<Type>::type; template <typename T> using arithmetic_tag = std::is_same<T, arithmetic>; template <typename... Extra> enum_(const handle &scope, const char *name, const Extra&... extra) - : class_<Type>(scope, name, extra...), m_parent(scope) { + : class_<Type>(scope, name, extra...), m_entries(), m_parent(scope) { constexpr bool is_arithmetic = !std::is_same<detail::first_of_t<arithmetic_tag, void, Extra...>, void>::value; - auto entries = new std::unordered_map<Scalar, const char *>(); - def("__repr__", [name, entries](Type value) -> std::string { - auto it = entries->find((Scalar) value); - return std::string(name) + "." + - ((it == entries->end()) ? std::string("???") - : std::string(it->second)); + auto m_entries_ptr = m_entries.inc_ref().ptr(); + def("__repr__", [name, m_entries_ptr](Type value) -> pybind11::str { + for (const auto &kv : reinterpret_borrow<dict>(m_entries_ptr)) { + if (pybind11::cast<Type>(kv.second) == value) + return pybind11::str("{}.{}").format(name, kv.first); + } + return pybind11::str("{}.???").format(name); }); + def_property_readonly_static("__members__", [m_entries_ptr](object /* self */) { + dict m; + for (const auto &kv : reinterpret_borrow<dict>(m_entries_ptr)) + m[kv.first] = kv.second; + return m; + }, return_value_policy::copy); def("__init__", [](Type& value, Scalar i) { value = (Type)i; }); - def("__init__", [](Type& value, Scalar i) { new (&value) Type((Type) i); }); def("__int__", [](Type value) { return (Scalar) value; }); def("__eq__", [](const Type &value, Type *value2) { return value2 && value == *value2; }); def("__ne__", [](const Type &value, Type *value2) { return !value2 || value != *value2; }); @@ -1253,28 +1217,25 @@ public: // Pickling and unpickling -- needed for use with the 'multiprocessing' module def("__getstate__", [](const Type &value) { return pybind11::make_tuple((Scalar) value); }); def("__setstate__", [](Type &p, tuple t) { new (&p) Type((Type) t[0].cast<Scalar>()); }); - m_entries = entries; } /// Export enumeration entries into the parent scope - enum_ &export_values() { - PyObject *dict = ((PyTypeObject *) this->m_ptr)->tp_dict; - PyObject *key, *value; - ssize_t pos = 0; - while (PyDict_Next(dict, &pos, &key, &value)) - if (PyObject_IsInstance(value, this->m_ptr)) - m_parent.attr(key) = value; + enum_& export_values() { + for (const auto &kv : m_entries) + m_parent.attr(kv.first) = kv.second; return *this; } /// Add an enumeration entry enum_& value(char const* name, Type value) { - this->attr(name) = pybind11::cast(value, return_value_policy::copy); - (*m_entries)[(Scalar) value] = name; + auto v = pybind11::cast(value, return_value_policy::copy); + this->attr(name) = v; + m_entries[pybind11::str(name)] = v; return *this; } + private: - std::unordered_map<Scalar, const char *> *m_entries; + dict m_entries; handle m_parent; }; @@ -1336,11 +1297,11 @@ inline void keep_alive_impl(handle nurse, handle patient) { (void) wr.release(); } -PYBIND11_NOINLINE inline void keep_alive_impl(int Nurse, int Patient, handle args, handle ret) { - handle nurse (Nurse > 0 ? PyTuple_GetItem(args.ptr(), Nurse - 1) : ret.ptr()); - handle patient(Patient > 0 ? PyTuple_GetItem(args.ptr(), Patient - 1) : ret.ptr()); - - keep_alive_impl(nurse, patient); +PYBIND11_NOINLINE inline void keep_alive_impl(size_t Nurse, size_t Patient, function_call &call, handle ret) { + keep_alive_impl( + Nurse == 0 ? ret : Nurse <= call.args.size() ? call.args[Nurse - 1] : handle(), + Patient == 0 ? ret : Patient <= call.args.size() ? call.args[Patient - 1] : handle() + ); } template <typename Iterator, typename Sentinel, bool KeyIterator, return_value_policy Policy> @@ -1355,6 +1316,7 @@ NAMESPACE_END(detail) template <typename... Args> detail::init<Args...> init() { return detail::init<Args...>(); } template <typename... Args> detail::init_alias<Args...> init_alias() { return detail::init_alias<Args...>(); } +/// Makes a python iterator from a first and past-the-end C++ InputIterator. template <return_value_policy Policy = return_value_policy::reference_internal, typename Iterator, typename Sentinel, @@ -1380,6 +1342,8 @@ iterator make_iterator(Iterator first, Sentinel last, Extra &&... extra) { return (iterator) cast(state { first, last, true }); } +/// Makes an python iterator over the keys (`.first`) of a iterator over pairs from a +/// first and past-the-end InputIterator. template <return_value_policy Policy = return_value_policy::reference_internal, typename Iterator, typename Sentinel, @@ -1405,11 +1369,15 @@ iterator make_key_iterator(Iterator first, Sentinel last, Extra &&... extra) { return (iterator) cast(state { first, last, true }); } +/// Makes an iterator over values of an stl container or other container supporting +/// `std::begin()`/`std::end()` template <return_value_policy Policy = return_value_policy::reference_internal, typename Type, typename... Extra> iterator make_iterator(Type &value, Extra&&... extra) { return make_iterator<Policy>(std::begin(value), std::end(value), extra...); } +/// Makes an iterator over the keys (`.first`) of a stl map-like container supporting +/// `std::begin()`/`std::end()` template <return_value_policy Policy = return_value_policy::reference_internal, typename Type, typename... Extra> iterator make_key_iterator(Type &value, Extra&&... extra) { return make_key_iterator<Policy>(std::begin(value), std::end(value), extra...); @@ -1417,7 +1385,7 @@ template <return_value_policy Policy = return_value_policy::reference_internal, template <typename InputType, typename OutputType> void implicitly_convertible() { auto implicit_caster = [](PyObject *obj, PyTypeObject *type) -> PyObject * { - if (!detail::type_caster<InputType>().load(obj, false)) + if (!detail::make_caster<InputType>().load(obj, false)) return nullptr; tuple args(1); args[0] = obj; @@ -1451,7 +1419,7 @@ public: exception(handle scope, const char *name, PyObject *base = PyExc_Exception) { std::string full_name = scope.attr("__name__").cast<std::string>() + std::string(".") + name; - m_ptr = PyErr_NewException((char *) full_name.c_str(), base, NULL); + m_ptr = PyErr_NewException(const_cast<char *>(full_name.c_str()), base, NULL); if (hasattr(scope, name)) pybind11_fail("Error during initialization: multiple incompatible " "definitions with name \"" + std::string(name) + "\""); @@ -1524,7 +1492,7 @@ void print(Args &&...args) { detail::print(c.args(), c.kwargs()); } -#if defined(WITH_THREAD) +#if defined(WITH_THREAD) && !defined(PYPY_VERSION) /* The functions below essentially reproduce the PyGILState_* API using a RAII * pattern, but there are a few important differences: @@ -1647,6 +1615,20 @@ private: PyThreadState *tstate; bool disassoc; }; +#elif defined(PYPY_VERSION) +class gil_scoped_acquire { + PyGILState_STATE state; +public: + gil_scoped_acquire() { state = PyGILState_Ensure(); } + ~gil_scoped_acquire() { PyGILState_Release(state); } +}; + +class gil_scoped_release { + PyThreadState *state; +public: + gil_scoped_release() { state = PyEval_SaveThread(); } + ~gil_scoped_release() { PyEval_RestoreThread(state); } +}; #else class gil_scoped_acquire { }; class gil_scoped_release { }; @@ -1655,16 +1637,15 @@ class gil_scoped_release { }; error_already_set::~error_already_set() { if (value) { gil_scoped_acquire gil; - PyErr_Restore(type, value, trace); - PyErr_Clear(); + clear(); } } inline function get_type_overload(const void *this_ptr, const detail::type_info *this_type, const char *name) { - handle py_object = detail::get_object_handle(this_ptr, this_type); - if (!py_object) + handle self = detail::get_object_handle(this_ptr, this_type); + if (!self) return function(); - handle type = py_object.get_type(); + handle type = self.get_type(); auto key = std::make_pair(type.ptr(), name); /* Cache functions that aren't overloaded in Python to avoid @@ -1673,22 +1654,47 @@ inline function get_type_overload(const void *this_ptr, const detail::type_info if (cache.find(key) != cache.end()) return function(); - function overload = getattr(py_object, name, function()); + function overload = getattr(self, name, function()); if (overload.is_cpp_function()) { cache.insert(key); return function(); } - /* Don't call dispatch code if invoked from overridden function */ + /* Don't call dispatch code if invoked from overridden function. + Unfortunately this doesn't work on PyPy. */ +#if !defined(PYPY_VERSION) PyFrameObject *frame = PyThreadState_Get()->frame; if (frame && (std::string) str(frame->f_code->co_name) == name && frame->f_code->co_argcount > 0) { PyFrame_FastToLocals(frame); PyObject *self_caller = PyDict_GetItem( frame->f_locals, PyTuple_GET_ITEM(frame->f_code->co_varnames, 0)); - if (self_caller == py_object.ptr()) + if (self_caller == self.ptr()) return function(); } +#else + /* PyPy currently doesn't provide a detailed cpyext emulation of + frame objects, so we have to emulate this using Python. This + is going to be slow..*/ + dict d; d["self"] = self; d["name"] = pybind11::str(name); + PyObject *result = PyRun_String( + "import inspect\n" + "frame = inspect.currentframe()\n" + "if frame is not None:\n" + " frame = frame.f_back\n" + " if frame is not None and str(frame.f_code.co_name) == name and " + "frame.f_code.co_argcount > 0:\n" + " self_caller = frame.f_locals[frame.f_code.co_varnames[0]]\n" + " if self_caller == self:\n" + " self = None\n", + Py_file_input, d.ptr(), d.ptr()); + if (result == nullptr) + throw error_already_set(); + if ((handle) d["self"] == Py_None) + return function(); + Py_DECREF(result); +#endif + return overload; } |