diff options
Diffstat (limited to 'ext/pybind11/include')
19 files changed, 1363 insertions, 710 deletions
diff --git a/ext/pybind11/include/pybind11/attr.h b/ext/pybind11/include/pybind11/attr.h index dce875a6b..6962d6fc5 100644 --- a/ext/pybind11/include/pybind11/attr.h +++ b/ext/pybind11/include/pybind11/attr.h @@ -200,7 +200,8 @@ struct function_record { /// Special data structure which (temporarily) holds metadata about a bound class struct type_record { PYBIND11_NOINLINE type_record() - : multiple_inheritance(false), dynamic_attr(false), buffer_protocol(false), module_local(false) { } + : multiple_inheritance(false), dynamic_attr(false), buffer_protocol(false), + default_holder(true), module_local(false) { } /// Handle to the parent scope handle scope; @@ -214,11 +215,14 @@ struct type_record { /// How large is the underlying C++ type? size_t type_size = 0; + /// What is the alignment of the underlying C++ type? + size_t type_align = 0; + /// How large is the type's holder? size_t holder_size = 0; /// The global operator new can be overridden with a class-specific variant - void *(*operator_new)(size_t) = ::operator new; + void *(*operator_new)(size_t) = nullptr; /// Function pointer to class_<..>::init_instance void (*init_instance)(instance *, const void *) = nullptr; @@ -278,7 +282,7 @@ struct type_record { } }; -inline function_call::function_call(function_record &f, handle p) : +inline function_call::function_call(const function_record &f, handle p) : func(f), parent(p) { args.reserve(f.nargs); args_convert.reserve(f.nargs); diff --git a/ext/pybind11/include/pybind11/cast.h b/ext/pybind11/include/pybind11/cast.h index eab904bee..605acb366 100644 --- a/ext/pybind11/include/pybind11/cast.h +++ b/ext/pybind11/include/pybind11/cast.h @@ -17,6 +17,7 @@ #include <array> #include <limits> #include <tuple> +#include <type_traits> #if defined(PYBIND11_CPP17) # if defined(__has_include) @@ -203,10 +204,10 @@ PYBIND11_NOINLINE inline handle get_type_handle(const std::type_info &tp, bool t } struct value_and_holder { - instance *inst; - size_t index; - const detail::type_info *type; - void **vh; + instance *inst = nullptr; + size_t index = 0u; + const detail::type_info *type = nullptr; + void **vh = nullptr; // Main constructor for a found value/holder: value_and_holder(instance *i, const detail::type_info *type, size_t vpos, size_t index) : @@ -215,7 +216,7 @@ struct value_and_holder { {} // Default constructor (used to signal a value-and-holder not found by get_value_and_holder()) - value_and_holder() : inst{nullptr} {} + value_and_holder() {} // Used for past-the-end iterator value_and_holder(size_t index) : index{index} {} @@ -269,8 +270,8 @@ public: struct iterator { private: - instance *inst; - const type_vec *types; + instance *inst = nullptr; + const type_vec *types = nullptr; value_and_holder curr; friend struct values_and_holders; iterator(instance *inst, const type_vec *tinfo) @@ -570,7 +571,17 @@ public: // Lazy allocation for unallocated values: if (vptr == nullptr) { auto *type = v_h.type ? v_h.type : typeinfo; - vptr = type->operator_new(type->type_size); + if (type->operator_new) { + vptr = type->operator_new(type->type_size); + } else { + #if defined(PYBIND11_CPP17) + if (type->type_align > __STDCPP_DEFAULT_NEW_ALIGNMENT__) + vptr = ::operator new(type->type_size, + (std::align_val_t) type->type_align); + else + #endif + vptr = ::operator new(type->type_size); + } } value = vptr; } @@ -764,7 +775,9 @@ template <typename T, typename SFINAE = void> struct is_copy_constructible : std // so, copy constructability depends on whether the value_type is copy constructible. template <typename Container> struct is_copy_constructible<Container, enable_if_t<all_of< std::is_copy_constructible<Container>, - std::is_same<typename Container::value_type &, typename Container::reference> + std::is_same<typename Container::value_type &, typename Container::reference>, + // Avoid infinite recursion + negation<std::is_same<Container, typename Container::value_type>> >::value>> : is_copy_constructible<typename Container::value_type> {}; #if !defined(PYBIND11_CPP17) @@ -774,11 +787,47 @@ template <typename T1, typename T2> struct is_copy_constructible<std::pair<T1, T : all_of<is_copy_constructible<T1>, is_copy_constructible<T2>> {}; #endif +NAMESPACE_END(detail) + +// polymorphic_type_hook<itype>::get(src, tinfo) determines whether the object pointed +// to by `src` actually is an instance of some class derived from `itype`. +// If so, it sets `tinfo` to point to the std::type_info representing that derived +// type, and returns a pointer to the start of the most-derived object of that type +// (in which `src` is a subobject; this will be the same address as `src` in most +// single inheritance cases). If not, or if `src` is nullptr, it simply returns `src` +// and leaves `tinfo` at its default value of nullptr. +// +// The default polymorphic_type_hook just returns src. A specialization for polymorphic +// types determines the runtime type of the passed object and adjusts the this-pointer +// appropriately via dynamic_cast<void*>. This is what enables a C++ Animal* to appear +// to Python as a Dog (if Dog inherits from Animal, Animal is polymorphic, Dog is +// registered with pybind11, and this Animal is in fact a Dog). +// +// You may specialize polymorphic_type_hook yourself for types that want to appear +// polymorphic to Python but do not use C++ RTTI. (This is a not uncommon pattern +// in performance-sensitive applications, used most notably in LLVM.) +template <typename itype, typename SFINAE = void> +struct polymorphic_type_hook +{ + static const void *get(const itype *src, const std::type_info*&) { return src; } +}; +template <typename itype> +struct polymorphic_type_hook<itype, detail::enable_if_t<std::is_polymorphic<itype>::value>> +{ + static const void *get(const itype *src, const std::type_info*& type) { + type = src ? &typeid(*src) : nullptr; + return dynamic_cast<const void*>(src); + } +}; + +NAMESPACE_BEGIN(detail) + /// Generic type caster for objects stored on the heap template <typename type> class type_caster_base : public type_caster_generic { using itype = intrinsic_t<type>; + public: - static PYBIND11_DESCR name() { return type_descr(_<type>()); } + static constexpr auto name = _<type>(); type_caster_base() : type_caster_base(typeid(type)) { } explicit type_caster_base(const std::type_info &info) : type_caster_generic(info) { } @@ -793,32 +842,28 @@ public: return cast(&src, return_value_policy::move, parent); } - // Returns a (pointer, type_info) pair taking care of necessary RTTI type lookup for a - // polymorphic type. If the instance isn't derived, returns the non-RTTI base version. - template <typename T = itype, enable_if_t<std::is_polymorphic<T>::value, int> = 0> + // Returns a (pointer, type_info) pair taking care of necessary type lookup for a + // polymorphic type (using RTTI by default, but can be overridden by specializing + // polymorphic_type_hook). If the instance isn't derived, returns the base version. static std::pair<const void *, const type_info *> src_and_type(const itype *src) { - const void *vsrc = src; auto &cast_type = typeid(itype); const std::type_info *instance_type = nullptr; - if (vsrc) { - instance_type = &typeid(*src); - if (!same_type(cast_type, *instance_type)) { - // This is a base pointer to a derived type; if it is a pybind11-registered type, we - // can get the correct derived pointer (which may be != base pointer) by a - // dynamic_cast to most derived type: - if (auto *tpi = get_type_info(*instance_type)) - return {dynamic_cast<const void *>(src), const_cast<const type_info *>(tpi)}; - } + const void *vsrc = polymorphic_type_hook<itype>::get(src, instance_type); + if (instance_type && !same_type(cast_type, *instance_type)) { + // This is a base pointer to a derived type. If the derived type is registered + // with pybind11, we want to make the full derived object available. + // In the typical case where itype is polymorphic, we get the correct + // derived pointer (which may be != base pointer) by a dynamic_cast to + // most derived type. If itype is not polymorphic, we won't get here + // except via a user-provided specialization of polymorphic_type_hook, + // and the user has promised that no this-pointer adjustment is + // required in that case, so it's OK to use static_cast. + if (const auto *tpi = get_type_info(*instance_type)) + return {vsrc, tpi}; } // Otherwise we have either a nullptr, an `itype` pointer, or an unknown derived pointer, so // don't do a cast - return type_caster_generic::src_and_type(vsrc, cast_type, instance_type); - } - - // Non-polymorphic type, so no dynamic casting; just call the generic version directly - template <typename T = itype, enable_if_t<!std::is_polymorphic<T>::value, int> = 0> - static std::pair<const void *, const type_info *> src_and_type(const itype *src) { - return type_caster_generic::src_and_type(src, typeid(itype)); + return type_caster_generic::src_and_type(src, cast_type, instance_type); } static handle cast(const itype *src, return_value_policy policy, handle parent) { @@ -835,7 +880,7 @@ public: nullptr, nullptr, holder); } - template <typename T> using cast_op_type = cast_op_type<T>; + template <typename T> using cast_op_type = detail::cast_op_type<T>; operator itype*() { return (type *) value; } operator itype&() { if (!value) throw reference_cast_error(); return *((itype *) value); } @@ -885,7 +930,7 @@ private: "std::reference_wrapper<T> caster requires T to have a caster with an `T &` operator"); public: bool load(handle src, bool convert) { return subcaster.load(src, convert); } - static PYBIND11_DESCR name() { return caster_t::name(); } + static constexpr auto name = caster_t::name; static handle cast(const std::reference_wrapper<type> &src, return_value_policy policy, handle parent) { // It is definitely wrong to take ownership of this pointer, so mask that rvp if (policy == return_value_policy::take_ownership || policy == return_value_policy::automatic) @@ -900,7 +945,7 @@ public: protected: \ type value; \ public: \ - static PYBIND11_DESCR name() { return type_descr(py_name); } \ + static constexpr auto name = py_name; \ template <typename T_, enable_if_t<std::is_same<type, remove_cv_t<T_>>::value, int> = 0> \ static handle cast(T_ *src, return_value_policy policy, handle parent) { \ if (!src) return none().release(); \ @@ -952,9 +997,11 @@ public: } bool py_err = py_value == (py_type) -1 && PyErr_Occurred(); + + // Protect std::numeric_limits::min/max with parentheses if (py_err || (std::is_integral<T>::value && sizeof(py_type) != sizeof(T) && - (py_value < (py_type) std::numeric_limits<T>::min() || - py_value > (py_type) std::numeric_limits<T>::max()))) { + (py_value < (py_type) (std::numeric_limits<T>::min)() || + py_value > (py_type) (std::numeric_limits<T>::max)()))) { bool type_error = py_err && PyErr_ExceptionMatches( #if PY_VERSION_HEX < 0x03000000 && !defined(PYPY_VERSION) PyExc_SystemError @@ -977,20 +1024,34 @@ public: return true; } - static handle cast(T src, return_value_policy /* policy */, handle /* parent */) { - if (std::is_floating_point<T>::value) { - return PyFloat_FromDouble((double) src); - } else if (sizeof(T) <= sizeof(long)) { - if (std::is_signed<T>::value) - return PyLong_FromLong((long) src); - else - return PyLong_FromUnsignedLong((unsigned long) src); - } else { - if (std::is_signed<T>::value) - return PyLong_FromLongLong((long long) src); - else - return PyLong_FromUnsignedLongLong((unsigned long long) src); - } + template<typename U = T> + static typename std::enable_if<std::is_floating_point<U>::value, handle>::type + cast(U src, return_value_policy /* policy */, handle /* parent */) { + return PyFloat_FromDouble((double) src); + } + + template<typename U = T> + static typename std::enable_if<!std::is_floating_point<U>::value && std::is_signed<U>::value && (sizeof(U) <= sizeof(long)), handle>::type + cast(U src, return_value_policy /* policy */, handle /* parent */) { + return PYBIND11_LONG_FROM_SIGNED((long) src); + } + + template<typename U = T> + static typename std::enable_if<!std::is_floating_point<U>::value && std::is_unsigned<U>::value && (sizeof(U) <= sizeof(unsigned long)), handle>::type + cast(U src, return_value_policy /* policy */, handle /* parent */) { + return PYBIND11_LONG_FROM_UNSIGNED((unsigned long) src); + } + + template<typename U = T> + static typename std::enable_if<!std::is_floating_point<U>::value && std::is_signed<U>::value && (sizeof(U) > sizeof(long)), handle>::type + cast(U src, return_value_policy /* policy */, handle /* parent */) { + return PyLong_FromLongLong((long long) src); + } + + template<typename U = T> + static typename std::enable_if<!std::is_floating_point<U>::value && std::is_unsigned<U>::value && (sizeof(U) > sizeof(unsigned long)), handle>::type + cast(U src, return_value_policy /* policy */, handle /* parent */) { + return PyLong_FromUnsignedLongLong((unsigned long long) src); } PYBIND11_TYPE_CASTER(T, _<std::is_integral<T>::value>("int", "float")); @@ -1049,7 +1110,7 @@ public: template <typename T> using cast_op_type = void*&; operator void *&() { return value; } - static PYBIND11_DESCR name() { return type_descr(_("capsule")); } + static constexpr auto name = _("capsule"); private: void *value = nullptr; }; @@ -1171,7 +1232,7 @@ private: #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 + // non-const char * arguments, which is also a nuisance, so bypass the whole thing by just // passing the encoding as a string value, which works properly: return PyUnicode_Decode(buffer, nbytes, UTF_N == 8 ? "utf-8" : UTF_N == 16 ? "utf-16" : "utf-32", nullptr); #endif @@ -1216,6 +1277,7 @@ template <typename CharT> struct type_caster<CharT, enable_if_t<is_std_char_type using StringCaster = type_caster<StringType>; StringCaster str_caster; bool none = false; + CharT one_char = 0; public: bool load(handle src, bool convert) { if (!src) return false; @@ -1243,7 +1305,7 @@ public: } operator CharT*() { return none ? nullptr : const_cast<CharT *>(static_cast<StringType &>(str_caster).c_str()); } - operator CharT() { + operator CharT&() { if (none) throw value_error("Cannot convert None to a character"); @@ -1267,7 +1329,8 @@ public: 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)); + one_char = static_cast<CharT>(((v0 & 3) << 6) + (static_cast<unsigned char>(value[1]) & 0x3F)); + return one_char; } // Otherwise we have a single character, but it's > U+00FF throw value_error("Character code point not in range(0x100)"); @@ -1278,19 +1341,20 @@ public: // 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) + one_char = static_cast<CharT>(value[0]); + if (one_char >= 0xD800 && one_char < 0xE000) throw value_error("Character code point not in range(0x10000)"); } if (str_len != 1) throw value_error("Expected a character, but multi-character string found"); - return value[0]; + one_char = value[0]; + return one_char; } - static PYBIND11_DESCR name() { return type_descr(_(PYBIND11_STRING_NAME)); } - template <typename _T> using cast_op_type = remove_reference_t<pybind11::detail::cast_op_type<_T>>; + static constexpr auto name = _(PYBIND11_STRING_NAME); + template <typename _T> using cast_op_type = pybind11::detail::cast_op_type<_T>; }; // Base implementation for std::tuple and std::pair @@ -1314,9 +1378,7 @@ public: return cast_impl(std::forward<T>(src), policy, parent, indices{}); } - static PYBIND11_DESCR name() { - return type_descr(_("Tuple[") + detail::concat(make_caster<Ts>::name()...) + _("]")); - } + static constexpr auto name = _("Tuple[") + concat(make_caster<Ts>::name...) + _("]"); template <typename T> using cast_op_type = type; @@ -1389,7 +1451,7 @@ public: explicit operator type*() { return this->value; } explicit operator type&() { return *(this->value); } - explicit operator holder_type*() { return &holder; } + explicit operator holder_type*() { return std::addressof(holder); } // Workaround for Intel compiler bug // see pybind11 issue 94 @@ -1414,7 +1476,7 @@ protected: bool load_value(value_and_holder &&v_h) { if (v_h.holder_constructed()) { value = v_h.value_ptr(); - holder = v_h.holder<holder_type>(); + holder = v_h.template holder<holder_type>(); return true; } else { throw cast_error("Unable to cast from non-held to held instance (T& to Holder<T>) " @@ -1459,9 +1521,9 @@ 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); + return type_caster_base<type>::cast_holder(ptr, std::addressof(src)); } - static PYBIND11_DESCR name() { return type_caster_base<type>::name(); } + static constexpr auto name = type_caster_base<type>::name; }; template <typename type, typename deleter> @@ -1492,10 +1554,10 @@ template <typename base, typename holder> struct is_holder_type : template <typename base, typename deleter> struct is_holder_type<base, std::unique_ptr<base, deleter>> : std::true_type {}; -template <typename T> struct handle_type_name { static PYBIND11_DESCR name() { return _<T>(); } }; -template <> struct handle_type_name<bytes> { static PYBIND11_DESCR name() { return _(PYBIND11_BYTES_NAME); } }; -template <> struct handle_type_name<args> { static PYBIND11_DESCR name() { return _("*args"); } }; -template <> struct handle_type_name<kwargs> { static PYBIND11_DESCR name() { return _("**kwargs"); } }; +template <typename T> struct handle_type_name { static constexpr auto name = _<T>(); }; +template <> struct handle_type_name<bytes> { static constexpr auto name = _(PYBIND11_BYTES_NAME); }; +template <> struct handle_type_name<args> { static constexpr auto name = _("*args"); }; +template <> struct handle_type_name<kwargs> { static constexpr auto name = _("**kwargs"); }; template <typename type> struct pyobject_caster { @@ -1513,7 +1575,7 @@ struct pyobject_caster { static handle cast(const handle &src, return_value_policy /* policy */, handle /* parent */) { return src.inc_ref(); } - PYBIND11_TYPE_CASTER(type, handle_type_name<type>::name()); + PYBIND11_TYPE_CASTER(type, handle_type_name<type>::name); }; template <typename T> @@ -1553,17 +1615,23 @@ template <typename T> using move_never = none_of<move_always<T>, move_if_unrefer // everything else returns a reference/pointer to a local variable. template <typename type> using cast_is_temporary_value_reference = bool_constant< (std::is_reference<type>::value || std::is_pointer<type>::value) && - !std::is_base_of<type_caster_generic, make_caster<type>>::value + !std::is_base_of<type_caster_generic, make_caster<type>>::value && + !std::is_same<intrinsic_t<type>, void>::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. +// with. template <typename Return, typename SFINAE = void> struct return_value_policy_override { + static return_value_policy policy(return_value_policy p) { return p; } +}; + +template <typename Return> struct return_value_policy_override<Return, + detail::enable_if_t<std::is_base_of<type_caster_generic, make_caster<Return>>::value, void>> { 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; + return !std::is_lvalue_reference<Return>::value && + !std::is_pointer<Return>::value + ? return_value_policy::move : p; } }; @@ -1574,7 +1642,7 @@ template <typename T, typename SFINAE> type_caster<T, SFINAE> &load_type(type_ca throw cast_error("Unable to cast Python instance to C++ type (compile in debug mode for details)"); #else throw cast_error("Unable to cast Python instance of type " + - (std::string) str(handle.get_type()) + " to C++ type '" + type_id<T>() + "''"); + (std::string) str(handle.get_type()) + " to C++ type '" + type_id<T>() + "'"); #endif } return conv; @@ -1683,6 +1751,9 @@ template <> inline void cast_safe<void>(object &&) {} NAMESPACE_END(detail) +template <return_value_policy policy = return_value_policy::automatic_reference> +tuple make_tuple() { return tuple(0); } + template <return_value_policy policy = return_value_policy::automatic_reference, typename... Args> tuple make_tuple(Args&&... args_) { constexpr size_t size = sizeof...(Args); @@ -1788,7 +1859,7 @@ 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 + function_call(const function_record &f, handle p); // Implementation in attr.h /// The function data: const function_record &func; @@ -1799,6 +1870,10 @@ struct function_call { /// The `convert` value the arguments should be loaded with std::vector<bool> args_convert; + /// Extra references for the optional `py::args` and/or `py::kwargs` arguments (which, if + /// present, are also in `args` but without a reference). + object args_ref, kwargs_ref; + /// The parent, if any handle parent; @@ -1826,7 +1901,7 @@ public: 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()...); } + static constexpr auto arg_names = concat(type_descr(make_caster<Args>::name)...); bool load_args(function_call &call) { return load_impl_sequence(call, indices{}); @@ -2045,9 +2120,13 @@ object object_api<Derived>::call(Args &&...args) const { NAMESPACE_END(detail) -#define PYBIND11_MAKE_OPAQUE(Type) \ +#define PYBIND11_MAKE_OPAQUE(...) \ namespace pybind11 { namespace detail { \ - template<> class type_caster<Type> : public type_caster_base<Type> { }; \ + template<> class type_caster<__VA_ARGS__> : public type_caster_base<__VA_ARGS__> { }; \ }} +/// Lets you pass a type containing a `,` through a macro parameter without needing a separate +/// typedef, e.g.: `PYBIND11_OVERLOAD(PYBIND11_TYPE(ReturnType<A, B>), PYBIND11_TYPE(Parent<C, D>), f, arg)` +#define PYBIND11_TYPE(...) __VA_ARGS__ + NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/ext/pybind11/include/pybind11/chrono.h b/ext/pybind11/include/pybind11/chrono.h index 95ada76e0..ea777e696 100644 --- a/ext/pybind11/include/pybind11/chrono.h +++ b/ext/pybind11/include/pybind11/chrono.h @@ -106,8 +106,11 @@ public: if (!PyDateTimeAPI) { PyDateTime_IMPORT; } if (!src) return false; + + std::tm cal; + microseconds msecs; + if (PyDateTime_Check(src.ptr())) { - std::tm cal; cal.tm_sec = PyDateTime_DATE_GET_SECOND(src.ptr()); cal.tm_min = PyDateTime_DATE_GET_MINUTE(src.ptr()); cal.tm_hour = PyDateTime_DATE_GET_HOUR(src.ptr()); @@ -115,11 +118,30 @@ public: cal.tm_mon = PyDateTime_GET_MONTH(src.ptr()) - 1; cal.tm_year = PyDateTime_GET_YEAR(src.ptr()) - 1900; cal.tm_isdst = -1; - - value = system_clock::from_time_t(std::mktime(&cal)) + microseconds(PyDateTime_DATE_GET_MICROSECOND(src.ptr())); - return true; + msecs = microseconds(PyDateTime_DATE_GET_MICROSECOND(src.ptr())); + } else if (PyDate_Check(src.ptr())) { + cal.tm_sec = 0; + cal.tm_min = 0; + cal.tm_hour = 0; + cal.tm_mday = PyDateTime_GET_DAY(src.ptr()); + cal.tm_mon = PyDateTime_GET_MONTH(src.ptr()) - 1; + cal.tm_year = PyDateTime_GET_YEAR(src.ptr()) - 1900; + cal.tm_isdst = -1; + msecs = microseconds(0); + } else if (PyTime_Check(src.ptr())) { + cal.tm_sec = PyDateTime_TIME_GET_SECOND(src.ptr()); + cal.tm_min = PyDateTime_TIME_GET_MINUTE(src.ptr()); + cal.tm_hour = PyDateTime_TIME_GET_HOUR(src.ptr()); + cal.tm_mday = 1; // This date (day, month, year) = (1, 0, 70) + cal.tm_mon = 0; // represents 1-Jan-1970, which is the first + cal.tm_year = 70; // earliest available date for Python's datetime + cal.tm_isdst = -1; + msecs = microseconds(PyDateTime_TIME_GET_MICROSECOND(src.ptr())); } else return false; + + value = system_clock::from_time_t(std::mktime(&cal)) + msecs; + return true; } static handle cast(const std::chrono::time_point<std::chrono::system_clock, Duration> &src, return_value_policy /* policy */, handle /* parent */) { @@ -128,7 +150,7 @@ public: // Lazy initialise the PyDateTime import if (!PyDateTimeAPI) { PyDateTime_IMPORT; } - std::time_t tt = system_clock::to_time_t(src); + std::time_t tt = system_clock::to_time_t(time_point_cast<system_clock::duration>(src)); // this function uses static memory so it's best to copy it out asap just in case // otherwise other code that is using localtime may break this (not just python code) std::tm localtime = *std::localtime(&tt); diff --git a/ext/pybind11/include/pybind11/complex.h b/ext/pybind11/include/pybind11/complex.h index 5dac27cc4..3f8963857 100644 --- a/ext/pybind11/include/pybind11/complex.h +++ b/ext/pybind11/include/pybind11/complex.h @@ -25,9 +25,13 @@ template <typename T> struct format_descriptor<std::complex<T>, detail::enable_i static std::string format() { return std::string(value); } }; +#ifndef PYBIND11_CPP17 + template <typename T> constexpr const char format_descriptor< std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>>::value[3]; +#endif + NAMESPACE_BEGIN(detail) template <typename T> struct is_fmt_numeric<std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>> { diff --git a/ext/pybind11/include/pybind11/detail/class.h b/ext/pybind11/include/pybind11/detail/class.h index f745992a0..ffdfefe74 100644 --- a/ext/pybind11/include/pybind11/detail/class.h +++ b/ext/pybind11/include/pybind11/detail/class.h @@ -10,10 +10,20 @@ #pragma once #include "../attr.h" +#include "../options.h" NAMESPACE_BEGIN(PYBIND11_NAMESPACE) NAMESPACE_BEGIN(detail) +#if PY_VERSION_HEX >= 0x03030000 +# define PYBIND11_BUILTIN_QUALNAME +# define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj) +#else +// In pre-3.3 Python, we still set __qualname__ so that we can produce reliable function type +// signatures; in 3.3+ this macro expands to nothing: +# define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj) setattr((PyObject *) obj, "__qualname__", nameobj) +#endif + inline PyTypeObject *type_incref(PyTypeObject *type) { Py_INCREF(type); return type; @@ -48,7 +58,7 @@ inline PyTypeObject *make_static_property_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 +#ifdef PYBIND11_BUILTIN_QUALNAME heap_type->ht_qualname = name_obj.inc_ref().ptr(); #endif @@ -63,6 +73,7 @@ inline PyTypeObject *make_static_property_type() { pybind11_fail("make_static_property_type(): failure in PyType_Ready()!"); setattr((PyObject *) type, "__module__", str("pybind11_builtins")); + PYBIND11_SET_OLDPY_QUALNAME(type, name_obj); return type; } @@ -161,7 +172,7 @@ inline PyTypeObject* make_default_metaclass() { 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 +#ifdef PYBIND11_BUILTIN_QUALNAME heap_type->ht_qualname = name_obj.inc_ref().ptr(); #endif @@ -179,6 +190,7 @@ inline PyTypeObject* make_default_metaclass() { pybind11_fail("make_default_metaclass(): failure in PyType_Ready()!"); setattr((PyObject *) type, "__module__", str("pybind11_builtins")); + PYBIND11_SET_OLDPY_QUALNAME(type, name_obj); return type; } @@ -363,7 +375,7 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass) { 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 +#ifdef PYBIND11_BUILTIN_QUALNAME heap_type->ht_qualname = name_obj.inc_ref().ptr(); #endif @@ -384,6 +396,7 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass) { pybind11_fail("PyType_Ready failed in make_object_base_type():" + error_string()); setattr((PyObject *) type, "__module__", str("pybind11_builtins")); + PYBIND11_SET_OLDPY_QUALNAME(type, name_obj); assert(!PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC)); return (PyObject *) heap_type; @@ -456,7 +469,7 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla if (tinfo && tinfo->get_buffer) break; } - if (view == nullptr || obj == nullptr || !tinfo || !tinfo->get_buffer) { + if (view == nullptr || !tinfo || !tinfo->get_buffer) { if (view) view->obj = nullptr; PyErr_SetString(PyExc_BufferError, "pybind11_getbuffer(): Internal error"); @@ -504,13 +517,15 @@ inline void enable_buffer_protocol(PyHeapTypeObject *heap_type) { 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>( + auto qualname = name; + if (rec.scope && !PyModule_Check(rec.scope.ptr()) && hasattr(rec.scope, "__qualname__")) { +#if PY_MAJOR_VERSION >= 3 + qualname = reinterpret_steal<object>( PyUnicode_FromFormat("%U.%U", rec.scope.attr("__qualname__").ptr(), name.ptr())); - } +#else + qualname = str(rec.scope.attr("__qualname__").cast<std::string>() + "." + rec.name); #endif + } object module; if (rec.scope) { @@ -552,8 +567,8 @@ inline PyObject* make_new_python_type(const type_record &rec) { 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(); +#ifdef PYBIND11_BUILTIN_QUALNAME + heap_type->ht_qualname = qualname.inc_ref().ptr(); #endif auto type = &heap_type->ht_type; @@ -571,6 +586,9 @@ inline PyObject* make_new_python_type(const type_record &rec) { type->tp_as_number = &heap_type->as_number; type->tp_as_sequence = &heap_type->as_sequence; type->tp_as_mapping = &heap_type->as_mapping; +#if PY_VERSION_HEX >= 0x03050000 + type->tp_as_async = &heap_type->as_async; +#endif /* Flags */ type->tp_flags |= Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE; @@ -599,6 +617,8 @@ inline PyObject* make_new_python_type(const type_record &rec) { if (module) // Needed by pydoc setattr((PyObject *) type, "__module__", module); + PYBIND11_SET_OLDPY_QUALNAME(type, qualname); + return (PyObject *) type; } diff --git a/ext/pybind11/include/pybind11/detail/common.h b/ext/pybind11/include/pybind11/detail/common.h index 8f763f08a..879fb6ca9 100644 --- a/ext/pybind11/include/pybind11/detail/common.h +++ b/ext/pybind11/include/pybind11/detail/common.h @@ -27,15 +27,16 @@ # endif #endif -#if !defined(_MSC_VER) && !defined(__INTEL_COMPILER) +#if !(defined(_MSC_VER) && __cplusplus == 199711L) && !defined(__INTEL_COMPILER) # if __cplusplus >= 201402L # define PYBIND11_CPP14 -# if __cplusplus > 201402L /* Temporary: should be updated to >= the final C++17 value once known */ +# if __cplusplus >= 201703L # define PYBIND11_CPP17 # endif # endif -#elif defined(_MSC_VER) +#elif defined(_MSC_VER) && __cplusplus == 199711L // MSVC sets _MSVC_LANG rather than __cplusplus (supposedly until the standard is fully implemented) +// Unless you use the /Zc:__cplusplus flag on Visual Studio 2017 15.7 Preview 3 or newer # if _MSVC_LANG >= 201402L # define PYBIND11_CPP14 # if _MSVC_LANG > 201402L && _MSC_VER >= 1910 @@ -46,8 +47,8 @@ // Compiler version assertions #if defined(__INTEL_COMPILER) -# if __INTEL_COMPILER < 1500 -# error pybind11 requires Intel C++ compiler v15 or newer +# if __INTEL_COMPILER < 1700 +# error pybind11 requires Intel C++ compiler v17 or newer # endif #elif defined(__clang__) && !defined(__apple_build_version__) # if __clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ < 3) @@ -92,7 +93,7 @@ #endif #define PYBIND11_VERSION_MAJOR 2 -#define PYBIND11_VERSION_MINOR 2 +#define PYBIND11_VERSION_MINOR 4 #define PYBIND11_VERSION_PATCH 1 /// Include Python header, disable linking to pythonX_d.lib on Windows in debug mode @@ -112,10 +113,6 @@ #include <frameobject.h> #include <pythread.h> -#if defined(_WIN32) && (defined(min) || defined(max)) -# error Macro clash with min and max -- define NOMINMAX when compiling your program on Windows -#endif - #if defined(isalnum) # undef isalnum # undef isalpha @@ -158,6 +155,8 @@ #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_FROM_SIGNED(o) PyLong_FromSsize_t((ssize_t) o) +#define PYBIND11_LONG_FROM_UNSIGNED(o) PyLong_FromSize_t((size_t) o) #define PYBIND11_BYTES_NAME "bytes" #define PYBIND11_STRING_NAME "str" #define PYBIND11_SLICE_OBJECT PyObject @@ -165,7 +164,9 @@ #define PYBIND11_STR_TYPE ::pybind11::str #define PYBIND11_BOOL_ATTR "__bool__" #define PYBIND11_NB_BOOL(ptr) ((ptr)->nb_bool) +// Providing a separate declaration to make Clang's -Wmissing-prototypes happy #define PYBIND11_PLUGIN_IMPL(name) \ + extern "C" PYBIND11_EXPORT PyObject *PyInit_##name(); \ extern "C" PYBIND11_EXPORT PyObject *PyInit_##name() #else @@ -180,6 +181,8 @@ #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_FROM_SIGNED(o) PyInt_FromSsize_t((ssize_t) o) // Returns long if needed. +#define PYBIND11_LONG_FROM_UNSIGNED(o) PyInt_FromSize_t((size_t) o) // Returns long if needed. #define PYBIND11_BYTES_NAME "str" #define PYBIND11_STRING_NAME "unicode" #define PYBIND11_SLICE_OBJECT PySliceObject @@ -187,8 +190,10 @@ #define PYBIND11_STR_TYPE ::pybind11::bytes #define PYBIND11_BOOL_ATTR "__nonzero__" #define PYBIND11_NB_BOOL(ptr) ((ptr)->nb_nonzero) +// Providing a separate PyInit decl to make Clang's -Wmissing-prototypes happy #define PYBIND11_PLUGIN_IMPL(name) \ static PyObject *pybind11_init_wrapper(); \ + extern "C" PYBIND11_EXPORT void init##name(); \ extern "C" PYBIND11_EXPORT void init##name() { \ (void)pybind11_init_wrapper(); \ } \ @@ -207,6 +212,31 @@ extern "C" { #define PYBIND11_TOSTRING(x) PYBIND11_STRINGIFY(x) #define PYBIND11_CONCAT(first, second) first##second +#define PYBIND11_CHECK_PYTHON_VERSION \ + { \ + const char *compiled_ver = PYBIND11_TOSTRING(PY_MAJOR_VERSION) \ + "." PYBIND11_TOSTRING(PY_MINOR_VERSION); \ + const char *runtime_ver = Py_GetVersion(); \ + size_t len = std::strlen(compiled_ver); \ + if (std::strncmp(runtime_ver, compiled_ver, len) != 0 \ + || (runtime_ver[len] >= '0' && runtime_ver[len] <= '9')) { \ + PyErr_Format(PyExc_ImportError, \ + "Python version mismatch: module was compiled for Python %s, " \ + "but the interpreter version is incompatible: %s.", \ + compiled_ver, runtime_ver); \ + return nullptr; \ + } \ + } + +#define PYBIND11_CATCH_INIT_EXCEPTIONS \ + catch (pybind11::error_already_set &e) { \ + PyErr_SetString(PyExc_ImportError, e.what()); \ + return nullptr; \ + } catch (const std::exception &e) { \ + PyErr_SetString(PyExc_ImportError, e.what()); \ + return nullptr; \ + } \ + /** \rst ***Deprecated in favor of PYBIND11_MODULE*** @@ -226,27 +256,10 @@ extern "C" { PYBIND11_DEPRECATED("PYBIND11_PLUGIN is deprecated, use PYBIND11_MODULE") \ static PyObject *pybind11_init(); \ PYBIND11_PLUGIN_IMPL(name) { \ - int major, minor; \ - if (sscanf(Py_GetVersion(), "%i.%i", &major, &minor) != 2) { \ - PyErr_SetString(PyExc_ImportError, "Can't parse Python version."); \ - return nullptr; \ - } else if (major != PY_MAJOR_VERSION || minor != PY_MINOR_VERSION) { \ - PyErr_Format(PyExc_ImportError, \ - "Python version mismatch: module was compiled for " \ - "version %i.%i, while the interpreter is running " \ - "version %i.%i.", PY_MAJOR_VERSION, PY_MINOR_VERSION, \ - major, minor); \ - return nullptr; \ - } \ + PYBIND11_CHECK_PYTHON_VERSION \ try { \ return pybind11_init(); \ - } catch (pybind11::error_already_set &e) { \ - PyErr_SetString(PyExc_ImportError, e.what()); \ - return nullptr; \ - } catch (const std::exception &e) { \ - PyErr_SetString(PyExc_ImportError, e.what()); \ - return nullptr; \ - } \ + } PYBIND11_CATCH_INIT_EXCEPTIONS \ } \ PyObject *pybind11_init() @@ -270,29 +283,12 @@ extern "C" { #define PYBIND11_MODULE(name, variable) \ static void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module &); \ PYBIND11_PLUGIN_IMPL(name) { \ - int major, minor; \ - if (sscanf(Py_GetVersion(), "%i.%i", &major, &minor) != 2) { \ - PyErr_SetString(PyExc_ImportError, "Can't parse Python version."); \ - return nullptr; \ - } else if (major != PY_MAJOR_VERSION || minor != PY_MINOR_VERSION) { \ - PyErr_Format(PyExc_ImportError, \ - "Python version mismatch: module was compiled for " \ - "version %i.%i, while the interpreter is running " \ - "version %i.%i.", PY_MAJOR_VERSION, PY_MINOR_VERSION, \ - major, minor); \ - return nullptr; \ - } \ + PYBIND11_CHECK_PYTHON_VERSION \ auto m = pybind11::module(PYBIND11_TOSTRING(name)); \ try { \ PYBIND11_CONCAT(pybind11_init_, name)(m); \ return m.ptr(); \ - } catch (pybind11::error_already_set &e) { \ - PyErr_SetString(PyExc_ImportError, e.what()); \ - return nullptr; \ - } catch (const std::exception &e) { \ - PyErr_SetString(PyExc_ImportError, e.what()); \ - return nullptr; \ - } \ + } PYBIND11_CATCH_INIT_EXCEPTIONS \ } \ void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module &variable) @@ -377,18 +373,20 @@ constexpr size_t instance_simple_holder_in_ptrs() { struct type_info; struct value_and_holder; +struct nonsimple_values_and_holders { + void **values_and_holders; + uint8_t *status; +}; + /// The 'instance' type which needs to be standard layout (need to be able to use 'offsetof') struct instance { PyObject_HEAD /// Storage for pointers and holder; see simple_layout, below, for a description union { void *simple_value_holder[1 + instance_simple_holder_in_ptrs()]; - struct { - void **values_and_holders; - uint8_t *status; - } nonsimple; + nonsimple_values_and_holders nonsimple; }; - /// Weak references (needed for keep alive): + /// Weak references PyObject *weakrefs; /// If true, the pointer is owned which means we're free to manage it with a holder. bool owned : 1; @@ -405,10 +403,10 @@ struct instance { * (which is typically the size of two pointers), or when multiple inheritance is used on the * python side. Non-simple layout allocates the required amount of memory to have multiple * bound C++ classes as parents. Under this layout, `nonsimple.values_and_holders` is set to a - * pointer to allocated space of the required space to hold a a sequence of value pointers and + * pointer to allocated space of the required space to hold a sequence of value pointers and * holders followed `status`, a set of bit flags (1 byte each), i.e. * [val1*][holder1][val2*][holder2]...[bb...] where each [block] is rounded up to a multiple of - * `sizeof(void *)`. `nonsimple.holder_constructed` is, for convenience, a pointer to the + * `sizeof(void *)`. `nonsimple.status` is, for convenience, a pointer to the * beginning of the [bb...] block (but not independently allocated). * * Status bits indicate whether the associated holder is constructed (& @@ -471,7 +469,7 @@ template <size_t... IPrev, size_t I, bool B, bool... Bs> struct select_indices_i : select_indices_impl<conditional_t<B, index_sequence<IPrev..., I>, index_sequence<IPrev...>>, I + 1, Bs...> {}; template <bool... Bs> using select_indices = typename select_indices_impl<index_sequence<>, 0, Bs...>::type; -/// Backports of std::bool_constant and std::negation to accomodate older compilers +/// Backports of std::bool_constant and std::negation to accommodate older compilers template <bool B> using bool_constant = std::integral_constant<bool, B>; template <typename T> struct negation : bool_constant<!T::value> { }; @@ -479,7 +477,7 @@ 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 +#if defined(__cpp_fold_expressions) && !(defined(_MSC_VER) && (_MSC_VER < 1916)) template <class... Ts> using all_of = bool_constant<(Ts::value && ...)>; template <class... Ts> using any_of = bool_constant<(Ts::value || ...)>; #elif !defined(_MSC_VER) @@ -581,6 +579,11 @@ template <typename T, typename... Us> using deferred_t = typename deferred_type< template <typename Base, typename Derived> using is_strict_base_of = bool_constant< std::is_base_of<Base, Derived>::value && !std::is_same<Base, Derived>::value>; +/// Like is_base_of, but also requires that the base type is accessible (i.e. that a Derived pointer +/// can be converted to a Base pointer) +template <typename Base, typename Derived> using is_accessible_base_of = bool_constant< + std::is_base_of<Base, Derived>::value && std::is_convertible<Derived *, Base *>::value>; + template <template<typename...> class Base> struct is_template_base_of_impl { template <typename... Us> static std::true_type check(Base<Us...> *); @@ -670,6 +673,7 @@ PYBIND11_RUNTIME_EXCEPTION(index_error, PyExc_IndexError) PYBIND11_RUNTIME_EXCEPTION(key_error, PyExc_KeyError) PYBIND11_RUNTIME_EXCEPTION(value_error, PyExc_ValueError) PYBIND11_RUNTIME_EXCEPTION(type_error, PyExc_TypeError) +PYBIND11_RUNTIME_EXCEPTION(buffer_error, PyExc_BufferError) PYBIND11_RUNTIME_EXCEPTION(cast_error, PyExc_RuntimeError) /// Thrown when pybind11::cast or handle::call fail due to a type casting error PYBIND11_RUNTIME_EXCEPTION(reference_cast_error, PyExc_RuntimeError) /// Used internally @@ -699,9 +703,13 @@ template <typename T> struct format_descriptor<T, detail::enable_if_t<std::is_ar static std::string format() { return std::string(1, c); } }; +#if !defined(PYBIND11_CPP17) + template <typename T> constexpr const char format_descriptor< T, detail::enable_if_t<std::is_arithmetic<T>::value>>::value[2]; +#endif + /// RAII wrapper that temporarily clears any Python error state struct error_scope { PyObject *type, *value, *trace; @@ -712,10 +720,6 @@ struct error_scope { /// 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 -#if defined(PYBIND11_CPP14) -#define PYBIND11_OVERLOAD_CAST 1 - NAMESPACE_BEGIN(detail) template <typename... Args> struct overload_cast_impl { @@ -735,19 +739,23 @@ struct overload_cast_impl { }; NAMESPACE_END(detail) +// overload_cast requires variable templates: C++14 +#if defined(PYBIND11_CPP14) +#define PYBIND11_OVERLOAD_CAST 1 /// Syntax sugar for resolving overloaded function pointers: /// - regular: static_cast<Return (Class::*)(Arg0, Arg1, Arg2)>(&Class::func) /// - sweet: overload_cast<Arg0, Arg1, Arg2>(&Class::func) template <typename... Args> static constexpr detail::overload_cast_impl<Args...> overload_cast = {}; // MSVC 2015 only accepts this particular initialization syntax for this variable template. +#endif /// Const member function selector for overload_cast /// - regular: static_cast<Return (Class::*)(Arg) const>(&Class::func) /// - sweet: overload_cast<Arg>(&Class::func, const_) static constexpr auto const_ = std::true_type{}; -#else // no overload_cast: providing something that static_assert-fails: +#if !defined(PYBIND11_CPP14) // no overload_cast: providing something that static_assert-fails: template <typename... Args> struct overload_cast { static_assert(detail::deferred_t<std::false_type, Args...>::value, "pybind11::overload_cast<...> requires compiling in C++14 mode"); diff --git a/ext/pybind11/include/pybind11/detail/descr.h b/ext/pybind11/include/pybind11/detail/descr.h index e3bf2ba97..8d404e534 100644 --- a/ext/pybind11/include/pybind11/detail/descr.h +++ b/ext/pybind11/include/pybind11/detail/descr.h @@ -1,6 +1,5 @@ /* - pybind11/detail/descr.h: Helper type for concatenating type signatures - either at runtime (C++11) or compile time (C++14) + pybind11/detail/descr.h: Helper type for concatenating type signatures at compile time Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> @@ -15,171 +14,87 @@ NAMESPACE_BEGIN(PYBIND11_NAMESPACE) NAMESPACE_BEGIN(detail) -/* Concatenate type signatures at compile time using C++14 */ -#if defined(PYBIND11_CPP14) && !defined(_MSC_VER) -#define PYBIND11_CONSTEXPR_DESCR - -template <size_t Size1, size_t Size2> class descr { - template <size_t Size1_, size_t Size2_> friend class descr; -public: - constexpr descr(char const (&text) [Size1+1], const std::type_info * const (&types)[Size2+1]) - : descr(text, types, - make_index_sequence<Size1>(), - make_index_sequence<Size2>()) { } - - constexpr const char *text() const { return m_text; } - constexpr const std::type_info * const * types() const { return m_types; } - - template <size_t OtherSize1, size_t OtherSize2> - constexpr descr<Size1 + OtherSize1, Size2 + OtherSize2> operator+(const descr<OtherSize1, OtherSize2> &other) const { - return concat(other, - make_index_sequence<Size1>(), - make_index_sequence<Size2>(), - make_index_sequence<OtherSize1>(), - make_index_sequence<OtherSize2>()); - } +#if !defined(_MSC_VER) +# define PYBIND11_DESCR_CONSTEXPR static constexpr +#else +# define PYBIND11_DESCR_CONSTEXPR const +#endif -protected: - template <size_t... Indices1, size_t... Indices2> - constexpr descr( - char const (&text) [Size1+1], - const std::type_info * const (&types) [Size2+1], - index_sequence<Indices1...>, index_sequence<Indices2...>) - : m_text{text[Indices1]..., '\0'}, - m_types{types[Indices2]..., nullptr } {} - - template <size_t OtherSize1, size_t OtherSize2, size_t... Indices1, - size_t... Indices2, size_t... OtherIndices1, size_t... OtherIndices2> - constexpr descr<Size1 + OtherSize1, Size2 + OtherSize2> - concat(const descr<OtherSize1, OtherSize2> &other, - index_sequence<Indices1...>, index_sequence<Indices2...>, - index_sequence<OtherIndices1...>, index_sequence<OtherIndices2...>) const { - return descr<Size1 + OtherSize1, Size2 + OtherSize2>( - { m_text[Indices1]..., other.m_text[OtherIndices1]..., '\0' }, - { m_types[Indices2]..., other.m_types[OtherIndices2]..., nullptr } - ); - } +/* Concatenate type signatures at compile time */ +template <size_t N, typename... Ts> +struct descr { + char text[N + 1]; + + constexpr descr() : text{'\0'} { } + constexpr descr(char const (&s)[N+1]) : descr(s, make_index_sequence<N>()) { } + + template <size_t... Is> + constexpr descr(char const (&s)[N+1], index_sequence<Is...>) : text{s[Is]..., '\0'} { } -protected: - char m_text[Size1 + 1]; - const std::type_info * m_types[Size2 + 1]; + template <typename... Chars> + constexpr descr(char c, Chars... cs) : text{c, static_cast<char>(cs)..., '\0'} { } + + static constexpr std::array<const std::type_info *, sizeof...(Ts) + 1> types() { + return {{&typeid(Ts)..., nullptr}}; + } }; -template <size_t Size> constexpr descr<Size - 1, 0> _(char const(&text)[Size]) { - return descr<Size - 1, 0>(text, { nullptr }); +template <size_t N1, size_t N2, typename... Ts1, typename... Ts2, size_t... Is1, size_t... Is2> +constexpr descr<N1 + N2, Ts1..., Ts2...> plus_impl(const descr<N1, Ts1...> &a, const descr<N2, Ts2...> &b, + index_sequence<Is1...>, index_sequence<Is2...>) { + return {a.text[Is1]..., b.text[Is2]...}; +} + +template <size_t N1, size_t N2, typename... Ts1, typename... Ts2> +constexpr descr<N1 + N2, Ts1..., Ts2...> operator+(const descr<N1, Ts1...> &a, const descr<N2, Ts2...> &b) { + return plus_impl(a, b, make_index_sequence<N1>(), make_index_sequence<N2>()); } +template <size_t N> +constexpr descr<N - 1> _(char const(&text)[N]) { return descr<N - 1>(text); } +constexpr descr<0> _(char const(&)[1]) { return {}; } + template <size_t Rem, size_t... Digits> struct int_to_str : int_to_str<Rem/10, Rem%10, Digits...> { }; template <size_t...Digits> struct int_to_str<0, Digits...> { - static constexpr auto digits = descr<sizeof...(Digits), 0>({ ('0' + Digits)..., '\0' }, { nullptr }); + static constexpr auto digits = descr<sizeof...(Digits)>(('0' + Digits)...); }; // Ternary description (like std::conditional) -template <bool B, size_t Size1, size_t Size2> -constexpr enable_if_t<B, descr<Size1 - 1, 0>> _(char const(&text1)[Size1], char const(&)[Size2]) { +template <bool B, size_t N1, size_t N2> +constexpr enable_if_t<B, descr<N1 - 1>> _(char const(&text1)[N1], char const(&)[N2]) { return _(text1); } -template <bool B, size_t Size1, size_t Size2> -constexpr enable_if_t<!B, descr<Size2 - 1, 0>> _(char const(&)[Size1], char const(&text2)[Size2]) { +template <bool B, size_t N1, size_t N2> +constexpr enable_if_t<!B, descr<N2 - 1>> _(char const(&)[N1], char const(&text2)[N2]) { return _(text2); } -template <bool B, size_t SizeA1, size_t SizeA2, size_t SizeB1, size_t SizeB2> -constexpr enable_if_t<B, descr<SizeA1, SizeA2>> _(descr<SizeA1, SizeA2> d, descr<SizeB1, SizeB2>) { return d; } -template <bool B, size_t SizeA1, size_t SizeA2, size_t SizeB1, size_t SizeB2> -constexpr enable_if_t<!B, descr<SizeB1, SizeB2>> _(descr<SizeA1, SizeA2>, descr<SizeB1, SizeB2> d) { return d; } + +template <bool B, typename T1, typename T2> +constexpr enable_if_t<B, T1> _(const T1 &d, const T2 &) { return d; } +template <bool B, typename T1, typename T2> +constexpr enable_if_t<!B, T2> _(const T1 &, const T2 &d) { return d; } template <size_t Size> auto constexpr _() -> decltype(int_to_str<Size / 10, Size % 10>::digits) { return int_to_str<Size / 10, Size % 10>::digits; } -template <typename Type> constexpr descr<1, 1> _() { - return descr<1, 1>({ '%', '\0' }, { &typeid(Type), nullptr }); -} - -inline constexpr descr<0, 0> concat() { return _(""); } -template <size_t Size1, size_t Size2, typename... Args> auto constexpr concat(descr<Size1, Size2> descr) { return descr; } -template <size_t Size1, size_t Size2, typename... Args> auto constexpr concat(descr<Size1, Size2> descr, Args&&... args) { return descr + _(", ") + concat(args...); } -template <size_t Size1, size_t Size2> auto constexpr type_descr(descr<Size1, Size2> descr) { return _("{") + descr + _("}"); } - -#define PYBIND11_DESCR constexpr auto - -#else /* Simpler C++11 implementation based on run-time memory allocation and copying */ - -class descr { -public: - PYBIND11_NOINLINE descr(const char *text, const std::type_info * const * types) { - size_t nChars = len(text), nTypes = len(types); - m_text = new char[nChars]; - m_types = new const std::type_info *[nTypes]; - memcpy(m_text, text, nChars * sizeof(char)); - memcpy(m_types, types, nTypes * sizeof(const std::type_info *)); - } - - PYBIND11_NOINLINE descr operator+(descr &&d2) && { - descr r; - - size_t nChars1 = len(m_text), nTypes1 = len(m_types); - size_t nChars2 = len(d2.m_text), nTypes2 = len(d2.m_types); - - r.m_text = new char[nChars1 + nChars2 - 1]; - r.m_types = new const std::type_info *[nTypes1 + nTypes2 - 1]; - memcpy(r.m_text, m_text, (nChars1-1) * sizeof(char)); - memcpy(r.m_text + nChars1 - 1, d2.m_text, nChars2 * sizeof(char)); - memcpy(r.m_types, m_types, (nTypes1-1) * sizeof(std::type_info *)); - memcpy(r.m_types + nTypes1 - 1, d2.m_types, nTypes2 * sizeof(std::type_info *)); +template <typename Type> constexpr descr<1, Type> _() { return {'%'}; } - delete[] m_text; delete[] m_types; - delete[] d2.m_text; delete[] d2.m_types; - - return r; - } +constexpr descr<0> concat() { return {}; } - char *text() { return m_text; } - const std::type_info * * types() { return m_types; } +template <size_t N, typename... Ts> +constexpr descr<N, Ts...> concat(const descr<N, Ts...> &descr) { return descr; } -protected: - PYBIND11_NOINLINE descr() { } - - template <typename T> static size_t len(const T *ptr) { // return length including null termination - const T *it = ptr; - while (*it++ != (T) 0) - ; - return static_cast<size_t>(it - ptr); - } - - const std::type_info **m_types = nullptr; - char *m_text = nullptr; -}; - -/* The 'PYBIND11_NOINLINE inline' combinations below are intentional to get the desired linkage while producing as little object code as possible */ - -PYBIND11_NOINLINE inline descr _(const char *text) { - const std::type_info *types[1] = { nullptr }; - return descr(text, types); -} - -template <bool B> PYBIND11_NOINLINE enable_if_t<B, descr> _(const char *text1, const char *) { return _(text1); } -template <bool B> PYBIND11_NOINLINE enable_if_t<!B, descr> _(char const *, const char *text2) { return _(text2); } -template <bool B> PYBIND11_NOINLINE enable_if_t<B, descr> _(descr d, descr) { return d; } -template <bool B> PYBIND11_NOINLINE enable_if_t<!B, descr> _(descr, descr d) { return d; } - -template <typename Type> PYBIND11_NOINLINE descr _() { - const std::type_info *types[2] = { &typeid(Type), nullptr }; - return descr("%", types); +template <size_t N, typename... Ts, typename... Args> +constexpr auto concat(const descr<N, Ts...> &d, const Args &...args) + -> decltype(std::declval<descr<N + 2, Ts...>>() + concat(args...)) { + return d + _(", ") + concat(args...); } -template <size_t Size> PYBIND11_NOINLINE descr _() { - const std::type_info *types[1] = { nullptr }; - return descr(std::to_string(Size).c_str(), types); +template <size_t N, typename... Ts> +constexpr descr<N + 2, Ts...> type_descr(const descr<N, Ts...> &descr) { + return _("{") + descr + _("}"); } -PYBIND11_NOINLINE inline descr concat() { return _(""); } -PYBIND11_NOINLINE inline descr concat(descr &&d) { return d; } -template <typename... Args> PYBIND11_NOINLINE descr concat(descr &&d, Args&&... args) { return std::move(d) + _(", ") + concat(std::forward<Args>(args)...); } -PYBIND11_NOINLINE inline descr type_descr(descr&& d) { return _("{") + std::move(d) + _("}"); } - -#define PYBIND11_DESCR ::pybind11::detail::descr -#endif - NAMESPACE_END(detail) NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/ext/pybind11/include/pybind11/detail/init.h b/ext/pybind11/include/pybind11/detail/init.h index c3594a190..acfe00bdb 100644 --- a/ext/pybind11/include/pybind11/detail/init.h +++ b/ext/pybind11/include/pybind11/detail/init.h @@ -24,7 +24,7 @@ public: template <typename> using cast_op_type = value_and_holder &; operator value_and_holder &() { return *value; } - static PYBIND11_DESCR name() { return type_descr(_<value_and_holder>()); } + static constexpr auto name = _<value_and_holder>(); private: value_and_holder *value = nullptr; @@ -52,6 +52,16 @@ bool is_alias(Cpp<Class> *ptr) { template <typename /*Class*/> constexpr bool is_alias(void *) { return false; } +// Constructs and returns a new object; if the given arguments don't map to a constructor, we fall +// back to brace aggregate initiailization so that for aggregate initialization can be used with +// py::init, e.g. `py::init<int, int>` to initialize a `struct T { int a; int b; }`. For +// non-aggregate types, we need to use an ordinary T(...) constructor (invoking as `T{...}` usually +// works, but will not do the expected thing when `T` has an `initializer_list<T>` constructor). +template <typename Class, typename... Args, detail::enable_if_t<std::is_constructible<Class, Args...>::value, int> = 0> +inline Class *construct_or_initialize(Args &&...args) { return new Class(std::forward<Args>(args)...); } +template <typename Class, typename... Args, detail::enable_if_t<!std::is_constructible<Class, Args...>::value, int> = 0> +inline Class *construct_or_initialize(Args &&...args) { return new Class{std::forward<Args>(args)...}; } + // Attempts to constructs an alias using a `Alias(Cpp &&)` constructor. This allows types with // an alias to provide only a single Cpp factory function as long as the Alias can be // constructed from an rvalue reference of the base Cpp type. This means that Alias classes @@ -161,7 +171,7 @@ struct constructor { template <typename Class, typename... Extra, enable_if_t<!Class::has_alias, int> = 0> static void execute(Class &cl, const Extra&... extra) { cl.def("__init__", [](value_and_holder &v_h, Args... args) { - v_h.value_ptr() = new Cpp<Class>{std::forward<Args>(args)...}; + v_h.value_ptr() = construct_or_initialize<Cpp<Class>>(std::forward<Args>(args)...); }, is_new_style_constructor(), extra...); } @@ -171,9 +181,9 @@ struct constructor { static void execute(Class &cl, const Extra&... extra) { cl.def("__init__", [](value_and_holder &v_h, Args... args) { if (Py_TYPE(v_h.inst) == v_h.type->type) - v_h.value_ptr() = new Cpp<Class>{std::forward<Args>(args)...}; + v_h.value_ptr() = construct_or_initialize<Cpp<Class>>(std::forward<Args>(args)...); else - v_h.value_ptr() = new Alias<Class>{std::forward<Args>(args)...}; + v_h.value_ptr() = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...); }, is_new_style_constructor(), extra...); } @@ -182,7 +192,7 @@ struct constructor { !std::is_constructible<Cpp<Class>, Args...>::value, int> = 0> static void execute(Class &cl, const Extra&... extra) { cl.def("__init__", [](value_and_holder &v_h, Args... args) { - v_h.value_ptr() = new Alias<Class>{std::forward<Args>(args)...}; + v_h.value_ptr() = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...); }, is_new_style_constructor(), extra...); } }; @@ -193,7 +203,7 @@ template <typename... Args> struct alias_constructor { enable_if_t<Class::has_alias && std::is_constructible<Alias<Class>, Args...>::value, int> = 0> static void execute(Class &cl, const Extra&... extra) { cl.def("__init__", [](value_and_holder &v_h, Args... args) { - v_h.value_ptr() = new Alias<Class>{std::forward<Args>(args)...}; + v_h.value_ptr() = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...); }, is_new_style_constructor(), extra...); } }; diff --git a/ext/pybind11/include/pybind11/detail/internals.h b/ext/pybind11/include/pybind11/detail/internals.h index 213cbaeb2..067780c26 100644 --- a/ext/pybind11/include/pybind11/detail/internals.h +++ b/ext/pybind11/include/pybind11/detail/internals.h @@ -18,6 +18,33 @@ inline PyTypeObject *make_static_property_type(); inline PyTypeObject *make_default_metaclass(); inline PyObject *make_object_base_type(PyTypeObject *metaclass); +// The old Python Thread Local Storage (TLS) API is deprecated in Python 3.7 in favor of the new +// Thread Specific Storage (TSS) API. +#if PY_VERSION_HEX >= 0x03070000 +# define PYBIND11_TLS_KEY_INIT(var) Py_tss_t *var = nullptr +# define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get((key)) +# define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set((key), (value)) +# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set((key), nullptr) +#else + // Usually an int but a long on Cygwin64 with Python 3.x +# define PYBIND11_TLS_KEY_INIT(var) decltype(PyThread_create_key()) var = 0 +# define PYBIND11_TLS_GET_VALUE(key) PyThread_get_key_value((key)) +# if PY_MAJOR_VERSION < 3 +# define PYBIND11_TLS_DELETE_VALUE(key) \ + PyThread_delete_key_value(key) +# define PYBIND11_TLS_REPLACE_VALUE(key, value) \ + do { \ + PyThread_delete_key_value((key)); \ + PyThread_set_key_value((key), (value)); \ + } while (false) +# else +# define PYBIND11_TLS_DELETE_VALUE(key) \ + PyThread_set_key_value((key), nullptr) +# define PYBIND11_TLS_REPLACE_VALUE(key, value) \ + PyThread_set_key_value((key), (value)) +# endif +#endif + // Python loads modules by default with dlopen with the RTLD_LOCAL flag; under libc++ and possibly // other STLs, this means `typeid(A)` from one module won't equal `typeid(A)` from another module // even when `A` is the same, non-hidden-visibility type (e.g. from a common include). Under @@ -79,7 +106,7 @@ struct internals { PyTypeObject *default_metaclass; PyObject *instance_base; #if defined(WITH_THREAD) - decltype(PyThread_create_key()) tstate = 0; // Usually an int but a long on Cygwin64 with Python 3.x + PYBIND11_TLS_KEY_INIT(tstate); PyInterpreterState *istate = nullptr; #endif }; @@ -89,7 +116,7 @@ struct internals { struct type_info { PyTypeObject *type; const std::type_info *cpptype; - size_t type_size, holder_size_in_ptrs; + size_t type_size, type_align, holder_size_in_ptrs; void *(*operator_new)(size_t); void (*init_instance)(instance *, const void *); void (*dealloc)(value_and_holder &v_h); @@ -111,7 +138,48 @@ struct type_info { }; /// Tracks the `internals` and `type_info` ABI version independent of the main library version -#define PYBIND11_INTERNALS_VERSION 1 +#define PYBIND11_INTERNALS_VERSION 3 + +/// On MSVC, debug and release builds are not ABI-compatible! +#if defined(_MSC_VER) && defined(_DEBUG) +# define PYBIND11_BUILD_TYPE "_debug" +#else +# define PYBIND11_BUILD_TYPE "" +#endif + +/// Let's assume that different compilers are ABI-incompatible. +#if defined(_MSC_VER) +# define PYBIND11_COMPILER_TYPE "_msvc" +#elif defined(__INTEL_COMPILER) +# define PYBIND11_COMPILER_TYPE "_icc" +#elif defined(__clang__) +# define PYBIND11_COMPILER_TYPE "_clang" +#elif defined(__PGI) +# define PYBIND11_COMPILER_TYPE "_pgi" +#elif defined(__MINGW32__) +# define PYBIND11_COMPILER_TYPE "_mingw" +#elif defined(__CYGWIN__) +# define PYBIND11_COMPILER_TYPE "_gcc_cygwin" +#elif defined(__GNUC__) +# define PYBIND11_COMPILER_TYPE "_gcc" +#else +# define PYBIND11_COMPILER_TYPE "_unknown" +#endif + +#if defined(_LIBCPP_VERSION) +# define PYBIND11_STDLIB "_libcpp" +#elif defined(__GLIBCXX__) || defined(__GLIBCPP__) +# define PYBIND11_STDLIB "_libstdcpp" +#else +# define PYBIND11_STDLIB "" +#endif + +/// On Linux/OSX, changes in __GXX_ABI_VERSION__ indicate ABI incompatibility. +#if defined(__GXX_ABI_VERSION) +# define PYBIND11_BUILD_ABI "_cxxabi" PYBIND11_TOSTRING(__GXX_ABI_VERSION) +#else +# define PYBIND11_BUILD_ABI "" +#endif #if defined(WITH_THREAD) # define PYBIND11_INTERNALS_KIND "" @@ -120,28 +188,64 @@ struct type_info { #endif #define PYBIND11_INTERNALS_ID "__pybind11_internals_v" \ - PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) PYBIND11_INTERNALS_KIND "__" + PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI PYBIND11_BUILD_TYPE "__" #define PYBIND11_MODULE_LOCAL_ID "__pybind11_module_local_v" \ - PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) PYBIND11_INTERNALS_KIND "__" + PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI PYBIND11_BUILD_TYPE "__" /// Each module locally stores a pointer to the `internals` data. The data /// itself is shared among modules with the same `PYBIND11_INTERNALS_ID`. -inline internals *&get_internals_ptr() { - static internals *internals_ptr = nullptr; - return internals_ptr; +inline internals **&get_internals_pp() { + static internals **internals_pp = nullptr; + return internals_pp; +} + +inline void translate_exception(std::exception_ptr p) { + try { + if (p) std::rethrow_exception(p); + } catch (error_already_set &e) { e.restore(); return; + } catch (const builtin_exception &e) { e.set_error(); return; + } catch (const std::bad_alloc &e) { PyErr_SetString(PyExc_MemoryError, e.what()); return; + } catch (const std::domain_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return; + } catch (const std::invalid_argument &e) { PyErr_SetString(PyExc_ValueError, e.what()); return; + } catch (const std::length_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return; + } catch (const std::out_of_range &e) { PyErr_SetString(PyExc_IndexError, e.what()); return; + } catch (const std::range_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return; + } catch (const std::exception &e) { PyErr_SetString(PyExc_RuntimeError, e.what()); return; + } catch (...) { + PyErr_SetString(PyExc_RuntimeError, "Caught an unknown exception!"); + return; + } } +#if !defined(__GLIBCXX__) +inline void translate_local_exception(std::exception_ptr p) { + try { + if (p) std::rethrow_exception(p); + } catch (error_already_set &e) { e.restore(); return; + } catch (const builtin_exception &e) { e.set_error(); return; + } +} +#endif + /// Return a reference to the current `internals` data PYBIND11_NOINLINE inline internals &get_internals() { - auto *&internals_ptr = get_internals_ptr(); - if (internals_ptr) - return *internals_ptr; + auto **&internals_pp = get_internals_pp(); + if (internals_pp && *internals_pp) + return **internals_pp; + + // Ensure that the GIL is held since we will need to make Python calls. + // Cannot use py::gil_scoped_acquire here since that constructor calls get_internals. + struct gil_scoped_acquire_local { + gil_scoped_acquire_local() : state (PyGILState_Ensure()) {} + ~gil_scoped_acquire_local() { PyGILState_Release(state); } + const PyGILState_STATE state; + } gil; constexpr auto *id = PYBIND11_INTERNALS_ID; auto builtins = handle(PyEval_GetBuiltins()); if (builtins.contains(id) && isinstance<capsule>(builtins[id])) { - internals_ptr = *static_cast<internals **>(capsule(builtins[id])); + internals_pp = static_cast<internals **>(capsule(builtins[id])); // We loaded builtins through python's builtins, which means that our `error_already_set` // and `builtin_exception` may be different local classes than the ones set up in the @@ -149,50 +253,35 @@ PYBIND11_NOINLINE inline internals &get_internals() { // // libstdc++ doesn't require this (types there are identified only by name) #if !defined(__GLIBCXX__) - internals_ptr->registered_exception_translators.push_front( - [](std::exception_ptr p) -> void { - try { - if (p) std::rethrow_exception(p); - } catch (error_already_set &e) { e.restore(); return; - } catch (const builtin_exception &e) { e.set_error(); return; - } - } - ); + (*internals_pp)->registered_exception_translators.push_front(&translate_local_exception); #endif } else { + if (!internals_pp) internals_pp = new internals*(); + auto *&internals_ptr = *internals_pp; internals_ptr = new internals(); #if defined(WITH_THREAD) PyEval_InitThreads(); PyThreadState *tstate = PyThreadState_Get(); - internals_ptr->tstate = PyThread_create_key(); - PyThread_set_key_value(internals_ptr->tstate, tstate); + #if PY_VERSION_HEX >= 0x03070000 + internals_ptr->tstate = PyThread_tss_alloc(); + if (!internals_ptr->tstate || PyThread_tss_create(internals_ptr->tstate)) + pybind11_fail("get_internals: could not successfully initialize the TSS key!"); + PyThread_tss_set(internals_ptr->tstate, tstate); + #else + internals_ptr->tstate = PyThread_create_key(); + if (internals_ptr->tstate == -1) + pybind11_fail("get_internals: could not successfully initialize the TLS key!"); + PyThread_set_key_value(internals_ptr->tstate, tstate); + #endif internals_ptr->istate = tstate->interp; #endif - builtins[id] = capsule(&internals_ptr); - internals_ptr->registered_exception_translators.push_front( - [](std::exception_ptr p) -> void { - try { - if (p) std::rethrow_exception(p); - } catch (error_already_set &e) { e.restore(); return; - } catch (const builtin_exception &e) { e.set_error(); return; - } catch (const std::bad_alloc &e) { PyErr_SetString(PyExc_MemoryError, e.what()); return; - } catch (const std::domain_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return; - } catch (const std::invalid_argument &e) { PyErr_SetString(PyExc_ValueError, e.what()); return; - } catch (const std::length_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return; - } catch (const std::out_of_range &e) { PyErr_SetString(PyExc_IndexError, e.what()); return; - } catch (const std::range_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return; - } catch (const std::exception &e) { PyErr_SetString(PyExc_RuntimeError, e.what()); return; - } catch (...) { - PyErr_SetString(PyExc_RuntimeError, "Caught an unknown exception!"); - return; - } - } - ); + builtins[id] = capsule(internals_pp); + internals_ptr->registered_exception_translators.push_front(&translate_exception); internals_ptr->static_property_type = make_static_property_type(); internals_ptr->default_metaclass = make_default_metaclass(); internals_ptr->instance_base = make_object_base_type(internals_ptr->default_metaclass); } - return *internals_ptr; + return **internals_pp; } /// Works like `internals.registered_types_cpp`, but for module-local registered types: diff --git a/ext/pybind11/include/pybind11/detail/typeid.h b/ext/pybind11/include/pybind11/detail/typeid.h index 6f36aab75..9c8a4fc69 100644 --- a/ext/pybind11/include/pybind11/detail/typeid.h +++ b/ext/pybind11/include/pybind11/detail/typeid.h @@ -16,6 +16,8 @@ #include <cxxabi.h> #endif +#include "common.h" + NAMESPACE_BEGIN(PYBIND11_NAMESPACE) NAMESPACE_BEGIN(detail) /// Erase all occurrences of a substring diff --git a/ext/pybind11/include/pybind11/eigen.h b/ext/pybind11/include/pybind11/eigen.h index a702bf39e..d963d9650 100644 --- a/ext/pybind11/include/pybind11/eigen.h +++ b/ext/pybind11/include/pybind11/eigen.h @@ -17,19 +17,25 @@ # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wconversion" # pragma GCC diagnostic ignored "-Wdeprecated-declarations" +# ifdef __clang__ +// Eigen generates a bunch of implicit-copy-constructor-is-deprecated warnings with -Wdeprecated +// under Clang, so disable that warning here: +# pragma GCC diagnostic ignored "-Wdeprecated" +# endif # if __GNUC__ >= 7 # pragma GCC diagnostic ignored "-Wint-in-bool-context" # endif #endif -#include <Eigen/Core> -#include <Eigen/SparseCore> - #if defined(_MSC_VER) # pragma warning(push) # pragma warning(disable: 4127) // warning C4127: Conditional expression is constant +# pragma warning(disable: 4996) // warning C4996: std::unary_negate is deprecated in C++17 #endif +#include <Eigen/Core> +#include <Eigen/SparseCore> + // 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. @@ -180,28 +186,26 @@ template <typename Type_> struct EigenProps { } } - 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 type_descr(_("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", "") + - _("]") - ); - } + static constexpr bool show_writeable = is_eigen_dense_map<Type>::value && is_eigen_mutable_map<Type>::value; + static constexpr bool show_order = is_eigen_dense_map<Type>::value; + static constexpr bool show_c_contiguous = show_order && requires_row_major; + static constexpr bool show_f_contiguous = !show_c_contiguous && show_order && requires_col_major; + + static constexpr auto descriptor = + _("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, @@ -272,6 +276,7 @@ struct type_caster<Type, enable_if_t<is_eigen_dense_plain<Type>::value>> { value = Type(fits.rows, fits.cols); auto ref = reinterpret_steal<array>(eigen_ref_array<props>(value)); if (dims == 1) ref = ref.squeeze(); + else if (ref.ndim() == 1) buf = buf.squeeze(); int result = detail::npy_api::get().PyArray_CopyInto_(ref.ptr(), buf.ptr()); @@ -337,7 +342,7 @@ public: return cast_impl(src, policy, parent); } - static PYBIND11_DESCR name() { return props::descriptor(); } + static constexpr auto name = props::descriptor; operator Type*() { return &value; } operator Type&() { return value; } @@ -348,14 +353,6 @@ 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: @@ -385,7 +382,7 @@ public: } } - static PYBIND11_DESCR name() { return props::descriptor(); } + static constexpr auto name = props::descriptor; // 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 @@ -530,7 +527,7 @@ public: } static handle cast(const Type *src, return_value_policy policy, handle parent) { return cast(*src, policy, parent); } - static PYBIND11_DESCR name() { return props::descriptor(); } + static constexpr auto name = props::descriptor; // 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 @@ -597,7 +594,7 @@ struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> { } PYBIND11_TYPE_CASTER(Type, _<(Type::IsRowMajor) != 0>("scipy.sparse.csr_matrix[", "scipy.sparse.csc_matrix[") - + npy_format_descriptor<Scalar>::name() + _("]")); + + npy_format_descriptor<Scalar>::name + _("]")); }; NAMESPACE_END(detail) diff --git a/ext/pybind11/include/pybind11/embed.h b/ext/pybind11/include/pybind11/embed.h index 6664967c1..72655885e 100644 --- a/ext/pybind11/include/pybind11/embed.h +++ b/ext/pybind11/include/pybind11/embed.h @@ -90,8 +90,14 @@ NAMESPACE_END(detail) Initialize the Python interpreter. No other pybind11 or CPython API functions can be called before this is done; with the exception of `PYBIND11_EMBEDDED_MODULE`. The optional parameter can be used to skip the registration of signal handlers (see the - Python documentation for details). Calling this function again after the interpreter + `Python documentation`_ for details). Calling this function again after the interpreter has already been initialized is a fatal error. + + If initializing the Python interpreter fails, then the program is terminated. (This + is controlled by the CPython runtime and is an exception to pybind11's normal behavior + of throwing exceptions on errors.) + + .. _Python documentation: https://docs.python.org/3/c-api/init.html#c.Py_InitializeEx \endrst */ inline void initialize_interpreter(bool init_signal_handlers = true) { if (Py_IsInitialized()) @@ -145,7 +151,7 @@ inline void finalize_interpreter() { // Get the internals pointer (without creating it if it doesn't exist). It's possible for the // internals to be created during Py_Finalize() (e.g. if a py::capsule calls `get_internals()` // during destruction), so we get the pointer-pointer here and check it after Py_Finalize(). - detail::internals **internals_ptr_ptr = &detail::get_internals_ptr(); + detail::internals **internals_ptr_ptr = detail::get_internals_pp(); // It could also be stashed in builtins, so look there too: if (builtins.contains(id) && isinstance<capsule>(builtins[id])) internals_ptr_ptr = capsule(builtins[id]); diff --git a/ext/pybind11/include/pybind11/functional.h b/ext/pybind11/include/pybind11/functional.h index eda14ba58..f8bda6483 100644 --- a/ext/pybind11/include/pybind11/functional.h +++ b/ext/pybind11/include/pybind11/functional.h @@ -54,12 +54,30 @@ public: } } - value = [func](Args... args) -> Return { - gil_scoped_acquire acq; - object retval(func(std::forward<Args>(args)...)); - /* Visual studio 2015 parser issue: need parentheses around this expression */ - return (retval.template cast<Return>()); + // ensure GIL is held during functor destruction + struct func_handle { + function f; + func_handle(function&& f_) : f(std::move(f_)) {} + func_handle(const func_handle&) = default; + ~func_handle() { + gil_scoped_acquire acq; + function kill_f(std::move(f)); + } }; + + // to emulate 'move initialization capture' in C++11 + struct func_wrapper { + func_handle hfunc; + func_wrapper(func_handle&& hf): hfunc(std::move(hf)) {} + Return operator()(Args... args) const { + gil_scoped_acquire acq; + object retval(hfunc.f(std::forward<Args>(args)...)); + /* Visual studio 2015 parser issue: need parentheses around this expression */ + return (retval.template cast<Return>()); + } + }; + + value = func_wrapper(func_handle(std::move(func))); return true; } @@ -75,10 +93,8 @@ public: return cpp_function(std::forward<Func>(f_), policy).release(); } - PYBIND11_TYPE_CASTER(type, _("Callable[[") + - argument_loader<Args...>::arg_names() + _("], ") + - make_caster<retval_type>::name() + - _("]")); + PYBIND11_TYPE_CASTER(type, _("Callable[[") + concat(make_caster<Args>::name...) + _("], ") + + make_caster<retval_type>::name + _("]")); }; NAMESPACE_END(detail) diff --git a/ext/pybind11/include/pybind11/iostream.h b/ext/pybind11/include/pybind11/iostream.h index a9c27aac1..c43b7c93a 100644 --- a/ext/pybind11/include/pybind11/iostream.h +++ b/ext/pybind11/include/pybind11/iostream.h @@ -25,7 +25,8 @@ class pythonbuf : public std::streambuf { private: using traits_type = std::streambuf::traits_type; - char d_buffer[1024]; + const size_t buf_size; + std::unique_ptr<char[]> d_buffer; object pywrite; object pyflush; @@ -34,7 +35,7 @@ private: *pptr() = traits_type::to_char_type(c); pbump(1); } - return sync() ? traits_type::not_eof(c) : traits_type::eof(); + return sync() == 0 ? traits_type::not_eof(c) : traits_type::eof(); } int sync() { @@ -42,8 +43,11 @@ private: // This subtraction cannot be negative, so dropping the sign str line(pbase(), static_cast<size_t>(pptr() - pbase())); - pywrite(line); - pyflush(); + { + gil_scoped_acquire tmp; + pywrite(line); + pyflush(); + } setp(pbase(), epptr()); } @@ -51,12 +55,17 @@ private: } public: - pythonbuf(object pyostream) - : pywrite(pyostream.attr("write")), + + pythonbuf(object pyostream, size_t buffer_size = 1024) + : buf_size(buffer_size), + d_buffer(new char[buf_size]), + pywrite(pyostream.attr("write")), pyflush(pyostream.attr("flush")) { - setp(d_buffer, d_buffer + sizeof(d_buffer) - 1); + setp(d_buffer.get(), d_buffer.get() + buf_size - 1); } + pythonbuf(pythonbuf&&) = default; + /// Sync before destroy ~pythonbuf() { sync(); @@ -194,7 +203,7 @@ inline class_<detail::OstreamRedirect> add_ostream_redirect(module m, std::strin return class_<detail::OstreamRedirect>(m, name.c_str(), module_local()) .def(init<bool,bool>(), arg("stdout")=true, arg("stderr")=true) .def("__enter__", &detail::OstreamRedirect::enter) - .def("__exit__", [](detail::OstreamRedirect &self, args) { self.exit(); }); + .def("__exit__", [](detail::OstreamRedirect &self_, args) { self_.exit(); }); } NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/ext/pybind11/include/pybind11/numpy.h b/ext/pybind11/include/pybind11/numpy.h index 55bb81698..8b21d3d43 100644 --- a/ext/pybind11/include/pybind11/numpy.h +++ b/ext/pybind11/include/pybind11/numpy.h @@ -14,13 +14,14 @@ #include <numeric> #include <algorithm> #include <array> +#include <cstdint> #include <cstdlib> #include <cstring> #include <sstream> #include <string> -#include <initializer_list> #include <functional> #include <utility> +#include <vector> #include <typeindex> #if defined(_MSC_VER) @@ -108,6 +109,18 @@ inline numpy_internals& get_numpy_internals() { return *ptr; } +template <typename T> struct same_size { + template <typename U> using as = bool_constant<sizeof(T) == sizeof(U)>; +}; + +// Lookup a type according to its size, and return a value corresponding to the NumPy typenum. +template <typename Concrete, typename... Check, typename... Int> +constexpr int platform_lookup(Int... codes) { + using code_index = std::integral_constant<int, constexpr_first<same_size<Concrete>::template as, Check...>()>; + static_assert(code_index::value != sizeof...(Check), "Unable to match type on this platform"); + return std::get<code_index::value>(std::make_tuple(codes...)); +} + struct npy_api { enum constants { NPY_ARRAY_C_CONTIGUOUS_ = 0x0001, @@ -126,7 +139,23 @@ struct npy_api { NPY_FLOAT_, NPY_DOUBLE_, NPY_LONGDOUBLE_, NPY_CFLOAT_, NPY_CDOUBLE_, NPY_CLONGDOUBLE_, NPY_OBJECT_ = 17, - NPY_STRING_, NPY_UNICODE_, NPY_VOID_ + NPY_STRING_, NPY_UNICODE_, NPY_VOID_, + // Platform-dependent normalization + NPY_INT8_ = NPY_BYTE_, + NPY_UINT8_ = NPY_UBYTE_, + NPY_INT16_ = NPY_SHORT_, + NPY_UINT16_ = NPY_USHORT_, + // `npy_common.h` defines the integer aliases. In order, it checks: + // NPY_BITSOF_LONG, NPY_BITSOF_LONGLONG, NPY_BITSOF_INT, NPY_BITSOF_SHORT, NPY_BITSOF_CHAR + // and assigns the alias to the first matching size, so we should check in this order. + NPY_INT32_ = platform_lookup<std::int32_t, long, int, short>( + NPY_LONG_, NPY_INT_, NPY_SHORT_), + NPY_UINT32_ = platform_lookup<std::uint32_t, unsigned long, unsigned int, unsigned short>( + NPY_ULONG_, NPY_UINT_, NPY_USHORT_), + NPY_INT64_ = platform_lookup<std::int64_t, long, long long, int>( + NPY_LONG_, NPY_LONGLONG_, NPY_INT_), + NPY_UINT64_ = platform_lookup<std::uint64_t, unsigned long, unsigned long long, unsigned int>( + NPY_ULONG_, NPY_ULONGLONG_, NPY_UINT_), }; typedef struct { @@ -250,7 +279,7 @@ template <typename T> struct array_info_scalar { typedef T type; static constexpr bool is_array = false; static constexpr bool is_empty = false; - static PYBIND11_DESCR extents() { return _(""); } + static constexpr auto extents = _(""); static void append_extents(list& /* shape */) { } }; // Computes underlying type and a comma-separated list of extents for array @@ -269,15 +298,9 @@ template <typename T, size_t N> struct array_info<std::array<T, N>> { array_info<T>::append_extents(shape); } - template<typename T2 = T, enable_if_t<!array_info<T2>::is_array, int> = 0> - static PYBIND11_DESCR extents() { - return _<N>(); - } - - template<typename T2 = T, enable_if_t<array_info<T2>::is_array, int> = 0> - static PYBIND11_DESCR extents() { - return concat(_<N>(), array_info<T>::extents()); - } + static constexpr auto extents = _<array_info<T>::is_array>( + concat(_<N>(), array_info<T>::extents), _<N>() + ); }; // For numpy we have special handling for arrays of characters, so we don't include // the size in the array extents. @@ -446,7 +469,7 @@ public: /// This is essentially the same as calling numpy.dtype(args) in Python. static dtype from_args(object args) { PyObject *ptr = nullptr; - if (!detail::npy_api::get().PyArray_DescrConverter_(args.release().ptr(), &ptr) || !ptr) + if (!detail::npy_api::get().PyArray_DescrConverter_(args.ptr(), &ptr) || !ptr) throw error_already_set(); return reinterpret_steal<dtype>(ptr); } @@ -764,8 +787,9 @@ protected: static std::vector<ssize_t> c_strides(const std::vector<ssize_t> &shape, ssize_t itemsize) { auto ndim = shape.size(); std::vector<ssize_t> strides(ndim, itemsize); - for (size_t i = ndim - 1; i > 0; --i) - strides[i - 1] = strides[i] * shape[i]; + if (ndim > 0) + for (size_t i = ndim - 1; i > 0; --i) + strides[i - 1] = strides[i] * shape[i]; return strides; } @@ -860,14 +884,14 @@ public: // Reference to element at a given index template<typename... Ix> const T& at(Ix... index) const { - if (sizeof...(index) != ndim()) + if ((ssize_t) sizeof...(index) != ndim()) fail_dim_check(sizeof...(index), "index dimension mismatch"); return *(static_cast<const T*>(array::data()) + byte_offset(ssize_t(index)...) / itemsize()); } // Mutable reference to element at a given index template<typename... Ix> T& mutable_at(Ix... index) { - if (sizeof...(index) != ndim()) + if ((ssize_t) sizeof...(index) != ndim()) fail_dim_check(sizeof...(index), "index dimension mismatch"); return *(static_cast<T*>(array::mutable_data()) + byte_offset(ssize_t(index)...) / itemsize()); } @@ -946,9 +970,9 @@ struct format_descriptor<T, detail::enable_if_t<std::is_enum<T>::value>> { template <typename T> struct format_descriptor<T, detail::enable_if_t<detail::array_info<T>::is_array>> { static std::string format() { - using detail::_; - PYBIND11_DESCR extents = _("(") + detail::array_info<T>::extents() + _(")"); - return extents.text() + format_descriptor<detail::remove_all_extents_t<T>>::format(); + using namespace detail; + static constexpr auto extents = _("(") + array_info<T>::extents + _(")"); + return extents.text + format_descriptor<remove_all_extents_t<T>>::format(); } }; @@ -967,7 +991,7 @@ struct pyobject_caster<array_t<T, ExtraFlags>> { static handle cast(const handle &src, return_value_policy /* policy */, handle /* parent */) { return src.inc_ref(); } - PYBIND11_TYPE_CASTER(type, handle_type_name<type>::name()); + PYBIND11_TYPE_CASTER(type, handle_type_name<type>::name); }; template <typename T> @@ -977,13 +1001,40 @@ struct compare_buffer_info<T, detail::enable_if_t<detail::is_pod_struct<T>::valu } }; -template <typename T> struct npy_format_descriptor<T, enable_if_t<satisfies_any_of<T, std::is_arithmetic, is_complex>::value>> { +template <typename T, typename = void> +struct npy_format_descriptor_name; + +template <typename T> +struct npy_format_descriptor_name<T, enable_if_t<std::is_integral<T>::value>> { + static constexpr auto name = _<std::is_same<T, bool>::value>( + _("bool"), _<std::is_signed<T>::value>("int", "uint") + _<sizeof(T)*8>() + ); +}; + +template <typename T> +struct npy_format_descriptor_name<T, enable_if_t<std::is_floating_point<T>::value>> { + static constexpr auto name = _<std::is_same<T, float>::value || std::is_same<T, double>::value>( + _("float") + _<sizeof(T)*8>(), _("longdouble") + ); +}; + +template <typename T> +struct npy_format_descriptor_name<T, enable_if_t<is_complex<T>::value>> { + static constexpr auto name = _<std::is_same<typename T::value_type, float>::value + || std::is_same<typename T::value_type, double>::value>( + _("complex") + _<sizeof(typename T::value_type)*16>(), _("longcomplex") + ); +}; + +template <typename T> +struct npy_format_descriptor<T, enable_if_t<satisfies_any_of<T, std::is_arithmetic, is_complex>::value>> + : npy_format_descriptor_name<T> { private: // 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_BYTE_, npy_api::NPY_UBYTE_, npy_api::NPY_INT16_, npy_api::NPY_UINT16_, + npy_api::NPY_INT32_, npy_api::NPY_UINT32_, npy_api::NPY_INT64_, npy_api::NPY_UINT64_, npy_api::NPY_FLOAT_, npy_api::NPY_DOUBLE_, npy_api::NPY_LONGDOUBLE_, npy_api::NPY_CFLOAT_, npy_api::NPY_CDOUBLE_, npy_api::NPY_CLONGDOUBLE_ }; @@ -993,28 +1044,13 @@ public: static pybind11::dtype dtype() { if (auto ptr = npy_api::get().PyArray_DescrFromType_(value)) - return reinterpret_borrow<pybind11::dtype>(ptr); + return reinterpret_steal<pybind11::dtype>(ptr); pybind11_fail("Unsupported buffer format!"); } - 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")); - } }; #define PYBIND11_DECL_CHAR_FMT \ - static PYBIND11_DESCR name() { return _("S") + _<N>(); } \ + static constexpr auto name = _("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]> { PYBIND11_DECL_CHAR_FMT }; template <size_t N> struct npy_format_descriptor<std::array<char, N>> { PYBIND11_DECL_CHAR_FMT }; @@ -1026,7 +1062,7 @@ private: public: static_assert(!array_info<T>::is_empty, "Zero-sized arrays are not supported"); - static PYBIND11_DESCR name() { return _("(") + array_info<T>::extents() + _(")") + base_descr::name(); } + static constexpr auto name = _("(") + array_info<T>::extents + _(")") + base_descr::name; static pybind11::dtype dtype() { list shape; array_info<T>::append_extents(shape); @@ -1038,7 +1074,7 @@ template<typename T> struct npy_format_descriptor<T, enable_if_t<std::is_enum<T> private: using base_descr = npy_format_descriptor<typename std::underlying_type<T>::type>; public: - static PYBIND11_DESCR name() { return base_descr::name(); } + static constexpr auto name = base_descr::name; static pybind11::dtype dtype() { return base_descr::dtype(); } }; @@ -1051,7 +1087,7 @@ struct field_descriptor { }; inline PYBIND11_NOINLINE void register_structured_dtype( - const std::initializer_list<field_descriptor>& fields, + any_container<field_descriptor> fields, const std::type_info& tinfo, ssize_t itemsize, bool (*direct_converter)(PyObject *, void *&)) { @@ -1059,8 +1095,14 @@ inline PYBIND11_NOINLINE void register_structured_dtype( if (numpy_internals.get_type_info(tinfo, false)) pybind11_fail("NumPy: dtype is already registered"); + // Use ordered fields because order matters as of NumPy 1.14: + // https://docs.scipy.org/doc/numpy/release.html#multiple-field-indexing-assignment-of-structured-arrays + std::vector<field_descriptor> ordered_fields(std::move(fields)); + std::sort(ordered_fields.begin(), ordered_fields.end(), + [](const field_descriptor &a, const field_descriptor &b) { return a.offset < b.offset; }); + list names, formats, offsets; - for (auto field : fields) { + for (auto& field : ordered_fields) { if (!field.descr) pybind11_fail(std::string("NumPy: unsupported field dtype: `") + field.name + "` @ " + tinfo.name()); @@ -1077,9 +1119,6 @@ inline PYBIND11_NOINLINE void register_structured_dtype( // - https://github.com/numpy/numpy/pull/7798 // Because of this, we won't use numpy's logic to generate buffer format // strings and will just do it ourselves. - std::vector<field_descriptor> ordered_fields(fields); - std::sort(ordered_fields.begin(), ordered_fields.end(), - [](const field_descriptor &a, const field_descriptor &b) { return a.offset < b.offset; }); ssize_t offset = 0; std::ostringstream oss; // mark the structure as unaligned with '^', because numpy and C++ don't @@ -1113,7 +1152,7 @@ inline PYBIND11_NOINLINE void register_structured_dtype( 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 constexpr auto name = make_caster<T>::name; static pybind11::dtype dtype() { return reinterpret_borrow<pybind11::dtype>(dtype_ptr()); @@ -1124,8 +1163,8 @@ template <typename T, typename SFINAE> struct npy_format_descriptor { return format_str; } - static void register_dtype(const std::initializer_list<field_descriptor>& fields) { - register_structured_dtype(fields, typeid(typename std::remove_cv<T>::type), + static void register_dtype(any_container<field_descriptor> fields) { + register_structured_dtype(std::move(fields), typeid(typename std::remove_cv<T>::type), sizeof(T), &direct_converter); } @@ -1198,7 +1237,8 @@ private: #define PYBIND11_NUMPY_DTYPE(Type, ...) \ ::pybind11::detail::npy_format_descriptor<Type>::register_dtype \ - ({PYBIND11_MAP_LIST (PYBIND11_FIELD_DESCRIPTOR, Type, __VA_ARGS__)}) + (::std::vector<::pybind11::detail::field_descriptor> \ + {PYBIND11_MAP_LIST (PYBIND11_FIELD_DESCRIPTOR, Type, __VA_ARGS__)}) #ifdef _MSC_VER #define PYBIND11_MAP2_LIST_NEXT1(test, next) \ @@ -1219,7 +1259,8 @@ private: #define PYBIND11_NUMPY_DTYPE_EX(Type, ...) \ ::pybind11::detail::npy_format_descriptor<Type>::register_dtype \ - ({PYBIND11_MAP2_LIST (PYBIND11_FIELD_DESCRIPTOR_EX, Type, __VA_ARGS__)}) + (::std::vector<::pybind11::detail::field_descriptor> \ + {PYBIND11_MAP2_LIST (PYBIND11_FIELD_DESCRIPTOR_EX, Type, __VA_ARGS__)}) #endif // __CLION_IDE__ @@ -1457,7 +1498,10 @@ public: private: remove_reference_t<Func> f; - template <size_t Index> using param_n_t = typename pack_element<Index, typename vectorize_arg<Args>::call_type...>::type; + // Internal compiler error in MSVC 19.16.27025.1 (Visual Studio 2017 15.9.4), when compiling with "/permissive-" flag + // when arg_call_types is manually inlined. + using arg_call_types = std::tuple<typename vectorize_arg<Args>::call_type...>; + template <size_t Index> using param_n_t = typename std::tuple_element<Index, arg_call_types>::type; // Runs a vectorized function given arguments tuple and three index sequences: // - Index is the full set of 0 ... (N-1) argument indices; @@ -1497,7 +1541,7 @@ private: if (trivial == broadcast_trivial::f_trivial) result = array_t<Return, array::f_style>(shape); else result = array_t<Return>(shape); - if (size == 0) return result; + if (size == 0) return std::move(result); /* Call the function */ if (trivial == broadcast_trivial::non_trivial) @@ -1505,7 +1549,7 @@ private: else apply_trivial(buffers, params, result.mutable_data(), size, i_seq, vi_seq, bi_seq); - return result; + return std::move(result); } template <size_t... Index, size_t... VIndex, size_t... BIndex> @@ -1558,9 +1602,7 @@ vectorize_extractor(const Func &f, Return (*) (Args ...)) { } template <typename T, int Flags> struct handle_type_name<array_t<T, Flags>> { - static PYBIND11_DESCR name() { - return _("numpy.ndarray[") + npy_format_descriptor<T>::name() + _("]"); - } + static constexpr auto name = _("numpy.ndarray[") + npy_format_descriptor<T>::name + _("]"); }; NAMESPACE_END(detail) @@ -1586,7 +1628,7 @@ Helper vectorize(Return (Class::*f)(Args...)) { return Helper(std::mem_fn(f)); } -// Vectorize a class method (non-const): +// Vectorize a class method (const): template <typename Return, typename Class, typename... Args, typename Helper = detail::vectorize_helper<decltype(std::mem_fn(std::declval<Return (Class::*)(Args...) const>())), Return, const Class *, Args...>> Helper vectorize(Return (Class::*f)(Args...) const) { diff --git a/ext/pybind11/include/pybind11/pybind11.h b/ext/pybind11/include/pybind11/pybind11.h index db325e0c5..a0e639583 100644 --- a/ext/pybind11/include/pybind11/pybind11.h +++ b/ext/pybind11/include/pybind11/pybind11.h @@ -10,7 +10,17 @@ #pragma once -#if defined(_MSC_VER) +#if defined(__INTEL_COMPILER) +# pragma warning push +# pragma warning disable 68 // integer conversion resulted in a change of sign +# pragma warning disable 186 // pointless comparison of unsigned integer with zero +# pragma warning disable 878 // incompatible exception specifications +# pragma warning disable 1334 // the "template" keyword used for syntactic disambiguation may only be used within a template +# pragma warning disable 1682 // implicit conversion of a 64-bit integral type to a smaller integral type (potential portability problem) +# pragma warning disable 1786 // function "strdup" was declared deprecated +# pragma warning disable 1875 // offsetof applied to non-POD (Plain Old Data) types is nonstandard +# pragma warning disable 2196 // warning #2196: routine is both "inline" and "noinline" +#elif defined(_MSC_VER) # pragma warning(push) # pragma warning(disable: 4100) // warning C4100: Unreferenced formal parameter # pragma warning(disable: 4127) // warning C4127: Conditional expression is constant @@ -19,15 +29,6 @@ # pragma warning(disable: 4996) // warning C4996: The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name # pragma warning(disable: 4702) // warning C4702: unreachable code # pragma warning(disable: 4522) // warning C4522: multiple assignment operators specified -#elif defined(__INTEL_COMPILER) -# pragma warning(push) -# pragma warning(disable: 68) // integer conversion resulted in a change of sign -# pragma warning(disable: 186) // pointless comparison of unsigned integer with zero -# pragma warning(disable: 878) // incompatible exception specifications -# pragma warning(disable: 1334) // the "template" keyword used for syntactic disambiguation may only be used within a template -# pragma warning(disable: 1682) // implicit conversion of a 64-bit integral type to a smaller integral type (potential portability problem) -# pragma warning(disable: 1875) // offsetof applied to non-POD (Plain Old Data) types is nonstandard -# pragma warning(disable: 2196) // warning #2196: routine is both "inline" and "noinline" #elif defined(__GNUG__) && !defined(__clang__) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wunused-but-set-parameter" @@ -45,12 +46,17 @@ #include "detail/class.h" #include "detail/init.h" +#if defined(__GNUG__) && !defined(__clang__) +# include <cxxabi.h> +#endif + NAMESPACE_BEGIN(PYBIND11_NAMESPACE) /// Wraps an arbitrary C++ function/method/lambda function/.. into a callable Python object class cpp_function : public function { public: cpp_function() { } + cpp_function(std::nullptr_t) { } /// Construct a cpp_function from a vanilla function pointer template <typename Return, typename... Args, typename... Extra> @@ -92,8 +98,8 @@ 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) { - - struct capture { detail::remove_reference_t<Func> f; }; + using namespace detail; + struct capture { remove_reference_t<Func> f; }; /* Store the function including any extra state it might have (e.g. a lambda capture object) */ auto rec = make_function_record(); @@ -112,23 +118,23 @@ protected: # pragma GCC diagnostic pop #endif if (!std::is_trivially_destructible<Func>::value) - rec->free_data = [](detail::function_record *r) { ((capture *) &r->data)->~capture(); }; + rec->free_data = [](function_record *r) { ((capture *) &r->data)->~capture(); }; } else { rec->data[0] = new capture { std::forward<Func>(f) }; - rec->free_data = [](detail::function_record *r) { delete ((capture *) r->data[0]); }; + rec->free_data = [](function_record *r) { delete ((capture *) r->data[0]); }; } /* Type casters for the function arguments and return value */ - using cast_in = detail::argument_loader<Args...>; - using cast_out = detail::make_caster< - detail::conditional_t<std::is_void<Return>::value, detail::void_type, Return> + using cast_in = argument_loader<Args...>; + using cast_out = make_caster< + conditional_t<std::is_void<Return>::value, void_type, Return> >; - static_assert(detail::expected_num_args<Extra...>(sizeof...(Args), cast_in::has_args, cast_in::has_kwargs), + static_assert(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_call &call) -> handle { + rec->impl = [](function_call &call) -> handle { cast_in args_converter; /* Try to cast the function arguments into the C++ domain */ @@ -136,7 +142,7 @@ protected: return PYBIND11_TRY_NEXT_OVERLOAD; /* Invoke call policy pre-call hook */ - detail::process_attributes<Extra...>::precall(call); + process_attributes<Extra...>::precall(call); /* Get a pointer to the capture object */ auto data = (sizeof(capture) <= sizeof(call.func.data) @@ -144,30 +150,30 @@ protected: capture *cap = const_cast<capture *>(reinterpret_cast<const capture *>(data)); /* 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); + return_value_policy policy = return_value_policy_override<Return>::policy(call.func.policy); /* Function scope guard -- defaults to the compile-to-nothing `void_type` */ - using Guard = detail::extract_guard_t<Extra...>; + using Guard = extract_guard_t<Extra...>; /* Perform the function call */ handle result = cast_out::cast( std::move(args_converter).template call<Return, Guard>(cap->f), policy, call.parent); /* Invoke call policy post-call hook */ - detail::process_attributes<Extra...>::postcall(call, result); + process_attributes<Extra...>::postcall(call, result); return result; }; /* Process any user-provided function attributes */ - detail::process_attributes<Extra...>::init(extra..., rec); + process_attributes<Extra...>::init(extra..., rec); /* Generate a readable signature describing the function's arguments and return value types */ - using detail::descr; using detail::_; - PYBIND11_DESCR signature = _("(") + cast_in::arg_names() + _(") -> ") + cast_out::name(); + static constexpr auto signature = _("(") + cast_in::arg_names + _(") -> ") + cast_out::name; + PYBIND11_DESCR_CONSTEXPR auto types = decltype(signature)::types(); /* Register the function with Python from generic (non-templated) code */ - initialize_generic(rec, signature.text(), signature.types(), sizeof...(Args)); + initialize_generic(rec, signature.text, types.data(), sizeof...(Args)); if (cast_in::has_args) rec->has_args = true; if (cast_in::has_kwargs) rec->has_kwargs = true; @@ -217,52 +223,45 @@ protected: /* Generate a proper function signature */ std::string signature; - size_t type_depth = 0, char_index = 0, type_index = 0, arg_index = 0; - while (true) { - char c = text[char_index++]; - if (c == '\0') - break; + size_t type_index = 0, arg_index = 0; + for (auto *pc = text; *pc != '\0'; ++pc) { + const auto c = *pc; 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() && rec->args[arg_index].name) { - signature += rec->args[arg_index].name; - } else if (arg_index == 0 && rec->is_method) { - signature += "self"; - } else { - signature += "arg" + std::to_string(arg_index - (rec->is_method ? 1 : 0)); - } - signature += ": "; + // Write arg name for everything except *args and **kwargs. + if (*(pc + 1) == '*') + continue; + + if (arg_index < rec->args.size() && rec->args[arg_index].name) { + signature += rec->args[arg_index].name; + } else if (arg_index == 0 && rec->is_method) { + signature += "self"; + } else { + signature += "arg" + std::to_string(arg_index - (rec->is_method ? 1 : 0)); } - ++type_depth; + signature += ": "; } else if (c == '}') { - --type_depth; - if (type_depth == 0) { - if (arg_index < rec->args.size() && rec->args[arg_index].descr) { - signature += "="; - signature += rec->args[arg_index].descr; - } - arg_index++; + // Write default value if available. + if (arg_index < rec->args.size() && rec->args[arg_index].descr) { + signature += " = "; + signature += rec->args[arg_index].descr; } + arg_index++; } else if (c == '%') { const std::type_info *t = types[type_index++]; 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; + handle th((PyObject *) tinfo->type); + signature += + th.attr("__module__").cast<std::string>() + "." + + th.attr("__qualname__").cast<std::string>(); // Python 3.3+, but we backport it to earlier versions } else if (rec->is_new_style_constructor && arg_index == 0) { // A new-style `__init__` takes `self` as `value_and_holder`. // Rewrite it to the proper class type. -#if defined(PYPY_VERSION) - signature += rec->scope.attr("__module__").cast<std::string>() + "."; -#endif - signature += ((PyTypeObject *) rec->scope.ptr())->tp_name; + signature += + rec->scope.attr("__module__").cast<std::string>() + "." + + rec->scope.attr("__qualname__").cast<std::string>(); } else { std::string tname(t->name()); detail::clean_type_id(tname); @@ -272,14 +271,9 @@ protected: signature += c; } } - if (type_depth != 0 || types[type_index] != nullptr) + if (arg_index != args || types[type_index] != nullptr) pybind11_fail("Internal error while parsing type signature (2)"); - #if !defined(PYBIND11_CONSTEXPR_DESCR) - delete[] types; - delete[] text; - #endif - #if PY_MAJOR_VERSION < 3 if (strcmp(rec->name, "__next__") == 0) { std::free(rec->name); @@ -431,8 +425,8 @@ protected: using namespace detail; /* Iterator over the list of potentially admissible overloads */ - function_record *overloads = (function_record *) PyCapsule_GetPointer(self, nullptr), - *it = overloads; + const 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 */ const size_t n_args_in = (size_t) PyTuple_GET_SIZE(args_in); @@ -488,7 +482,7 @@ protected: result other than PYBIND11_TRY_NEXT_OVERLOAD. */ - function_record &func = *it; + const 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) @@ -501,7 +495,7 @@ protected: function_call call(func, parent); - size_t args_to_copy = std::min(pos_args, n_args_in); + size_t args_to_copy = (std::min)(pos_args, n_args_in); // Protect std::min with parentheses size_t args_copied = 0; // 0. Inject new-style `self` argument @@ -520,7 +514,7 @@ protected: // 1. Copy any position arguments given. bool bad_arg = false; for (; args_copied < args_to_copy; ++args_copied) { - argument_record *arg_rec = args_copied < func.args.size() ? &func.args[args_copied] : nullptr; + const argument_record *arg_rec = args_copied < func.args.size() ? &func.args[args_copied] : nullptr; if (kwargs_in && arg_rec && arg_rec->name && PyDict_GetItemString(kwargs_in, arg_rec->name)) { bad_arg = true; break; @@ -579,8 +573,8 @@ protected: 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) { + tuple extra_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: @@ -591,12 +585,12 @@ protected: 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(); + extra_args[i] = PyTuple_GET_ITEM(args_in, args_copied + i); } } call.args.push_back(extra_args); call.args_convert.push_back(false); + call.args_ref = std::move(extra_args); } // 4b. If we have a py::kwargs, pass on any remaining kwargs @@ -605,6 +599,7 @@ protected: kwargs = dict(); // If we didn't get one, send an empty one call.args.push_back(kwargs); call.args_convert.push_back(false); + call.kwargs_ref = std::move(kwargs); } // 5. Put everything in a vector. Not technically step 5, we've been building it @@ -660,13 +655,22 @@ protected: result = PYBIND11_TRY_NEXT_OVERLOAD; } - if (result.ptr() != PYBIND11_TRY_NEXT_OVERLOAD) + if (result.ptr() != PYBIND11_TRY_NEXT_OVERLOAD) { + // The error reporting logic below expects 'it' to be valid, as it would be + // if we'd encountered this failure in the first-pass loop. + if (!result) + it = &call.func; break; + } } } } catch (error_already_set &e) { e.restore(); return nullptr; +#if defined(__GNUG__) && !defined(__clang__) + } catch ( abi::__forced_unwind& ) { + throw; +#endif } catch (...) { /* When an exception is caught, give each registered exception translator a chance to translate it to a Python exception @@ -713,7 +717,7 @@ protected: " arguments. The following argument types are supported:\n"; int ctr = 0; - for (function_record *it2 = overloads; it2 != nullptr; it2 = it2->next) { + for (const function_record *it2 = overloads; it2 != nullptr; it2 = it2->next) { msg += " "+ std::to_string(++ctr) + ". "; bool wrote_sig = false; @@ -901,6 +905,7 @@ protected: tinfo->type = (PyTypeObject *) m_ptr; tinfo->cpptype = rec.type; tinfo->type_size = rec.type_size; + tinfo->type_align = rec.type_align; tinfo->operator_new = rec.operator_new; tinfo->holder_size_in_ptrs = size_in_ptrs(rec.holder_size); tinfo->init_instance = rec.init_instance; @@ -963,18 +968,18 @@ protected: tinfo->get_buffer_data = get_buffer_data; } + // rec_func must be set for either fget or fset. 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(); - + detail::function_record *rec_func) { + const auto is_static = rec_func && !(rec_func->is_method && rec_func->scope); + const auto has_doc = rec_func && rec_func->doc && pybind11::options::show_user_defined_docstrings(); 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 : "")); + pybind11::str(has_doc ? rec_func->doc : "")); } }; @@ -992,11 +997,21 @@ template <typename T> struct has_operator_delete_size<T, void_t<decltype(static_ : std::true_type { }; /// Call class-specific delete if it exists or global otherwise. Can also be an overload set. template <typename T, enable_if_t<has_operator_delete<T>::value, int> = 0> -void call_operator_delete(T *p, size_t) { T::operator delete(p); } +void call_operator_delete(T *p, size_t, size_t) { T::operator delete(p); } template <typename T, enable_if_t<!has_operator_delete<T>::value && has_operator_delete_size<T>::value, int> = 0> -void call_operator_delete(T *p, size_t s) { T::operator delete(p, s); } +void call_operator_delete(T *p, size_t s, size_t) { T::operator delete(p, s); } -inline void call_operator_delete(void *p, size_t) { ::operator delete(p); } +inline void call_operator_delete(void *p, size_t s, size_t a) { + (void)s; (void)a; +#if defined(PYBIND11_CPP17) + if (a > __STDCPP_DEFAULT_NEW_ALIGNMENT__) + ::operator delete(p, s, std::align_val_t(a)); + else + ::operator delete(p, s); +#else + ::operator delete(p); +#endif +} NAMESPACE_END(detail) @@ -1006,10 +1021,18 @@ template <typename /*Derived*/, typename F> auto method_adaptor(F &&f) -> decltype(std::forward<F>(f)) { return std::forward<F>(f); } template <typename Derived, typename Return, typename Class, typename... Args> -auto method_adaptor(Return (Class::*pmf)(Args...)) -> Return (Derived::*)(Args...) { return pmf; } +auto method_adaptor(Return (Class::*pmf)(Args...)) -> Return (Derived::*)(Args...) { + static_assert(detail::is_accessible_base_of<Class, Derived>::value, + "Cannot bind an inaccessible base class method; use a lambda definition instead"); + return pmf; +} template <typename Derived, typename Return, typename Class, typename... Args> -auto method_adaptor(Return (Class::*pmf)(Args...) const) -> Return (Derived::*)(Args...) const { return pmf; } +auto method_adaptor(Return (Class::*pmf)(Args...) const) -> Return (Derived::*)(Args...) const { + static_assert(detail::is_accessible_base_of<Class, Derived>::value, + "Cannot bind an inaccessible base class method; use a lambda definition instead"); + return pmf; +} template <typename type_, typename... options> class class_ : public detail::generic_type { @@ -1051,10 +1074,11 @@ public: record.name = name; record.type = &typeid(type); record.type_size = sizeof(conditional_t<has_alias, type_alias, type>); + record.type_align = alignof(conditional_t<has_alias, type_alias, type>&); record.holder_size = sizeof(holder_type); record.init_instance = init_instance; record.dealloc = dealloc; - record.default_holder = std::is_same<holder_type, std::unique_ptr<type>>::value; + record.default_holder = detail::is_instantiation<std::unique_ptr, holder_type>::value; set_operator_new<type>(&record); @@ -1096,7 +1120,7 @@ public: "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; + attr(cf.name()) = staticmethod(cf); return *this; } @@ -1160,7 +1184,7 @@ public: template <typename C, typename D, typename... Extra> class_ &def_readwrite(const char *name, D C::*pm, const Extra&... extra) { - static_assert(std::is_base_of<C, type>::value, "def_readwrite() requires a class member (or base class member)"); + static_assert(std::is_same<C, type>::value || std::is_base_of<C, type>::value, "def_readwrite() requires a class member (or base class member)"); cpp_function fget([pm](const type &c) -> const D &{ return c.*pm; }, is_method(*this)), fset([pm](type &c, const D &value) { c.*pm = value; }, is_method(*this)); def_property(name, fget, fset, return_value_policy::reference_internal, extra...); @@ -1169,7 +1193,7 @@ public: template <typename C, typename D, typename... Extra> class_ &def_readonly(const char *name, const D C::*pm, const Extra& ...extra) { - static_assert(std::is_base_of<C, type>::value, "def_readonly() requires a class member (or base class member)"); + static_assert(std::is_same<C, type>::value || std::is_base_of<C, type>::value, "def_readonly() requires a class member (or base class member)"); cpp_function fget([pm](const type &c) -> const D &{ return c.*pm; }, is_method(*this)); def_property_readonly(name, fget, return_value_policy::reference_internal, extra...); return *this; @@ -1200,7 +1224,7 @@ public: /// Uses cpp_function's return_value_policy by default template <typename... Extra> class_ &def_property_readonly(const char *name, const cpp_function &fget, const Extra& ...extra) { - return def_property(name, fget, cpp_function(), extra...); + return def_property(name, fget, nullptr, extra...); } /// Uses return_value_policy::reference by default @@ -1212,7 +1236,7 @@ public: /// Uses cpp_function's return_value_policy by default template <typename... Extra> class_ &def_property_readonly_static(const char *name, const cpp_function &fget, const Extra& ...extra) { - return def_property_static(name, fget, cpp_function(), extra...); + return def_property_static(name, fget, nullptr, extra...); } /// Uses return_value_policy::reference_internal by default @@ -1241,22 +1265,28 @@ public: /// Uses cpp_function's return_value_policy by default template <typename... Extra> class_ &def_property_static(const char *name, const cpp_function &fget, const cpp_function &fset, const Extra& ...extra) { + static_assert( 0 == detail::constexpr_sum(std::is_base_of<arg, Extra>::value...), + "Argument annotations are not allowed for properties"); auto rec_fget = get_function_record(fget), rec_fset = get_function_record(fset); - char *doc_prev = rec_fget->doc; /* 'extra' field may include a property-specific documentation string */ - detail::process_attributes<Extra...>::init(extra..., rec_fget); - if (rec_fget->doc && rec_fget->doc != doc_prev) { - free(doc_prev); - rec_fget->doc = strdup(rec_fget->doc); + auto *rec_active = rec_fget; + if (rec_fget) { + char *doc_prev = rec_fget->doc; /* 'extra' field may include a property-specific documentation string */ + detail::process_attributes<Extra...>::init(extra..., rec_fget); + if (rec_fget->doc && rec_fget->doc != doc_prev) { + free(doc_prev); + rec_fget->doc = strdup(rec_fget->doc); + } } if (rec_fset) { - doc_prev = rec_fset->doc; + char *doc_prev = rec_fset->doc; detail::process_attributes<Extra...>::init(extra..., rec_fset); if (rec_fset->doc && rec_fset->doc != doc_prev) { free(doc_prev); rec_fset->doc = strdup(rec_fset->doc); } + if (! rec_active) rec_active = rec_fset; } - def_property_static_impl(name, fget, fset, rec_fget); + def_property_static_impl(name, fget, fset, rec_active); return *this; } @@ -1269,25 +1299,25 @@ private: auto sh = std::dynamic_pointer_cast<typename holder_type::element_type>( v_h.value_ptr<type>()->shared_from_this()); if (sh) { - new (&v_h.holder<holder_type>()) holder_type(std::move(sh)); + new (std::addressof(v_h.holder<holder_type>())) holder_type(std::move(sh)); v_h.set_holder_constructed(); } } catch (const std::bad_weak_ptr &) {} if (!v_h.holder_constructed() && inst->owned) { - new (&v_h.holder<holder_type>()) holder_type(v_h.value_ptr<type>()); + new (std::addressof(v_h.holder<holder_type>())) holder_type(v_h.value_ptr<type>()); v_h.set_holder_constructed(); } } static void init_holder_from_existing(const detail::value_and_holder &v_h, const holder_type *holder_ptr, std::true_type /*is_copy_constructible*/) { - new (&v_h.holder<holder_type>()) holder_type(*reinterpret_cast<const holder_type *>(holder_ptr)); + new (std::addressof(v_h.holder<holder_type>())) holder_type(*reinterpret_cast<const holder_type *>(holder_ptr)); } static void init_holder_from_existing(const detail::value_and_holder &v_h, const holder_type *holder_ptr, std::false_type /*is_copy_constructible*/) { - new (&v_h.holder<holder_type>()) holder_type(std::move(*const_cast<holder_type *>(holder_ptr))); + new (std::addressof(v_h.holder<holder_type>())) holder_type(std::move(*const_cast<holder_type *>(holder_ptr))); } /// Initialize holder object, variant 2: try to construct from existing holder object, if possible @@ -1297,7 +1327,7 @@ private: init_holder_from_existing(v_h, holder_ptr, std::is_copy_constructible<holder_type>()); v_h.set_holder_constructed(); } else if (inst->owned || detail::always_construct_holder<holder_type>::value) { - new (&v_h.holder<holder_type>()) holder_type(v_h.value_ptr<type>()); + new (std::addressof(v_h.holder<holder_type>())) holder_type(v_h.value_ptr<type>()); v_h.set_holder_constructed(); } } @@ -1322,7 +1352,10 @@ private: v_h.set_holder_constructed(false); } else { - detail::call_operator_delete(v_h.value_ptr<type>(), v_h.type->type_size); + detail::call_operator_delete(v_h.value_ptr<type>(), + v_h.type->type_size, + v_h.type->type_align + ); } v_h.value_ptr() = nullptr; } @@ -1358,93 +1391,205 @@ detail::initimpl::pickle_factory<GetState, SetState> pickle(GetState &&g, SetSta return {std::forward<GetState>(g), std::forward<SetState>(s)}; } +NAMESPACE_BEGIN(detail) +struct enum_base { + enum_base(handle base, handle parent) : m_base(base), m_parent(parent) { } + + PYBIND11_NOINLINE void init(bool is_arithmetic, bool is_convertible) { + m_base.attr("__entries") = dict(); + auto property = handle((PyObject *) &PyProperty_Type); + auto static_property = handle((PyObject *) get_internals().static_property_type); + + m_base.attr("__repr__") = cpp_function( + [](handle arg) -> str { + handle type = arg.get_type(); + object type_name = type.attr("__name__"); + dict entries = type.attr("__entries"); + for (const auto &kv : entries) { + object other = kv.second[int_(0)]; + if (other.equal(arg)) + return pybind11::str("{}.{}").format(type_name, kv.first); + } + return pybind11::str("{}.???").format(type_name); + }, is_method(m_base) + ); + + m_base.attr("name") = property(cpp_function( + [](handle arg) -> str { + dict entries = arg.get_type().attr("__entries"); + for (const auto &kv : entries) { + if (handle(kv.second[int_(0)]).equal(arg)) + return pybind11::str(kv.first); + } + return "???"; + }, is_method(m_base) + )); + + m_base.attr("__doc__") = static_property(cpp_function( + [](handle arg) -> std::string { + std::string docstring; + dict entries = arg.attr("__entries"); + if (((PyTypeObject *) arg.ptr())->tp_doc) + docstring += std::string(((PyTypeObject *) arg.ptr())->tp_doc) + "\n\n"; + docstring += "Members:"; + for (const auto &kv : entries) { + auto key = std::string(pybind11::str(kv.first)); + auto comment = kv.second[int_(1)]; + docstring += "\n\n " + key; + if (!comment.is_none()) + docstring += " : " + (std::string) pybind11::str(comment); + } + return docstring; + } + ), none(), none(), ""); + + m_base.attr("__members__") = static_property(cpp_function( + [](handle arg) -> dict { + dict entries = arg.attr("__entries"), m; + for (const auto &kv : entries) + m[kv.first] = kv.second[int_(0)]; + return m; + }), none(), none(), "" + ); + + #define PYBIND11_ENUM_OP_STRICT(op, expr, strict_behavior) \ + m_base.attr(op) = cpp_function( \ + [](object a, object b) { \ + if (!a.get_type().is(b.get_type())) \ + strict_behavior; \ + return expr; \ + }, \ + is_method(m_base)) + + #define PYBIND11_ENUM_OP_CONV(op, expr) \ + m_base.attr(op) = cpp_function( \ + [](object a_, object b_) { \ + int_ a(a_), b(b_); \ + return expr; \ + }, \ + is_method(m_base)) + + #define PYBIND11_ENUM_OP_CONV_LHS(op, expr) \ + m_base.attr(op) = cpp_function( \ + [](object a_, object b) { \ + int_ a(a_); \ + return expr; \ + }, \ + is_method(m_base)) + + if (is_convertible) { + PYBIND11_ENUM_OP_CONV_LHS("__eq__", !b.is_none() && a.equal(b)); + PYBIND11_ENUM_OP_CONV_LHS("__ne__", b.is_none() || !a.equal(b)); + + if (is_arithmetic) { + PYBIND11_ENUM_OP_CONV("__lt__", a < b); + PYBIND11_ENUM_OP_CONV("__gt__", a > b); + PYBIND11_ENUM_OP_CONV("__le__", a <= b); + PYBIND11_ENUM_OP_CONV("__ge__", a >= b); + PYBIND11_ENUM_OP_CONV("__and__", a & b); + PYBIND11_ENUM_OP_CONV("__rand__", a & b); + PYBIND11_ENUM_OP_CONV("__or__", a | b); + PYBIND11_ENUM_OP_CONV("__ror__", a | b); + PYBIND11_ENUM_OP_CONV("__xor__", a ^ b); + PYBIND11_ENUM_OP_CONV("__rxor__", a ^ b); + m_base.attr("__invert__") = cpp_function( + [](object arg) { return ~(int_(arg)); }, is_method(m_base)); + } + } else { + PYBIND11_ENUM_OP_STRICT("__eq__", int_(a).equal(int_(b)), return false); + PYBIND11_ENUM_OP_STRICT("__ne__", !int_(a).equal(int_(b)), return true); + + if (is_arithmetic) { + #define PYBIND11_THROW throw type_error("Expected an enumeration of matching type!"); + PYBIND11_ENUM_OP_STRICT("__lt__", int_(a) < int_(b), PYBIND11_THROW); + PYBIND11_ENUM_OP_STRICT("__gt__", int_(a) > int_(b), PYBIND11_THROW); + PYBIND11_ENUM_OP_STRICT("__le__", int_(a) <= int_(b), PYBIND11_THROW); + PYBIND11_ENUM_OP_STRICT("__ge__", int_(a) >= int_(b), PYBIND11_THROW); + #undef PYBIND11_THROW + } + } + + #undef PYBIND11_ENUM_OP_CONV_LHS + #undef PYBIND11_ENUM_OP_CONV + #undef PYBIND11_ENUM_OP_STRICT + + object getstate = cpp_function( + [](object arg) { return int_(arg); }, is_method(m_base)); + + m_base.attr("__getstate__") = getstate; + m_base.attr("__hash__") = getstate; + } + + PYBIND11_NOINLINE void value(char const* name_, object value, const char *doc = nullptr) { + dict entries = m_base.attr("__entries"); + str name(name_); + if (entries.contains(name)) { + std::string type_name = (std::string) str(m_base.attr("__name__")); + throw value_error(type_name + ": element \"" + std::string(name_) + "\" already exists!"); + } + + entries[name] = std::make_pair(value, doc); + m_base.attr(name) = value; + } + + PYBIND11_NOINLINE void export_values() { + dict entries = m_base.attr("__entries"); + for (const auto &kv : entries) + m_parent.attr(kv.first) = kv.second[int_(0)]; + } + + handle m_base; + handle m_parent; +}; + +NAMESPACE_END(detail) + /// Binds C++ enumerations and enumeration classes to Python template <typename Type> class enum_ : public class_<Type> { public: - using class_<Type>::def; - using class_<Type>::def_property_readonly_static; + using Base = class_<Type>; + using Base::def; + using Base::attr; + using Base::def_property_readonly; + using Base::def_property_readonly_static; using Scalar = typename std::underlying_type<Type>::type; template <typename... Extra> enum_(const handle &scope, const char *name, const Extra&... extra) - : class_<Type>(scope, name, extra...), m_entries(), m_parent(scope) { - + : class_<Type>(scope, name, extra...), m_base(*this, scope) { constexpr bool is_arithmetic = detail::any_of<std::is_same<arithmetic, Extra>...>::value; + constexpr bool is_convertible = std::is_convertible<Type, Scalar>::value; + m_base.init(is_arithmetic, is_convertible); - 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([](Scalar i) { return static_cast<Type>(i); })); def("__int__", [](Type value) { return (Scalar) value; }); #if PY_MAJOR_VERSION < 3 def("__long__", [](Type value) { return (Scalar) value; }); #endif - def("__eq__", [](const Type &value, Type *value2) { return value2 && value == *value2; }); - def("__ne__", [](const Type &value, Type *value2) { return !value2 || value != *value2; }); - if (is_arithmetic) { - def("__lt__", [](const Type &value, Type *value2) { return value2 && value < *value2; }); - def("__gt__", [](const Type &value, Type *value2) { return value2 && value > *value2; }); - def("__le__", [](const Type &value, Type *value2) { return value2 && value <= *value2; }); - def("__ge__", [](const Type &value, Type *value2) { return value2 && value >= *value2; }); - } - if (std::is_convertible<Type, Scalar>::value) { - // Don't provide comparison with the underlying type if the enum isn't convertible, - // i.e. if Type is a scoped enum, mirroring the C++ behaviour. (NB: we explicitly - // convert Type to Scalar below anyway because this needs to compile). - def("__eq__", [](const Type &value, Scalar value2) { return (Scalar) value == value2; }); - def("__ne__", [](const Type &value, Scalar value2) { return (Scalar) value != value2; }); - if (is_arithmetic) { - def("__lt__", [](const Type &value, Scalar value2) { return (Scalar) value < value2; }); - def("__gt__", [](const Type &value, Scalar value2) { return (Scalar) value > value2; }); - def("__le__", [](const Type &value, Scalar value2) { return (Scalar) value <= value2; }); - def("__ge__", [](const Type &value, Scalar value2) { return (Scalar) value >= value2; }); - def("__invert__", [](const Type &value) { return ~((Scalar) value); }); - def("__and__", [](const Type &value, Scalar value2) { return (Scalar) value & value2; }); - def("__or__", [](const Type &value, Scalar value2) { return (Scalar) value | value2; }); - def("__xor__", [](const Type &value, Scalar value2) { return (Scalar) value ^ value2; }); - def("__rand__", [](const Type &value, Scalar value2) { return (Scalar) value & value2; }); - def("__ror__", [](const Type &value, Scalar value2) { return (Scalar) value | value2; }); - def("__rxor__", [](const Type &value, Scalar value2) { return (Scalar) value ^ value2; }); - def("__and__", [](const Type &value, const Type &value2) { return (Scalar) value & (Scalar) value2; }); - def("__or__", [](const Type &value, const Type &value2) { return (Scalar) value | (Scalar) value2; }); - def("__xor__", [](const Type &value, const Type &value2) { return (Scalar) value ^ (Scalar) value2; }); - } - } - def("__hash__", [](const Type &value) { return (Scalar) value; }); - // Pickling and unpickling -- needed for use with the 'multiprocessing' module - def(pickle([](const Type &value) { return pybind11::make_tuple((Scalar) value); }, - [](tuple t) { return static_cast<Type>(t[0].cast<Scalar>()); })); + #if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 8 + def("__index__", [](Type value) { return (Scalar) value; }); + #endif + + cpp_function setstate( + [](Type &value, Scalar arg) { value = static_cast<Type>(arg); }, + is_method(*this)); + attr("__setstate__") = setstate; } /// Export enumeration entries into the parent scope enum_& export_values() { - for (const auto &kv : m_entries) - m_parent.attr(kv.first) = kv.second; + m_base.export_values(); return *this; } /// Add an enumeration entry - enum_& value(char const* name, Type value) { - auto v = pybind11::cast(value, return_value_policy::copy); - this->attr(name) = v; - m_entries[pybind11::str(name)] = v; + enum_& value(char const* name, Type value, const char *doc = nullptr) { + m_base.value(name, pybind11::cast(value, return_value_policy::copy), doc); return *this; } private: - dict m_entries; - handle m_parent; + detail::enum_base m_base; }; NAMESPACE_BEGIN(detail) @@ -1633,6 +1778,7 @@ void register_exception_translator(ExceptionTranslator&& translator) { template <typename type> class exception : public object { public: + exception() = default; exception(handle scope, const char *name, PyObject *base = PyExc_Exception) { std::string full_name = scope.attr("__name__").cast<std::string>() + std::string(".") + name; @@ -1649,6 +1795,14 @@ public: } }; +NAMESPACE_BEGIN(detail) +// Returns a reference to a function-local static exception object used in the simple +// register_exception approach below. (It would be simpler to have the static local variable +// directly in register_exception, but that makes clang <3.5 segfault - issue #1349). +template <typename CppException> +exception<CppException> &get_exception_object() { static exception<CppException> ex; return ex; } +NAMESPACE_END(detail) + /** * Registers a Python exception in `m` of the given `name` and installs an exception translator to * translate the C++ exception to the created Python exception using the exceptions what() method. @@ -1659,13 +1813,15 @@ template <typename CppException> exception<CppException> ®ister_exception(handle scope, const char *name, PyObject *base = PyExc_Exception) { - static exception<CppException> ex(scope, name, base); + auto &ex = detail::get_exception_object<CppException>(); + if (!ex) ex = exception<CppException>(scope, name, base); + register_exception_translator([](std::exception_ptr p) { if (!p) return; try { std::rethrow_exception(p); } catch (const CppException &e) { - ex(e.what()); + detail::get_exception_object<CppException>()(e.what()); } }); return ex; @@ -1738,7 +1894,16 @@ class gil_scoped_acquire { public: PYBIND11_NOINLINE gil_scoped_acquire() { auto const &internals = detail::get_internals(); - tstate = (PyThreadState *) PyThread_get_key_value(internals.tstate); + tstate = (PyThreadState *) PYBIND11_TLS_GET_VALUE(internals.tstate); + + if (!tstate) { + /* Check if the GIL was acquired using the PyGILState_* API instead (e.g. if + calling from a Python thread). Since we use a different key, this ensures + we don't create a new thread state and deadlock in PyEval_AcquireThread + below. Note we don't save this state with internals.tstate, since we don't + create it we would fail to clear it (its reference count should be > 0). */ + tstate = PyGILState_GetThisThreadState(); + } if (!tstate) { tstate = PyThreadState_New(internals.istate); @@ -1747,10 +1912,7 @@ public: pybind11_fail("scoped_acquire: could not create thread state!"); #endif tstate->gilstate_counter = 0; - #if PY_MAJOR_VERSION < 3 - PyThread_delete_key_value(internals.tstate); - #endif - PyThread_set_key_value(internals.tstate, tstate); + PYBIND11_TLS_REPLACE_VALUE(internals.tstate, tstate); } else { release = detail::get_thread_state_unchecked() != tstate; } @@ -1789,7 +1951,7 @@ public: #endif PyThreadState_Clear(tstate); PyThreadState_DeleteCurrent(); - PyThread_delete_key_value(detail::get_internals().tstate); + PYBIND11_TLS_DELETE_VALUE(detail::get_internals().tstate); release = false; } } @@ -1814,11 +1976,7 @@ public: tstate = PyEval_SaveThread(); if (disassoc) { auto key = internals.tstate; - #if PY_MAJOR_VERSION < 3 - PyThread_delete_key_value(key); - #else - PyThread_set_key_value(key, nullptr); - #endif + PYBIND11_TLS_DELETE_VALUE(key); } } ~gil_scoped_release() { @@ -1827,10 +1985,7 @@ public: PyEval_RestoreThread(tstate); if (disassoc) { auto key = detail::get_internals().tstate; - #if PY_MAJOR_VERSION < 3 - PyThread_delete_key_value(key); - #endif - PyThread_set_key_value(key, tstate); + PYBIND11_TLS_REPLACE_VALUE(key, tstate); } } private: @@ -1857,11 +2012,12 @@ class gil_scoped_release { }; #endif error_already_set::~error_already_set() { - if (type) { + if (m_type) { gil_scoped_acquire gil; - type.release().dec_ref(); - value.release().dec_ref(); - trace.release().dec_ref(); + error_scope scope; + m_type.release().dec_ref(); + m_value.release().dec_ref(); + m_trace.release().dec_ref(); } } @@ -1922,6 +2078,14 @@ inline function get_type_overload(const void *this_ptr, const detail::type_info return overload; } +/** \rst + Try to retrieve a python method by the provided name from the instance pointed to by the this_ptr. + + :this_ptr: The pointer to the object the overload should be retrieved for. This should be the first + non-trampoline class encountered in the inheritance chain. + :name: The name of the overloaded Python method to retrieve. + :return: The Python method by this name from the object or an empty function wrapper. + \endrst */ template <class T> function get_overload(const T *this_ptr, const char *name) { auto tinfo = detail::get_type_info(typeid(T)); return tinfo ? get_type_overload(this_ptr, tinfo, name) : function(); @@ -1940,26 +2104,73 @@ template <class T> function get_overload(const T *this_ptr, const char *name) { } \ } +/** \rst + Macro to populate the virtual method in the trampoline class. This macro tries to look up a method named 'fn' + from the Python side, deals with the :ref:`gil` and necessary argument conversions to call this method and return + the appropriate type. See :ref:`overriding_virtuals` for more information. This macro should be used when the method + name in C is not the same as the method name in Python. For example with `__str__`. + + .. code-block:: cpp + + std::string toString() override { + PYBIND11_OVERLOAD_NAME( + std::string, // Return type (ret_type) + Animal, // Parent class (cname) + toString, // Name of function in C++ (name) + "__str__", // Name of method in Python (fn) + ); + } +\endrst */ #define PYBIND11_OVERLOAD_NAME(ret_type, cname, name, fn, ...) \ - PYBIND11_OVERLOAD_INT(ret_type, cname, name, __VA_ARGS__) \ + PYBIND11_OVERLOAD_INT(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, __VA_ARGS__) \ return cname::fn(__VA_ARGS__) +/** \rst + Macro for pure virtual functions, this function is identical to :c:macro:`PYBIND11_OVERLOAD_NAME`, except that it + throws if no overload can be found. +\endrst */ #define PYBIND11_OVERLOAD_PURE_NAME(ret_type, cname, name, fn, ...) \ - PYBIND11_OVERLOAD_INT(ret_type, cname, name, __VA_ARGS__) \ - pybind11::pybind11_fail("Tried to call pure virtual function \"" #cname "::" name "\""); - + PYBIND11_OVERLOAD_INT(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, __VA_ARGS__) \ + pybind11::pybind11_fail("Tried to call pure virtual function \"" PYBIND11_STRINGIFY(cname) "::" name "\""); + +/** \rst + Macro to populate the virtual method in the trampoline class. This macro tries to look up the method + from the Python side, deals with the :ref:`gil` and necessary argument conversions to call this method and return + the appropriate type. This macro should be used if the method name in C and in Python are identical. + See :ref:`overriding_virtuals` for more information. + + .. code-block:: cpp + + class PyAnimal : public Animal { + public: + // Inherit the constructors + using Animal::Animal; + + // Trampoline (need one for each virtual function) + std::string go(int n_times) override { + PYBIND11_OVERLOAD_PURE( + std::string, // Return type (ret_type) + Animal, // Parent class (cname) + go, // Name of function in C++ (must match Python name) (fn) + n_times // Argument(s) (...) + ); + } + }; +\endrst */ #define PYBIND11_OVERLOAD(ret_type, cname, fn, ...) \ - PYBIND11_OVERLOAD_NAME(ret_type, cname, #fn, fn, __VA_ARGS__) + PYBIND11_OVERLOAD_NAME(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), #fn, fn, __VA_ARGS__) +/** \rst + Macro for pure virtual functions, this function is identical to :c:macro:`PYBIND11_OVERLOAD`, except that it throws + if no overload can be found. +\endrst */ #define PYBIND11_OVERLOAD_PURE(ret_type, cname, fn, ...) \ - PYBIND11_OVERLOAD_PURE_NAME(ret_type, cname, #fn, fn, __VA_ARGS__) + PYBIND11_OVERLOAD_PURE_NAME(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), #fn, fn, __VA_ARGS__) NAMESPACE_END(PYBIND11_NAMESPACE) -#if defined(_MSC_VER) +#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) # pragma warning(pop) -#elif defined(__INTEL_COMPILER) -/* Leave ignored warnings on */ #elif defined(__GNUG__) && !defined(__clang__) # pragma GCC diagnostic pop #endif diff --git a/ext/pybind11/include/pybind11/pytypes.h b/ext/pybind11/include/pybind11/pytypes.h index d7fa17775..96eab9662 100644 --- a/ext/pybind11/include/pybind11/pytypes.h +++ b/ext/pybind11/include/pybind11/pytypes.h @@ -114,6 +114,35 @@ public: bool is(object_api const& other) const { return derived().ptr() == other.derived().ptr(); } /// Equivalent to ``obj is None`` in Python. bool is_none() const { return derived().ptr() == Py_None; } + /// Equivalent to obj == other in Python + bool equal(object_api const &other) const { return rich_compare(other, Py_EQ); } + bool not_equal(object_api const &other) const { return rich_compare(other, Py_NE); } + bool operator<(object_api const &other) const { return rich_compare(other, Py_LT); } + bool operator<=(object_api const &other) const { return rich_compare(other, Py_LE); } + bool operator>(object_api const &other) const { return rich_compare(other, Py_GT); } + bool operator>=(object_api const &other) const { return rich_compare(other, Py_GE); } + + object operator-() const; + object operator~() const; + object operator+(object_api const &other) const; + object operator+=(object_api const &other) const; + object operator-(object_api const &other) const; + object operator-=(object_api const &other) const; + object operator*(object_api const &other) const; + object operator*=(object_api const &other) const; + object operator/(object_api const &other) const; + object operator/=(object_api const &other) const; + object operator|(object_api const &other) const; + object operator|=(object_api const &other) const; + object operator&(object_api const &other) const; + object operator&=(object_api const &other) const; + object operator^(object_api const &other) const; + object operator^=(object_api const &other) const; + object operator<<(object_api const &other) const; + object operator<<=(object_api const &other) const; + object operator>>(object_api const &other) const; + object operator>>=(object_api const &other) const; + PYBIND11_DEPRECATED("Use py::str(obj) instead") pybind11::str str() const; @@ -124,6 +153,9 @@ public: 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; + +private: + bool rich_compare(object_api const &other, int value) const; }; NAMESPACE_END(detail) @@ -292,15 +324,18 @@ public: /// Constructs a new exception from the current Python error indicator, if any. The current /// Python error indicator will be cleared. error_already_set() : std::runtime_error(detail::error_string()) { - PyErr_Fetch(&type.ptr(), &value.ptr(), &trace.ptr()); + PyErr_Fetch(&m_type.ptr(), &m_value.ptr(), &m_trace.ptr()); } + error_already_set(const error_already_set &) = default; + error_already_set(error_already_set &&) = default; + inline ~error_already_set(); /// Give the currently-held error back to Python, if any. If there is currently a Python error /// already set it is cleared first. After this call, the current object no longer stores the /// error variables (but the `.what()` string is still available). - void restore() { PyErr_Restore(type.release().ptr(), value.release().ptr(), trace.release().ptr()); } + void restore() { PyErr_Restore(m_type.release().ptr(), m_value.release().ptr(), m_trace.release().ptr()); } // Does nothing; provided for backwards compatibility. PYBIND11_DEPRECATED("Use of error_already_set.clear() is deprecated") @@ -309,10 +344,14 @@ public: /// Check if the currently trapped error type matches the given Python exception class (or a /// subclass thereof). May also be passed a tuple to search for any exception class matches in /// the given tuple. - bool matches(handle ex) const { return PyErr_GivenExceptionMatches(ex.ptr(), type.ptr()); } + bool matches(handle exc) const { return PyErr_GivenExceptionMatches(m_type.ptr(), exc.ptr()); } + + const object& type() const { return m_type; } + const object& value() const { return m_value; } + const object& trace() const { return m_trace; } private: - object type, value, trace; + object m_type, m_value, m_trace; }; /** \defgroup python_builtins _ @@ -353,6 +392,14 @@ inline bool hasattr(handle obj, const char *name) { return PyObject_HasAttrString(obj.ptr(), name) == 1; } +inline void delattr(handle obj, handle name) { + if (PyObject_DelAttr(obj.ptr(), name.ptr()) != 0) { throw error_already_set(); } +} + +inline void delattr(handle obj, const char *name) { + if (PyObject_DelAttrString(obj.ptr(), name) != 0) { throw error_already_set(); } +} + inline object getattr(handle obj, handle name) { PyObject *result = PyObject_GetAttr(obj.ptr(), name.ptr()); if (!result) { throw error_already_set(); } @@ -424,7 +471,6 @@ object object_or_cast(T &&o); // Match a PyObject*, which we want to convert directly to handle via its converting constructor inline handle object_or_cast(PyObject *ptr) { return ptr; } - template <typename Policy> class accessor : public object_api<accessor<Policy>> { using key_type = typename Policy::key_type; @@ -662,7 +708,7 @@ protected: private: handle obj; - PyObject *key, *value; + PyObject *key = nullptr, *value = nullptr; ssize_t pos = -1; }; NAMESPACE_END(iterator_policies) @@ -690,9 +736,14 @@ inline bool PyIterable_Check(PyObject *obj) { } inline bool PyNone_Check(PyObject *o) { return o == Py_None; } +#if PY_MAJOR_VERSION >= 3 +inline bool PyEllipsis_Check(PyObject *o) { return o == Py_Ellipsis; } +#endif inline bool PyUnicode_Check_Permissive(PyObject *o) { return PyUnicode_Check(o) || PYBIND11_BYTES_CHECK(o); } +inline bool PyStaticMethod_Check(PyObject *o) { return o->ob_type == &PyStaticMethod_Type; } + class kwargs_proxy : public handle { public: explicit kwargs_proxy(handle h) : handle(h) { } @@ -964,6 +1015,14 @@ public: none() : object(Py_None, borrowed_t{}) { } }; +#if PY_MAJOR_VERSION >= 3 +class ellipsis : public object { +public: + PYBIND11_OBJECT(ellipsis, object, detail::PyEllipsis_Check) + ellipsis() : object(Py_Ellipsis, borrowed_t{}) { } +}; +#endif + class bool_ : public object { public: PYBIND11_OBJECT_CVT(bool_, object, PyBool_Check, raw_bool) @@ -1074,6 +1133,13 @@ public: (ssize_t *) stop, (ssize_t *) step, (ssize_t *) slicelength) == 0; } + bool compute(ssize_t length, ssize_t *start, ssize_t *stop, ssize_t *step, + ssize_t *slicelength) const { + return PySlice_GetIndicesEx((PYBIND11_SLICE_OBJECT *) m_ptr, + length, start, + stop, step, + slicelength) == 0; + } }; class capsule : public object { @@ -1136,7 +1202,9 @@ public: if (!m_ptr) pybind11_fail("Could not allocate tuple object!"); } size_t size() const { return (size_t) PyTuple_Size(m_ptr); } + bool empty() const { return size() == 0; } detail::tuple_accessor operator[](size_t index) const { return {*this, index}; } + detail::item_accessor operator[](handle h) const { return object::operator[](h); } detail::tuple_iterator begin() const { return {*this, 0}; } detail::tuple_iterator end() const { return {*this, PyTuple_GET_SIZE(m_ptr)}; } }; @@ -1154,11 +1222,13 @@ public: explicit dict(Args &&...args) : dict(collector(std::forward<Args>(args)...).kwargs()) { } size_t size() const { return (size_t) PyDict_Size(m_ptr); } + bool empty() const { return size() == 0; } 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; } + template <typename T> bool contains(T &&key) const { + return PyDict_Contains(m_ptr, detail::object_or_cast(std::forward<T>(key)).ptr()) == 1; + } private: /// Call the `dict` Python type -- always returns a new reference @@ -1173,7 +1243,9 @@ class sequence : public object { public: PYBIND11_OBJECT_DEFAULT(sequence, object, PySequence_Check) size_t size() const { return (size_t) PySequence_Size(m_ptr); } + bool empty() const { return size() == 0; } detail::sequence_accessor operator[](size_t index) const { return {*this, index}; } + detail::item_accessor operator[](handle h) const { return object::operator[](h); } detail::sequence_iterator begin() const { return {*this, 0}; } detail::sequence_iterator end() const { return {*this, PySequence_Size(m_ptr)}; } }; @@ -1185,12 +1257,18 @@ public: if (!m_ptr) pybind11_fail("Could not allocate list object!"); } size_t size() const { return (size_t) PyList_Size(m_ptr); } + bool empty() const { return size() == 0; } detail::list_accessor operator[](size_t index) const { return {*this, index}; } + detail::item_accessor operator[](handle h) const { return object::operator[](h); } 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()); } + template <typename T> void insert(size_t index, T &&val) const { + PyList_Insert(m_ptr, static_cast<ssize_t>(index), + detail::object_or_cast(std::forward<T>(val)).ptr()); + } }; class args : public tuple { PYBIND11_OBJECT_DEFAULT(args, tuple, PyTuple_Check) }; @@ -1203,10 +1281,14 @@ public: if (!m_ptr) pybind11_fail("Could not allocate set object!"); } size_t size() const { return (size_t) PySet_Size(m_ptr); } + bool empty() const { return size() == 0; } template <typename T> bool add(T &&val) const { return PySet_Add(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr()) == 0; } void clear() const { PySet_Clear(m_ptr); } + template <typename T> bool contains(T &&val) const { + return PySet_Contains(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr()) == 1; + } }; class function : public object { @@ -1221,11 +1303,16 @@ public: bool is_cpp_function() const { return (bool) cpp_function(); } }; +class staticmethod : public object { +public: + PYBIND11_OBJECT_CVT(staticmethod, object, detail::PyStaticMethod_Check, PyStaticMethod_New) +}; + class buffer : public object { public: PYBIND11_OBJECT_DEFAULT(buffer, object, PyObject_CheckBuffer) - buffer_info request(bool writable = false) { + buffer_info request(bool writable = false) const { int flags = PyBUF_STRIDES | PyBUF_FORMAT; if (writable) flags |= PyBUF_WRITABLE; Py_buffer *view = new Py_buffer(); @@ -1279,6 +1366,21 @@ inline size_t len(handle h) { return (size_t) result; } +inline size_t len_hint(handle h) { +#if PY_VERSION_HEX >= 0x03040000 + ssize_t result = PyObject_LengthHint(h.ptr(), 0); +#else + ssize_t result = PyObject_Length(h.ptr()); +#endif + if (result < 0) { + // Sometimes a length can't be determined at all (eg generators) + // In which case simply return 0 + PyErr_Clear(); + return 0; + } + return (size_t) result; +} + inline str repr(handle h) { PyObject *str_value = PyObject_Repr(h.ptr()); if (!str_value) throw error_already_set(); @@ -1328,5 +1430,55 @@ str_attr_accessor object_api<D>::doc() const { return attr("__doc__"); } template <typename D> handle object_api<D>::get_type() const { return (PyObject *) Py_TYPE(derived().ptr()); } +template <typename D> +bool object_api<D>::rich_compare(object_api const &other, int value) const { + int rv = PyObject_RichCompareBool(derived().ptr(), other.derived().ptr(), value); + if (rv == -1) + throw error_already_set(); + return rv == 1; +} + +#define PYBIND11_MATH_OPERATOR_UNARY(op, fn) \ + template <typename D> object object_api<D>::op() const { \ + object result = reinterpret_steal<object>(fn(derived().ptr())); \ + if (!result.ptr()) \ + throw error_already_set(); \ + return result; \ + } + +#define PYBIND11_MATH_OPERATOR_BINARY(op, fn) \ + template <typename D> \ + object object_api<D>::op(object_api const &other) const { \ + object result = reinterpret_steal<object>( \ + fn(derived().ptr(), other.derived().ptr())); \ + if (!result.ptr()) \ + throw error_already_set(); \ + return result; \ + } + +PYBIND11_MATH_OPERATOR_UNARY (operator~, PyNumber_Invert) +PYBIND11_MATH_OPERATOR_UNARY (operator-, PyNumber_Negative) +PYBIND11_MATH_OPERATOR_BINARY(operator+, PyNumber_Add) +PYBIND11_MATH_OPERATOR_BINARY(operator+=, PyNumber_InPlaceAdd) +PYBIND11_MATH_OPERATOR_BINARY(operator-, PyNumber_Subtract) +PYBIND11_MATH_OPERATOR_BINARY(operator-=, PyNumber_InPlaceSubtract) +PYBIND11_MATH_OPERATOR_BINARY(operator*, PyNumber_Multiply) +PYBIND11_MATH_OPERATOR_BINARY(operator*=, PyNumber_InPlaceMultiply) +PYBIND11_MATH_OPERATOR_BINARY(operator/, PyNumber_TrueDivide) +PYBIND11_MATH_OPERATOR_BINARY(operator/=, PyNumber_InPlaceTrueDivide) +PYBIND11_MATH_OPERATOR_BINARY(operator|, PyNumber_Or) +PYBIND11_MATH_OPERATOR_BINARY(operator|=, PyNumber_InPlaceOr) +PYBIND11_MATH_OPERATOR_BINARY(operator&, PyNumber_And) +PYBIND11_MATH_OPERATOR_BINARY(operator&=, PyNumber_InPlaceAnd) +PYBIND11_MATH_OPERATOR_BINARY(operator^, PyNumber_Xor) +PYBIND11_MATH_OPERATOR_BINARY(operator^=, PyNumber_InPlaceXor) +PYBIND11_MATH_OPERATOR_BINARY(operator<<, PyNumber_Lshift) +PYBIND11_MATH_OPERATOR_BINARY(operator<<=, PyNumber_InPlaceLshift) +PYBIND11_MATH_OPERATOR_BINARY(operator>>, PyNumber_Rshift) +PYBIND11_MATH_OPERATOR_BINARY(operator>>=, PyNumber_InPlaceRshift) + +#undef PYBIND11_MATH_OPERATOR_UNARY +#undef PYBIND11_MATH_OPERATOR_BINARY + NAMESPACE_END(detail) NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/ext/pybind11/include/pybind11/stl.h b/ext/pybind11/include/pybind11/stl.h index 44abb8c6c..f9723ae06 100644 --- a/ext/pybind11/include/pybind11/stl.h +++ b/ext/pybind11/include/pybind11/stl.h @@ -16,6 +16,7 @@ #include <unordered_map> #include <iostream> #include <list> +#include <deque> #include <valarray> #if defined(_MSC_VER) @@ -30,7 +31,8 @@ # define PYBIND11_HAS_OPTIONAL 1 # endif // std::experimental::optional (but not allowed in c++11 mode) -# if defined(PYBIND11_CPP14) && __has_include(<experimental/optional>) +# if defined(PYBIND11_CPP14) && (__has_include(<experimental/optional>) && \ + !__has_include(<optional>)) # include <experimental/optional> # define PYBIND11_HAS_EXP_OPTIONAL 1 # endif @@ -82,6 +84,8 @@ template <typename Type, typename Key> struct set_caster { template <typename T> static handle cast(T &&src, return_value_policy policy, handle parent) { + if (!std::is_lvalue_reference<T>::value) + policy = return_value_policy_override<Key>::policy(policy); pybind11::set s; for (auto &&value : src) { auto value_ = reinterpret_steal<object>(key_conv::cast(forward_like<T>(value), policy, parent)); @@ -91,7 +95,7 @@ template <typename Type, typename Key> struct set_caster { return s.release(); } - PYBIND11_TYPE_CASTER(type, _("Set[") + key_conv::name() + _("]")); + PYBIND11_TYPE_CASTER(type, _("Set[") + key_conv::name + _("]")); }; template <typename Type, typename Key, typename Value> struct map_caster { @@ -117,9 +121,15 @@ template <typename Type, typename Key, typename Value> struct map_caster { template <typename T> static handle cast(T &&src, return_value_policy policy, handle parent) { dict d; + return_value_policy policy_key = policy; + return_value_policy policy_value = policy; + if (!std::is_lvalue_reference<T>::value) { + policy_key = return_value_policy_override<Key>::policy(policy_key); + policy_value = return_value_policy_override<Value>::policy(policy_value); + } for (auto &&kv : src) { - auto key = reinterpret_steal<object>(key_conv::cast(forward_like<T>(kv.first), policy, parent)); - auto value = reinterpret_steal<object>(value_conv::cast(forward_like<T>(kv.second), policy, parent)); + auto key = reinterpret_steal<object>(key_conv::cast(forward_like<T>(kv.first), policy_key, parent)); + auto value = reinterpret_steal<object>(value_conv::cast(forward_like<T>(kv.second), policy_value, parent)); if (!key || !value) return handle(); d[key] = value; @@ -127,14 +137,14 @@ template <typename Type, typename Key, typename Value> struct map_caster { return d.release(); } - PYBIND11_TYPE_CASTER(Type, _("Dict[") + key_conv::name() + _(", ") + value_conv::name() + _("]")); + PYBIND11_TYPE_CASTER(Type, _("Dict[") + key_conv::name + _(", ") + value_conv::name + _("]")); }; template <typename Type, typename Value> struct list_caster { using value_conv = make_caster<Value>; bool load(handle src, bool convert) { - if (!isinstance<sequence>(src)) + if (!isinstance<sequence>(src) || isinstance<str>(src)) return false; auto s = reinterpret_borrow<sequence>(src); value.clear(); @@ -157,6 +167,8 @@ private: public: template <typename T> static handle cast(T &&src, return_value_policy policy, handle parent) { + if (!std::is_lvalue_reference<T>::value) + policy = return_value_policy_override<Value>::policy(policy); list l(src.size()); size_t index = 0; for (auto &&value : src) { @@ -168,12 +180,15 @@ public: return l.release(); } - PYBIND11_TYPE_CASTER(Type, _("List[") + value_conv::name() + _("]")); + PYBIND11_TYPE_CASTER(Type, _("List[") + value_conv::name + _("]")); }; template <typename Type, typename Alloc> struct type_caster<std::vector<Type, Alloc>> : list_caster<std::vector<Type, Alloc>, Type> { }; +template <typename Type, typename Alloc> struct type_caster<std::deque<Type, Alloc>> + : list_caster<std::deque<Type, Alloc>, Type> { }; + template <typename Type, typename Alloc> struct type_caster<std::list<Type, Alloc>> : list_caster<std::list<Type, Alloc>, Type> { }; @@ -194,9 +209,9 @@ private: public: bool load(handle src, bool convert) { - if (!isinstance<list>(src)) + if (!isinstance<sequence>(src)) return false; - auto l = reinterpret_borrow<list>(src); + auto l = reinterpret_borrow<sequence>(src); if (!require_size(l.size())) return false; size_t ctr = 0; @@ -222,7 +237,7 @@ public: return l.release(); } - PYBIND11_TYPE_CASTER(ArrayType, _("List[") + value_conv::name() + _<Resizable>(_(""), _("[") + _<Size>() + _("]")) + _("]")); + PYBIND11_TYPE_CASTER(ArrayType, _("List[") + value_conv::name + _<Resizable>(_(""), _("[") + _<Size>() + _("]")) + _("]")); }; template <typename Type, size_t Size> struct type_caster<std::array<Type, Size>> @@ -251,6 +266,7 @@ template<typename T> struct optional_caster { static handle cast(T_ &&src, return_value_policy policy, handle parent) { if (!src) return none().inc_ref(); + policy = return_value_policy_override<typename T::value_type>::policy(policy); return value_conv::cast(*std::forward<T_>(src), policy, parent); } @@ -268,7 +284,7 @@ template<typename T> struct optional_caster { return true; } - PYBIND11_TYPE_CASTER(T, _("Optional[") + value_conv::name() + _("]")); + PYBIND11_TYPE_CASTER(T, _("Optional[") + value_conv::name + _("]")); }; #ifdef PYBIND11_HAS_OPTIONAL @@ -348,13 +364,14 @@ struct variant_caster<V<Ts...>> { } using Type = V<Ts...>; - PYBIND11_TYPE_CASTER(Type, _("Union[") + detail::concat(make_caster<Ts>::name()...) + _("]")); + PYBIND11_TYPE_CASTER(Type, _("Union[") + detail::concat(make_caster<Ts>::name...) + _("]")); }; #ifdef PYBIND11_HAS_VARIANT template <typename... Ts> struct type_caster<std::variant<Ts...>> : variant_caster<std::variant<Ts...>> { }; #endif + NAMESPACE_END(detail) inline std::ostream &operator<<(std::ostream &os, const handle &obj) { diff --git a/ext/pybind11/include/pybind11/stl_bind.h b/ext/pybind11/include/pybind11/stl_bind.h index 7ef687878..d3adaed3a 100644 --- a/ext/pybind11/include/pybind11/stl_bind.h +++ b/ext/pybind11/include/pybind11/stl_bind.h @@ -115,6 +115,14 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t using SizeType = typename Vector::size_type; using DiffType = typename Vector::difference_type; + auto wrap_i = [](DiffType i, SizeType n) { + if (i < 0) + i += n; + if (i < 0 || (SizeType)i >= n) + throw index_error(); + return i; + }; + cl.def("append", [](Vector &v, const T &value) { v.push_back(value); }, arg("x"), @@ -122,7 +130,7 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t cl.def(init([](iterable it) { auto v = std::unique_ptr<Vector>(new Vector()); - v->reserve(len(it)); + v->reserve(len_hint(it)); for (handle h : it) v->push_back(h.cast<T>()); return v.release(); @@ -136,11 +144,36 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t "Extend the list by appending all the items in the given list" ); + cl.def("extend", + [](Vector &v, iterable it) { + const size_t old_size = v.size(); + v.reserve(old_size + len_hint(it)); + try { + for (handle h : it) { + v.push_back(h.cast<T>()); + } + } catch (const cast_error &) { + v.erase(v.begin() + static_cast<typename Vector::difference_type>(old_size), v.end()); + try { + v.shrink_to_fit(); + } catch (const std::exception &) { + // Do nothing + } + throw; + } + }, + arg("L"), + "Extend the list by appending all the items in the given list" + ); + cl.def("insert", - [](Vector &v, SizeType i, const T &x) { - if (i > v.size()) + [](Vector &v, DiffType i, const T &x) { + // Can't use wrap_i; i == v.size() is OK + if (i < 0) + i += v.size(); + if (i < 0 || (SizeType)i > v.size()) throw index_error(); - v.insert(v.begin() + (DiffType) i, x); + v.insert(v.begin() + i, x); }, arg("i") , arg("x"), "Insert an item at a given position." @@ -158,11 +191,10 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t ); cl.def("pop", - [](Vector &v, SizeType i) { - if (i >= v.size()) - throw index_error(); - T t = v[i]; - v.erase(v.begin() + (DiffType) i); + [wrap_i](Vector &v, DiffType i) { + i = wrap_i(i, v.size()); + T t = v[(SizeType) i]; + v.erase(v.begin() + i); return t; }, arg("i"), @@ -170,10 +202,9 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t ); cl.def("__setitem__", - [](Vector &v, SizeType i, const T &t) { - if (i >= v.size()) - throw index_error(); - v[i] = t; + [wrap_i](Vector &v, DiffType i, const T &t) { + i = wrap_i(i, v.size()); + v[(SizeType)i] = t; } ); @@ -216,10 +247,9 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t ); cl.def("__delitem__", - [](Vector &v, SizeType i) { - if (i >= v.size()) - throw index_error(); - v.erase(v.begin() + DiffType(i)); + [wrap_i](Vector &v, DiffType i) { + i = wrap_i(i, v.size()); + v.erase(v.begin() + i); }, "Delete the list elements at index ``i``" ); @@ -255,13 +285,21 @@ template <typename Vector, typename Class_> void vector_accessor(enable_if_t<!vector_needs_copy<Vector>::value, Class_> &cl) { using T = typename Vector::value_type; using SizeType = typename Vector::size_type; + using DiffType = typename Vector::difference_type; using ItType = typename Vector::iterator; + auto wrap_i = [](DiffType i, SizeType n) { + if (i < 0) + i += n; + if (i < 0 || (SizeType)i >= n) + throw index_error(); + return i; + }; + cl.def("__getitem__", - [](Vector &v, SizeType i) -> T & { - if (i >= v.size()) - throw index_error(); - return v[i]; + [wrap_i](Vector &v, DiffType i) -> T & { + i = wrap_i(i, v.size()); + return v[(SizeType)i]; }, return_value_policy::reference_internal // ref + keepalive ); @@ -281,12 +319,15 @@ template <typename Vector, typename Class_> void vector_accessor(enable_if_t<vector_needs_copy<Vector>::value, Class_> &cl) { using T = typename Vector::value_type; using SizeType = typename Vector::size_type; + using DiffType = typename Vector::difference_type; using ItType = typename Vector::iterator; cl.def("__getitem__", - [](const Vector &v, SizeType i) -> T { - if (i >= v.size()) + [](const Vector &v, DiffType i) -> T { + if (i < 0 && (i += v.size()) < 0) throw index_error(); - return v[i]; + if ((SizeType)i >= v.size()) + throw index_error(); + return v[(SizeType)i]; } ); @@ -579,6 +620,15 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args&&. return_value_policy::reference_internal // ref + keepalive ); + cl.def("__contains__", + [](Map &m, const KeyType &k) -> bool { + auto it = m.find(k); + if (it == m.end()) + return false; + return true; + } + ); + // Assignment provided only if the type is copyable detail::map_assignment<Map, Class_>(cl); @@ -587,7 +637,7 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args&&. auto it = m.find(k); if (it == m.end()) throw key_error(); - return m.erase(it); + m.erase(it); } ); |