summaryrefslogtreecommitdiff
path: root/ext/pybind11/include/pybind11/pybind11.h
diff options
context:
space:
mode:
Diffstat (limited to 'ext/pybind11/include/pybind11/pybind11.h')
-rw-r--r--ext/pybind11/include/pybind11/pybind11.h858
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 &registered_exception_translators = pybind11::detail::get_internals().registered_exception_translators;
+ auto &registered_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 &registered_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;
}