diff options
author | Andreas Sandberg <andreas.sandberg@arm.com> | 2017-05-09 19:22:53 +0100 |
---|---|---|
committer | Andreas Sandberg <andreas.sandberg@arm.com> | 2017-05-22 17:15:09 +0000 |
commit | 6914a229a038206341ae1fea46393965a555ca9a (patch) | |
tree | 4a11cfaed46dabc827c5ee17cd976f42b5f53d49 /ext/pybind11/include | |
parent | ca1d18d599dcc620bf526fb22042af95b1b60b68 (diff) | |
download | gem5-6914a229a038206341ae1fea46393965a555ca9a.tar.xz |
ext: Upgrade PyBind11 to version 2.1.1
Change-Id: I16870dec402d661295f9d013dc23e362b2b2c169
Signed-off-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-by: Curtis Dunham <curtis.dunham@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/3225
Reviewed-by: Jason Lowe-Power <jason@lowepower.com>
Diffstat (limited to 'ext/pybind11/include')
-rw-r--r-- | ext/pybind11/include/pybind11/attr.h | 132 | ||||
-rw-r--r-- | ext/pybind11/include/pybind11/cast.h | 522 | ||||
-rw-r--r-- | ext/pybind11/include/pybind11/chrono.h | 8 | ||||
-rw-r--r-- | ext/pybind11/include/pybind11/class_support.h | 504 | ||||
-rw-r--r-- | ext/pybind11/include/pybind11/common.h | 219 | ||||
-rw-r--r-- | ext/pybind11/include/pybind11/complex.h | 13 | ||||
-rw-r--r-- | ext/pybind11/include/pybind11/eigen.h | 564 | ||||
-rw-r--r-- | ext/pybind11/include/pybind11/eval.h | 7 | ||||
-rw-r--r-- | ext/pybind11/include/pybind11/functional.h | 22 | ||||
-rw-r--r-- | ext/pybind11/include/pybind11/numpy.h | 462 | ||||
-rw-r--r-- | ext/pybind11/include/pybind11/pybind11.h | 858 | ||||
-rw-r--r-- | ext/pybind11/include/pybind11/pytypes.h | 458 | ||||
-rw-r--r-- | ext/pybind11/include/pybind11/stl.h | 4 | ||||
-rw-r--r-- | ext/pybind11/include/pybind11/stl_bind.h | 108 |
14 files changed, 2835 insertions, 1046 deletions
diff --git a/ext/pybind11/include/pybind11/attr.h b/ext/pybind11/include/pybind11/attr.h index 448612c52..e38a1a32d 100644 --- a/ext/pybind11/include/pybind11/attr.h +++ b/ext/pybind11/include/pybind11/attr.h @@ -14,6 +14,9 @@ NAMESPACE_BEGIN(pybind11) +/// \addtogroup annotations +/// @{ + /// Annotation for methods struct is_method { handle class_; is_method(const handle &c) : class_(c) { } }; @@ -39,7 +42,7 @@ template <typename T> struct base { }; /// Keep patient alive while nurse lives -template <int Nurse, int Patient> struct keep_alive { }; +template <size_t Nurse, size_t Patient> struct keep_alive { }; /// Annotation indicating that a class is involved in a multiple inheritance relationship struct multiple_inheritance { }; @@ -47,9 +50,25 @@ struct multiple_inheritance { }; /// Annotation which enables dynamic attributes, i.e. adds `__dict__` to a class struct dynamic_attr { }; +/// Annotation which enables the buffer protocol for a type +struct buffer_protocol { }; + +/// Annotation which requests that a special metaclass is created for a type +struct metaclass { + handle value; + + PYBIND11_DEPRECATED("py::metaclass() is no longer required. It's turned on by default now.") + metaclass() = default; + + /// Override pybind11's default metaclass + explicit metaclass(handle value) : value(value) { } +}; + /// Annotation to mark enums as an arithmetic type struct arithmetic { }; +/// @} annotations + NAMESPACE_BEGIN(detail) /* Forward declarations */ enum op_id : int; @@ -58,16 +77,17 @@ struct undefined_t; template <op_id id, op_type ot, typename L = undefined_t, typename R = undefined_t> struct op_; template <typename... Args> struct init; template <typename... Args> struct init_alias; -inline void keep_alive_impl(int Nurse, int Patient, handle args, handle ret); +inline void keep_alive_impl(size_t Nurse, size_t Patient, function_call &call, handle ret); /// Internal data structure which holds metadata about a keyword argument struct argument_record { const char *name; ///< Argument name const char *descr; ///< Human-readable version of the argument value handle value; ///< Associated Python object + bool convert : 1; ///< True if the argument is allowed to convert when loading - argument_record(const char *name, const char *descr, handle value) - : name(name), descr(descr), value(value) { } + argument_record(const char *name, const char *descr, handle value, bool convert) + : name(name), descr(descr), value(value), convert(convert) { } }; /// Internal data structure which holds metadata about a bound function (signature, overloads, etc.) @@ -89,7 +109,7 @@ struct function_record { std::vector<argument_record> args; /// Pointer to lambda function which converts arguments and performs the actual call - handle (*impl) (function_record *, handle, handle, handle) = nullptr; + handle (*impl) (function_call &) = nullptr; /// Storage for the wrapped function pointer and captured data, if any void *data[3] = { }; @@ -118,8 +138,8 @@ struct function_record { /// True if this is a method bool is_method : 1; - /// Number of arguments - uint16_t nargs; + /// Number of arguments (including py::args and/or py::kwargs, if present) + std::uint16_t nargs; /// Python method object PyMethodDef *def = nullptr; @@ -136,7 +156,8 @@ struct function_record { /// Special data structure which (temporarily) holds metadata about a bound class struct type_record { - PYBIND11_NOINLINE type_record() { } + PYBIND11_NOINLINE type_record() + : multiple_inheritance(false), dynamic_attr(false), buffer_protocol(false) { } /// Handle to the parent scope handle scope; @@ -153,6 +174,9 @@ struct type_record { /// How large is pybind11::instance<type>? size_t instance_size = 0; + /// The global operator new can be overridden with a class-specific variant + void *(*operator_new)(size_t) = ::operator new; + /// Function pointer to class_<..>::init_holder void (*init_holder)(PyObject *, const void *) = nullptr; @@ -165,11 +189,20 @@ struct type_record { /// Optional docstring const char *doc = nullptr; + /// Custom metaclass (optional) + handle metaclass; + /// Multiple inheritance marker - bool multiple_inheritance = false; + bool multiple_inheritance : 1; /// Does the class manage a __dict__? - bool dynamic_attr = false; + bool dynamic_attr : 1; + + /// Does the class implement the buffer protocol? + bool buffer_protocol : 1; + + /// Is the default (unique_ptr) holder type used? + bool default_holder : 1; PYBIND11_NOINLINE void add_base(const std::type_info *base, void *(*caster)(void *)) { auto base_info = detail::get_type_info(*base, false); @@ -180,6 +213,15 @@ struct type_record { "\" referenced unknown base type \"" + tname + "\""); } + if (default_holder != base_info->default_holder) { + std::string tname(base->name()); + detail::clean_type_id(tname); + pybind11_fail("generic_type: type \"" + std::string(name) + "\" " + + (default_holder ? "does not have" : "has") + + " a non-default holder type while its base \"" + tname + "\" " + + (base_info->default_holder ? "does not" : "does")); + } + bases.append((PyObject *) base_info->type); if (base_info->type->tp_dictoffset != 0) @@ -190,6 +232,12 @@ struct type_record { } }; +inline function_call::function_call(function_record &f, handle p) : + func(f), parent(p) { + args.reserve(f.nargs); + args_convert.reserve(f.nargs); +} + /** * Partial template specializations to process custom attributes provided to * cpp_function_ and class_. These are either used to initialize the respective @@ -202,8 +250,8 @@ template <typename T> struct process_attribute_default { /// Default implementation: do nothing static void init(const T &, function_record *) { } static void init(const T &, type_record *) { } - static void precall(handle) { } - static void postcall(handle, handle) { } + static void precall(function_call &) { } + static void postcall(function_call &, handle) { } }; /// Process an attribute specifying the function's name @@ -252,8 +300,8 @@ template <> struct process_attribute<is_operator> : process_attribute_default<is template <> struct process_attribute<arg> : process_attribute_default<arg> { static void init(const arg &a, function_record *r) { if (r->is_method && r->args.empty()) - r->args.emplace_back("self", nullptr, handle()); - r->args.emplace_back(a.name, nullptr, handle()); + r->args.emplace_back("self", nullptr, handle(), true /*convert*/); + r->args.emplace_back(a.name, nullptr, handle(), !a.flag_noconvert); } }; @@ -261,32 +309,34 @@ template <> struct process_attribute<arg> : process_attribute_default<arg> { template <> struct process_attribute<arg_v> : process_attribute_default<arg_v> { static void init(const arg_v &a, function_record *r) { if (r->is_method && r->args.empty()) - r->args.emplace_back("self", nullptr, handle()); + r->args.emplace_back("self", nullptr /*descr*/, handle() /*parent*/, true /*convert*/); if (!a.value) { #if !defined(NDEBUG) - auto descr = "'" + std::string(a.name) + ": " + a.type + "'"; + std::string descr("'"); + if (a.name) descr += std::string(a.name) + ": "; + descr += a.type + "'"; if (r->is_method) { if (r->name) descr += " in method '" + (std::string) str(r->scope) + "." + (std::string) r->name + "'"; else descr += " in method of '" + (std::string) str(r->scope) + "'"; } else if (r->name) { - descr += " in function named '" + (std::string) r->name + "'"; + descr += " in function '" + (std::string) r->name + "'"; } - pybind11_fail("arg(): could not convert default keyword argument " + pybind11_fail("arg(): could not convert default argument " + descr + " into a Python object (type not registered yet?)"); #else - pybind11_fail("arg(): could not convert default keyword argument " + pybind11_fail("arg(): could not convert default argument " "into a Python object (type not registered yet?). " "Compile in debug mode for more information."); #endif } - r->args.emplace_back(a.name, a.descr, a.value.inc_ref()); + r->args.emplace_back(a.name, a.descr, a.value.inc_ref(), !a.flag_noconvert); } }; -/// Process a parent class attribute +/// Process a parent class attribute. Single inheritance only (class_ itself already guarantees that) template <typename T> struct process_attribute<T, enable_if_t<is_pyobject<T>::value>> : process_attribute_default<handle> { static void init(const handle &h, type_record *r) { r->bases.append(h); } @@ -309,6 +359,16 @@ struct process_attribute<dynamic_attr> : process_attribute_default<dynamic_attr> static void init(const dynamic_attr &, type_record *r) { r->dynamic_attr = true; } }; +template <> +struct process_attribute<buffer_protocol> : process_attribute_default<buffer_protocol> { + static void init(const buffer_protocol &, type_record *r) { r->buffer_protocol = true; } +}; + +template <> +struct process_attribute<metaclass> : process_attribute_default<metaclass> { + static void init(const metaclass &m, type_record *r) { r->metaclass = m.value; } +}; + /// Process an 'arithmetic' attribute for enums (does nothing here) template <> @@ -319,15 +379,15 @@ struct process_attribute<arithmetic> : process_attribute_default<arithmetic> {}; * pre-call handler if both Nurse, Patient != 0 and use the post-call handler * otherwise */ -template <int Nurse, int Patient> struct process_attribute<keep_alive<Nurse, Patient>> : public process_attribute_default<keep_alive<Nurse, Patient>> { - template <int N = Nurse, int P = Patient, enable_if_t<N != 0 && P != 0, int> = 0> - static void precall(handle args) { keep_alive_impl(Nurse, Patient, args, handle()); } - template <int N = Nurse, int P = Patient, enable_if_t<N != 0 && P != 0, int> = 0> - static void postcall(handle, handle) { } - template <int N = Nurse, int P = Patient, enable_if_t<N == 0 || P == 0, int> = 0> - static void precall(handle) { } - template <int N = Nurse, int P = Patient, enable_if_t<N == 0 || P == 0, int> = 0> - static void postcall(handle args, handle ret) { keep_alive_impl(Nurse, Patient, args, ret); } +template <size_t Nurse, size_t Patient> struct process_attribute<keep_alive<Nurse, Patient>> : public process_attribute_default<keep_alive<Nurse, Patient>> { + template <size_t N = Nurse, size_t P = Patient, enable_if_t<N != 0 && P != 0, int> = 0> + static void precall(function_call &call) { keep_alive_impl(Nurse, Patient, call, handle()); } + template <size_t N = Nurse, size_t P = Patient, enable_if_t<N != 0 && P != 0, int> = 0> + static void postcall(function_call &, handle) { } + template <size_t N = Nurse, size_t P = Patient, enable_if_t<N == 0 || P == 0, int> = 0> + static void precall(function_call &) { } + template <size_t N = Nurse, size_t P = Patient, enable_if_t<N == 0 || P == 0, int> = 0> + static void postcall(function_call &call, handle ret) { keep_alive_impl(Nurse, Patient, call, ret); } }; /// Recursively iterate over variadic template arguments @@ -340,12 +400,12 @@ template <typename... Args> struct process_attributes { int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::init(args, r), 0) ... }; ignore_unused(unused); } - static void precall(handle fn_args) { - int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::precall(fn_args), 0) ... }; + static void precall(function_call &call) { + int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::precall(call), 0) ... }; ignore_unused(unused); } - static void postcall(handle fn_args, handle fn_ret) { - int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::postcall(fn_args, fn_ret), 0) ... }; + static void postcall(function_call &call, handle fn_ret) { + int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::postcall(call, fn_ret), 0) ... }; ignore_unused(unused); } }; @@ -354,8 +414,8 @@ template <typename... Args> struct process_attributes { template <typename... Extra, size_t named = constexpr_sum(std::is_base_of<arg, Extra>::value...), size_t self = constexpr_sum(std::is_same<is_method, Extra>::value...)> -constexpr bool expected_num_args(size_t nargs) { - return named == 0 || (self + named) == nargs; +constexpr bool expected_num_args(size_t nargs, bool has_args, bool has_kwargs) { + return named == 0 || (self + named + has_args + has_kwargs) == nargs; } NAMESPACE_END(detail) diff --git a/ext/pybind11/include/pybind11/cast.h b/ext/pybind11/include/pybind11/cast.h index 535516b37..fe19075e4 100644 --- a/ext/pybind11/include/pybind11/cast.h +++ b/ext/pybind11/include/pybind11/cast.h @@ -18,12 +18,16 @@ NAMESPACE_BEGIN(pybind11) NAMESPACE_BEGIN(detail) +inline PyTypeObject *make_static_property_type(); +inline PyTypeObject *make_default_metaclass(); /// Additional type information which does not fit into the PyTypeObject struct type_info { PyTypeObject *type; size_t type_size; + void *(*operator_new)(size_t); void (*init_holder)(PyObject *, const void *); + void (*dealloc)(PyObject *); std::vector<PyObject *(*)(PyObject *, PyTypeObject *)> implicit_conversions; std::vector<std::pair<const std::type_info *, void *(*)(void *)>> implicit_casts; std::vector<bool (*)(PyObject *, void *&)> *direct_conversions; @@ -32,6 +36,8 @@ struct type_info { /** A simple type never occurs as a (direct or indirect) parent * of a class that makes use of multiple inheritance */ bool simple_type = true; + /* for base vs derived holder_type checks */ + bool default_holder = true; }; PYBIND11_NOINLINE inline internals &get_internals() { @@ -71,6 +77,8 @@ PYBIND11_NOINLINE inline internals &get_internals() { } } ); + internals_ptr->static_property_type = make_static_property_type(); + internals_ptr->default_metaclass = make_default_metaclass(); } return *internals_ptr; } @@ -108,14 +116,10 @@ PYBIND11_NOINLINE inline handle get_type_handle(const std::type_info &tp, bool t } PYBIND11_NOINLINE inline bool isinstance_generic(handle obj, const std::type_info &tp) { - const auto type = detail::get_type_handle(tp, false); + handle type = detail::get_type_handle(tp, false); if (!type) return false; - - const auto result = PyObject_IsInstance(obj.ptr(), type.ptr()); - if (result == -1) - throw error_already_set(); - return result != 0; + return isinstance(obj, type); } PYBIND11_NOINLINE inline std::string error_string() { @@ -141,6 +145,7 @@ PYBIND11_NOINLINE inline std::string error_string() { PyException_SetTraceback(scope.value, scope.trace); #endif +#if !defined(PYPY_VERSION) if (scope.trace) { PyTracebackObject *trace = (PyTracebackObject *) scope.trace; @@ -160,6 +165,7 @@ PYBIND11_NOINLINE inline std::string error_string() { } trace = trace->tb_next; } +#endif return errorString; } @@ -176,7 +182,9 @@ PYBIND11_NOINLINE inline handle get_object_handle(const void *ptr, const detail: } inline PyThreadState *get_thread_state_unchecked() { -#if PY_VERSION_HEX < 0x03000000 +#if defined(PYPY_VERSION) + return PyThreadState_GET(); +#elif PY_VERSION_HEX < 0x03000000 return _PyThreadState_Current; #elif PY_VERSION_HEX < 0x03050000 return (PyThreadState*) _Py_atomic_load_relaxed(&_PyThreadState_Current); @@ -224,7 +232,7 @@ public: /* If this is a python class, also check the parents recursively */ auto const &type_dict = get_internals().registered_types_py; - bool new_style_class = PyType_Check(tobj); + bool new_style_class = PyType_Check((PyObject *) tobj); if (type_dict.find(tobj) == type_dict.end() && new_style_class && tobj->tp_bases) { auto parents = reinterpret_borrow<tuple>(tobj->tp_bases); for (handle parent : parents) { @@ -400,6 +408,13 @@ public: make_copy_constructor(src), make_move_constructor(src)); } + static handle cast_holder(const itype *src, const void *holder) { + return type_caster_generic::cast( + src, return_value_policy::take_ownership, {}, + src ? &typeid(*src) : nullptr, &typeid(type), + nullptr, nullptr, holder); + } + template <typename T> using cast_op_type = pybind11::detail::cast_op_type<T>; operator itype*() { return (type *) value; } @@ -413,7 +428,7 @@ protected: template <typename T = type, typename = enable_if_t<is_copy_constructible<T>::value>> static auto make_copy_constructor(const T *value) -> decltype(new T(*value), Constructor(nullptr)) { return [](const void *arg) -> void * { return new T(*((const T *) arg)); }; } template <typename T = type> static auto make_move_constructor(const T *value) -> decltype(new T(std::move(*((T *) value))), Constructor(nullptr)) { - return [](const void *arg) -> void * { return (void *) new T(std::move(*((T *) arg))); }; } + return [](const void *arg) -> void * { return (void *) new T(std::move(*const_cast<T *>(reinterpret_cast<const T *>(arg)))); }; } #else /* Visual Studio 2015's SFINAE implementation doesn't yet handle the above robustly in all situations. Use a workaround that only tests for constructibility for now. */ @@ -455,6 +470,7 @@ public: public: \ static PYBIND11_DESCR name() { return type_descr(py_name); } \ static handle cast(const type *src, return_value_policy policy, handle parent) { \ + if (!src) return none().release(); \ return cast(*src, policy, parent); \ } \ operator type*() { return &value; } \ @@ -462,20 +478,31 @@ public: template <typename _T> using cast_op_type = pybind11::detail::cast_op_type<_T> +template <typename CharT> using is_std_char_type = any_of< + std::is_same<CharT, char>, /* std::string */ + std::is_same<CharT, char16_t>, /* std::u16string */ + std::is_same<CharT, char32_t>, /* std::u32string */ + std::is_same<CharT, wchar_t> /* std::wstring */ +>; + template <typename T> -struct type_caster<T, enable_if_t<std::is_arithmetic<T>::value>> { - typedef typename std::conditional<sizeof(T) <= sizeof(long), long, long long>::type _py_type_0; - typedef typename std::conditional<std::is_signed<T>::value, _py_type_0, typename std::make_unsigned<_py_type_0>::type>::type _py_type_1; - typedef typename std::conditional<std::is_floating_point<T>::value, double, _py_type_1>::type py_type; +struct type_caster<T, enable_if_t<std::is_arithmetic<T>::value && !is_std_char_type<T>::value>> { + using _py_type_0 = conditional_t<sizeof(T) <= sizeof(long), long, long long>; + using _py_type_1 = conditional_t<std::is_signed<T>::value, _py_type_0, typename std::make_unsigned<_py_type_0>::type>; + using py_type = conditional_t<std::is_floating_point<T>::value, double, _py_type_1>; public: - bool load(handle src, bool) { + bool load(handle src, bool convert) { py_type py_value; - if (!src) { + if (!src) return false; - } if (std::is_floating_point<T>::value) { - py_value = (py_type) PyFloat_AsDouble(src.ptr()); + + if (std::is_floating_point<T>::value) { + if (convert || PyFloat_Check(src.ptr())) + py_value = (py_type) PyFloat_AsDouble(src.ptr()); + else + return false; } else if (sizeof(T) <= sizeof(long)) { if (PyFloat_Check(src.ptr())) return false; @@ -502,7 +529,7 @@ public: bool type_error = PyErr_ExceptionMatches(PyExc_TypeError); #endif PyErr_Clear(); - if (type_error && PyNumber_Check(src.ptr())) { + if (type_error && convert && PyNumber_Check(src.ptr())) { auto tmp = reinterpret_borrow<object>(std::is_floating_point<T>::value ? PyNumber_Float(src.ptr()) : PyNumber_Long(src.ptr())); @@ -604,133 +631,161 @@ public: PYBIND11_TYPE_CASTER(bool, _("bool")); }; -template <> class type_caster<std::string> { -public: - bool load(handle src, bool) { - object temp; - handle load_src = src; - if (!src) { - return false; - } else if (PyUnicode_Check(load_src.ptr())) { - temp = reinterpret_steal<object>(PyUnicode_AsUTF8String(load_src.ptr())); - if (!temp) { PyErr_Clear(); return false; } // UnicodeEncodeError - load_src = temp; - } - char *buffer; - ssize_t length; - int err = PYBIND11_BYTES_AS_STRING_AND_SIZE(load_src.ptr(), &buffer, &length); - if (err == -1) { PyErr_Clear(); return false; } // TypeError - value = std::string(buffer, (size_t) length); - success = true; - return true; - } +// Helper class for UTF-{8,16,32} C++ stl strings: +template <typename CharT, class Traits, class Allocator> +struct type_caster<std::basic_string<CharT, Traits, Allocator>, enable_if_t<is_std_char_type<CharT>::value>> { + // Simplify life by being able to assume standard char sizes (the standard only guarantees + // minimums), but Python requires exact sizes + static_assert(!std::is_same<CharT, char>::value || sizeof(CharT) == 1, "Unsupported char size != 1"); + static_assert(!std::is_same<CharT, char16_t>::value || sizeof(CharT) == 2, "Unsupported char16_t size != 2"); + static_assert(!std::is_same<CharT, char32_t>::value || sizeof(CharT) == 4, "Unsupported char32_t size != 4"); + // wchar_t can be either 16 bits (Windows) or 32 (everywhere else) + static_assert(!std::is_same<CharT, wchar_t>::value || sizeof(CharT) == 2 || sizeof(CharT) == 4, + "Unsupported wchar_t size != 2/4"); + static constexpr size_t UTF_N = 8 * sizeof(CharT); + + using StringType = std::basic_string<CharT, Traits, Allocator>; - static handle cast(const std::string &src, return_value_policy /* policy */, handle /* parent */) { - return PyUnicode_FromStringAndSize(src.c_str(), (ssize_t) src.length()); - } - - PYBIND11_TYPE_CASTER(std::string, _(PYBIND11_STRING_NAME)); -protected: - bool success = false; -}; - -template <typename type, typename deleter> class type_caster<std::unique_ptr<type, deleter>> { -public: - static handle cast(std::unique_ptr<type, deleter> &&src, return_value_policy policy, handle parent) { - handle result = type_caster_base<type>::cast(src.get(), policy, parent); - if (result) - src.release(); - return result; - } - static PYBIND11_DESCR name() { return type_caster_base<type>::name(); } -}; - -template <> class type_caster<std::wstring> { -public: bool load(handle src, bool) { +#if PY_MAJOR_VERSION < 3 object temp; +#endif handle load_src = src; if (!src) { return false; } else if (!PyUnicode_Check(load_src.ptr())) { +#if PY_MAJOR_VERSION >= 3 + return false; + // The below is a guaranteed failure in Python 3 when PyUnicode_Check returns false +#else + if (!PYBIND11_BYTES_CHECK(load_src.ptr())) + return false; temp = reinterpret_steal<object>(PyUnicode_FromObject(load_src.ptr())); if (!temp) { PyErr_Clear(); return false; } load_src = temp; - } - wchar_t *buffer = nullptr; - ssize_t length = -1; -#if PY_MAJOR_VERSION >= 3 - buffer = PyUnicode_AsWideCharString(load_src.ptr(), &length); -#else - temp = reinterpret_steal<object>( - sizeof(wchar_t) == sizeof(short) - ? PyUnicode_AsUTF16String(load_src.ptr()) - : PyUnicode_AsUTF32String(load_src.ptr())); - if (temp) { - int err = PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), (char **) &buffer, &length); - if (err == -1) { buffer = nullptr; } // TypeError - length = length / (ssize_t) sizeof(wchar_t) - 1; ++buffer; // Skip BOM - } #endif - if (!buffer) { PyErr_Clear(); return false; } - value = std::wstring(buffer, (size_t) length); - success = true; + } + + object utfNbytes = reinterpret_steal<object>(PyUnicode_AsEncodedString( + load_src.ptr(), UTF_N == 8 ? "utf-8" : UTF_N == 16 ? "utf-16" : "utf-32", nullptr)); + if (!utfNbytes) { PyErr_Clear(); return false; } + + const CharT *buffer = reinterpret_cast<const CharT *>(PYBIND11_BYTES_AS_STRING(utfNbytes.ptr())); + size_t length = (size_t) PYBIND11_BYTES_SIZE(utfNbytes.ptr()) / sizeof(CharT); + if (UTF_N > 8) { buffer++; length--; } // Skip BOM for UTF-16/32 + value = StringType(buffer, length); return true; } - static handle cast(const std::wstring &src, return_value_policy /* policy */, handle /* parent */) { - return PyUnicode_FromWideChar(src.c_str(), (ssize_t) src.length()); + static handle cast(const StringType &src, return_value_policy /* policy */, handle /* parent */) { + const char *buffer = reinterpret_cast<const char *>(src.c_str()); + ssize_t nbytes = ssize_t(src.size() * sizeof(CharT)); + handle s = decode_utfN(buffer, nbytes); + if (!s) throw error_already_set(); + return s; } - PYBIND11_TYPE_CASTER(std::wstring, _(PYBIND11_STRING_NAME)); -protected: - bool success = false; + PYBIND11_TYPE_CASTER(StringType, _(PYBIND11_STRING_NAME)); + +private: + static handle decode_utfN(const char *buffer, ssize_t nbytes) { +#if !defined(PYPY_VERSION) + return + UTF_N == 8 ? PyUnicode_DecodeUTF8(buffer, nbytes, nullptr) : + UTF_N == 16 ? PyUnicode_DecodeUTF16(buffer, nbytes, nullptr, nullptr) : + PyUnicode_DecodeUTF32(buffer, nbytes, nullptr, nullptr); +#else + // PyPy seems to have multiple problems related to PyUnicode_UTF*: the UTF8 version + // sometimes segfaults for unknown reasons, while the UTF16 and 32 versions require a + // non-const char * arguments, which is also a nuissance, so bypass the whole thing by just + // passing the encoding as a string value, which works properly: + return PyUnicode_Decode(buffer, nbytes, UTF_N == 8 ? "utf-8" : UTF_N == 16 ? "utf-16" : "utf-32", nullptr); +#endif + } }; -template <> class type_caster<char> : public type_caster<std::string> { +// Type caster for C-style strings. We basically use a std::string type caster, but also add the +// ability to use None as a nullptr char* (which the string caster doesn't allow). +template <typename CharT> struct type_caster<CharT, enable_if_t<is_std_char_type<CharT>::value>> { + using StringType = std::basic_string<CharT>; + using StringCaster = type_caster<StringType>; + StringCaster str_caster; + bool none = false; public: bool load(handle src, bool convert) { - if (src.is_none()) return true; - return type_caster<std::string>::load(src, convert); - } - - static handle cast(const char *src, return_value_policy /* policy */, handle /* parent */) { - if (src == nullptr) return none().inc_ref(); - return PyUnicode_FromString(src); + if (!src) return false; + if (src.is_none()) { + // Defer accepting None to other overloads (if we aren't in convert mode): + if (!convert) return false; + none = true; + return true; + } + return str_caster.load(src, convert); } - static handle cast(char src, return_value_policy /* policy */, handle /* parent */) { - char str[2] = { src, '\0' }; - return PyUnicode_DecodeLatin1(str, 1, nullptr); + static handle cast(const CharT *src, return_value_policy policy, handle parent) { + if (src == nullptr) return pybind11::none().inc_ref(); + return StringCaster::cast(StringType(src), policy, parent); } - operator char*() { return success ? (char *) value.c_str() : nullptr; } - operator char&() { return value[0]; } - - static PYBIND11_DESCR name() { return type_descr(_(PYBIND11_STRING_NAME)); } -}; + static handle cast(CharT src, return_value_policy policy, handle parent) { + if (std::is_same<char, CharT>::value) { + handle s = PyUnicode_DecodeLatin1((const char *) &src, 1, nullptr); + if (!s) throw error_already_set(); + return s; + } + return StringCaster::cast(StringType(1, src), policy, parent); + } + + operator CharT*() { return none ? nullptr : const_cast<CharT *>(static_cast<StringType &>(str_caster).c_str()); } + operator CharT() { + if (none) + throw value_error("Cannot convert None to a character"); + + auto &value = static_cast<StringType &>(str_caster); + size_t str_len = value.size(); + if (str_len == 0) + throw value_error("Cannot convert empty string to a character"); + + // If we're in UTF-8 mode, we have two possible failures: one for a unicode character that + // is too high, and one for multiple unicode characters (caught later), so we need to figure + // out how long the first encoded character is in bytes to distinguish between these two + // errors. We also allow want to allow unicode characters U+0080 through U+00FF, as those + // can fit into a single char value. + if (StringCaster::UTF_N == 8 && str_len > 1 && str_len <= 4) { + unsigned char v0 = static_cast<unsigned char>(value[0]); + size_t char0_bytes = !(v0 & 0x80) ? 1 : // low bits only: 0-127 + (v0 & 0xE0) == 0xC0 ? 2 : // 0b110xxxxx - start of 2-byte sequence + (v0 & 0xF0) == 0xE0 ? 3 : // 0b1110xxxx - start of 3-byte sequence + 4; // 0b11110xxx - start of 4-byte sequence + + if (char0_bytes == str_len) { + // If we have a 128-255 value, we can decode it into a single char: + if (char0_bytes == 2 && (v0 & 0xFC) == 0xC0) { // 0x110000xx 0x10xxxxxx + return static_cast<CharT>(((v0 & 3) << 6) + (static_cast<unsigned char>(value[1]) & 0x3F)); + } + // Otherwise we have a single character, but it's > U+00FF + throw value_error("Character code point not in range(0x100)"); + } + } -template <> class type_caster<wchar_t> : public type_caster<std::wstring> { -public: - bool load(handle src, bool convert) { - if (src.is_none()) return true; - return type_caster<std::wstring>::load(src, convert); - } + // UTF-16 is much easier: we can only have a surrogate pair for values above U+FFFF, thus a + // surrogate pair with total length 2 instantly indicates a range error (but not a "your + // string was too long" error). + else if (StringCaster::UTF_N == 16 && str_len == 2) { + char16_t v0 = static_cast<char16_t>(value[0]); + if (v0 >= 0xD800 && v0 < 0xE000) + throw value_error("Character code point not in range(0x10000)"); + } - static handle cast(const wchar_t *src, return_value_policy /* policy */, handle /* parent */) { - if (src == nullptr) return none().inc_ref(); - return PyUnicode_FromWideChar(src, (ssize_t) wcslen(src)); - } + if (str_len != 1) + throw value_error("Expected a character, but multi-character string found"); - static handle cast(wchar_t src, return_value_policy /* policy */, handle /* parent */) { - wchar_t wstr[2] = { src, L'\0' }; - return PyUnicode_FromWideChar(wstr, 1); + return value[0]; } - operator wchar_t*() { return success ? (wchar_t *) value.c_str() : nullptr; } - operator wchar_t&() { return value[0]; } - static PYBIND11_DESCR name() { return type_descr(_(PYBIND11_STRING_NAME)); } + template <typename _T> using cast_op_type = typename std::remove_reference<pybind11::detail::cast_op_type<_T>>::type; }; template <typename T1, typename T2> class type_caster<std::pair<T1, T2>> { @@ -832,12 +887,19 @@ protected: return result.release(); } -protected: std::tuple<make_caster<Tuple>...> value; }; +/// Helper class which abstracts away certain actions. Users can provide specializations for +/// custom holders, but it's only necessary if the type has a non-standard interface. +template <typename T> +struct holder_helper { + static auto get(const T &p) -> decltype(p.get()) { return p.get(); } +}; + /// Type caster for holder types like std::shared_ptr, etc. -template <typename type, typename holder_type> class type_caster_holder : public type_caster_base<type> { +template <typename type, typename holder_type> +struct copyable_holder_caster : public type_caster_base<type> { public: using base = type_caster_base<type>; using base::base; @@ -858,6 +920,9 @@ public: return true; } + if (typeinfo->default_holder) + throw cast_error("Unable to load a custom holder type from a default-holder instance"); + if (typeinfo->simple_type) { /* Case 1: no multiple inheritance etc. involved */ /* Check if we can safely perform a reinterpret-style cast */ if (PyType_IsSubtype(tobj, typeinfo->type)) @@ -869,7 +934,7 @@ public: /* If this is a python class, also check the parents recursively */ auto const &type_dict = get_internals().registered_types_py; - bool new_style_class = PyType_Check(tobj); + bool new_style_class = PyType_Check((PyObject *) tobj); if (type_dict.find(tobj) == type_dict.end() && new_style_class && tobj->tp_bases) { auto parents = reinterpret_borrow<tuple>(tobj->tp_bases); for (handle parent : parents) { @@ -916,7 +981,7 @@ public: template <typename T = holder_type, detail::enable_if_t<std::is_constructible<T, const T &, type*>::value, int> = 0> bool try_implicit_casts(handle src, bool convert) { for (auto &cast : typeinfo->implicit_casts) { - type_caster_holder sub_caster(*cast.first); + copyable_holder_caster sub_caster(*cast.first); if (sub_caster.load(src, convert)) { value = cast.second(sub_caster.value); holder = holder_type(sub_caster.holder, (type *) value); @@ -939,10 +1004,8 @@ public: #endif static handle cast(const holder_type &src, return_value_policy, handle) { - return type_caster_generic::cast( - src.get(), return_value_policy::take_ownership, handle(), - src.get() ? &typeid(*src.get()) : nullptr, &typeid(type), - nullptr, nullptr, &src); + const auto *ptr = holder_helper<holder_type>::get(src); + return type_caster_base<type>::cast_holder(ptr, &src); } protected: @@ -951,12 +1014,34 @@ protected: /// Specialize for the common std::shared_ptr, so users don't need to template <typename T> -class type_caster<std::shared_ptr<T>> : public type_caster_holder<T, std::shared_ptr<T>> { }; +class type_caster<std::shared_ptr<T>> : public copyable_holder_caster<T, std::shared_ptr<T>> { }; + +template <typename type, typename holder_type> +struct move_only_holder_caster { + static handle cast(holder_type &&src, return_value_policy, handle) { + auto *ptr = holder_helper<holder_type>::get(src); + return type_caster_base<type>::cast_holder(ptr, &src); + } + static PYBIND11_DESCR name() { return type_caster_base<type>::name(); } +}; + +template <typename type, typename deleter> +class type_caster<std::unique_ptr<type, deleter>> + : public move_only_holder_caster<type, std::unique_ptr<type, deleter>> { }; + +template <typename type, typename holder_type> +using type_caster_holder = conditional_t<std::is_copy_constructible<holder_type>::value, + copyable_holder_caster<type, holder_type>, + move_only_holder_caster<type, holder_type>>; + +template <typename T, bool Value = false> struct always_construct_holder { static constexpr bool value = Value; }; /// Create a specialization for custom holder types (silently ignores std::shared_ptr) -#define PYBIND11_DECLARE_HOLDER_TYPE(type, holder_type) \ +#define PYBIND11_DECLARE_HOLDER_TYPE(type, holder_type, ...) \ namespace pybind11 { namespace detail { \ template <typename type> \ + struct always_construct_holder<holder_type> : always_construct_holder<void, ##__VA_ARGS__> { }; \ + template <typename type> \ class type_caster<holder_type, enable_if_t<!is_shared_ptr<holder_type>::value>> \ : public type_caster_holder<type, holder_type> { }; \ }} @@ -1004,23 +1089,24 @@ class type_caster<T, enable_if_t<is_pyobject<T>::value>> : public pyobject_caste // - if the type is non-copy-constructible, the object must be the sole owner of the type (i.e. it // must have ref_count() == 1)h // If any of the above are not satisfied, we fall back to copying. -template <typename T, typename SFINAE = void> struct move_is_plain_type : std::false_type {}; -template <typename T> struct move_is_plain_type<T, enable_if_t< - !std::is_void<T>::value && !std::is_pointer<T>::value && !std::is_reference<T>::value && !std::is_const<T>::value - >> : std::true_type { }; +template <typename T> using move_is_plain_type = satisfies_none_of<T, + std::is_void, std::is_pointer, std::is_reference, std::is_const +>; template <typename T, typename SFINAE = void> struct move_always : std::false_type {}; -template <typename T> struct move_always<T, enable_if_t< - move_is_plain_type<T>::value && - !std::is_copy_constructible<T>::value && std::is_move_constructible<T>::value && - std::is_same<decltype(std::declval<type_caster<T>>().operator T&()), T&>::value - >> : std::true_type { }; +template <typename T> struct move_always<T, enable_if_t<all_of< + move_is_plain_type<T>, + negation<std::is_copy_constructible<T>>, + std::is_move_constructible<T>, + std::is_same<decltype(std::declval<make_caster<T>>().operator T&()), T&> +>::value>> : std::true_type {}; template <typename T, typename SFINAE = void> struct move_if_unreferenced : std::false_type {}; -template <typename T> struct move_if_unreferenced<T, enable_if_t< - move_is_plain_type<T>::value && - !move_always<T>::value && std::is_move_constructible<T>::value && - std::is_same<decltype(std::declval<type_caster<T>>().operator T&()), T&>::value - >> : std::true_type { }; -template <typename T> using move_never = std::integral_constant<bool, !move_always<T>::value && !move_if_unreferenced<T>::value>; +template <typename T> struct move_if_unreferenced<T, enable_if_t<all_of< + move_is_plain_type<T>, + negation<move_always<T>>, + std::is_move_constructible<T>, + std::is_same<decltype(std::declval<make_caster<T>>().operator T&()), T&> +>::value>> : std::true_type {}; +template <typename T> using move_never = none_of<move_always<T>, move_if_unreferenced<T>>; // Detect whether returning a `type` from a cast on type's type_caster is going to result in a // reference or pointer to a local variable of the type_caster. Basically, only @@ -1031,6 +1117,17 @@ template <typename type> using cast_is_temporary_value_reference = bool_constant !std::is_base_of<type_caster_generic, make_caster<type>>::value >; +// When a value returned from a C++ function is being cast back to Python, we almost always want to +// force `policy = move`, regardless of the return value policy the function/method was declared +// with. Some classes (most notably Eigen::Ref and related) need to avoid this, and so can do so by +// specializing this struct. +template <typename Return, typename SFINAE = void> struct return_value_policy_override { + static return_value_policy policy(return_value_policy p) { + return !std::is_lvalue_reference<Return>::value && !std::is_pointer<Return>::value + ? return_value_policy::move : p; + } +}; + // Basic python -> C++ casting; throws if casting fails template <typename T, typename SFINAE> type_caster<T, SFINAE> &load_type(type_caster<T, SFINAE> &conv, const handle &handle) { if (!conv.load(handle, true)) { @@ -1080,7 +1177,7 @@ template <typename T> T handle::cast() const { return pybind11::cast<T>(*this); template <> inline void handle::cast() const { return; } template <typename T> -detail::enable_if_t<detail::move_always<T>::value || detail::move_if_unreferenced<T>::value, T> move(object &&obj) { +detail::enable_if_t<!detail::move_never<T>::value, T> move(object &&obj) { if (obj.ref_count() > 1) #if defined(NDEBUG) throw cast_error("Unable to cast Python instance to C++ rvalue: instance has multiple references" @@ -1171,19 +1268,27 @@ template <return_value_policy policy = return_value_policy::automatic_reference, return result; } -/// Annotation for keyword arguments +/// \ingroup annotations +/// Annotation for arguments struct arg { - constexpr explicit arg(const char *name) : name(name) { } + /// Constructs an argument with the name of the argument; if null or omitted, this is a positional argument. + constexpr explicit arg(const char *name = nullptr) : name(name), flag_noconvert(false) { } + /// Assign a value to this argument template <typename T> arg_v operator=(T &&value) const; + /// Indicate that the type should not be converted in the type caster + arg &noconvert(bool flag = true) { flag_noconvert = flag; return *this; } - const char *name; + const char *name; ///< If non-null, this is a named kwargs argument + bool flag_noconvert : 1; ///< If set, do not allow conversion (requires a supporting type caster!) }; -/// Annotation for keyword arguments with values +/// \ingroup annotations +/// Annotation for arguments with values struct arg_v : arg { +private: template <typename T> - arg_v(const char *name, T &&x, const char *descr = nullptr) - : arg(name), + arg_v(arg &&base, T &&x, const char *descr = nullptr) + : arg(base), value(reinterpret_steal<object>( detail::make_caster<T>::cast(x, return_value_policy::automatic, {}) )), @@ -1193,40 +1298,89 @@ struct arg_v : arg { #endif { } +public: + /// Direct construction with name, default, and description + template <typename T> + arg_v(const char *name, T &&x, const char *descr = nullptr) + : arg_v(arg(name), std::forward<T>(x), descr) { } + + /// Called internally when invoking `py::arg("a") = value` + template <typename T> + arg_v(const arg &base, T &&x, const char *descr = nullptr) + : arg_v(arg(base), std::forward<T>(x), descr) { } + + /// Same as `arg::noconvert()`, but returns *this as arg_v&, not arg& + arg_v &noconvert(bool flag = true) { arg::noconvert(flag); return *this; } + + /// The default value object value; + /// The (optional) description of the default value const char *descr; #if !defined(NDEBUG) + /// The C++ type name of the default value (only available when compiled in debug mode) std::string type; #endif }; template <typename T> -arg_v arg::operator=(T &&value) const { return {name, std::forward<T>(value)}; } +arg_v arg::operator=(T &&value) const { return {std::move(*this), std::forward<T>(value)}; } /// Alias for backward compatibility -- to be removed in version 2.0 template <typename /*unused*/> using arg_t = arg_v; inline namespace literals { -/// String literal version of arg +/** \rst + String literal version of `arg` + \endrst */ constexpr arg operator"" _a(const char *name, size_t) { return arg(name); } } NAMESPACE_BEGIN(detail) +// forward declaration +struct function_record; + +/// Internal data associated with a single function call +struct function_call { + function_call(function_record &f, handle p); // Implementation in attr.h + + /// The function data: + const function_record &func; + + /// Arguments passed to the function: + std::vector<handle> args; + + /// The `convert` value the arguments should be loaded with + std::vector<bool> args_convert; + + /// The parent, if any + handle parent; +}; + + /// Helper class which loads arguments for C++ functions called from Python template <typename... Args> class argument_loader { - using itypes = type_list<intrinsic_t<Args>...>; using indices = make_index_sequence<sizeof...(Args)>; + template <typename Arg> using argument_is_args = std::is_same<intrinsic_t<Arg>, args>; + template <typename Arg> using argument_is_kwargs = std::is_same<intrinsic_t<Arg>, kwargs>; + // Get args/kwargs argument positions relative to the end of the argument list: + static constexpr auto args_pos = constexpr_first<argument_is_args, Args...>() - (int) sizeof...(Args), + kwargs_pos = constexpr_first<argument_is_kwargs, Args...>() - (int) sizeof...(Args); + + static constexpr bool args_kwargs_are_last = kwargs_pos >= - 1 && args_pos >= kwargs_pos - 1; + + static_assert(args_kwargs_are_last, "py::args/py::kwargs are only permitted as the last argument(s) of a function"); + public: - static constexpr auto has_kwargs = std::is_same<itypes, type_list<args, kwargs>>::value; - static constexpr auto has_args = has_kwargs || std::is_same<itypes, type_list<args>>::value; + static constexpr bool has_kwargs = kwargs_pos < 0; + static constexpr bool has_args = args_pos < 0; static PYBIND11_DESCR arg_names() { return detail::concat(make_caster<Args>::name()...); } - bool load_args(handle args, handle kwargs, bool convert) { - return load_impl(args, kwargs, convert, itypes{}); + bool load_args(function_call &call) { + return load_impl_sequence(call, indices{}); } template <typename Return, typename Func> @@ -1241,26 +1395,12 @@ public: } private: - bool load_impl(handle args_, handle, bool convert, type_list<args>) { - std::get<0>(value).load(args_, convert); - return true; - } - - bool load_impl(handle args_, handle kwargs_, bool convert, type_list<args, kwargs>) { - std::get<0>(value).load(args_, convert); - std::get<1>(value).load(kwargs_, convert); - return true; - } - - bool load_impl(handle args, handle, bool convert, ... /* anything else */) { - return load_impl_sequence(args, convert, indices{}); - } - static constexpr bool load_impl_sequence(handle, bool, index_sequence<>) { return true; } + static bool load_impl_sequence(function_call &, index_sequence<>) { return true; } template <size_t... Is> - bool load_impl_sequence(handle src, bool convert, index_sequence<Is...>) { - for (bool r : {std::get<Is>(value).load(PyTuple_GET_ITEM(src.ptr(), Is), convert)...}) + bool load_impl_sequence(function_call &call, index_sequence<Is...>) { + for (bool r : {std::get<Is>(value).load(call.args[Is], call.args_convert[Is])...}) if (!r) return false; return true; @@ -1271,29 +1411,9 @@ private: return std::forward<Func>(f)(cast_op<Args>(std::get<Is>(value))...); } -private: std::tuple<make_caster<Args>...> value; }; -NAMESPACE_BEGIN(constexpr_impl) -/// Implementation details for constexpr functions -constexpr int first(int i) { return i; } -template <typename T, typename... Ts> -constexpr int first(int i, T v, Ts... vs) { return v ? i : first(i + 1, vs...); } - -constexpr int last(int /*i*/, int result) { return result; } -template <typename T, typename... Ts> -constexpr int last(int i, int result, T v, Ts... vs) { return last(i + 1, v ? i : result, vs...); } -NAMESPACE_END(constexpr_impl) - -/// Return the index of the first type in Ts which satisfies Predicate<T> -template <template<typename> class Predicate, typename... Ts> -constexpr int constexpr_first() { return constexpr_impl::first(0, Predicate<Ts>::value...); } - -/// Return the index of the last type in Ts which satisfies Predicate<T> -template <template<typename> class Predicate, typename... Ts> -constexpr int constexpr_last() { return constexpr_impl::last(0, -1, Predicate<Ts>::value...); } - /// Helper class which collects only positional arguments for a Python function call. /// A fancier version below can collect any argument, but this one is optimal for simple calls. template <return_value_policy policy> @@ -1369,6 +1489,13 @@ private: } void process(list &/*args_list*/, arg_v a) { + if (!a.name) +#if defined(NDEBUG) + nameless_argument_error(); +#else + nameless_argument_error(a.type); +#endif + if (m_kwargs.contains(a.name)) { #if defined(NDEBUG) multiple_values_error(); @@ -1401,6 +1528,15 @@ private: } } + [[noreturn]] static void nameless_argument_error() { + throw type_error("Got kwargs without a name; only named arguments " + "may be passed via py::arg() to a python function call. " + "(compile in debug mode for details)"); + } + [[noreturn]] static void nameless_argument_error(std::string type) { + throw type_error("Got kwargs without a name of type '" + type + "'; only named " + "arguments may be passed via py::arg() to a python function call. "); + } [[noreturn]] static void multiple_values_error() { throw type_error("Got multiple values for keyword argument " "(compile in debug mode for details)"); @@ -1427,14 +1563,14 @@ private: /// Collect only positional arguments for a Python function call template <return_value_policy policy, typename... Args, - typename = enable_if_t<all_of_t<is_positional, Args...>::value>> + typename = enable_if_t<all_of<is_positional<Args>...>::value>> simple_collector<policy> collect_arguments(Args &&...args) { return simple_collector<policy>(std::forward<Args>(args)...); } /// Collect all arguments, including keywords and unpacking (only instantiated when needed) template <return_value_policy policy, typename... Args, - typename = enable_if_t<!all_of_t<is_positional, Args...>::value>> + typename = enable_if_t<!all_of<is_positional<Args>...>::value>> unpacking_collector<policy> collect_arguments(Args &&...args) { // Following argument order rules for generalized unpacking according to PEP 448 static_assert( diff --git a/ext/pybind11/include/pybind11/chrono.h b/ext/pybind11/include/pybind11/chrono.h index 2b37f56f1..8a41d08b0 100644 --- a/ext/pybind11/include/pybind11/chrono.h +++ b/ext/pybind11/include/pybind11/chrono.h @@ -85,9 +85,11 @@ public: using ss_t = duration<int, std::ratio<1>>; using us_t = duration<int, std::micro>; - return PyDelta_FromDSU(duration_cast<dd_t>(d).count(), - duration_cast<ss_t>(d % days(1)).count(), - duration_cast<us_t>(d % seconds(1)).count()); + auto dd = duration_cast<dd_t>(d); + auto subd = d - dd; + auto ss = duration_cast<ss_t>(subd); + auto us = duration_cast<us_t>(subd - ss); + return PyDelta_FromDSU(dd.count(), ss.count(), us.count()); } PYBIND11_TYPE_CASTER(type, _("datetime.timedelta")); diff --git a/ext/pybind11/include/pybind11/class_support.h b/ext/pybind11/include/pybind11/class_support.h new file mode 100644 index 000000000..992703ff3 --- /dev/null +++ b/ext/pybind11/include/pybind11/class_support.h @@ -0,0 +1,504 @@ +/* + pybind11/class_support.h: Python C API implementation details for py::class_ + + Copyright (c) 2017 Wenzel Jakob <wenzel.jakob@epfl.ch> + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "attr.h" + +NAMESPACE_BEGIN(pybind11) +NAMESPACE_BEGIN(detail) + +#if !defined(PYPY_VERSION) + +/// `pybind11_static_property.__get__()`: Always pass the class instead of the instance. +extern "C" inline PyObject *pybind11_static_get(PyObject *self, PyObject * /*ob*/, PyObject *cls) { + return PyProperty_Type.tp_descr_get(self, cls, cls); +} + +/// `pybind11_static_property.__set__()`: Just like the above `__get__()`. +extern "C" inline int pybind11_static_set(PyObject *self, PyObject *obj, PyObject *value) { + PyObject *cls = PyType_Check(obj) ? obj : (PyObject *) Py_TYPE(obj); + return PyProperty_Type.tp_descr_set(self, cls, value); +} + +/** A `static_property` is the same as a `property` but the `__get__()` and `__set__()` + methods are modified to always use the object type instead of a concrete instance. + Return value: New reference. */ +inline PyTypeObject *make_static_property_type() { + constexpr auto *name = "pybind11_static_property"; + auto name_obj = reinterpret_steal<object>(PYBIND11_FROM_STRING(name)); + + /* 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 heap_type = (PyHeapTypeObject *) PyType_Type.tp_alloc(&PyType_Type, 0); + if (!heap_type) + pybind11_fail("make_static_property_type(): error allocating type!"); + + heap_type->ht_name = name_obj.inc_ref().ptr(); +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3 + heap_type->ht_qualname = name_obj.inc_ref().ptr(); +#endif + + auto type = &heap_type->ht_type; + type->tp_name = name; + type->tp_base = &PyProperty_Type; + type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE; + type->tp_descr_get = pybind11_static_get; + type->tp_descr_set = pybind11_static_set; + + if (PyType_Ready(type) < 0) + pybind11_fail("make_static_property_type(): failure in PyType_Ready()!"); + + setattr((PyObject *) type, "__module__", str("pybind11_builtins")); + + return type; +} + +#else // PYPY + +/** PyPy has some issues with the above C API, so we evaluate Python code instead. + This function will only be called once so performance isn't really a concern. + Return value: New reference. */ +inline PyTypeObject *make_static_property_type() { + auto d = dict(); + PyObject *result = PyRun_String(R"(\ + class pybind11_static_property(property): + def __get__(self, obj, cls): + return property.__get__(self, cls, cls) + + def __set__(self, obj, value): + cls = obj if isinstance(obj, type) else type(obj) + property.__set__(self, cls, value) + )", Py_file_input, d.ptr(), d.ptr() + ); + if (result == nullptr) + throw error_already_set(); + Py_DECREF(result); + return (PyTypeObject *) d["pybind11_static_property"].cast<object>().release().ptr(); +} + +#endif // PYPY + +/** Inheriting from multiple C++ types in Python is not supported -- set an error instead. + A Python definition (`class C(A, B): pass`) will call `tp_new` so we check for multiple + C++ bases here. On the other hand, C++ type definitions (`py::class_<C, A, B>(m, "C")`) + don't not use `tp_new` and will not trigger this error. */ +extern "C" inline PyObject *pybind11_meta_new(PyTypeObject *metaclass, PyObject *args, + PyObject *kwargs) { + PyObject *bases = PyTuple_GetItem(args, 1); // arguments: (name, bases, dict) + if (!bases) + return nullptr; + + auto &internals = get_internals(); + auto num_cpp_bases = 0; + for (auto base : reinterpret_borrow<tuple>(bases)) { + auto base_type = (PyTypeObject *) base.ptr(); + auto instance_size = static_cast<size_t>(base_type->tp_basicsize); + if (PyObject_IsSubclass(base.ptr(), internals.get_base(instance_size))) + ++num_cpp_bases; + } + + if (num_cpp_bases > 1) { + PyErr_SetString(PyExc_TypeError, "Can't inherit from multiple C++ classes in Python." + "Use py::class_ to define the class in C++ instead."); + return nullptr; + } else { + return PyType_Type.tp_new(metaclass, args, kwargs); + } +} + +/** Types with static properties need to handle `Type.static_prop = x` in a specific way. + By default, Python replaces the `static_property` itself, but for wrapped C++ types + we need to call `static_property.__set__()` in order to propagate the new value to + the underlying C++ data structure. */ +extern "C" inline int pybind11_meta_setattro(PyObject* obj, PyObject* name, PyObject* value) { + // Use `_PyType_Lookup()` instead of `PyObject_GetAttr()` in order to get the raw + // descriptor (`property`) instead of calling `tp_descr_get` (`property.__get__()`). + PyObject *descr = _PyType_Lookup((PyTypeObject *) obj, name); + + // Call `static_property.__set__()` instead of replacing the `static_property`. + if (descr && PyObject_IsInstance(descr, (PyObject *) get_internals().static_property_type)) { +#if !defined(PYPY_VERSION) + return Py_TYPE(descr)->tp_descr_set(descr, obj, value); +#else + if (PyObject *result = PyObject_CallMethod(descr, "__set__", "OO", obj, value)) { + Py_DECREF(result); + return 0; + } else { + return -1; + } +#endif + } else { + return PyType_Type.tp_setattro(obj, name, value); + } +} + +/** This metaclass is assigned by default to all pybind11 types and is required in order + for static properties to function correctly. Users may override this using `py::metaclass`. + Return value: New reference. */ +inline PyTypeObject* make_default_metaclass() { + constexpr auto *name = "pybind11_type"; + auto name_obj = reinterpret_steal<object>(PYBIND11_FROM_STRING(name)); + + /* 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 heap_type = (PyHeapTypeObject *) PyType_Type.tp_alloc(&PyType_Type, 0); + if (!heap_type) + pybind11_fail("make_default_metaclass(): error allocating metaclass!"); + + heap_type->ht_name = name_obj.inc_ref().ptr(); +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3 + heap_type->ht_qualname = name_obj.inc_ref().ptr(); +#endif + + auto type = &heap_type->ht_type; + type->tp_name = name; + type->tp_base = &PyType_Type; + type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE; + + type->tp_new = pybind11_meta_new; + type->tp_setattro = pybind11_meta_setattro; + + if (PyType_Ready(type) < 0) + pybind11_fail("make_default_metaclass(): failure in PyType_Ready()!"); + + setattr((PyObject *) type, "__module__", str("pybind11_builtins")); + + return type; +} + +/// Instance creation function for all pybind11 types. It only allocates space for the +/// C++ object, but doesn't call the constructor -- an `__init__` function must do that. +extern "C" inline PyObject *pybind11_object_new(PyTypeObject *type, PyObject *, PyObject *) { + PyObject *self = type->tp_alloc(type, 0); + auto instance = (instance_essentials<void> *) self; + auto tinfo = get_type_info(type); + instance->value = tinfo->operator_new(tinfo->type_size); + instance->owned = true; + instance->holder_constructed = false; + get_internals().registered_instances.emplace(instance->value, self); + return self; +} + +/// An `__init__` function constructs the C++ object. Users should provide at least one +/// of these using `py::init` or directly with `.def(__init__, ...)`. Otherwise, the +/// following default function will be used which simply throws an exception. +extern "C" inline int pybind11_object_init(PyObject *self, PyObject *, PyObject *) { + PyTypeObject *type = Py_TYPE(self); + std::string msg; +#if defined(PYPY_VERSION) + msg += handle((PyObject *) type).attr("__module__").cast<std::string>() + "."; +#endif + msg += type->tp_name; + msg += ": No constructor defined!"; + PyErr_SetString(PyExc_TypeError, msg.c_str()); + return -1; +} + +/// Instance destructor function for all pybind11 types. It calls `type_info.dealloc` +/// to destroy the C++ object itself, while the rest is Python bookkeeping. +extern "C" inline void pybind11_object_dealloc(PyObject *self) { + auto instance = (instance_essentials<void> *) self; + if (instance->value) { + auto type = Py_TYPE(self); + get_type_info(type)->dealloc(self); + + auto ®istered_instances = get_internals().registered_instances; + auto range = registered_instances.equal_range(instance->value); + bool found = false; + for (auto it = range.first; it != range.second; ++it) { + if (type == Py_TYPE(it->second)) { + registered_instances.erase(it); + found = true; + break; + } + } + if (!found) + pybind11_fail("pybind11_object_dealloc(): Tried to deallocate unregistered instance!"); + + if (instance->weakrefs) + PyObject_ClearWeakRefs(self); + + PyObject **dict_ptr = _PyObject_GetDictPtr(self); + if (dict_ptr) + Py_CLEAR(*dict_ptr); + } + Py_TYPE(self)->tp_free(self); +} + +/** Create a type which can be used as a common base for all classes with the same + instance size, i.e. all classes with the same `sizeof(holder_type)`. This is + needed in order to satisfy Python's requirements for multiple inheritance. + Return value: New reference. */ +inline PyObject *make_object_base_type(size_t instance_size) { + auto name = "pybind11_object_" + std::to_string(instance_size); + auto name_obj = reinterpret_steal<object>(PYBIND11_FROM_STRING(name.c_str())); + + /* 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 metaclass = get_internals().default_metaclass; + auto heap_type = (PyHeapTypeObject *) metaclass->tp_alloc(metaclass, 0); + if (!heap_type) + pybind11_fail("make_object_base_type(): error allocating type!"); + + heap_type->ht_name = name_obj.inc_ref().ptr(); +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3 + heap_type->ht_qualname = name_obj.inc_ref().ptr(); +#endif + + auto type = &heap_type->ht_type; + type->tp_name = strdup(name.c_str()); + type->tp_base = &PyBaseObject_Type; + type->tp_basicsize = static_cast<ssize_t>(instance_size); + type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE; + + type->tp_new = pybind11_object_new; + type->tp_init = pybind11_object_init; + type->tp_dealloc = pybind11_object_dealloc; + + /* Support weak references (needed for the keep_alive feature) */ + type->tp_weaklistoffset = offsetof(instance_essentials<void>, weakrefs); + + if (PyType_Ready(type) < 0) + pybind11_fail("PyType_Ready failed in make_object_base_type():" + error_string()); + + setattr((PyObject *) type, "__module__", str("pybind11_builtins")); + + assert(!PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC)); + return (PyObject *) heap_type; +} + +/** Return the appropriate base type for the given instance size. The results are cached + in `internals.bases` so that only a single base is ever created for any size value. + Return value: Borrowed reference. */ +inline PyObject *internals::get_base(size_t instance_size) { + auto it = bases.find(instance_size); + if (it != bases.end()) { + return it->second; + } else { + auto base = make_object_base_type(instance_size); + bases[instance_size] = base; + return base; + } +} + +/// dynamic_attr: Support for `d = instance.__dict__`. +extern "C" inline PyObject *pybind11_get_dict(PyObject *self, void *) { + PyObject *&dict = *_PyObject_GetDictPtr(self); + if (!dict) + dict = PyDict_New(); + Py_XINCREF(dict); + return dict; +} + +/// dynamic_attr: Support for `instance.__dict__ = dict()`. +extern "C" inline int pybind11_set_dict(PyObject *self, 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(self); + Py_INCREF(new_dict); + Py_CLEAR(dict); + dict = new_dict; + return 0; +} + +/// dynamic_attr: Allow the garbage collector to traverse the internal instance `__dict__`. +extern "C" inline int pybind11_traverse(PyObject *self, visitproc visit, void *arg) { + PyObject *&dict = *_PyObject_GetDictPtr(self); + Py_VISIT(dict); + return 0; +} + +/// dynamic_attr: Allow the GC to clear the dictionary. +extern "C" inline int pybind11_clear(PyObject *self) { + PyObject *&dict = *_PyObject_GetDictPtr(self); + Py_CLEAR(dict); + return 0; +} + +/// Give instances of this type a `__dict__` and opt into garbage collection. +inline void enable_dynamic_attributes(PyHeapTypeObject *heap_type) { + auto type = &heap_type->ht_type; +#if defined(PYPY_VERSION) + pybind11_fail(std::string(type->tp_name) + ": dynamic attributes are " + "currently not supported in " + "conjunction with PyPy!"); +#endif + type->tp_flags |= Py_TPFLAGS_HAVE_GC; + type->tp_dictoffset = type->tp_basicsize; // place dict at the end + type->tp_basicsize += sizeof(PyObject *); // and allocate enough space for it + type->tp_traverse = pybind11_traverse; + type->tp_clear = pybind11_clear; + + static PyGetSetDef getset[] = { + {const_cast<char*>("__dict__"), pybind11_get_dict, pybind11_set_dict, nullptr, nullptr}, + {nullptr, nullptr, nullptr, nullptr, nullptr} + }; + type->tp_getset = getset; +} + +/// buffer_protocol: Fill in the view as specified by flags. +extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int flags) { + auto tinfo = get_type_info(Py_TYPE(obj)); + if (view == nullptr || obj == nullptr || !tinfo || !tinfo->get_buffer) { + if (view) + view->obj = nullptr; + 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; +} + +/// buffer_protocol: Release the resources of the buffer. +extern "C" inline void pybind11_releasebuffer(PyObject *, Py_buffer *view) { + delete (buffer_info *) view->internal; +} + +/// Give this type a buffer interface. +inline void enable_buffer_protocol(PyHeapTypeObject *heap_type) { + heap_type->ht_type.tp_as_buffer = &heap_type->as_buffer; +#if PY_MAJOR_VERSION < 3 + heap_type->ht_type.tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER; +#endif + + heap_type->as_buffer.bf_getbuffer = pybind11_getbuffer; + heap_type->as_buffer.bf_releasebuffer = pybind11_releasebuffer; +} + +/** Create a brand new Python type according to the `type_record` specification. + Return value: New reference. */ +inline PyObject* make_new_python_type(const type_record &rec) { + auto name = reinterpret_steal<object>(PYBIND11_FROM_STRING(rec.name)); + +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3 + auto ht_qualname = name; + if (rec.scope && hasattr(rec.scope, "__qualname__")) { + ht_qualname = reinterpret_steal<object>( + PyUnicode_FromFormat("%U.%U", rec.scope.attr("__qualname__").ptr(), name.ptr())); + } +#endif + + object module; + if (rec.scope) { + if (hasattr(rec.scope, "__module__")) + module = rec.scope.attr("__module__"); + else if (hasattr(rec.scope, "__name__")) + module = rec.scope.attr("__name__"); + } + +#if !defined(PYPY_VERSION) + const auto full_name = module ? str(module).cast<std::string>() + "." + rec.name + : std::string(rec.name); +#else + const auto full_name = std::string(rec.name); +#endif + + 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); + } + + auto &internals = get_internals(); + auto bases = tuple(rec.bases); + auto base = (bases.size() == 0) ? internals.get_base(rec.instance_size) + : bases[0].ptr(); + + /* 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 metaclass = rec.metaclass.ptr() ? (PyTypeObject *) rec.metaclass.ptr() + : internals.default_metaclass; + + auto heap_type = (PyHeapTypeObject *) metaclass->tp_alloc(metaclass, 0); + if (!heap_type) + pybind11_fail(std::string(rec.name) + ": Unable to create type object!"); + + heap_type->ht_name = name.release().ptr(); +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3 + heap_type->ht_qualname = ht_qualname.release().ptr(); +#endif + + auto type = &heap_type->ht_type; + type->tp_name = strdup(full_name.c_str()); + type->tp_doc = tp_doc; + type->tp_base = (PyTypeObject *) handle(base).inc_ref().ptr(); + type->tp_basicsize = static_cast<ssize_t>(rec.instance_size); + if (bases.size() > 0) + type->tp_bases = bases.release().ptr(); + + /* Don't inherit base __init__ */ + type->tp_init = pybind11_object_init; + + /* Supported protocols */ + type->tp_as_number = &heap_type->as_number; + type->tp_as_sequence = &heap_type->as_sequence; + type->tp_as_mapping = &heap_type->as_mapping; + + /* Flags */ + type->tp_flags |= Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE; +#if PY_MAJOR_VERSION < 3 + type->tp_flags |= Py_TPFLAGS_CHECKTYPES; +#endif + + if (rec.dynamic_attr) + enable_dynamic_attributes(heap_type); + + if (rec.buffer_protocol) + enable_buffer_protocol(heap_type); + + if (PyType_Ready(type) < 0) + pybind11_fail(std::string(rec.name) + ": PyType_Ready failed (" + error_string() + ")!"); + + assert(rec.dynamic_attr ? PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC) + : !PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC)); + + /* Register type with the parent scope */ + if (rec.scope) + setattr(rec.scope, rec.name, (PyObject *) type); + + if (module) // Needed by pydoc + setattr((PyObject *) type, "__module__", module); + + return (PyObject *) type; +} + +NAMESPACE_END(detail) +NAMESPACE_END(pybind11) diff --git a/ext/pybind11/include/pybind11/common.h b/ext/pybind11/include/pybind11/common.h index f7a383007..ac2be7aef 100644 --- a/ext/pybind11/include/pybind11/common.h +++ b/ext/pybind11/include/pybind11/common.h @@ -28,6 +28,33 @@ # endif #endif +// Compiler version assertions +#if defined(__INTEL_COMPILER) +# if __INTEL_COMPILER < 1500 +# error pybind11 requires Intel C++ compiler v15 or newer +# endif +#elif defined(__clang__) && !defined(__apple_build_version__) +# if __clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ < 3) +# error pybind11 requires clang 3.3 or newer +# endif +#elif defined(__clang__) +// Apple changes clang version macros to its Xcode version; the first Xcode release based on +// (upstream) clang 3.3 was Xcode 5: +# if __clang_major__ < 5 +# error pybind11 requires Xcode/clang 5.0 or newer +# endif +#elif defined(__GNUG__) +# if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8) +# error pybind11 requires gcc 4.8 or newer +# endif +#elif defined(_MSC_VER) +// Pybind hits various compiler bugs in 2015u2 and earlier, and also makes use of some stl features +// (e.g. std::negation) added in 2015u3: +# if _MSC_FULL_VER < 190024210 +# error pybind11 requires MSVC 2015 update 3 or newer +# endif +#endif + #if !defined(PYBIND11_EXPORT) # if defined(WIN32) || defined(_WIN32) # define PYBIND11_EXPORT __declspec(dllexport) @@ -52,16 +79,18 @@ # define PYBIND11_DEPRECATED(reason) __declspec(deprecated) #endif -#define PYBIND11_VERSION_MAJOR 1 -#define PYBIND11_VERSION_MINOR 9 -#define PYBIND11_VERSION_PATCH dev0 +#define PYBIND11_VERSION_MAJOR 2 +#define PYBIND11_VERSION_MINOR 1 +#define PYBIND11_VERSION_PATCH 1 /// Include Python header, disable linking to pythonX_d.lib on Windows in debug mode #if defined(_MSC_VER) -# define HAVE_ROUND +# if (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 4) +# define HAVE_ROUND 1 +# endif # pragma warning(push) # pragma warning(disable: 4510 4610 4512 4005) -# if _DEBUG +# if defined(_DEBUG) # define PYBIND11_DEBUG_MARKER # undef _DEBUG # endif @@ -111,6 +140,7 @@ #define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyBytes_FromStringAndSize #define PYBIND11_BYTES_AS_STRING_AND_SIZE PyBytes_AsStringAndSize #define PYBIND11_BYTES_AS_STRING PyBytes_AsString +#define PYBIND11_BYTES_SIZE PyBytes_Size #define PYBIND11_LONG_CHECK(o) PyLong_Check(o) #define PYBIND11_LONG_AS_LONGLONG(o) PyLong_AsLongLong(o) #define PYBIND11_LONG_AS_UNSIGNED_LONGLONG(o) PyLong_AsUnsignedLongLong(o) @@ -119,7 +149,6 @@ #define PYBIND11_SLICE_OBJECT PyObject #define PYBIND11_FROM_STRING PyUnicode_FromString #define PYBIND11_STR_TYPE ::pybind11::str -#define PYBIND11_OB_TYPE(ht_type) (ht_type).ob_base.ob_base.ob_type #define PYBIND11_PLUGIN_IMPL(name) \ extern "C" PYBIND11_EXPORT PyObject *PyInit_##name() #else @@ -129,6 +158,7 @@ #define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyString_FromStringAndSize #define PYBIND11_BYTES_AS_STRING_AND_SIZE PyString_AsStringAndSize #define PYBIND11_BYTES_AS_STRING PyString_AsString +#define PYBIND11_BYTES_SIZE PyString_Size #define PYBIND11_LONG_CHECK(o) (PyInt_Check(o) || PyLong_Check(o)) #define PYBIND11_LONG_AS_LONGLONG(o) (PyInt_Check(o) ? (long long) PyLong_AsLong(o) : PyLong_AsLongLong(o)) #define PYBIND11_LONG_AS_UNSIGNED_LONGLONG(o) (PyInt_Check(o) ? (unsigned long long) PyLong_AsUnsignedLong(o) : PyLong_AsUnsignedLongLong(o)) @@ -137,9 +167,12 @@ #define PYBIND11_SLICE_OBJECT PySliceObject #define PYBIND11_FROM_STRING PyString_FromString #define PYBIND11_STR_TYPE ::pybind11::bytes -#define PYBIND11_OB_TYPE(ht_type) (ht_type).ob_type #define PYBIND11_PLUGIN_IMPL(name) \ - extern "C" PYBIND11_EXPORT PyObject *init##name() + static PyObject *pybind11_init_wrapper(); \ + extern "C" PYBIND11_EXPORT void init##name() { \ + (void)pybind11_init_wrapper(); \ + } \ + PyObject *pybind11_init_wrapper() #endif #if PY_VERSION_HEX >= 0x03050000 && PY_VERSION_HEX < 0x03050200 @@ -155,6 +188,19 @@ extern "C" { #define PYBIND11_INTERNALS_ID "__pybind11_" \ PYBIND11_TOSTRING(PYBIND11_VERSION_MAJOR) "_" PYBIND11_TOSTRING(PYBIND11_VERSION_MINOR) "__" +/** \rst + This macro creates the entry point that will be invoked when the Python interpreter + imports a plugin library. Please create a `module` in the function body and return + the pointer to its underlying Python object at the end. + + .. code-block:: cpp + + PYBIND11_PLUGIN(example) { + pybind11::module m("example", "pybind11 example plugin"); + /// Set up bindings here + return m.ptr(); + } +\endrst */ #define PYBIND11_PLUGIN(name) \ static PyObject *pybind11_init(); \ PYBIND11_PLUGIN_IMPL(name) { \ @@ -172,6 +218,10 @@ extern "C" { } \ try { \ return pybind11_init(); \ + } catch (pybind11::error_already_set &e) { \ + e.clear(); \ + PyErr_SetString(PyExc_ImportError, e.what()); \ + return nullptr; \ } catch (const std::exception &e) { \ PyErr_SetString(PyExc_ImportError, e.what()); \ return nullptr; \ @@ -327,7 +377,7 @@ struct overload_hash { } }; -/// Internal data struture used to track registered instances and types +/// Internal data structure used to track registered instances and types struct internals { std::unordered_map<std::type_index, void*> registered_types_cpp; // std::type_index -> type_info std::unordered_map<const void *, void*> registered_types_py; // PyTypeObject* -> type_info @@ -336,17 +386,34 @@ struct internals { std::unordered_map<std::type_index, std::vector<bool (*)(PyObject *, void *&)>> direct_conversions; std::forward_list<void (*) (std::exception_ptr)> registered_exception_translators; std::unordered_map<std::string, void *> shared_data; // Custom data to be shared across extensions + PyTypeObject *static_property_type; + PyTypeObject *default_metaclass; + std::unordered_map<size_t, PyObject *> bases; // one base type per `instance_size` (very few) #if defined(WITH_THREAD) decltype(PyThread_create_key()) tstate = 0; // Usually an int but a long on Cygwin64 with Python 3.x PyInterpreterState *istate = nullptr; #endif + + /// Return the appropriate base type for the given instance size + PyObject *get_base(size_t instance_size); }; /// Return a reference to the current 'internals' information inline internals &get_internals(); -/// Index sequence for convenient template metaprogramming involving tuples +/// from __cpp_future__ import (convenient aliases from C++14/17) #ifdef PYBIND11_CPP14 +using std::enable_if_t; +using std::conditional_t; +using std::remove_cv_t; +#else +template <bool B, typename T = void> using enable_if_t = typename std::enable_if<B, T>::type; +template <bool B, typename T, typename F> using conditional_t = typename std::conditional<B, T, F>::type; +template <typename T> using remove_cv_t = typename std::remove_cv<T>::type; +#endif + +/// Index sequences +#if defined(PYBIND11_CPP14) || defined(_MSC_VER) using std::index_sequence; using std::make_index_sequence; #else @@ -356,6 +423,35 @@ template<size_t ...S> struct make_index_sequence_impl <0, S...> { typedef index_ template<size_t N> using make_index_sequence = typename make_index_sequence_impl<N>::type; #endif +/// Backports of std::bool_constant and std::negation to accomodate older compilers +template <bool B> using bool_constant = std::integral_constant<bool, B>; +template <typename T> struct negation : bool_constant<!T::value> { }; + +template <typename...> struct void_t_impl { using type = void; }; +template <typename... Ts> using void_t = typename void_t_impl<Ts...>::type; + +/// Compile-time all/any/none of that check the boolean value of all template types +#ifdef __cpp_fold_expressions +template <class... Ts> using all_of = bool_constant<(Ts::value && ...)>; +template <class... Ts> using any_of = bool_constant<(Ts::value || ...)>; +#elif !defined(_MSC_VER) +template <bool...> struct bools {}; +template <class... Ts> using all_of = std::is_same< + bools<Ts::value..., true>, + bools<true, Ts::value...>>; +template <class... Ts> using any_of = negation<all_of<negation<Ts>...>>; +#else +// MSVC has trouble with the above, but supports std::conjunction, which we can use instead (albeit +// at a slight loss of compilation efficiency). +template <class... Ts> using all_of = std::conjunction<Ts...>; +template <class... Ts> using any_of = std::disjunction<Ts...>; +#endif +template <class... Ts> using none_of = negation<any_of<Ts...>>; + +template <class T, template<class> class... Predicates> using satisfies_all_of = all_of<Predicates<T>...>; +template <class T, template<class> class... Predicates> using satisfies_any_of = any_of<Predicates<T>...>; +template <class T, template<class> class... Predicates> using satisfies_none_of = none_of<Predicates<T>...>; + /// Strip the class from a method type template <typename T> struct remove_class { }; template <typename C, typename R, typename... A> struct remove_class<R (C::*)(A...)> { typedef R type(A...); }; @@ -377,34 +473,34 @@ struct void_type { }; /// Helper template which holds a list of types template <typename...> struct type_list { }; -/// from __cpp_future__ import (convenient aliases from C++14/17) -template <bool B> using bool_constant = std::integral_constant<bool, B>; -template <class T> using negation = bool_constant<!T::value>; -template <bool B, typename T = void> using enable_if_t = typename std::enable_if<B, T>::type; -template <bool B, typename T, typename F> using conditional_t = typename std::conditional<B, T, F>::type; - /// Compile-time integer sum +#ifdef __cpp_fold_expressions +template <typename... Ts> constexpr size_t constexpr_sum(Ts... ns) { return (0 + ... + size_t{ns}); } +#else constexpr size_t constexpr_sum() { return 0; } template <typename T, typename... Ts> constexpr size_t constexpr_sum(T n, Ts... ns) { return size_t{n} + constexpr_sum(ns...); } - -// Counts the number of types in the template parameter pack matching the predicate -#if !defined(_MSC_VER) -template <template<typename> class Predicate, typename... Ts> -using count_t = std::integral_constant<size_t, constexpr_sum(Predicate<Ts>::value...)>; -#else -// MSVC workaround (2015 Update 3 has issues with some member type aliases and constexpr) -template <template<typename> class Predicate, typename... Ts> struct count_t; -template <template<typename> class Predicate> struct count_t<Predicate> : std::integral_constant<size_t, 0> {}; -template <template<typename> class Predicate, class T, class... Ts> -struct count_t<Predicate, T, Ts...> : std::integral_constant<size_t, Predicate<T>::value + count_t<Predicate, Ts...>::value> {}; #endif -/// Return true if all/any Ts satify Predicate<T> +NAMESPACE_BEGIN(constexpr_impl) +/// Implementation details for constexpr functions +constexpr int first(int i) { return i; } +template <typename T, typename... Ts> +constexpr int first(int i, T v, Ts... vs) { return v ? i : first(i + 1, vs...); } + +constexpr int last(int /*i*/, int result) { return result; } +template <typename T, typename... Ts> +constexpr int last(int i, int result, T v, Ts... vs) { return last(i + 1, v ? i : result, vs...); } +NAMESPACE_END(constexpr_impl) + +/// Return the index of the first type in Ts which satisfies Predicate<T>. Returns sizeof...(Ts) if +/// none match. template <template<typename> class Predicate, typename... Ts> -using all_of_t = bool_constant<(count_t<Predicate, Ts...>::value == sizeof...(Ts))>; +constexpr int constexpr_first() { return constexpr_impl::first(0, Predicate<Ts>::value...); } + +/// Return the index of the last type in Ts which satisfies Predicate<T>, or -1 if none match. template <template<typename> class Predicate, typename... Ts> -using any_of_t = bool_constant<(count_t<Predicate, Ts...>::value > 0)>; +constexpr int constexpr_last() { return constexpr_impl::last(0, -1, Predicate<Ts>::value...); } // Extracts the first type from the template parameter pack matching the predicate, or Default if none match. template <template<class> class Predicate, class Default, class... Ts> struct first_of; @@ -435,9 +531,9 @@ struct is_template_base_of_impl { /// `is_template_base_of<Base, T>` is true if `struct T : Base<U> {}` where U can be anything template <template<typename...> class Base, typename T> #if !defined(_MSC_VER) -using is_template_base_of = decltype(is_template_base_of_impl<Base>::check((T*)nullptr)); +using is_template_base_of = decltype(is_template_base_of_impl<Base>::check((remove_cv_t<T>*)nullptr)); #else // MSVC2015 has trouble with decltype in template aliases -struct is_template_base_of : decltype(is_template_base_of_impl<Base>::check((T*)nullptr)) { }; +struct is_template_base_of : decltype(is_template_base_of_impl<Base>::check((remove_cv_t<T>*)nullptr)) { }; #endif /// Check if T is std::shared_ptr<U> where U can be anything @@ -498,6 +594,9 @@ public: /// Give the error back to Python void restore() { PyErr_Restore(type, value, trace); type = value = trace = nullptr; } + /// Clear the held Python error state (the C++ `what()` message remains intact) + void clear() { restore(); PyErr_Clear(); } + private: PyObject *type, *value, *trace; }; @@ -506,7 +605,8 @@ private: class builtin_exception : public std::runtime_error { public: using std::runtime_error::runtime_error; - virtual void set_error() const = 0; /// Set the error using the Python C API + /// Set the error using the Python C API + virtual void set_error() const = 0; }; #define PYBIND11_RUNTIME_EXCEPTION(name, type) \ @@ -527,21 +627,49 @@ PYBIND11_RUNTIME_EXCEPTION(reference_cast_error, PyExc_RuntimeError) /// Used in [[noreturn]] PYBIND11_NOINLINE inline void pybind11_fail(const char *reason) { throw std::runtime_error(reason); } [[noreturn]] PYBIND11_NOINLINE inline void pybind11_fail(const std::string &reason) { throw std::runtime_error(reason); } -/// Format strings for basic number types -#define PYBIND11_DECL_FMT(t, v) template<> struct format_descriptor<t> \ - { static constexpr const char* value = v; /* for backwards compatibility */ \ - static std::string format() { return value; } } - template <typename T, typename SFINAE = void> struct format_descriptor { }; -template <typename T> struct format_descriptor<T, detail::enable_if_t<std::is_integral<T>::value>> { - static constexpr const char c = "bBhHiIqQ"[detail::log2(sizeof(T))*2 + std::is_unsigned<T>::value]; +NAMESPACE_BEGIN(detail) +// Returns the index of the given type in the type char array below, and in the list in numpy.h +// The order here is: bool; 8 ints ((signed,unsigned)x(8,16,32,64)bits); float,double,long double; +// complex float,double,long double. Note that the long double types only participate when long +// double is actually longer than double (it isn't under MSVC). +// NB: not only the string below but also complex.h and numpy.h rely on this order. +template <typename T, typename SFINAE = void> struct is_fmt_numeric { static constexpr bool value = false; }; +template <typename T> struct is_fmt_numeric<T, enable_if_t<std::is_arithmetic<T>::value>> { + static constexpr bool value = true; + static constexpr int index = std::is_same<T, bool>::value ? 0 : 1 + ( + std::is_integral<T>::value ? detail::log2(sizeof(T))*2 + std::is_unsigned<T>::value : 8 + ( + std::is_same<T, double>::value ? 1 : std::is_same<T, long double>::value ? 2 : 0)); +}; +NAMESPACE_END(detail) + +template <typename T> struct format_descriptor<T, detail::enable_if_t<detail::is_fmt_numeric<T>::value>> { + static constexpr const char c = "?bBhHiIqQfdgFDG"[detail::is_fmt_numeric<T>::index]; static constexpr const char value[2] = { c, '\0' }; static std::string format() { return std::string(1, c); } }; template <typename T> constexpr const char format_descriptor< - T, detail::enable_if_t<std::is_integral<T>::value>>::value[2]; + T, detail::enable_if_t<detail::is_fmt_numeric<T>::value>>::value[2]; + +NAMESPACE_BEGIN(detail) + +template <typename T, typename SFINAE = void> struct compare_buffer_info { + static bool compare(const buffer_info& b) { + return b.format == format_descriptor<T>::format() && b.itemsize == sizeof(T); + } +}; + +template <typename T> struct compare_buffer_info<T, detail::enable_if_t<std::is_integral<T>::value>> { + static bool compare(const buffer_info& b) { + return b.itemsize == sizeof(T) && (b.format == format_descriptor<T>::value || + ((sizeof(T) == sizeof(long)) && b.format == (std::is_unsigned<T>::value ? "L" : "l")) || + ((sizeof(T) == sizeof(size_t)) && b.format == (std::is_unsigned<T>::value ? "N" : "n"))); + } +}; + +NAMESPACE_END(detail) /// RAII wrapper that temporarily clears any Python error state struct error_scope { @@ -550,16 +678,11 @@ struct error_scope { ~error_scope() { PyErr_Restore(type, value, trace); } }; -PYBIND11_DECL_FMT(float, "f"); -PYBIND11_DECL_FMT(double, "d"); -PYBIND11_DECL_FMT(bool, "?"); - /// Dummy destructor wrapper that can be used to expose classes with a private destructor struct nodelete { template <typename T> void operator()(T*) { } }; -// overload_cast requires variable templates: C++14 or MSVC 2015 Update 2 -#if defined(PYBIND11_CPP14) || ( \ - defined(_MSC_FULL_VER) &&_MSC_FULL_VER >= 190023918) +// overload_cast requires variable templates: C++14 or MSVC +#if defined(PYBIND11_CPP14) || defined(_MSC_VER) #define PYBIND11_OVERLOAD_CAST 1 NAMESPACE_BEGIN(detail) diff --git a/ext/pybind11/include/pybind11/complex.h b/ext/pybind11/include/pybind11/complex.h index f767f354c..945ca0710 100644 --- a/ext/pybind11/include/pybind11/complex.h +++ b/ext/pybind11/include/pybind11/complex.h @@ -18,16 +18,21 @@ #endif NAMESPACE_BEGIN(pybind11) +NAMESPACE_BEGIN(detail) -PYBIND11_DECL_FMT(std::complex<float>, "Zf"); -PYBIND11_DECL_FMT(std::complex<double>, "Zd"); +// The format codes are already in the string in common.h, we just need to provide a specialization +template <typename T> struct is_fmt_numeric<std::complex<T>> { + static constexpr bool value = true; + static constexpr int index = is_fmt_numeric<T>::index + 3; +}; -NAMESPACE_BEGIN(detail) template <typename T> class type_caster<std::complex<T>> { public: - bool load(handle src, bool) { + bool load(handle src, bool convert) { if (!src) return false; + if (!convert && !PyComplex_Check(src.ptr())) + return false; Py_complex result = PyComplex_AsCComplex(src.ptr()); if (result.real == -1.0 && PyErr_Occurred()) { PyErr_Clear(); diff --git a/ext/pybind11/include/pybind11/eigen.h b/ext/pybind11/include/pybind11/eigen.h index 0a1208e16..6abe8c48f 100644 --- a/ext/pybind11/include/pybind11/eigen.h +++ b/ext/pybind11/include/pybind11/eigen.h @@ -17,158 +17,506 @@ # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wconversion" # pragma GCC diagnostic ignored "-Wdeprecated-declarations" +# if __GNUC__ >= 7 +# pragma GCC diagnostic ignored "-Wint-in-bool-context" +# endif #endif #include <Eigen/Core> #include <Eigen/SparseCore> -#if defined(__GNUG__) || defined(__clang__) -# pragma GCC diagnostic pop -#endif - #if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable: 4127) // warning C4127: Conditional expression is constant +# pragma warning(push) +# pragma warning(disable: 4127) // warning C4127: Conditional expression is constant #endif +// Eigen prior to 3.2.7 doesn't have proper move constructors--but worse, some classes get implicit +// move constructors that break things. We could detect this an explicitly copy, but an extra copy +// of matrices seems highly undesirable. +static_assert(EIGEN_VERSION_AT_LEAST(3,2,7), "Eigen support in pybind11 requires Eigen >= 3.2.7"); + NAMESPACE_BEGIN(pybind11) + +// Provide a convenience alias for easier pass-by-ref usage with fully dynamic strides: +using EigenDStride = Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic>; +template <typename MatrixType> using EigenDRef = Eigen::Ref<MatrixType, 0, EigenDStride>; +template <typename MatrixType> using EigenDMap = Eigen::Map<MatrixType, 0, EigenDStride>; + NAMESPACE_BEGIN(detail) -template <typename T> using is_eigen_dense = is_template_base_of<Eigen::DenseBase, T>; -template <typename T> using is_eigen_sparse = is_template_base_of<Eigen::SparseMatrixBase, T>; -template <typename T> using is_eigen_ref = is_template_base_of<Eigen::RefBase, T>; +#if EIGEN_VERSION_AT_LEAST(3,3,0) +using EigenIndex = Eigen::Index; +#else +using EigenIndex = EIGEN_DEFAULT_DENSE_INDEX_TYPE; +#endif +// Matches Eigen::Map, Eigen::Ref, blocks, etc: +template <typename T> using is_eigen_dense_map = all_of<is_template_base_of<Eigen::DenseBase, T>, std::is_base_of<Eigen::MapBase<T, Eigen::ReadOnlyAccessors>, T>>; +template <typename T> using is_eigen_mutable_map = std::is_base_of<Eigen::MapBase<T, Eigen::WriteAccessors>, T>; +template <typename T> using is_eigen_dense_plain = all_of<negation<is_eigen_dense_map<T>>, is_template_base_of<Eigen::PlainObjectBase, T>>; +template <typename T> using is_eigen_sparse = is_template_base_of<Eigen::SparseMatrixBase, T>; // Test for objects inheriting from EigenBase<Derived> that aren't captured by the above. This // basically covers anything that can be assigned to a dense matrix but that don't have a typical // matrix data layout that can be copied from their .data(). For example, DiagonalMatrix and // SelfAdjointView fall into this category. -template <typename T> using is_eigen_base = bool_constant< - is_template_base_of<Eigen::EigenBase, T>::value - && !is_eigen_dense<T>::value && !is_eigen_sparse<T>::value +template <typename T> using is_eigen_other = all_of< + is_template_base_of<Eigen::EigenBase, T>, + negation<any_of<is_eigen_dense_map<T>, is_eigen_dense_plain<T>, is_eigen_sparse<T>>> >; +// Captures numpy/eigen conformability status (returned by EigenProps::conformable()): +template <bool EigenRowMajor> struct EigenConformable { + bool conformable = false; + EigenIndex rows = 0, cols = 0; + EigenDStride stride{0, 0}; + + EigenConformable(bool fits = false) : conformable{fits} {} + // Matrix type: + EigenConformable(EigenIndex r, EigenIndex c, + EigenIndex rstride, EigenIndex cstride) : + conformable{true}, rows{r}, cols{c}, + stride(EigenRowMajor ? rstride : cstride /* outer stride */, + EigenRowMajor ? cstride : rstride /* inner stride */) + {} + // Vector type: + EigenConformable(EigenIndex r, EigenIndex c, EigenIndex stride) + : EigenConformable(r, c, r == 1 ? c*stride : stride, c == 1 ? r : r*stride) {} + + template <typename props> bool stride_compatible() const { + // To have compatible strides, we need (on both dimensions) one of fully dynamic strides, + // matching strides, or a dimension size of 1 (in which case the stride value is irrelevant) + return + (props::inner_stride == Eigen::Dynamic || props::inner_stride == stride.inner() || + (EigenRowMajor ? cols : rows) == 1) && + (props::outer_stride == Eigen::Dynamic || props::outer_stride == stride.outer() || + (EigenRowMajor ? rows : cols) == 1); + } + operator bool() const { return conformable; } +}; + +template <typename Type> struct eigen_extract_stride { using type = Type; }; +template <typename PlainObjectType, int MapOptions, typename StrideType> +struct eigen_extract_stride<Eigen::Map<PlainObjectType, MapOptions, StrideType>> { using type = StrideType; }; +template <typename PlainObjectType, int Options, typename StrideType> +struct eigen_extract_stride<Eigen::Ref<PlainObjectType, Options, StrideType>> { using type = StrideType; }; + +// Helper struct for extracting information from an Eigen type +template <typename Type_> struct EigenProps { + using Type = Type_; + using Scalar = typename Type::Scalar; + using StrideType = typename eigen_extract_stride<Type>::type; + static constexpr EigenIndex + rows = Type::RowsAtCompileTime, + cols = Type::ColsAtCompileTime, + size = Type::SizeAtCompileTime; + static constexpr bool + row_major = Type::IsRowMajor, + vector = Type::IsVectorAtCompileTime, // At least one dimension has fixed size 1 + fixed_rows = rows != Eigen::Dynamic, + fixed_cols = cols != Eigen::Dynamic, + fixed = size != Eigen::Dynamic, // Fully-fixed size + dynamic = !fixed_rows && !fixed_cols; // Fully-dynamic size + + template <EigenIndex i, EigenIndex ifzero> using if_zero = std::integral_constant<EigenIndex, i == 0 ? ifzero : i>; + static constexpr EigenIndex inner_stride = if_zero<StrideType::InnerStrideAtCompileTime, 1>::value, + outer_stride = if_zero<StrideType::OuterStrideAtCompileTime, + vector ? size : row_major ? cols : rows>::value; + static constexpr bool dynamic_stride = inner_stride == Eigen::Dynamic && outer_stride == Eigen::Dynamic; + static constexpr bool requires_row_major = !dynamic_stride && !vector && (row_major ? inner_stride : outer_stride) == 1; + static constexpr bool requires_col_major = !dynamic_stride && !vector && (row_major ? outer_stride : inner_stride) == 1; + + // Takes an input array and determines whether we can make it fit into the Eigen type. If + // the array is a vector, we attempt to fit it into either an Eigen 1xN or Nx1 vector + // (preferring the latter if it will fit in either, i.e. for a fully dynamic matrix type). + static EigenConformable<row_major> conformable(const array &a) { + const auto dims = a.ndim(); + if (dims < 1 || dims > 2) + return false; + + if (dims == 2) { // Matrix type: require exact match (or dynamic) + + EigenIndex + np_rows = a.shape(0), + np_cols = a.shape(1), + np_rstride = a.strides(0) / sizeof(Scalar), + np_cstride = a.strides(1) / sizeof(Scalar); + if ((fixed_rows && np_rows != rows) || (fixed_cols && np_cols != cols)) + return false; + + return {np_rows, np_cols, np_rstride, np_cstride}; + } + + // Otherwise we're storing an n-vector. Only one of the strides will be used, but whichever + // is used, we want the (single) numpy stride value. + const EigenIndex n = a.shape(0), + stride = a.strides(0) / sizeof(Scalar); + + if (vector) { // Eigen type is a compile-time vector + if (fixed && size != n) + return false; // Vector size mismatch + return {rows == 1 ? 1 : n, cols == 1 ? 1 : n, stride}; + } + else if (fixed) { + // The type has a fixed size, but is not a vector: abort + return false; + } + else if (fixed_cols) { + // Since this isn't a vector, cols must be != 1. We allow this only if it exactly + // equals the number of elements (rows is Dynamic, and so 1 row is allowed). + if (cols != n) return false; + return {1, n, stride}; + } + else { + // Otherwise it's either fully dynamic, or column dynamic; both become a column vector + if (fixed_rows && rows != n) return false; + return {n, 1, stride}; + } + } + + static PYBIND11_DESCR descriptor() { + constexpr bool show_writeable = is_eigen_dense_map<Type>::value && is_eigen_mutable_map<Type>::value; + constexpr bool show_order = is_eigen_dense_map<Type>::value; + constexpr bool show_c_contiguous = show_order && requires_row_major; + constexpr bool show_f_contiguous = !show_c_contiguous && show_order && requires_col_major; + + return _("numpy.ndarray[") + npy_format_descriptor<Scalar>::name() + + _("[") + _<fixed_rows>(_<(size_t) rows>(), _("m")) + + _(", ") + _<fixed_cols>(_<(size_t) cols>(), _("n")) + + _("]") + + // For a reference type (e.g. Ref<MatrixXd>) we have other constraints that might need to be + // satisfied: writeable=True (for a mutable reference), and, depending on the map's stride + // options, possibly f_contiguous or c_contiguous. We include them in the descriptor output + // to provide some hint as to why a TypeError is occurring (otherwise it can be confusing to + // see that a function accepts a 'numpy.ndarray[float64[3,2]]' and an error message that you + // *gave* a numpy.ndarray of the right type and dimensions. + _<show_writeable>(", flags.writeable", "") + + _<show_c_contiguous>(", flags.c_contiguous", "") + + _<show_f_contiguous>(", flags.f_contiguous", "") + + _("]"); + } +}; + +// Casts an Eigen type to numpy array. If given a base, the numpy array references the src data, +// otherwise it'll make a copy. writeable lets you turn off the writeable flag for the array. +template <typename props> handle eigen_array_cast(typename props::Type const &src, handle base = handle(), bool writeable = true) { + constexpr size_t elem_size = sizeof(typename props::Scalar); + std::vector<size_t> shape, strides; + if (props::vector) { + shape.push_back(src.size()); + strides.push_back(elem_size * src.innerStride()); + } + else { + shape.push_back(src.rows()); + shape.push_back(src.cols()); + strides.push_back(elem_size * src.rowStride()); + strides.push_back(elem_size * src.colStride()); + } + array a(std::move(shape), std::move(strides), src.data(), base); + if (!writeable) + array_proxy(a.ptr())->flags &= ~detail::npy_api::NPY_ARRAY_WRITEABLE_; + + return a.release(); +} + +// Takes an lvalue ref to some Eigen type and a (python) base object, creating a numpy array that +// reference the Eigen object's data with `base` as the python-registered base class (if omitted, +// the base will be set to None, and lifetime management is up to the caller). The numpy array is +// non-writeable if the given type is const. +template <typename props, typename Type> +handle eigen_ref_array(Type &src, handle parent = none()) { + // none here is to get past array's should-we-copy detection, which currently always + // copies when there is no base. Setting the base to None should be harmless. + return eigen_array_cast<props>(src, parent, !std::is_const<Type>::value); +} + +// Takes a pointer to some dense, plain Eigen type, builds a capsule around it, then returns a numpy +// array that references the encapsulated data with a python-side reference to the capsule to tie +// its destruction to that of any dependent python objects. Const-ness is determined by whether or +// not the Type of the pointer given is const. +template <typename props, typename Type, typename = enable_if_t<is_eigen_dense_plain<Type>::value>> +handle eigen_encapsulate(Type *src) { + capsule base(src, [](void *o) { delete static_cast<Type *>(o); }); + return eigen_ref_array<props>(*src, base); +} + +// Type caster for regular, dense matrix types (e.g. MatrixXd), but not maps/refs/etc. of dense +// types. template<typename Type> -struct type_caster<Type, enable_if_t<is_eigen_dense<Type>::value && !is_eigen_ref<Type>::value>> { - typedef typename Type::Scalar Scalar; - static constexpr bool rowMajor = Type::Flags & Eigen::RowMajorBit; - static constexpr bool isVector = Type::IsVectorAtCompileTime; +struct type_caster<Type, enable_if_t<is_eigen_dense_plain<Type>::value>> { + using Scalar = typename Type::Scalar; + using props = EigenProps<Type>; bool load(handle src, bool) { auto buf = array_t<Scalar>::ensure(src); if (!buf) return false; - if (buf.ndim() == 1) { - typedef Eigen::InnerStride<> Strides; - if (!isVector && - !(Type::RowsAtCompileTime == Eigen::Dynamic && - Type::ColsAtCompileTime == Eigen::Dynamic)) - return false; + auto dims = buf.ndim(); + if (dims < 1 || dims > 2) + return false; - if (Type::SizeAtCompileTime != Eigen::Dynamic && - buf.shape(0) != (size_t) Type::SizeAtCompileTime) - return false; + auto fits = props::conformable(buf); + if (!fits) + return false; // Non-comformable vector/matrix types - Strides::Index n_elts = (Strides::Index) buf.shape(0); - Strides::Index unity = 1; + value = Eigen::Map<const Type, 0, EigenDStride>(buf.data(), fits.rows, fits.cols, fits.stride); - value = Eigen::Map<Type, 0, Strides>( - buf.mutable_data(), - rowMajor ? unity : n_elts, - rowMajor ? n_elts : unity, - Strides(buf.strides(0) / sizeof(Scalar)) - ); - } else if (buf.ndim() == 2) { - typedef Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic> Strides; + return true; + } - if ((Type::RowsAtCompileTime != Eigen::Dynamic && buf.shape(0) != (size_t) Type::RowsAtCompileTime) || - (Type::ColsAtCompileTime != Eigen::Dynamic && buf.shape(1) != (size_t) Type::ColsAtCompileTime)) - return false; +private: + + // Cast implementation + template <typename CType> + static handle cast_impl(CType *src, return_value_policy policy, handle parent) { + switch (policy) { + case return_value_policy::take_ownership: + case return_value_policy::automatic: + return eigen_encapsulate<props>(src); + case return_value_policy::move: + return eigen_encapsulate<props>(new CType(std::move(*src))); + case return_value_policy::copy: + return eigen_array_cast<props>(*src); + case return_value_policy::reference: + case return_value_policy::automatic_reference: + return eigen_ref_array<props>(*src); + case return_value_policy::reference_internal: + return eigen_ref_array<props>(*src, parent); + default: + throw cast_error("unhandled return_value_policy: should not happen!"); + }; + } - value = Eigen::Map<Type, 0, Strides>( - buf.mutable_data(), - typename Strides::Index(buf.shape(0)), - typename Strides::Index(buf.shape(1)), - Strides(buf.strides(rowMajor ? 0 : 1) / sizeof(Scalar), - buf.strides(rowMajor ? 1 : 0) / sizeof(Scalar)) - ); - } else { - return false; - } - return true; +public: + + // Normal returned non-reference, non-const value: + static handle cast(Type &&src, return_value_policy /* policy */, handle parent) { + return cast_impl(&src, return_value_policy::move, parent); + } + // If you return a non-reference const, we mark the numpy array readonly: + static handle cast(const Type &&src, return_value_policy /* policy */, handle parent) { + return cast_impl(&src, return_value_policy::move, parent); + } + // lvalue reference return; default (automatic) becomes copy + static handle cast(Type &src, return_value_policy policy, handle parent) { + if (policy == return_value_policy::automatic || policy == return_value_policy::automatic_reference) + policy = return_value_policy::copy; + return cast_impl(&src, policy, parent); + } + // const lvalue reference return; default (automatic) becomes copy + static handle cast(const Type &src, return_value_policy policy, handle parent) { + if (policy == return_value_policy::automatic || policy == return_value_policy::automatic_reference) + policy = return_value_policy::copy; + return cast(&src, policy, parent); + } + // non-const pointer return + static handle cast(Type *src, return_value_policy policy, handle parent) { + return cast_impl(src, policy, parent); + } + // const pointer return + static handle cast(const Type *src, return_value_policy policy, handle parent) { + return cast_impl(src, policy, parent); } - static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) { - if (isVector) { - return array( - { (size_t) src.size() }, // shape - { sizeof(Scalar) * static_cast<size_t>(src.innerStride()) }, // strides - src.data() // data - ).release(); - } else { - return array( - { (size_t) src.rows(), // shape - (size_t) src.cols() }, - { sizeof(Scalar) * static_cast<size_t>(src.rowStride()), // strides - sizeof(Scalar) * static_cast<size_t>(src.colStride()) }, - src.data() // data - ).release(); + static PYBIND11_DESCR name() { return type_descr(props::descriptor()); } + + operator Type*() { return &value; } + operator Type&() { return value; } + template <typename T> using cast_op_type = cast_op_type<T>; + +private: + Type value; +}; + +// Eigen Ref/Map classes have slightly different policy requirements, meaning we don't want to force +// `move` when a Ref/Map rvalue is returned; we treat Ref<> sort of like a pointer (we care about +// the underlying data, not the outer shell). +template <typename Return> +struct return_value_policy_override<Return, enable_if_t<is_eigen_dense_map<Return>::value>> { + static return_value_policy policy(return_value_policy p) { return p; } +}; + +// Base class for casting reference/map/block/etc. objects back to python. +template <typename MapType> struct eigen_map_caster { +private: + using props = EigenProps<MapType>; + +public: + + // Directly referencing a ref/map's data is a bit dangerous (whatever the map/ref points to has + // to stay around), but we'll allow it under the assumption that you know what you're doing (and + // have an appropriate keep_alive in place). We return a numpy array pointing directly at the + // ref's data (The numpy array ends up read-only if the ref was to a const matrix type.) Note + // that this means you need to ensure you don't destroy the object in some other way (e.g. with + // an appropriate keep_alive, or with a reference to a statically allocated matrix). + static handle cast(const MapType &src, return_value_policy policy, handle parent) { + switch (policy) { + case return_value_policy::copy: + return eigen_array_cast<props>(src); + case return_value_policy::reference_internal: + return eigen_array_cast<props>(src, parent, is_eigen_mutable_map<MapType>::value); + case return_value_policy::reference: + case return_value_policy::automatic: + case return_value_policy::automatic_reference: + return eigen_array_cast<props>(src, none(), is_eigen_mutable_map<MapType>::value); + default: + // move, take_ownership don't make any sense for a ref/map: + pybind11_fail("Invalid return_value_policy for Eigen Map/Ref/Block type"); } } - PYBIND11_TYPE_CASTER(Type, _("numpy.ndarray[") + npy_format_descriptor<Scalar>::name() + - _("[") + rows() + _(", ") + cols() + _("]]")); + static PYBIND11_DESCR name() { return props::descriptor(); } -protected: - template <typename T = Type, enable_if_t<T::RowsAtCompileTime == Eigen::Dynamic, int> = 0> - static PYBIND11_DESCR rows() { return _("m"); } - template <typename T = Type, enable_if_t<T::RowsAtCompileTime != Eigen::Dynamic, int> = 0> - static PYBIND11_DESCR rows() { return _<T::RowsAtCompileTime>(); } - template <typename T = Type, enable_if_t<T::ColsAtCompileTime == Eigen::Dynamic, int> = 0> - static PYBIND11_DESCR cols() { return _("n"); } - template <typename T = Type, enable_if_t<T::ColsAtCompileTime != Eigen::Dynamic, int> = 0> - static PYBIND11_DESCR cols() { return _<T::ColsAtCompileTime>(); } + // Explicitly delete these: support python -> C++ conversion on these (i.e. these can be return + // types but not bound arguments). We still provide them (with an explicitly delete) so that + // you end up here if you try anyway. + bool load(handle, bool) = delete; + operator MapType() = delete; + template <typename> using cast_op_type = MapType; }; -// Eigen::Ref<Derived> satisfies is_eigen_dense, but isn't constructable, so it needs a special -// type_caster to handle argument copying/forwarding. -template <typename CVDerived, int Options, typename StrideType> -struct type_caster<Eigen::Ref<CVDerived, Options, StrideType>> { -protected: - using Type = Eigen::Ref<CVDerived, Options, StrideType>; - using Derived = typename std::remove_const<CVDerived>::type; - using DerivedCaster = type_caster<Derived>; - DerivedCaster derived_caster; - std::unique_ptr<Type> value; +// We can return any map-like object (but can only load Refs, specialized next): +template <typename Type> struct type_caster<Type, enable_if_t<is_eigen_dense_map<Type>::value>> + : eigen_map_caster<Type> {}; + +// Loader for Ref<...> arguments. See the documentation for info on how to make this work without +// copying (it requires some extra effort in many cases). +template <typename PlainObjectType, typename StrideType> +struct type_caster< + Eigen::Ref<PlainObjectType, 0, StrideType>, + enable_if_t<is_eigen_dense_map<Eigen::Ref<PlainObjectType, 0, StrideType>>::value> +> : public eigen_map_caster<Eigen::Ref<PlainObjectType, 0, StrideType>> { +private: + using Type = Eigen::Ref<PlainObjectType, 0, StrideType>; + using props = EigenProps<Type>; + using Scalar = typename props::Scalar; + using MapType = Eigen::Map<PlainObjectType, 0, StrideType>; + using Array = array_t<Scalar, array::forcecast | + ((props::row_major ? props::inner_stride : props::outer_stride) == 1 ? array::c_style : + (props::row_major ? props::outer_stride : props::inner_stride) == 1 ? array::f_style : 0)>; + static constexpr bool need_writeable = is_eigen_mutable_map<Type>::value; + // Delay construction (these have no default constructor) + std::unique_ptr<MapType> map; + std::unique_ptr<Type> ref; + // Our array. When possible, this is just a numpy array pointing to the source data, but + // sometimes we can't avoid copying (e.g. input is not a numpy array at all, has an incompatible + // layout, or is an array of a type that needs to be converted). Using a numpy temporary + // (rather than an Eigen temporary) saves an extra copy when we need both type conversion and + // storage order conversion. (Note that we refuse to use this temporary copy when loading an + // argument for a Ref<M> with M non-const, i.e. a read-write reference). + Array copy_or_ref; public: - bool load(handle src, bool convert) { if (derived_caster.load(src, convert)) { value.reset(new Type(derived_caster.operator Derived&())); return true; } return false; } - static handle cast(const Type &src, return_value_policy policy, handle parent) { return DerivedCaster::cast(src, policy, parent); } - static handle cast(const Type *src, return_value_policy policy, handle parent) { return DerivedCaster::cast(*src, policy, parent); } + bool load(handle src, bool convert) { + // First check whether what we have is already an array of the right type. If not, we can't + // avoid a copy (because the copy is also going to do type conversion). + bool need_copy = !isinstance<Array>(src); + + EigenConformable<props::row_major> fits; + if (!need_copy) { + // We don't need a converting copy, but we also need to check whether the strides are + // compatible with the Ref's stride requirements + Array aref = reinterpret_borrow<Array>(src); + + if (aref && (!need_writeable || aref.writeable())) { + fits = props::conformable(aref); + if (!fits) return false; // Incompatible dimensions + if (!fits.template stride_compatible<props>()) + need_copy = true; + else + copy_or_ref = std::move(aref); + } + else { + need_copy = true; + } + } + + if (need_copy) { + // We need to copy: If we need a mutable reference, or we're not supposed to convert + // (either because we're in the no-convert overload pass, or because we're explicitly + // instructed not to copy (via `py::arg().noconvert()`) we have to fail loading. + if (!convert || need_writeable) return false; + + Array copy = Array::ensure(src); + if (!copy) return false; + fits = props::conformable(copy); + if (!fits || !fits.template stride_compatible<props>()) + return false; + copy_or_ref = std::move(copy); + } + + ref.reset(); + map.reset(new MapType(data(copy_or_ref), fits.rows, fits.cols, make_stride(fits.stride.outer(), fits.stride.inner()))); + ref.reset(new Type(*map)); - static PYBIND11_DESCR name() { return DerivedCaster::name(); } + return true; + } - operator Type*() { return value.get(); } - operator Type&() { if (!value) pybind11_fail("Eigen::Ref<...> value not loaded"); return *value; } + operator Type*() { return ref.get(); } + operator Type&() { return *ref; } template <typename _T> using cast_op_type = pybind11::detail::cast_op_type<_T>; + +private: + template <typename T = Type, enable_if_t<is_eigen_mutable_map<T>::value, int> = 0> + Scalar *data(Array &a) { return a.mutable_data(); } + + template <typename T = Type, enable_if_t<!is_eigen_mutable_map<T>::value, int> = 0> + const Scalar *data(Array &a) { return a.data(); } + + // Attempt to figure out a constructor of `Stride` that will work. + // If both strides are fixed, use a default constructor: + template <typename S> using stride_ctor_default = bool_constant< + S::InnerStrideAtCompileTime != Eigen::Dynamic && S::OuterStrideAtCompileTime != Eigen::Dynamic && + std::is_default_constructible<S>::value>; + // Otherwise, if there is a two-index constructor, assume it is (outer,inner) like + // Eigen::Stride, and use it: + template <typename S> using stride_ctor_dual = bool_constant< + !stride_ctor_default<S>::value && std::is_constructible<S, EigenIndex, EigenIndex>::value>; + // Otherwise, if there is a one-index constructor, and just one of the strides is dynamic, use + // it (passing whichever stride is dynamic). + template <typename S> using stride_ctor_outer = bool_constant< + !any_of<stride_ctor_default<S>, stride_ctor_dual<S>>::value && + S::OuterStrideAtCompileTime == Eigen::Dynamic && S::InnerStrideAtCompileTime != Eigen::Dynamic && + std::is_constructible<S, EigenIndex>::value>; + template <typename S> using stride_ctor_inner = bool_constant< + !any_of<stride_ctor_default<S>, stride_ctor_dual<S>>::value && + S::InnerStrideAtCompileTime == Eigen::Dynamic && S::OuterStrideAtCompileTime != Eigen::Dynamic && + std::is_constructible<S, EigenIndex>::value>; + + template <typename S = StrideType, enable_if_t<stride_ctor_default<S>::value, int> = 0> + static S make_stride(EigenIndex, EigenIndex) { return S(); } + template <typename S = StrideType, enable_if_t<stride_ctor_dual<S>::value, int> = 0> + static S make_stride(EigenIndex outer, EigenIndex inner) { return S(outer, inner); } + template <typename S = StrideType, enable_if_t<stride_ctor_outer<S>::value, int> = 0> + static S make_stride(EigenIndex outer, EigenIndex) { return S(outer); } + template <typename S = StrideType, enable_if_t<stride_ctor_inner<S>::value, int> = 0> + static S make_stride(EigenIndex, EigenIndex inner) { return S(inner); } + }; -// type_caster for special matrix types (e.g. DiagonalMatrix): load() is not supported, but we can -// cast them into the python domain by first copying to a regular Eigen::Matrix, then casting that. +// type_caster for special matrix types (e.g. DiagonalMatrix), which are EigenBase, but not +// EigenDense (i.e. they don't have a data(), at least not with the usual matrix layout). +// load() is not supported, but we can cast them into the python domain by first copying to a +// regular Eigen::Matrix, then casting that. template <typename Type> -struct type_caster<Type, enable_if_t<is_eigen_base<Type>::value && !is_eigen_ref<Type>::value>> { +struct type_caster<Type, enable_if_t<is_eigen_other<Type>::value>> { protected: - using Matrix = Eigen::Matrix<typename Type::Scalar, Eigen::Dynamic, Eigen::Dynamic>; - using MatrixCaster = type_caster<Matrix>; + using Matrix = Eigen::Matrix<typename Type::Scalar, Type::RowsAtCompileTime, Type::ColsAtCompileTime>; + using props = EigenProps<Matrix>; public: - [[noreturn]] bool load(handle, bool) { pybind11_fail("Unable to load() into specialized EigenBase object"); } - static handle cast(const Type &src, return_value_policy policy, handle parent) { return MatrixCaster::cast(Matrix(src), policy, parent); } - static handle cast(const Type *src, return_value_policy policy, handle parent) { return MatrixCaster::cast(Matrix(*src), policy, parent); } + static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) { + handle h = eigen_encapsulate<props>(new Matrix(src)); + return h; + } + static handle cast(const Type *src, return_value_policy policy, handle parent) { return cast(*src, policy, parent); } - static PYBIND11_DESCR name() { return MatrixCaster::name(); } + static PYBIND11_DESCR name() { return props::descriptor(); } - [[noreturn]] operator Type*() { pybind11_fail("Loading not supported for specialized EigenBase object"); } - [[noreturn]] operator Type&() { pybind11_fail("Loading not supported for specialized EigenBase object"); } - template <typename _T> using cast_op_type = pybind11::detail::cast_op_type<_T>; + // Explicitly delete these: support python -> C++ conversion on these (i.e. these can be return + // types but not bound arguments). We still provide them (with an explicitly delete) so that + // you end up here if you try anyway. + bool load(handle, bool) = delete; + operator Type() = delete; + template <typename> using cast_op_type = Type; }; template<typename Type> @@ -176,7 +524,7 @@ struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> { typedef typename Type::Scalar Scalar; typedef typename std::remove_reference<decltype(*std::declval<Type>().outerIndexPtr())>::type StorageIndex; typedef typename Type::Index Index; - static constexpr bool rowMajor = Type::Flags & Eigen::RowMajorBit; + static constexpr bool rowMajor = Type::IsRowMajor; bool load(handle src, bool) { if (!src) @@ -227,13 +575,15 @@ struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> { ).release(); } - PYBIND11_TYPE_CASTER(Type, _<(Type::Flags & Eigen::RowMajorBit) != 0>("scipy.sparse.csr_matrix[", "scipy.sparse.csc_matrix[") + PYBIND11_TYPE_CASTER(Type, _<(Type::IsRowMajor) != 0>("scipy.sparse.csr_matrix[", "scipy.sparse.csc_matrix[") + npy_format_descriptor<Scalar>::name() + _("]")); }; NAMESPACE_END(detail) NAMESPACE_END(pybind11) -#if defined(_MSC_VER) -#pragma warning(pop) +#if defined(__GNUG__) || defined(__clang__) +# pragma GCC diagnostic pop +#elif defined(_MSC_VER) +# pragma warning(pop) #endif diff --git a/ext/pybind11/include/pybind11/eval.h b/ext/pybind11/include/pybind11/eval.h index 204427d77..5b2b98272 100644 --- a/ext/pybind11/include/pybind11/eval.h +++ b/ext/pybind11/include/pybind11/eval.h @@ -95,8 +95,15 @@ object eval_file(str fname, object global = object(), object local = object()) { pybind11_fail("File \"" + fname_str + "\" could not be opened!"); } +#if PY_VERSION_HEX < 0x03000000 && defined(PYPY_VERSION) + PyObject *result = PyRun_File(f, fname_str.c_str(), start, global.ptr(), + local.ptr()); + (void) closeFile; +#else PyObject *result = PyRun_FileEx(f, fname_str.c_str(), start, global.ptr(), local.ptr(), closeFile); +#endif + if (!result) throw error_already_set(); return reinterpret_steal<object>(result); diff --git a/ext/pybind11/include/pybind11/functional.h b/ext/pybind11/include/pybind11/functional.h index f1b0ebbbf..a99ee737f 100644 --- a/ext/pybind11/include/pybind11/functional.h +++ b/ext/pybind11/include/pybind11/functional.h @@ -15,9 +15,12 @@ NAMESPACE_BEGIN(pybind11) NAMESPACE_BEGIN(detail) -template <typename Return, typename... Args> struct type_caster<std::function<Return(Args...)>> { - typedef std::function<Return(Args...)> type; - typedef typename std::conditional<std::is_same<Return, void>::value, void_type, Return>::type retval_type; +template <typename Return, typename... Args> +struct type_caster<std::function<Return(Args...)>> { + using type = std::function<Return(Args...)>; + using retval_type = conditional_t<std::is_same<Return, void>::value, void_type, Return>; + using function_type = Return (*) (Args...); + public: bool load(handle src_, bool) { if (src_.is_none()) @@ -36,12 +39,11 @@ public: captured variables), in which case the roundtrip can be avoided. */ if (PyCFunction_Check(src_.ptr())) { - auto c = reinterpret_borrow<capsule>(PyCFunction_GetSelf(src_.ptr())); + auto c = reinterpret_borrow<capsule>(PyCFunction_GET_SELF(src_.ptr())); auto rec = (function_record *) c; - using FunctionType = Return (*) (Args...); - if (rec && rec->is_stateless && rec->data[1] == &typeid(FunctionType)) { - struct capture { FunctionType f; }; + if (rec && rec->is_stateless && rec->data[1] == &typeid(function_type)) { + struct capture { function_type f; }; value = ((capture *) &rec->data)->f; return true; } @@ -50,7 +52,7 @@ public: auto src = reinterpret_borrow<object>(src_); value = [src](Args... args) -> Return { gil_scoped_acquire acq; - object retval(src(std::move(args)...)); + object retval(src(std::forward<Args>(args)...)); /* Visual studio 2015 parser issue: need parentheses around this expression */ return (retval.template cast<Return>()); }; @@ -62,7 +64,7 @@ public: if (!f_) return none().inc_ref(); - auto result = f_.template target<Return (*)(Args...)>(); + auto result = f_.template target<function_type>(); if (result) return cpp_function(*result, policy).release(); else @@ -71,7 +73,7 @@ public: PYBIND11_TYPE_CASTER(type, _("Callable[[") + argument_loader<Args...>::arg_names() + _("], ") + - type_caster<retval_type>::name() + + make_caster<retval_type>::name() + _("]")); }; diff --git a/ext/pybind11/include/pybind11/numpy.h b/ext/pybind11/include/pybind11/numpy.h index e6f4efdf9..3227a12eb 100644 --- a/ext/pybind11/include/pybind11/numpy.h +++ b/ext/pybind11/include/pybind11/numpy.h @@ -35,9 +35,11 @@ static_assert(sizeof(size_t) == sizeof(Py_intptr_t), "size_t != Py_intptr_t"); NAMESPACE_BEGIN(pybind11) + +class array; // Forward declaration + NAMESPACE_BEGIN(detail) -template <typename type, typename SFINAE = void> struct npy_format_descriptor { }; -template <typename type> struct is_pod_struct; +template <typename type, typename SFINAE = void> struct npy_format_descriptor; struct PyArrayDescr_Proxy { PyObject_HEAD @@ -108,11 +110,11 @@ inline numpy_internals& get_numpy_internals() { struct npy_api { enum constants { - NPY_C_CONTIGUOUS_ = 0x0001, - NPY_F_CONTIGUOUS_ = 0x0002, + NPY_ARRAY_C_CONTIGUOUS_ = 0x0001, + NPY_ARRAY_F_CONTIGUOUS_ = 0x0002, NPY_ARRAY_OWNDATA_ = 0x0004, NPY_ARRAY_FORCECAST_ = 0x0010, - NPY_ENSURE_ARRAY_ = 0x0040, + NPY_ARRAY_ENSUREARRAY_ = 0x0040, NPY_ARRAY_ALIGNED_ = 0x0100, NPY_ARRAY_WRITEABLE_ = 0x0400, NPY_BOOL_ = 0, @@ -155,6 +157,7 @@ struct npy_api { int (*PyArray_GetArrayParamsFromObject_)(PyObject *, PyObject *, char, PyObject **, int *, Py_ssize_t *, PyObject **, PyObject *); PyObject *(*PyArray_Squeeze_)(PyObject *); + int (*PyArray_SetBaseObject_)(PyObject *, PyObject *); private: enum functions { API_PyArray_Type = 2, @@ -169,7 +172,8 @@ private: API_PyArray_DescrConverter = 174, API_PyArray_EquivTypes = 182, API_PyArray_GetArrayParamsFromObject = 278, - API_PyArray_Squeeze = 136 + API_PyArray_Squeeze = 136, + API_PyArray_SetBaseObject = 282 }; static npy_api lookup() { @@ -195,6 +199,7 @@ private: DECL_NPY_API(PyArray_EquivTypes); DECL_NPY_API(PyArray_GetArrayParamsFromObject); DECL_NPY_API(PyArray_Squeeze); + DECL_NPY_API(PyArray_SetBaseObject); #undef DECL_NPY_API return api; } @@ -220,6 +225,128 @@ inline bool check_flags(const void* ptr, int flag) { return (flag == (array_proxy(ptr)->flags & flag)); } +template <typename T> struct is_std_array : std::false_type { }; +template <typename T, size_t N> struct is_std_array<std::array<T, N>> : std::true_type { }; +template <typename T> struct is_complex : std::false_type { }; +template <typename T> struct is_complex<std::complex<T>> : std::true_type { }; + +template <typename T> using is_pod_struct = all_of< + std::is_pod<T>, // since we're accessing directly in memory we need a POD type + satisfies_none_of<T, std::is_reference, std::is_array, is_std_array, std::is_arithmetic, is_complex, std::is_enum> +>; + +template <size_t Dim = 0, typename Strides> size_t byte_offset_unsafe(const Strides &) { return 0; } +template <size_t Dim = 0, typename Strides, typename... Ix> +size_t byte_offset_unsafe(const Strides &strides, size_t i, Ix... index) { + return i * strides[Dim] + byte_offset_unsafe<Dim + 1>(strides, index...); +} + +/** Proxy class providing unsafe, unchecked const access to array data. This is constructed through + * the `unchecked<T, N>()` method of `array` or the `unchecked<N>()` method of `array_t<T>`. `Dims` + * will be -1 for dimensions determined at runtime. + */ +template <typename T, ssize_t Dims> +class unchecked_reference { +protected: + static constexpr bool Dynamic = Dims < 0; + const unsigned char *data_; + // Storing the shape & strides in local variables (i.e. these arrays) allows the compiler to + // make large performance gains on big, nested loops, but requires compile-time dimensions + conditional_t<Dynamic, const size_t *, std::array<size_t, (size_t) Dims>> + shape_, strides_; + const size_t dims_; + + friend class pybind11::array; + // Constructor for compile-time dimensions: + template <bool Dyn = Dynamic> + unchecked_reference(const void *data, const size_t *shape, const size_t *strides, enable_if_t<!Dyn, size_t>) + : data_{reinterpret_cast<const unsigned char *>(data)}, dims_{Dims} { + for (size_t i = 0; i < dims_; i++) { + shape_[i] = shape[i]; + strides_[i] = strides[i]; + } + } + // Constructor for runtime dimensions: + template <bool Dyn = Dynamic> + unchecked_reference(const void *data, const size_t *shape, const size_t *strides, enable_if_t<Dyn, size_t> dims) + : data_{reinterpret_cast<const unsigned char *>(data)}, shape_{shape}, strides_{strides}, dims_{dims} {} + +public: + /** Unchecked const reference access to data at the given indices. For a compile-time known + * number of dimensions, this requires the correct number of arguments; for run-time + * dimensionality, this is not checked (and so is up to the caller to use safely). + */ + template <typename... Ix> const T &operator()(Ix... index) const { + static_assert(sizeof...(Ix) == Dims || Dynamic, + "Invalid number of indices for unchecked array reference"); + return *reinterpret_cast<const T *>(data_ + byte_offset_unsafe(strides_, size_t(index)...)); + } + /** Unchecked const reference access to data; this operator only participates if the reference + * is to a 1-dimensional array. When present, this is exactly equivalent to `obj(index)`. + */ + template <size_t D = Dims, typename = enable_if_t<D == 1 || Dynamic>> + const T &operator[](size_t index) const { return operator()(index); } + + /// Pointer access to the data at the given indices. + template <typename... Ix> const T *data(Ix... ix) const { return &operator()(size_t(ix)...); } + + /// Returns the item size, i.e. sizeof(T) + constexpr static size_t itemsize() { return sizeof(T); } + + /// Returns the shape (i.e. size) of dimension `dim` + size_t shape(size_t dim) const { return shape_[dim]; } + + /// Returns the number of dimensions of the array + size_t ndim() const { return dims_; } + + /// Returns the total number of elements in the referenced array, i.e. the product of the shapes + template <bool Dyn = Dynamic> + enable_if_t<!Dyn, size_t> size() const { + return std::accumulate(shape_.begin(), shape_.end(), (size_t) 1, std::multiplies<size_t>()); + } + template <bool Dyn = Dynamic> + enable_if_t<Dyn, size_t> size() const { + return std::accumulate(shape_, shape_ + ndim(), (size_t) 1, std::multiplies<size_t>()); + } + + /// Returns the total number of bytes used by the referenced data. Note that the actual span in + /// memory may be larger if the referenced array has non-contiguous strides (e.g. for a slice). + size_t nbytes() const { + return size() * itemsize(); + } +}; + +template <typename T, ssize_t Dims> +class unchecked_mutable_reference : public unchecked_reference<T, Dims> { + friend class pybind11::array; + using ConstBase = unchecked_reference<T, Dims>; + using ConstBase::ConstBase; + using ConstBase::Dynamic; +public: + /// Mutable, unchecked access to data at the given indices. + template <typename... Ix> T& operator()(Ix... index) { + static_assert(sizeof...(Ix) == Dims || Dynamic, + "Invalid number of indices for unchecked array reference"); + return const_cast<T &>(ConstBase::operator()(index...)); + } + /** Mutable, unchecked access data at the given index; this operator only participates if the + * reference is to a 1-dimensional array (or has runtime dimensions). When present, this is + * exactly equivalent to `obj(index)`. + */ + template <size_t D = Dims, typename = enable_if_t<D == 1 || Dynamic>> + T &operator[](size_t index) { return operator()(index); } + + /// Mutable pointer access to the data at the given indices. + template <typename... Ix> T *mutable_data(Ix... ix) { return &operator()(size_t(ix)...); } +}; + +template <typename T, size_t Dim> +struct type_caster<unchecked_reference<T, Dim>> { + static_assert(Dim == 0 && Dim > 0 /* always fail */, "unchecked array proxy object is not castable"); +}; +template <typename T, size_t Dim> +struct type_caster<unchecked_mutable_reference<T, Dim>> : type_caster<unchecked_reference<T, Dim>> {}; + NAMESPACE_END(detail) class dtype : public object { @@ -321,8 +448,8 @@ public: PYBIND11_OBJECT_CVT(array, buffer, detail::npy_api::get().PyArray_Check_, raw_array) enum { - c_style = detail::npy_api::NPY_C_CONTIGUOUS_, - f_style = detail::npy_api::NPY_F_CONTIGUOUS_, + c_style = detail::npy_api::NPY_ARRAY_C_CONTIGUOUS_, + f_style = detail::npy_api::NPY_ARRAY_F_CONTIGUOUS_, forcecast = detail::npy_api::NPY_ARRAY_FORCECAST_ }; @@ -340,7 +467,7 @@ public: int flags = 0; if (base && ptr) { if (isinstance<array>(base)) - /* Copy flags from base (except baseship bit) */ + /* Copy flags from base (except ownership bit) */ flags = reinterpret_borrow<array>(base).flags() & ~detail::npy_api::NPY_ARRAY_OWNDATA_; else /* Writable by default, easy to downgrade later on if needed */ @@ -348,13 +475,15 @@ public: } auto tmp = reinterpret_steal<object>(api.PyArray_NewFromDescr_( - api.PyArray_Type_, descr.release().ptr(), (int) ndim, (Py_intptr_t *) shape.data(), - (Py_intptr_t *) strides.data(), const_cast<void *>(ptr), flags, nullptr)); + api.PyArray_Type_, descr.release().ptr(), (int) ndim, + reinterpret_cast<Py_intptr_t *>(const_cast<size_t*>(shape.data())), + reinterpret_cast<Py_intptr_t *>(const_cast<size_t*>(strides.data())), + const_cast<void *>(ptr), flags, nullptr)); if (!tmp) pybind11_fail("NumPy: unable to create array!"); if (ptr) { if (base) { - detail::array_proxy(tmp.ptr())->base = base.inc_ref().ptr(); + api.PyArray_SetBaseObject_(tmp.ptr(), base.inc_ref().ptr()); } else { tmp = reinterpret_steal<object>(api.PyArray_NewCopy_(tmp.ptr(), -1 /* any order */)); } @@ -373,7 +502,7 @@ public: template<typename T> array(const std::vector<size_t>& shape, const std::vector<size_t>& strides, const T* ptr, handle base = handle()) - : array(pybind11::dtype::of<T>(), shape, strides, (void *) ptr, base) { } + : array(pybind11::dtype::of<T>(), shape, strides, (const void *) ptr, base) { } template <typename T> array(const std::vector<size_t> &shape, const T *ptr, @@ -486,6 +615,31 @@ public: return offset_at(index...) / itemsize(); } + /** Returns a proxy object that provides access to the array's data without bounds or + * dimensionality checking. Will throw if the array is missing the `writeable` flag. Use with + * care: the array must not be destroyed or reshaped for the duration of the returned object, + * and the caller must take care not to access invalid dimensions or dimension indices. + */ + template <typename T, ssize_t Dims = -1> detail::unchecked_mutable_reference<T, Dims> mutable_unchecked() { + if (Dims >= 0 && ndim() != (size_t) Dims) + throw std::domain_error("array has incorrect number of dimensions: " + std::to_string(ndim()) + + "; expected " + std::to_string(Dims)); + return detail::unchecked_mutable_reference<T, Dims>(mutable_data(), shape(), strides(), ndim()); + } + + /** Returns a proxy object that provides const access to the array's data without bounds or + * dimensionality checking. Unlike `mutable_unchecked()`, this does not require that the + * underlying array have the `writable` flag. Use with care: the array must not be destroyed or + * reshaped for the duration of the returned object, and the caller must take care not to access + * invalid dimensions or dimension indices. + */ + template <typename T, ssize_t Dims = -1> detail::unchecked_reference<T, Dims> unchecked() const { + if (Dims >= 0 && ndim() != (size_t) Dims) + throw std::domain_error("array has incorrect number of dimensions: " + std::to_string(ndim()) + + "; expected " + std::to_string(Dims)); + return detail::unchecked_reference<T, Dims>(data(), shape(), strides(), ndim()); + } + /// Return a new view with all of the dimensions of length 1 removed array squeeze() { auto& api = detail::npy_api::get(); @@ -511,18 +665,12 @@ protected: template<typename... Ix> size_t byte_offset(Ix... index) const { check_dimensions(index...); - return byte_offset_unsafe(index...); - } - - template<size_t dim = 0, typename... Ix> size_t byte_offset_unsafe(size_t i, Ix... index) const { - return i * strides()[dim] + byte_offset_unsafe<dim + 1>(index...); + return detail::byte_offset_unsafe(strides(), size_t(index)...); } - template<size_t dim = 0> size_t byte_offset_unsafe() const { return 0; } - void check_writeable() const { if (!writeable()) - throw std::runtime_error("array is not writeable"); + throw std::domain_error("array is not writeable"); } static std::vector<size_t> default_strides(const std::vector<size_t>& shape, size_t itemsize) { @@ -557,12 +705,14 @@ protected: if (ptr == nullptr) return nullptr; return detail::npy_api::get().PyArray_FromAny_( - ptr, nullptr, 0, 0, detail::npy_api::NPY_ENSURE_ARRAY_ | ExtraFlags, nullptr); + ptr, nullptr, 0, 0, detail::npy_api::NPY_ARRAY_ENSUREARRAY_ | ExtraFlags, nullptr); } }; template <typename T, int ExtraFlags = array::forcecast> class array_t : public array { public: + using value_type = T; + array_t() : array(0, static_cast<const T *>(nullptr)) {} array_t(handle h, borrowed_t) : array(h, borrowed) { } array_t(handle h, stolen_t) : array(h, stolen) { } @@ -621,8 +771,27 @@ public: return *(static_cast<T*>(array::mutable_data()) + byte_offset(size_t(index)...) / itemsize()); } - /// Ensure that the argument is a NumPy array of the correct dtype. - /// In case of an error, nullptr is returned and the Python error is cleared. + /** Returns a proxy object that provides access to the array's data without bounds or + * dimensionality checking. Will throw if the array is missing the `writeable` flag. Use with + * care: the array must not be destroyed or reshaped for the duration of the returned object, + * and the caller must take care not to access invalid dimensions or dimension indices. + */ + template <ssize_t Dims = -1> detail::unchecked_mutable_reference<T, Dims> mutable_unchecked() { + return array::mutable_unchecked<T, Dims>(); + } + + /** Returns a proxy object that provides const access to the array's data without bounds or + * dimensionality checking. Unlike `unchecked()`, this does not require that the underlying + * array have the `writable` flag. Use with care: the array must not be destroyed or reshaped + * for the duration of the returned object, and the caller must take care not to access invalid + * dimensions or dimension indices. + */ + template <ssize_t Dims = -1> detail::unchecked_reference<T, Dims> unchecked() const { + return array::unchecked<T, Dims>(); + } + + /// Ensure that the argument is a NumPy array of the correct dtype (and if not, try to convert + /// it). In case of an error, nullptr is returned and the Python error is cleared. static array_t ensure(handle h) { auto result = reinterpret_steal<array_t>(raw_array_t(h.ptr())); if (!result) @@ -630,7 +799,7 @@ public: return result; } - static bool _check(handle h) { + static bool check_(handle h) { const auto &api = detail::npy_api::get(); return api.PyArray_Check_(h.ptr()) && api.PyArray_EquivTypes_(detail::array_proxy(h.ptr())->descr, dtype::of<T>().ptr()); @@ -643,7 +812,7 @@ protected: return nullptr; return detail::npy_api::get().PyArray_FromAny_( ptr, dtype::of<T>().release().ptr(), 0, 0, - detail::npy_api::NPY_ENSURE_ARRAY_ | ExtraFlags, nullptr); + detail::npy_api::NPY_ARRAY_ENSUREARRAY_ | ExtraFlags, nullptr); } }; @@ -674,7 +843,9 @@ template <typename T, int ExtraFlags> struct pyobject_caster<array_t<T, ExtraFlags>> { using type = array_t<T, ExtraFlags>; - bool load(handle src, bool /* convert */) { + bool load(handle src, bool convert) { + if (!convert && !type::check_(src)) + return false; value = type::ensure(src); return static_cast<bool>(value); } @@ -685,65 +856,55 @@ struct pyobject_caster<array_t<T, ExtraFlags>> { PYBIND11_TYPE_CASTER(type, handle_type_name<type>::name()); }; -template <typename T> struct is_std_array : std::false_type { }; -template <typename T, size_t N> struct is_std_array<std::array<T, N>> : std::true_type { }; - template <typename T> -struct is_pod_struct { - enum { value = std::is_pod<T>::value && // offsetof only works correctly for POD types - !std::is_reference<T>::value && - !std::is_array<T>::value && - !is_std_array<T>::value && - !std::is_integral<T>::value && - !std::is_enum<T>::value && - !std::is_same<typename std::remove_cv<T>::type, float>::value && - !std::is_same<typename std::remove_cv<T>::type, double>::value && - !std::is_same<typename std::remove_cv<T>::type, bool>::value && - !std::is_same<typename std::remove_cv<T>::type, std::complex<float>>::value && - !std::is_same<typename std::remove_cv<T>::type, std::complex<double>>::value }; +struct compare_buffer_info<T, detail::enable_if_t<detail::is_pod_struct<T>::value>> { + static bool compare(const buffer_info& b) { + return npy_api::get().PyArray_EquivTypes_(dtype::of<T>().ptr(), dtype(b).ptr()); + } }; -template <typename T> struct npy_format_descriptor<T, enable_if_t<std::is_integral<T>::value>> { +template <typename T> struct npy_format_descriptor<T, enable_if_t<satisfies_any_of<T, std::is_arithmetic, is_complex>::value>> { private: - constexpr static const int values[8] = { - npy_api::NPY_BYTE_, npy_api::NPY_UBYTE_, npy_api::NPY_SHORT_, npy_api::NPY_USHORT_, - npy_api::NPY_INT_, npy_api::NPY_UINT_, npy_api::NPY_LONGLONG_, npy_api::NPY_ULONGLONG_ }; + // NB: the order here must match the one in common.h + constexpr static const int values[15] = { + npy_api::NPY_BOOL_, + npy_api::NPY_BYTE_, npy_api::NPY_UBYTE_, npy_api::NPY_SHORT_, npy_api::NPY_USHORT_, + npy_api::NPY_INT_, npy_api::NPY_UINT_, npy_api::NPY_LONGLONG_, npy_api::NPY_ULONGLONG_, + npy_api::NPY_FLOAT_, npy_api::NPY_DOUBLE_, npy_api::NPY_LONGDOUBLE_, + npy_api::NPY_CFLOAT_, npy_api::NPY_CDOUBLE_, npy_api::NPY_CLONGDOUBLE_ + }; + public: - enum { value = values[detail::log2(sizeof(T)) * 2 + (std::is_unsigned<T>::value ? 1 : 0)] }; + static constexpr int value = values[detail::is_fmt_numeric<T>::index]; + static pybind11::dtype dtype() { if (auto ptr = npy_api::get().PyArray_DescrFromType_(value)) return reinterpret_borrow<pybind11::dtype>(ptr); pybind11_fail("Unsupported buffer format!"); } - template <typename T2 = T, enable_if_t<std::is_signed<T2>::value, int> = 0> - static PYBIND11_DESCR name() { return _("int") + _<sizeof(T)*8>(); } - template <typename T2 = T, enable_if_t<!std::is_signed<T2>::value, int> = 0> - static PYBIND11_DESCR name() { return _("uint") + _<sizeof(T)*8>(); } + template <typename T2 = T, enable_if_t<std::is_integral<T2>::value, int> = 0> + static PYBIND11_DESCR name() { + return _<std::is_same<T, bool>::value>(_("bool"), + _<std::is_signed<T>::value>("int", "uint") + _<sizeof(T)*8>()); + } + template <typename T2 = T, enable_if_t<std::is_floating_point<T2>::value, int> = 0> + static PYBIND11_DESCR name() { + return _<std::is_same<T, float>::value || std::is_same<T, double>::value>( + _("float") + _<sizeof(T)*8>(), _("longdouble")); + } + template <typename T2 = T, enable_if_t<is_complex<T2>::value, int> = 0> + static PYBIND11_DESCR name() { + return _<std::is_same<typename T2::value_type, float>::value || std::is_same<typename T2::value_type, double>::value>( + _("complex") + _<sizeof(typename T2::value_type)*16>(), _("longcomplex")); + } }; -template <typename T> constexpr const int npy_format_descriptor< - T, enable_if_t<std::is_integral<T>::value>>::values[8]; - -#define DECL_FMT(Type, NumPyName, Name) template<> struct npy_format_descriptor<Type> { \ - enum { value = npy_api::NumPyName }; \ - static pybind11::dtype dtype() { \ - if (auto ptr = npy_api::get().PyArray_DescrFromType_(value)) \ - return reinterpret_borrow<pybind11::dtype>(ptr); \ - pybind11_fail("Unsupported buffer format!"); \ - } \ - static PYBIND11_DESCR name() { return _(Name); } } -DECL_FMT(float, NPY_FLOAT_, "float32"); -DECL_FMT(double, NPY_DOUBLE_, "float64"); -DECL_FMT(bool, NPY_BOOL_, "bool"); -DECL_FMT(std::complex<float>, NPY_CFLOAT_, "complex64"); -DECL_FMT(std::complex<double>, NPY_CDOUBLE_, "complex128"); -#undef DECL_FMT - -#define DECL_CHAR_FMT \ + +#define PYBIND11_DECL_CHAR_FMT \ static PYBIND11_DESCR name() { return _("S") + _<N>(); } \ static pybind11::dtype dtype() { return pybind11::dtype(std::string("S") + std::to_string(N)); } -template <size_t N> struct npy_format_descriptor<char[N]> { DECL_CHAR_FMT }; -template <size_t N> struct npy_format_descriptor<std::array<char, N>> { DECL_CHAR_FMT }; -#undef DECL_CHAR_FMT +template <size_t N> struct npy_format_descriptor<char[N]> { PYBIND11_DECL_CHAR_FMT }; +template <size_t N> struct npy_format_descriptor<std::array<char, N>> { PYBIND11_DECL_CHAR_FMT }; +#undef PYBIND11_DECL_CHAR_FMT template<typename T> struct npy_format_descriptor<T, enable_if_t<std::is_enum<T>::value>> { private: @@ -798,9 +959,9 @@ inline PYBIND11_NOINLINE void register_structured_dtype( for (auto& field : ordered_fields) { if (field.offset > offset) oss << (field.offset - offset) << 'x'; - // mark unaligned fields with '=' + // mark unaligned fields with '^' (unaligned native type) if (field.offset % field.alignment) - oss << '='; + oss << '^'; oss << field.format << ':' << field.name << ':'; offset = field.offset + field.size; } @@ -820,9 +981,10 @@ inline PYBIND11_NOINLINE void register_structured_dtype( get_internals().direct_conversions[tindex].push_back(direct_converter); } -template <typename T> -struct npy_format_descriptor<T, enable_if_t<is_pod_struct<T>::value>> { - static PYBIND11_DESCR name() { return _("struct"); } +template <typename T, typename SFINAE> struct npy_format_descriptor { + static_assert(is_pod_struct<T>::value, "Attempt to use a non-POD or unimplemented POD type as a numpy dtype"); + + static PYBIND11_DESCR name() { return make_caster<T>::name(); } static pybind11::dtype dtype() { return reinterpret_borrow<pybind11::dtype>(dtype_ptr()); @@ -1043,87 +1205,146 @@ private: std::array<common_iter, N> m_common_iterator; }; +enum class broadcast_trivial { non_trivial, c_trivial, f_trivial }; + +// Populates the shape and number of dimensions for the set of buffers. Returns a broadcast_trivial +// enum value indicating whether the broadcast is "trivial"--that is, has each buffer being either a +// singleton or a full-size, C-contiguous (`c_trivial`) or Fortran-contiguous (`f_trivial`) storage +// buffer; returns `non_trivial` otherwise. template <size_t N> -bool broadcast(const std::array<buffer_info, N>& buffers, size_t& ndim, std::vector<size_t>& shape) { +broadcast_trivial broadcast(const std::array<buffer_info, N> &buffers, size_t &ndim, std::vector<size_t> &shape) { ndim = std::accumulate(buffers.begin(), buffers.end(), size_t(0), [](size_t res, const buffer_info& buf) { return std::max(res, buf.ndim); }); - shape = std::vector<size_t>(ndim, 1); - bool trivial_broadcast = true; + shape.clear(); + shape.resize(ndim, 1); + + // Figure out the output size, and make sure all input arrays conform (i.e. are either size 1 or + // the full size). for (size_t i = 0; i < N; ++i) { auto res_iter = shape.rbegin(); - bool i_trivial_broadcast = (buffers[i].size == 1) || (buffers[i].ndim == ndim); - for (auto shape_iter = buffers[i].shape.rbegin(); - shape_iter != buffers[i].shape.rend(); ++shape_iter, ++res_iter) { - - if (*res_iter == 1) - *res_iter = *shape_iter; - else if ((*shape_iter != 1) && (*res_iter != *shape_iter)) + auto end = buffers[i].shape.rend(); + for (auto shape_iter = buffers[i].shape.rbegin(); shape_iter != end; ++shape_iter, ++res_iter) { + const auto &dim_size_in = *shape_iter; + auto &dim_size_out = *res_iter; + + // Each input dimension can either be 1 or `n`, but `n` values must match across buffers + if (dim_size_out == 1) + dim_size_out = dim_size_in; + else if (dim_size_in != 1 && dim_size_in != dim_size_out) pybind11_fail("pybind11::vectorize: incompatible size/dimension of inputs!"); + } + } - i_trivial_broadcast = i_trivial_broadcast && (*res_iter == *shape_iter); + bool trivial_broadcast_c = true; + bool trivial_broadcast_f = true; + for (size_t i = 0; i < N && (trivial_broadcast_c || trivial_broadcast_f); ++i) { + if (buffers[i].size == 1) + continue; + + // Require the same number of dimensions: + if (buffers[i].ndim != ndim) + return broadcast_trivial::non_trivial; + + // Require all dimensions be full-size: + if (!std::equal(buffers[i].shape.cbegin(), buffers[i].shape.cend(), shape.cbegin())) + return broadcast_trivial::non_trivial; + + // Check for C contiguity (but only if previous inputs were also C contiguous) + if (trivial_broadcast_c) { + size_t expect_stride = buffers[i].itemsize; + auto end = buffers[i].shape.crend(); + for (auto shape_iter = buffers[i].shape.crbegin(), stride_iter = buffers[i].strides.crbegin(); + trivial_broadcast_c && shape_iter != end; ++shape_iter, ++stride_iter) { + if (expect_stride == *stride_iter) + expect_stride *= *shape_iter; + else + trivial_broadcast_c = false; + } + } + + // Check for Fortran contiguity (if previous inputs were also F contiguous) + if (trivial_broadcast_f) { + size_t expect_stride = buffers[i].itemsize; + auto end = buffers[i].shape.cend(); + for (auto shape_iter = buffers[i].shape.cbegin(), stride_iter = buffers[i].strides.cbegin(); + trivial_broadcast_f && shape_iter != end; ++shape_iter, ++stride_iter) { + if (expect_stride == *stride_iter) + expect_stride *= *shape_iter; + else + trivial_broadcast_f = false; + } } - trivial_broadcast = trivial_broadcast && i_trivial_broadcast; } - return trivial_broadcast; + + return + trivial_broadcast_c ? broadcast_trivial::c_trivial : + trivial_broadcast_f ? broadcast_trivial::f_trivial : + broadcast_trivial::non_trivial; } template <typename Func, typename Return, typename... Args> struct vectorize_helper { typename std::remove_reference<Func>::type f; + static constexpr size_t N = sizeof...(Args); template <typename T> explicit vectorize_helper(T&&f) : f(std::forward<T>(f)) { } - object operator()(array_t<Args, array::c_style | array::forcecast>... args) { - return run(args..., make_index_sequence<sizeof...(Args)>()); + object operator()(array_t<Args, array::forcecast>... args) { + return run(args..., make_index_sequence<N>()); } - template <size_t ... Index> object run(array_t<Args, array::c_style | array::forcecast>&... args, index_sequence<Index...> index) { + template <size_t ... Index> object run(array_t<Args, array::forcecast>&... args, index_sequence<Index...> index) { /* Request buffers from all parameters */ - const size_t N = sizeof...(Args); - std::array<buffer_info, N> buffers {{ args.request()... }}; /* Determine dimensions parameters of output array */ size_t ndim = 0; std::vector<size_t> shape(0); - bool trivial_broadcast = broadcast(buffers, ndim, shape); + auto trivial = broadcast(buffers, ndim, shape); size_t size = 1; std::vector<size_t> strides(ndim); if (ndim > 0) { - strides[ndim-1] = sizeof(Return); - for (size_t i = ndim - 1; i > 0; --i) { - strides[i - 1] = strides[i] * shape[i]; - size *= shape[i]; + if (trivial == broadcast_trivial::f_trivial) { + strides[0] = sizeof(Return); + for (size_t i = 1; i < ndim; ++i) { + strides[i] = strides[i - 1] * shape[i - 1]; + size *= shape[i - 1]; + } + size *= shape[ndim - 1]; + } + else { + strides[ndim-1] = sizeof(Return); + for (size_t i = ndim - 1; i > 0; --i) { + strides[i - 1] = strides[i] * shape[i]; + size *= shape[i]; + } + size *= shape[0]; } - size *= shape[0]; } if (size == 1) - return cast(f(*((Args *) buffers[Index].ptr)...)); + return cast(f(*reinterpret_cast<Args *>(buffers[Index].ptr)...)); array_t<Return> result(shape, strides); auto buf = result.request(); auto output = (Return *) buf.ptr; - if (trivial_broadcast) { - /* Call the function */ - for (size_t i = 0; i < size; ++i) { - output[i] = f((buffers[Index].size == 1 - ? *((Args *) buffers[Index].ptr) - : ((Args *) buffers[Index].ptr)[i])...); - } + /* Call the function */ + if (trivial == broadcast_trivial::non_trivial) { + apply_broadcast<Index...>(buffers, buf, index); } else { - apply_broadcast<N, Index...>(buffers, buf, index); + for (size_t i = 0; i < size; ++i) + output[i] = f((reinterpret_cast<Args *>(buffers[Index].ptr)[buffers[Index].size == 1 ? 0 : i])...); } return result; } - template <size_t N, size_t... Index> + template <size_t... Index> void apply_broadcast(const std::array<buffer_info, N> &buffers, buffer_info &output, index_sequence<Index...>) { using input_iterator = multi_array_iterator<N>; @@ -1140,26 +1361,29 @@ struct vectorize_helper { }; template <typename T, int Flags> struct handle_type_name<array_t<T, Flags>> { - static PYBIND11_DESCR name() { return _("numpy.ndarray[") + type_caster<T>::name() + _("]"); } + static PYBIND11_DESCR name() { + return _("numpy.ndarray[") + npy_format_descriptor<T>::name() + _("]"); + } }; NAMESPACE_END(detail) template <typename Func, typename Return, typename... Args> -detail::vectorize_helper<Func, Return, Args...> vectorize(const Func &f, Return (*) (Args ...)) { +detail::vectorize_helper<Func, Return, Args...> +vectorize(const Func &f, Return (*) (Args ...)) { return detail::vectorize_helper<Func, Return, Args...>(f); } template <typename Return, typename... Args> -detail::vectorize_helper<Return (*) (Args ...), Return, Args...> vectorize(Return (*f) (Args ...)) { +detail::vectorize_helper<Return (*) (Args ...), Return, Args...> +vectorize(Return (*f) (Args ...)) { return vectorize<Return (*) (Args ...), Return, Args...>(f, f); } -template <typename Func> +template <typename Func, typename FuncType = typename detail::remove_class<decltype(&std::remove_reference<Func>::type::operator())>::type> auto vectorize(Func &&f) -> decltype( - vectorize(std::forward<Func>(f), (typename detail::remove_class<decltype(&std::remove_reference<Func>::type::operator())>::type *) nullptr)) { - return vectorize(std::forward<Func>(f), (typename detail::remove_class<decltype( - &std::remove_reference<Func>::type::operator())>::type *) nullptr); + vectorize(std::forward<Func>(f), (FuncType *) nullptr)) { + return vectorize(std::forward<Func>(f), (FuncType *) nullptr); } NAMESPACE_END(pybind11) 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; } diff --git a/ext/pybind11/include/pybind11/pytypes.h b/ext/pybind11/include/pybind11/pytypes.h index 2b49ecfc9..900c57564 100644 --- a/ext/pybind11/include/pybind11/pytypes.h +++ b/ext/pybind11/include/pybind11/pytypes.h @@ -45,51 +45,130 @@ using tuple_accessor = accessor<accessor_policies::tuple_item>; class pyobject_tag { }; template <typename T> using is_pyobject = std::is_base_of<pyobject_tag, typename std::remove_reference<T>::type>; -/// Mixin which adds common functions to handle, object and various accessors. -/// The only requirement for `Derived` is to implement `PyObject *Derived::ptr() const`. +/** \rst + A mixin class which adds common functions to `handle`, `object` and various accessors. + The only requirement for `Derived` is to implement ``PyObject *Derived::ptr() const``. +\endrst */ template <typename Derived> class object_api : public pyobject_tag { const Derived &derived() const { return static_cast<const Derived &>(*this); } public: + /** \rst + Return an iterator equivalent to calling ``iter()`` in Python. The object + must be a collection which supports the iteration protocol. + \endrst */ iterator begin() const; + /// Return a sentinel which ends iteration. iterator end() const; + + /** \rst + Return an internal functor to invoke the object's sequence protocol. Casting + the returned ``detail::item_accessor`` instance to a `handle` or `object` + subclass causes a corresponding call to ``__getitem__``. Assigning a `handle` + or `object` subclass causes a call to ``__setitem__``. + \endrst */ item_accessor operator[](handle key) const; + /// See above (the only difference is that they key is provided as a string literal) item_accessor operator[](const char *key) const; + + /** \rst + Return an internal functor to access the object's attributes. Casting the + returned ``detail::obj_attr_accessor`` instance to a `handle` or `object` + subclass causes a corresponding call to ``getattr``. Assigning a `handle` + or `object` subclass causes a call to ``setattr``. + \endrst */ obj_attr_accessor attr(handle key) const; + /// See above (the only difference is that they key is provided as a string literal) str_attr_accessor attr(const char *key) const; + + /** \rst + Matches * unpacking in Python, e.g. to unpack arguments out of a ``tuple`` + or ``list`` for a function call. Applying another * to the result yields + ** unpacking, e.g. to unpack a dict as function keyword arguments. + See :ref:`calling_python_functions`. + \endrst */ args_proxy operator*() const; - template <typename T> bool contains(T &&key) const; + /// Check if the given item is contained within this object, i.e. ``item in obj``. + template <typename T> bool contains(T &&item) const; + + /** \rst + Assuming the Python object is a function or implements the ``__call__`` + protocol, ``operator()`` invokes the underlying function, passing an + arbitrary set of parameters. The result is returned as a `object` and + may need to be converted back into a Python object using `handle::cast()`. + + When some of the arguments cannot be converted to Python objects, the + function will throw a `cast_error` exception. When the Python function + call fails, a `error_already_set` exception is thrown. + \endrst */ template <return_value_policy policy = return_value_policy::automatic_reference, typename... Args> object operator()(Args &&...args) const; template <return_value_policy policy = return_value_policy::automatic_reference, typename... Args> PYBIND11_DEPRECATED("call(...) was deprecated in favor of operator()(...)") object call(Args&&... args) const; + /// Equivalent to ``obj is None`` in Python. bool is_none() const { return derived().ptr() == Py_None; } - PYBIND11_DEPRECATED("Instead of obj.str(), use py::str(obj)") + PYBIND11_DEPRECATED("Use py::str(obj) instead") pybind11::str str() const; + /// Return the object's current reference count int ref_count() const { return static_cast<int>(Py_REFCNT(derived().ptr())); } + /// Return a handle to the Python type object underlying the instance handle get_type() const; }; NAMESPACE_END(detail) -/// Holds a reference to a Python object (no reference counting) +/** \rst + Holds a reference to a Python object (no reference counting) + + The `handle` class is a thin wrapper around an arbitrary Python object (i.e. a + ``PyObject *`` in Python's C API). It does not perform any automatic reference + counting and merely provides a basic C++ interface to various Python API functions. + + .. seealso:: + The `object` class inherits from `handle` and adds automatic reference + counting features. +\endrst */ class handle : public detail::object_api<handle> { public: + /// The default constructor creates a handle with a ``nullptr``-valued pointer handle() = default; + /// Creates a ``handle`` from the given raw Python object pointer handle(PyObject *ptr) : m_ptr(ptr) { } // Allow implicit conversion from PyObject* + /// Return the underlying ``PyObject *`` pointer PyObject *ptr() const { return m_ptr; } PyObject *&ptr() { return m_ptr; } - const handle& inc_ref() const { Py_XINCREF(m_ptr); return *this; } - const handle& dec_ref() const { Py_XDECREF(m_ptr); return *this; } + /** \rst + Manually increase the reference count of the Python object. Usually, it is + preferable to use the `object` class which derives from `handle` and calls + this function automatically. Returns a reference to itself. + \endrst */ + const handle& inc_ref() const & { Py_XINCREF(m_ptr); return *this; } + + /** \rst + Manually decrease the reference count of the Python object. Usually, it is + preferable to use the `object` class which derives from `handle` and calls + this function automatically. Returns a reference to itself. + \endrst */ + const handle& dec_ref() const & { Py_XDECREF(m_ptr); return *this; } + + /** \rst + Attempt to cast the Python object into the given C++ type. A `cast_error` + will be throw upon failure. + \endrst */ template <typename T> T cast() const; + /// Return ``true`` when the `handle` wraps a valid Python object explicit operator bool() const { return m_ptr != nullptr; } + /** \rst + Check that the underlying pointers are the same. + Equivalent to ``obj1 is obj2`` in Python. + \endrst */ bool operator==(const handle &h) const { return m_ptr == h.m_ptr; } bool operator!=(const handle &h) const { return m_ptr != h.m_ptr; } PYBIND11_DEPRECATED("Use handle::operator bool() instead") @@ -98,16 +177,33 @@ protected: PyObject *m_ptr = nullptr; }; -/// Holds a reference to a Python object (with reference counting) +/** \rst + Holds a reference to a Python object (with reference counting) + + Like `handle`, the `object` class is a thin wrapper around an arbitrary Python + object (i.e. a ``PyObject *`` in Python's C API). In contrast to `handle`, it + optionally increases the object's reference count upon construction, and it + *always* decreases the reference count when the `object` instance goes out of + scope and is destructed. When using `object` instances consistently, it is much + easier to get reference counting right at the first attempt. +\endrst */ class object : public handle { public: object() = default; PYBIND11_DEPRECATED("Use reinterpret_borrow<object>() or reinterpret_steal<object>()") object(handle h, bool is_borrowed) : handle(h) { if (is_borrowed) inc_ref(); } + /// Copy constructor; always increases the reference count object(const object &o) : handle(o) { inc_ref(); } + /// Move constructor; steals the object from ``other`` and preserves its reference count object(object &&other) noexcept { m_ptr = other.m_ptr; other.m_ptr = nullptr; } + /// Destructor; automatically calls `handle::dec_ref()` ~object() { dec_ref(); } + /** \rst + Resets the internal pointer to ``nullptr`` without without decreasing the + object's reference count. The function returns a raw handle to the original + Python object. + \endrst */ handle release() { PyObject *tmp = m_ptr; m_ptr = nullptr; @@ -150,14 +246,43 @@ public: object(handle h, stolen_t) : handle(h) { } }; -/** The following functions don't do any kind of conversion, they simply declare - that a PyObject is a certain type and borrow or steal the reference. */ +/** \rst + Declare that a `handle` or ``PyObject *`` is a certain type and borrow the reference. + The target type ``T`` must be `object` or one of its derived classes. The function + doesn't do any conversions or checks. It's up to the user to make sure that the + target type is correct. + + .. code-block:: cpp + + PyObject *p = PyList_GetItem(obj, index); + py::object o = reinterpret_borrow<py::object>(p); + // or + py::tuple t = reinterpret_borrow<py::tuple>(p); // <-- `p` must be already be a `tuple` +\endrst */ template <typename T> T reinterpret_borrow(handle h) { return {h, object::borrowed}; } + +/** \rst + Like `reinterpret_borrow`, but steals the reference. + + .. code-block:: cpp + + PyObject *p = PyObject_Str(obj); + py::str s = reinterpret_steal<py::str>(p); // <-- `p` must be already be a `str` +\endrst */ template <typename T> T reinterpret_steal(handle h) { return {h, object::stolen}; } -/// Check if `obj` is an instance of type `T` +/** \defgroup python_builtins _ + Unless stated otherwise, the following C++ functions behave the same + as their Python counterparts. + */ + +/** \ingroup python_builtins + \rst + Return true if ``obj`` is an instance of ``T``. Type ``T`` must be a subclass of + `object` or a class which was exposed to Python as ``py::class_<T>``. +\endrst */ template <typename T, detail::enable_if_t<std::is_base_of<object, T>::value, int> = 0> -bool isinstance(handle obj) { return T::_check(obj); } +bool isinstance(handle obj) { return T::check_(obj); } template <typename T, detail::enable_if_t<!std::is_base_of<object, T>::value, int> = 0> bool isinstance(handle obj) { return detail::isinstance_generic(obj, typeid(T)); } @@ -165,6 +290,17 @@ bool isinstance(handle obj) { return detail::isinstance_generic(obj, typeid(T)); template <> inline bool isinstance<handle>(handle obj) = delete; template <> inline bool isinstance<object>(handle obj) { return obj.ptr() != nullptr; } +/// \ingroup python_builtins +/// Return true if ``obj`` is an instance of the ``type``. +inline bool isinstance(handle obj, handle type) { + const auto result = PyObject_IsInstance(obj.ptr(), type.ptr()); + if (result == -1) + throw error_already_set(); + return result != 0; +} + +/// \addtogroup python_builtins +/// @{ inline bool hasattr(handle obj, handle name) { return PyObject_HasAttr(obj.ptr(), name.ptr()) == 1; } @@ -210,6 +346,7 @@ inline void setattr(handle obj, handle name, handle value) { inline void setattr(handle obj, const char *name, handle value) { if (PyObject_SetAttrString(obj.ptr(), name, value.ptr()) != 0) { throw error_already_set(); } } +/// @} python_builtins NAMESPACE_BEGIN(detail) inline handle get_function(handle value) { @@ -316,7 +453,7 @@ struct sequence_item { static object get(handle obj, size_t index) { PyObject *result = PySequence_GetItem(obj.ptr(), static_cast<ssize_t>(index)); if (!result) { throw error_already_set(); } - return reinterpret_borrow<object>(result); + return reinterpret_steal<object>(result); } static void set(handle obj, size_t index, handle val) { @@ -362,24 +499,131 @@ struct tuple_item { }; NAMESPACE_END(accessor_policies) -struct dict_iterator { +/// STL iterator template used for tuple, list, sequence and dict +template <typename Policy> +class generic_iterator : public Policy { + using It = generic_iterator; + public: - explicit dict_iterator(handle dict = handle(), ssize_t pos = -1) : dict(dict), pos(pos) { } - dict_iterator& operator++() { - if (!PyDict_Next(dict.ptr(), &pos, &key.ptr(), &value.ptr())) - pos = -1; - return *this; - } - std::pair<handle, handle> operator*() const { - return std::make_pair(key, value); - } - bool operator==(const dict_iterator &it) const { return it.pos == pos; } - bool operator!=(const dict_iterator &it) const { return it.pos != pos; } + using difference_type = ssize_t; + using iterator_category = typename Policy::iterator_category; + using value_type = typename Policy::value_type; + using reference = typename Policy::reference; + using pointer = typename Policy::pointer; + + generic_iterator() = default; + generic_iterator(handle seq, ssize_t index) : Policy(seq, index) { } + + reference operator*() const { return Policy::dereference(); } + reference operator[](difference_type n) const { return *(*this + n); } + pointer operator->() const { return **this; } + + It &operator++() { Policy::increment(); return *this; } + It operator++(int) { auto copy = *this; Policy::increment(); return copy; } + It &operator--() { Policy::decrement(); return *this; } + It operator--(int) { auto copy = *this; Policy::decrement(); return copy; } + It &operator+=(difference_type n) { Policy::advance(n); return *this; } + It &operator-=(difference_type n) { Policy::advance(-n); return *this; } + + friend It operator+(const It &a, difference_type n) { auto copy = a; return copy += n; } + friend It operator+(difference_type n, const It &b) { return b + n; } + friend It operator-(const It &a, difference_type n) { auto copy = a; return copy -= n; } + friend difference_type operator-(const It &a, const It &b) { return a.distance_to(b); } + + friend bool operator==(const It &a, const It &b) { return a.equal(b); } + friend bool operator!=(const It &a, const It &b) { return !(a == b); } + friend bool operator< (const It &a, const It &b) { return b - a > 0; } + friend bool operator> (const It &a, const It &b) { return b < a; } + friend bool operator>=(const It &a, const It &b) { return !(a < b); } + friend bool operator<=(const It &a, const It &b) { return !(a > b); } +}; + +NAMESPACE_BEGIN(iterator_policies) +/// Quick proxy class needed to implement ``operator->`` for iterators which can't return pointers +template <typename T> +struct arrow_proxy { + T value; + + arrow_proxy(T &&value) : value(std::move(value)) { } + T *operator->() const { return &value; } +}; + +/// Lightweight iterator policy using just a simple pointer: see ``PySequence_Fast_ITEMS`` +class sequence_fast_readonly { +protected: + using iterator_category = std::random_access_iterator_tag; + using value_type = handle; + using reference = const handle; + using pointer = arrow_proxy<const handle>; + + sequence_fast_readonly(handle obj, ssize_t n) : ptr(PySequence_Fast_ITEMS(obj.ptr()) + n) { } + + reference dereference() const { return *ptr; } + void increment() { ++ptr; } + void decrement() { --ptr; } + void advance(ssize_t n) { ptr += n; } + bool equal(const sequence_fast_readonly &b) const { return ptr == b.ptr; } + ssize_t distance_to(const sequence_fast_readonly &b) const { return ptr - b.ptr; } + +private: + PyObject **ptr; +}; + +/// Full read and write access using the sequence protocol: see ``detail::sequence_accessor`` +class sequence_slow_readwrite { +protected: + using iterator_category = std::random_access_iterator_tag; + using value_type = object; + using reference = sequence_accessor; + using pointer = arrow_proxy<const sequence_accessor>; + + sequence_slow_readwrite(handle obj, ssize_t index) : obj(obj), index(index) { } + + reference dereference() const { return {obj, static_cast<size_t>(index)}; } + void increment() { ++index; } + void decrement() { --index; } + void advance(ssize_t n) { index += n; } + bool equal(const sequence_slow_readwrite &b) const { return index == b.index; } + ssize_t distance_to(const sequence_slow_readwrite &b) const { return index - b.index; } + private: - handle dict, key, value; - ssize_t pos = 0; + handle obj; + ssize_t index; }; +/// Python's dictionary protocol permits this to be a forward iterator +class dict_readonly { +protected: + using iterator_category = std::forward_iterator_tag; + using value_type = std::pair<handle, handle>; + using reference = const value_type; + using pointer = arrow_proxy<const value_type>; + + dict_readonly() = default; + dict_readonly(handle obj, ssize_t pos) : obj(obj), pos(pos) { increment(); } + + reference dereference() const { return {key, value}; } + void increment() { if (!PyDict_Next(obj.ptr(), &pos, &key, &value)) { pos = -1; } } + bool equal(const dict_readonly &b) const { return pos == b.pos; } + +private: + handle obj; + PyObject *key, *value; + ssize_t pos = -1; +}; +NAMESPACE_END(iterator_policies) + +#if !defined(PYPY_VERSION) +using tuple_iterator = generic_iterator<iterator_policies::sequence_fast_readonly>; +using list_iterator = generic_iterator<iterator_policies::sequence_fast_readonly>; +#else +using tuple_iterator = generic_iterator<iterator_policies::sequence_slow_readwrite>; +using list_iterator = generic_iterator<iterator_policies::sequence_slow_readwrite>; +#endif + +using sequence_iterator = generic_iterator<iterator_policies::sequence_slow_readwrite>; +using dict_iterator = generic_iterator<iterator_policies::dict_readonly>; + inline bool PyIterable_Check(PyObject *obj) { PyObject *iter = PyObject_GetIter(obj); if (iter) { @@ -410,12 +654,10 @@ public: template <typename T> using is_keyword = std::is_base_of<arg, T>; template <typename T> using is_s_unpacking = std::is_same<args_proxy, T>; // * unpacking template <typename T> using is_ds_unpacking = std::is_same<kwargs_proxy, T>; // ** unpacking -template <typename T> using is_positional = bool_constant< - !is_keyword<T>::value && !is_s_unpacking<T>::value && !is_ds_unpacking<T>::value ->; -template <typename T> using is_keyword_or_ds = bool_constant< - is_keyword<T>::value || is_ds_unpacking<T>::value +template <typename T> using is_positional = satisfies_none_of<T, + is_keyword, is_s_unpacking, is_ds_unpacking >; +template <typename T> using is_keyword_or_ds = satisfies_any_of<T, is_keyword, is_ds_unpacking>; // Call argument collector forward declarations template <return_value_policy policy = return_value_policy::automatic_reference> @@ -437,7 +679,7 @@ NAMESPACE_END(detail) Name(handle h, stolen_t) : Parent(h, stolen) { } \ PYBIND11_DEPRECATED("Use py::isinstance<py::python_type>(obj) instead") \ bool check() const { return m_ptr != nullptr && (bool) CheckFun(m_ptr); } \ - static bool _check(handle h) { return h.ptr() != nullptr && CheckFun(h.ptr()); } + static bool check_(handle h) { return h.ptr() != nullptr && CheckFun(h.ptr()); } #define PYBIND11_OBJECT_CVT(Name, Parent, CheckFun, ConvertFun) \ PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun) \ @@ -454,47 +696,74 @@ NAMESPACE_END(detail) PYBIND11_OBJECT(Name, Parent, CheckFun) \ Name() : Parent() { } +/// \addtogroup pytypes +/// @{ + +/** \rst + Wraps a Python iterator so that it can also be used as a C++ input iterator + + Caveat: copying an iterator does not (and cannot) clone the internal + state of the Python iterable. This also applies to the post-increment + operator. This iterator should only be used to retrieve the current + value using ``operator*()``. +\endrst */ class iterator : public object { public: - /** Caveat: copying an iterator does not (and cannot) clone the internal - state of the Python iterable */ + using iterator_category = std::input_iterator_tag; + using difference_type = ssize_t; + using value_type = handle; + using reference = const handle; + using pointer = const handle *; + PYBIND11_OBJECT_DEFAULT(iterator, object, PyIter_Check) iterator& operator++() { - if (m_ptr) - advance(); + advance(); return *this; } - /** Caveat: this postincrement operator does not (and cannot) clone the - internal state of the Python iterable. It should only be used to - retrieve the current iterate using <tt>operator*()</tt> */ iterator operator++(int) { - iterator rv(*this); - rv.value = value; - if (m_ptr) - advance(); + auto rv = *this; + advance(); return rv; } - bool operator==(const iterator &it) const { return *it == **this; } - bool operator!=(const iterator &it) const { return *it != **this; } - - handle operator*() const { - if (!ready && m_ptr) { + reference operator*() const { + if (m_ptr && !value.ptr()) { auto& self = const_cast<iterator &>(*this); self.advance(); - self.ready = true; } return value; } + pointer operator->() const { operator*(); return &value; } + + /** \rst + The value which marks the end of the iteration. ``it == iterator::sentinel()`` + is equivalent to catching ``StopIteration`` in Python. + + .. code-block:: cpp + + void foo(py::iterator it) { + while (it != py::iterator::sentinel()) { + // use `*it` + ++it; + } + } + \endrst */ + static iterator sentinel() { return {}; } + + friend bool operator==(const iterator &a, const iterator &b) { return a->ptr() == b->ptr(); } + friend bool operator!=(const iterator &a, const iterator &b) { return a->ptr() != b->ptr(); } + private: - void advance() { value = reinterpret_steal<object>(PyIter_Next(m_ptr)); } + void advance() { + value = reinterpret_steal<object>(PyIter_Next(m_ptr)); + if (PyErr_Occurred()) { throw error_already_set(); } + } private: object value = {}; - bool ready = false; }; class iterable : public object { @@ -523,6 +792,10 @@ public: explicit str(const bytes &b); + /** \rst + Return a string representation of the object. This is analogous to + the ``str()`` function in Python. + \endrst */ explicit str(handle h) : object(raw_str(h.ptr()), stolen) { } operator std::string() const { @@ -556,12 +829,17 @@ private: return str_value; } }; +/// @} pytypes inline namespace literals { -/// String literal version of str +/** \rst + String literal version of `str` + \endrst */ inline str operator"" _s(const char *s, size_t size) { return {s, size}; } } +/// \addtogroup pytypes +/// @{ class bytes : public object { public: PYBIND11_OBJECT(bytes, object, PYBIND11_BYTES_CHECK) @@ -726,10 +1004,44 @@ public: PYBIND11_OBJECT_DEFAULT(capsule, object, PyCapsule_CheckExact) PYBIND11_DEPRECATED("Use reinterpret_borrow<capsule>() or reinterpret_steal<capsule>()") capsule(PyObject *ptr, bool is_borrowed) : object(is_borrowed ? object(ptr, borrowed) : object(ptr, stolen)) { } - explicit capsule(const void *value, void (*destruct)(PyObject *) = nullptr) + + explicit capsule(const void *value) + : object(PyCapsule_New(const_cast<void *>(value), nullptr, nullptr), stolen) { + if (!m_ptr) + pybind11_fail("Could not allocate capsule object!"); + } + + PYBIND11_DEPRECATED("Please pass a destructor that takes a void pointer as input") + capsule(const void *value, void (*destruct)(PyObject *)) : object(PyCapsule_New(const_cast<void*>(value), nullptr, destruct), stolen) { - if (!m_ptr) pybind11_fail("Could not allocate capsule object!"); + if (!m_ptr) + pybind11_fail("Could not allocate capsule object!"); + } + + capsule(const void *value, void (*destructor)(void *)) { + m_ptr = PyCapsule_New(const_cast<void *>(value), nullptr, [](PyObject *o) { + auto destructor = reinterpret_cast<void (*)(void *)>(PyCapsule_GetContext(o)); + void *ptr = PyCapsule_GetPointer(o, nullptr); + destructor(ptr); + }); + + if (!m_ptr) + pybind11_fail("Could not allocate capsule object!"); + + if (PyCapsule_SetContext(m_ptr, (void *) destructor) != 0) + pybind11_fail("Could not set capsule context!"); } + + capsule(void (*destructor)()) { + m_ptr = PyCapsule_New(reinterpret_cast<void *>(destructor), nullptr, [](PyObject *o) { + auto destructor = reinterpret_cast<void (*)()>(PyCapsule_GetPointer(o, nullptr)); + destructor(); + }); + + if (!m_ptr) + pybind11_fail("Could not allocate capsule object!"); + } + template <typename T> operator T *() const { T * result = static_cast<T *>(PyCapsule_GetPointer(m_ptr, nullptr)); if (!result) pybind11_fail("Unable to extract capsule contents!"); @@ -745,6 +1057,8 @@ public: } size_t size() const { return (size_t) PyTuple_Size(m_ptr); } detail::tuple_accessor operator[](size_t index) const { return {*this, index}; } + detail::tuple_iterator begin() const { return {*this, 0}; } + detail::tuple_iterator end() const { return {*this, PyTuple_GET_SIZE(m_ptr)}; } }; class dict : public object { @@ -754,14 +1068,14 @@ public: if (!m_ptr) pybind11_fail("Could not allocate dict object!"); } template <typename... Args, - typename = detail::enable_if_t<detail::all_of_t<detail::is_keyword_or_ds, Args...>::value>, + typename = detail::enable_if_t<detail::all_of<detail::is_keyword_or_ds<Args>...>::value>, // MSVC workaround: it can't compile an out-of-line definition, so defer the collector typename collector = detail::deferred_t<detail::unpacking_collector<>, Args...>> explicit dict(Args &&...args) : dict(collector(std::forward<Args>(args)...).kwargs()) { } size_t size() const { return (size_t) PyDict_Size(m_ptr); } - detail::dict_iterator begin() const { return (++detail::dict_iterator(*this, 0)); } - detail::dict_iterator end() const { return detail::dict_iterator(); } + detail::dict_iterator begin() const { return {*this, 0}; } + detail::dict_iterator end() const { return {}; } void clear() const { PyDict_Clear(ptr()); } bool contains(handle key) const { return PyDict_Contains(ptr(), key.ptr()) == 1; } bool contains(const char *key) const { return PyDict_Contains(ptr(), pybind11::str(key).ptr()) == 1; } @@ -777,9 +1091,11 @@ private: class sequence : public object { public: - PYBIND11_OBJECT(sequence, object, PySequence_Check) + PYBIND11_OBJECT_DEFAULT(sequence, object, PySequence_Check) size_t size() const { return (size_t) PySequence_Size(m_ptr); } detail::sequence_accessor operator[](size_t index) const { return {*this, index}; } + detail::sequence_iterator begin() const { return {*this, 0}; } + detail::sequence_iterator end() const { return {*this, PySequence_Size(m_ptr)}; } }; class list : public object { @@ -790,6 +1106,8 @@ public: } size_t size() const { return (size_t) PyList_Size(m_ptr); } detail::list_accessor operator[](size_t index) const { return {*this, index}; } + detail::list_iterator begin() const { return {*this, 0}; } + detail::list_iterator end() const { return {*this, PyList_GET_SIZE(m_ptr)}; } template <typename T> void append(T &&val) const { PyList_Append(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr()); } @@ -865,7 +1183,10 @@ public: PYBIND11_OBJECT_CVT(memoryview, object, PyMemoryView_Check, PyMemoryView_FromObject) }; +/// @} pytypes +/// \addtogroup python_builtins +/// @{ inline size_t len(handle h) { ssize_t result = PyObject_Length(h.ptr()); if (result < 0) @@ -884,13 +1205,16 @@ inline str repr(handle h) { return reinterpret_steal<str>(str_value); } -NAMESPACE_BEGIN(detail) -template <typename D> iterator object_api<D>::begin() const { - return reinterpret_steal<iterator>(PyObject_GetIter(derived().ptr())); -} -template <typename D> iterator object_api<D>::end() const { - return {}; +inline iterator iter(handle obj) { + PyObject *result = PyObject_GetIter(obj.ptr()); + if (!result) { throw error_already_set(); } + return reinterpret_steal<iterator>(result); } +/// @} python_builtins + +NAMESPACE_BEGIN(detail) +template <typename D> iterator object_api<D>::begin() const { return iter(derived()); } +template <typename D> iterator object_api<D>::end() const { return iterator::sentinel(); } template <typename D> item_accessor object_api<D>::operator[](handle key) const { return {derived(), reinterpret_borrow<object>(key)}; } @@ -906,8 +1230,8 @@ template <typename D> str_attr_accessor object_api<D>::attr(const char *key) con template <typename D> args_proxy object_api<D>::operator*() const { return args_proxy(derived().ptr()); } -template <typename D> template <typename T> bool object_api<D>::contains(T &&key) const { - return attr("__contains__")(std::forward<T>(key)).template cast<bool>(); +template <typename D> template <typename T> bool object_api<D>::contains(T &&item) const { + return attr("__contains__")(std::forward<T>(item)).template cast<bool>(); } template <typename D> diff --git a/ext/pybind11/include/pybind11/stl.h b/ext/pybind11/include/pybind11/stl.h index 7d6e8b102..37b6bcde3 100644 --- a/ext/pybind11/include/pybind11/stl.h +++ b/ext/pybind11/include/pybind11/stl.h @@ -139,7 +139,7 @@ public: auto value_ = reinterpret_steal<object>(value_conv::cast(value, policy, parent)); if (!value_) return handle(); - PyList_SET_ITEM(l.ptr(), index++, value_.release().ptr()); // steals a reference + PyList_SET_ITEM(l.ptr(), (ssize_t) index++, value_.release().ptr()); // steals a reference } return l.release(); } @@ -192,7 +192,7 @@ public: auto value_ = reinterpret_steal<object>(value_conv::cast(value, policy, parent)); if (!value_) return handle(); - PyList_SET_ITEM(l.ptr(), index++, value_.release().ptr()); // steals a reference + PyList_SET_ITEM(l.ptr(), (ssize_t) index++, value_.release().ptr()); // steals a reference } return l.release(); } diff --git a/ext/pybind11/include/pybind11/stl_bind.h b/ext/pybind11/include/pybind11/stl_bind.h index ef9950ebb..897188220 100644 --- a/ext/pybind11/include/pybind11/stl_bind.h +++ b/ext/pybind11/include/pybind11/stl_bind.h @@ -70,7 +70,7 @@ void vector_if_copy_constructible(enable_if_t< std::is_copy_constructible<Vector>::value && std::is_copy_constructible<typename Vector::value_type>::value, Class_> &cl) { - cl.def(pybind11::init<const Vector &>(), "Copy constructor"); + cl.def(init<const Vector &>(), "Copy constructor"); } template<typename Vector, typename Class_> @@ -93,7 +93,7 @@ void vector_if_equal_operator(enable_if_t<is_comparable<Vector>::value, Class_> if (p != v.end()) v.erase(p); else - throw pybind11::value_error(); + throw value_error(); }, arg("x"), "Remove the first item from the list whose value is x. " @@ -155,7 +155,7 @@ void vector_modifiers(enable_if_t<std::is_copy_constructible<typename Vector::va cl.def("pop", [](Vector &v) { if (v.empty()) - throw pybind11::index_error(); + throw index_error(); T t = v.back(); v.pop_back(); return t; @@ -166,7 +166,7 @@ void vector_modifiers(enable_if_t<std::is_copy_constructible<typename Vector::va cl.def("pop", [](Vector &v, SizeType i) { if (i >= v.size()) - throw pybind11::index_error(); + throw index_error(); T t = v[i]; v.erase(v.begin() + (DiffType) i); return t; @@ -178,7 +178,7 @@ void vector_modifiers(enable_if_t<std::is_copy_constructible<typename Vector::va cl.def("__setitem__", [](Vector &v, SizeType i, const T &t) { if (i >= v.size()) - throw pybind11::index_error(); + throw index_error(); v[i] = t; } ); @@ -189,7 +189,7 @@ void vector_modifiers(enable_if_t<std::is_copy_constructible<typename Vector::va size_t start, stop, step, slicelength; if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) - throw pybind11::error_already_set(); + throw error_already_set(); Vector *seq = new Vector(); seq->reserve((size_t) slicelength); @@ -208,7 +208,7 @@ void vector_modifiers(enable_if_t<std::is_copy_constructible<typename Vector::va [](Vector &v, slice slice, const Vector &value) { size_t start, stop, step, slicelength; if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) - throw pybind11::error_already_set(); + throw error_already_set(); if (slicelength != value.size()) throw std::runtime_error("Left and right hand size of slice assignment have different sizes!"); @@ -224,7 +224,7 @@ void vector_modifiers(enable_if_t<std::is_copy_constructible<typename Vector::va cl.def("__delitem__", [](Vector &v, SizeType i) { if (i >= v.size()) - throw pybind11::index_error(); + throw index_error(); v.erase(v.begin() + DiffType(i)); }, "Delete the list elements at index ``i``" @@ -235,7 +235,7 @@ void vector_modifiers(enable_if_t<std::is_copy_constructible<typename Vector::va size_t start, stop, step, slicelength; if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) - throw pybind11::error_already_set(); + throw error_already_set(); if (step == 1 && false) { v.erase(v.begin() + (DiffType) start, v.begin() + DiffType(start + slicelength)); @@ -253,8 +253,8 @@ void vector_modifiers(enable_if_t<std::is_copy_constructible<typename Vector::va // If the type has an operator[] that doesn't return a reference (most notably std::vector<bool>), // we have to access by copying; otherwise we return by reference. -template <typename Vector> using vector_needs_copy = bool_constant< - !std::is_same<decltype(std::declval<Vector>()[typename Vector::size_type()]), typename Vector::value_type &>::value>; +template <typename Vector> using vector_needs_copy = negation< + std::is_same<decltype(std::declval<Vector>()[typename Vector::size_type()]), typename Vector::value_type &>>; // The usual case: access and iterate by reference template <typename Vector, typename Class_> @@ -266,7 +266,7 @@ void vector_accessor(enable_if_t<!vector_needs_copy<Vector>::value, Class_> &cl) cl.def("__getitem__", [](Vector &v, SizeType i) -> T & { if (i >= v.size()) - throw pybind11::index_error(); + throw index_error(); return v[i]; }, return_value_policy::reference_internal // ref + keepalive @@ -274,7 +274,7 @@ void vector_accessor(enable_if_t<!vector_needs_copy<Vector>::value, Class_> &cl) cl.def("__iter__", [](Vector &v) { - return pybind11::make_iterator< + return make_iterator< return_value_policy::reference_internal, ItType, ItType, T&>( v.begin(), v.end()); }, @@ -291,14 +291,14 @@ void vector_accessor(enable_if_t<vector_needs_copy<Vector>::value, Class_> &cl) cl.def("__getitem__", [](const Vector &v, SizeType i) -> T { if (i >= v.size()) - throw pybind11::index_error(); + throw index_error(); return v[i]; } ); cl.def("__iter__", [](Vector &v) { - return pybind11::make_iterator< + return make_iterator< return_value_policy::copy, ItType, ItType, T>( v.begin(), v.end()); }, @@ -326,18 +326,64 @@ template <typename Vector, typename Class_> auto vector_if_insertion_operator(Cl ); } +// Provide the buffer interface for vectors if we have data() and we have a format for it +// GCC seems to have "void std::vector<bool>::data()" - doing SFINAE on the existence of data() is insufficient, we need to check it returns an appropriate pointer +template <typename Vector, typename = void> +struct vector_has_data_and_format : std::false_type {}; +template <typename Vector> +struct vector_has_data_and_format<Vector, enable_if_t<std::is_same<decltype(format_descriptor<typename Vector::value_type>::format(), std::declval<Vector>().data()), typename Vector::value_type*>::value>> : std::true_type {}; + +// Add the buffer interface to a vector +template <typename Vector, typename Class_, typename... Args> +enable_if_t<detail::any_of<std::is_same<Args, buffer_protocol>...>::value> +vector_buffer(Class_& cl) { + using T = typename Vector::value_type; + + static_assert(vector_has_data_and_format<Vector>::value, "There is not an appropriate format descriptor for this vector"); + + // numpy.h declares this for arbitrary types, but it may raise an exception and crash hard at runtime if PYBIND11_NUMPY_DTYPE hasn't been called, so check here + format_descriptor<T>::format(); + + cl.def_buffer([](Vector& v) -> buffer_info { + return buffer_info(v.data(), sizeof(T), format_descriptor<T>::format(), 1, {v.size()}, {sizeof(T)}); + }); + + cl.def("__init__", [](Vector& vec, buffer buf) { + auto info = buf.request(); + if (info.ndim != 1 || info.strides[0] <= 0 || info.strides[0] % sizeof(T)) + throw type_error("Only valid 1D buffers can be copied to a vector"); + if (!detail::compare_buffer_info<T>::compare(info) || sizeof(T) != info.itemsize) + throw type_error("Format mismatch (Python: " + info.format + " C++: " + format_descriptor<T>::format() + ")"); + new (&vec) Vector(); + vec.reserve(info.shape[0]); + T *p = static_cast<T*>(info.ptr); + auto step = info.strides[0] / sizeof(T); + T *end = p + info.shape[0] * step; + for (; p < end; p += step) + vec.push_back(*p); + }); + + return; +} + +template <typename Vector, typename Class_, typename... Args> +enable_if_t<!detail::any_of<std::is_same<Args, buffer_protocol>...>::value> vector_buffer(Class_&) {} + NAMESPACE_END(detail) // // std::vector // template <typename Vector, typename holder_type = std::unique_ptr<Vector>, typename... Args> -pybind11::class_<Vector, holder_type> bind_vector(pybind11::module &m, std::string const &name, Args&&... args) { - using Class_ = pybind11::class_<Vector, holder_type>; +class_<Vector, holder_type> bind_vector(module &m, std::string const &name, Args&&... args) { + using Class_ = class_<Vector, holder_type>; Class_ cl(m, name.c_str(), std::forward<Args>(args)...); - cl.def(pybind11::init<>()); + // Declare the buffer interface if a buffer_protocol() is passed in + detail::vector_buffer<Vector, Class_, Args...>(cl); + + cl.def(init<>()); // Register copy constructor (if possible) detail::vector_if_copy_constructible<Vector, Class_>(cl); @@ -368,7 +414,7 @@ pybind11::class_<Vector, holder_type> bind_vector(pybind11::module &m, std::stri #if 0 // C++ style functions deprecated, leaving it here as an example - cl.def(pybind11::init<size_type>()); + cl.def(init<size_type>()); cl.def("resize", (void (Vector::*) (size_type count)) & Vector::resize, @@ -377,7 +423,7 @@ pybind11::class_<Vector, holder_type> bind_vector(pybind11::module &m, std::stri cl.def("erase", [](Vector &v, SizeType i) { if (i >= v.size()) - throw pybind11::index_error(); + throw index_error(); v.erase(v.begin() + i); }, "erases element at index ``i``"); @@ -396,12 +442,12 @@ pybind11::class_<Vector, holder_type> bind_vector(pybind11::module &m, std::stri cl.def("front", [](Vector &v) { if (v.size()) return v.front(); - else throw pybind11::index_error(); + else throw index_error(); }, "access the first element"); cl.def("back", [](Vector &v) { if (v.size()) return v.back(); - else throw pybind11::index_error(); + else throw index_error(); }, "access the last element "); #endif @@ -484,14 +530,14 @@ template <typename Map, typename Class_> auto map_if_insertion_operator(Class_ & NAMESPACE_END(detail) template <typename Map, typename holder_type = std::unique_ptr<Map>, typename... Args> -pybind11::class_<Map, holder_type> bind_map(module &m, const std::string &name, Args&&... args) { +class_<Map, holder_type> bind_map(module &m, const std::string &name, Args&&... args) { using KeyType = typename Map::key_type; using MappedType = typename Map::mapped_type; - using Class_ = pybind11::class_<Map, holder_type>; + using Class_ = class_<Map, holder_type>; Class_ cl(m, name.c_str(), std::forward<Args>(args)...); - cl.def(pybind11::init<>()); + cl.def(init<>()); // Register stream insertion operator (if possible) detail::map_if_insertion_operator<Map, Class_>(cl, name); @@ -502,20 +548,20 @@ pybind11::class_<Map, holder_type> bind_map(module &m, const std::string &name, ); cl.def("__iter__", - [](Map &m) { return pybind11::make_key_iterator(m.begin(), m.end()); }, - pybind11::keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ + [](Map &m) { return make_key_iterator(m.begin(), m.end()); }, + keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ ); cl.def("items", - [](Map &m) { return pybind11::make_iterator(m.begin(), m.end()); }, - pybind11::keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ + [](Map &m) { return make_iterator(m.begin(), m.end()); }, + keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ ); cl.def("__getitem__", [](Map &m, const KeyType &k) -> MappedType & { auto it = m.find(k); if (it == m.end()) - throw pybind11::key_error(); + throw key_error(); return it->second; }, return_value_policy::reference_internal // ref + keepalive @@ -528,7 +574,7 @@ pybind11::class_<Map, holder_type> bind_map(module &m, const std::string &name, [](Map &m, const KeyType &k) { auto it = m.find(k); if (it == m.end()) - throw pybind11::key_error(); + throw key_error(); return m.erase(it); } ); |