diff --git a/dune/pybindxi/attr.h b/dune/pybindxi/attr.h index ae5df633e0d174b3b590f0249058bbfbdc4eaf4b..378b7a804495def3b89e23bae88f11a119848567 100644 --- a/dune/pybindxi/attr.h +++ b/dune/pybindxi/attr.h @@ -1,4 +1,3 @@ -#pragma GCC system_header /* pybind11/attr.h: Infrastructure for processing custom type and function attributes diff --git a/dune/pybindxi/buffer_info.h b/dune/pybindxi/buffer_info.h index 925133c379dfd3f2af67995424db9f83e5aebbc4..cd436083c3c8eb66dbff3e2979ad7eae75e194f5 100644 --- a/dune/pybindxi/buffer_info.h +++ b/dune/pybindxi/buffer_info.h @@ -1,4 +1,3 @@ -#pragma GCC system_header /* pybind11/buffer_info.h: Python buffer object interface @@ -23,7 +22,8 @@ struct buffer_info std::string format; // For homogeneous buffers, this should be set to format_descriptor<T>::format() ssize_t ndim = 0; // Number of dimensions std::vector<ssize_t> shape; // Shape of the tensor (1 entry per dimension) - std::vector<ssize_t> strides; // Number of entries between adjacent entries (for each per dimension) + std::vector<ssize_t> strides; // Number of bytes between adjacent entries (for each per dimension) + bool readonly = false; // flag to indicate if the underlying storage may be written to buffer_info() {} @@ -32,7 +32,8 @@ struct buffer_info const std::string& format, ssize_t ndim, detail::any_container<ssize_t> shape_in, - detail::any_container<ssize_t> strides_in) + detail::any_container<ssize_t> strides_in, + bool readonly = false) : ptr(ptr) , itemsize(itemsize) , size(1) @@ -40,6 +41,7 @@ struct buffer_info , ndim(ndim) , shape(std::move(shape_in)) , strides(std::move(strides_in)) + , readonly(readonly) { if (ndim != (ssize_t)shape.size() || ndim != (ssize_t)strides.size()) pybind11_fail("buffer_info: ndim doesn't match shape and/or strides length"); @@ -48,23 +50,32 @@ struct buffer_info } template <typename T> - buffer_info(T* ptr, detail::any_container<ssize_t> shape_in, detail::any_container<ssize_t> strides_in) + buffer_info(T* ptr, + detail::any_container<ssize_t> shape_in, + detail::any_container<ssize_t> strides_in, + bool readonly = false) : buffer_info(private_ctr_tag(), ptr, sizeof(T), format_descriptor<T>::format(), static_cast<ssize_t>(shape_in->size()), std::move(shape_in), - std::move(strides_in)) + std::move(strides_in), + readonly) + {} + + buffer_info(void* ptr, ssize_t itemsize, const std::string& format, ssize_t size, bool readonly = false) + : buffer_info(ptr, itemsize, format, 1, {size}, {itemsize}, readonly) {} - buffer_info(void* ptr, ssize_t itemsize, const std::string& format, ssize_t size) - : buffer_info(ptr, itemsize, format, 1, {size}, {itemsize}) + template <typename T> + buffer_info(T* ptr, ssize_t size, bool readonly = false) + : buffer_info(ptr, sizeof(T), format_descriptor<T>::format(), size, readonly) {} template <typename T> - buffer_info(T* ptr, ssize_t size) - : buffer_info(ptr, sizeof(T), format_descriptor<T>::format(), size) + buffer_info(const T* ptr, ssize_t size, bool readonly = true) + : buffer_info(const_cast<T*>(ptr), sizeof(T), format_descriptor<T>::format(), size, readonly) {} explicit buffer_info(Py_buffer* view, bool ownview = true) @@ -73,7 +84,8 @@ struct buffer_info view->format, view->ndim, {view->shape, view->shape + view->ndim}, - {view->strides, view->strides + view->ndim}) + {view->strides, view->strides + view->ndim}, + view->readonly) { this->view = view; this->ownview = ownview; @@ -98,6 +110,7 @@ struct buffer_info strides = std::move(rhs.strides); std::swap(view, rhs.view); std::swap(ownview, rhs.ownview); + readonly = rhs.readonly; return *this; } @@ -119,8 +132,9 @@ private: const std::string& format, ssize_t ndim, detail::any_container<ssize_t>&& shape_in, - detail::any_container<ssize_t>&& strides_in) - : buffer_info(ptr, itemsize, format, ndim, std::move(shape_in), std::move(strides_in)) + detail::any_container<ssize_t>&& strides_in, + bool readonly) + : buffer_info(ptr, itemsize, format, ndim, std::move(shape_in), std::move(strides_in), readonly) {} Py_buffer* view = nullptr; diff --git a/dune/pybindxi/cast.h b/dune/pybindxi/cast.h index e09413c51a5dbcf171220bb9f3cf36f0cc020880..641ed21068138b04a32b125ad3cb46f859b93a11 100644 --- a/dune/pybindxi/cast.h +++ b/dune/pybindxi/cast.h @@ -1,4 +1,3 @@ -#pragma GCC system_header /* pybind11/cast.h: Partial template specializations to cast between C++ and Python types @@ -33,6 +32,10 @@ # include <string_view> #endif +#if defined(__cpp_lib_char8_t) && __cpp_lib_char8_t >= 201811L +# define PYBIND11_HAS_U8STRING +#endif + NAMESPACE_BEGIN(PYBIND11_NAMESPACE) NAMESPACE_BEGIN(detail) @@ -610,9 +613,16 @@ public: case return_value_policy::copy: if (copy_constructor) valueptr = copy_constructor(src); - else - throw cast_error("return_value_policy = copy, but the " - "object is non-copyable!"); + else { +#if defined(NDEBUG) + throw cast_error("return_value_policy = copy, but type is " + "non-copyable! (compile in debug mode for details)"); +#else + std::string type_name(tinfo->cpptype->name()); + detail::clean_type_id(type_name); + throw cast_error("return_value_policy = copy, but type " + type_name + " is non-copyable!"); +#endif + } wrapper->owned = true; break; @@ -621,9 +631,17 @@ public: valueptr = move_constructor(src); else if (copy_constructor) valueptr = copy_constructor(src); - else - throw cast_error("return_value_policy = move, but the " - "object is neither movable nor copyable!"); + else { +#if defined(NDEBUG) + throw cast_error("return_value_policy = move, but type is neither " + "movable nor copyable! " + "(compile in debug mode for details)"); +#else + std::string type_name(tinfo->cpptype->name()); + detail::clean_type_id(type_name); + throw cast_error("return_value_policy = move, but type " + type_name + " is neither movable nor copyable!"); +#endif + } wrapper->owned = true; break; @@ -652,9 +670,9 @@ public: if (type->operator_new) { vptr = type->operator_new(type->type_size); } else { -#if defined(PYBIND11_CPP17) +#if defined(__cpp_aligned_new) && (!defined(_MSC_VER) || _MSC_VER >= 1912) if (type->type_align > __STDCPP_DEFAULT_NEW_ALIGNMENT__) - vptr = ::operator new(type->type_size, (std::align_val_t)type->type_align); + vptr = ::operator new(type->type_size, std::align_val_t(type->type_align)); else #endif vptr = ::operator new(type->type_size); @@ -863,17 +881,33 @@ 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>>::value>> + 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) -// Likewise for std::pair before C++17 (which mandates that the copy constructor not exist when the -// two types aren't themselves copy constructible). +// Likewise for std::pair +// (after C++17 it is mandatory that the copy constructor not exist when the two types aren't themselves +// copy constructible, but this can not be relied upon when T1 or T2 are themselves containers). template <typename T1, typename T2> struct is_copy_constructible<std::pair<T1, T2>> : all_of<is_copy_constructible<T1>, is_copy_constructible<T2>> {}; -#endif + +// The same problems arise with std::is_copy_assignable, so we use the same workaround. +template <typename T, typename SFINAE = void> +struct is_copy_assignable : std::is_copy_assignable<T> +{}; +template <typename Container> +struct is_copy_assignable< + Container, + enable_if_t<all_of<std::is_copy_assignable<Container>, + std::is_same<typename Container::value_type&, typename Container::reference>>::value>> + : is_copy_assignable<typename Container::value_type> +{}; +template <typename T1, typename T2> +struct is_copy_assignable<std::pair<T1, T2>> : all_of<is_copy_assignable<T1>, is_copy_assignable<T2>> +{}; NAMESPACE_END(detail) @@ -1110,6 +1144,9 @@ public: template <typename CharT> using is_std_char_type = any_of<std::is_same<CharT, char>, /* std::string */ +#if defined(PYBIND11_HAS_U8STRING) + std::is_same<CharT, char8_t>, /* std::u8string */ +#endif std::is_same<CharT, char16_t>, /* std::u16string */ std::is_same<CharT, char32_t>, /* std::u32string */ std::is_same<CharT, wchar_t> /* std::wstring */ @@ -1145,10 +1182,12 @@ 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) @@ -1332,6 +1371,8 @@ public: if (res == 0 || res == 1) { value = (bool)res; return true; + } else { + PyErr_Clear(); } } return false; @@ -1352,6 +1393,9 @@ struct string_caster // Simplify life by being able to assume standard char sizes (the standard only guarantees // minimums, but Python requires exact sizes) static_assert(!std::is_same<CharT, char>::value || sizeof(CharT) == 1, "Unsupported char size != 1"); +#if defined(PYBIND11_HAS_U8STRING) + static_assert(!std::is_same<CharT, char8_t>::value || sizeof(CharT) == 1, "Unsupported char8_t size != 1"); +#endif static_assert(!std::is_same<CharT, char16_t>::value || sizeof(CharT) == 2, "Unsupported char16_t size != 2"); static_assert(!std::is_same<CharT, char32_t>::value || sizeof(CharT) == 4, "Unsupported char32_t size != 4"); // wchar_t can be either 16 bits (Windows) or 32 (everywhere else) @@ -1371,7 +1415,7 @@ struct string_caster #if PY_MAJOR_VERSION >= 3 return load_bytes(load_src); #else - if (sizeof(CharT) == 1) { + if (std::is_same<CharT, char>::value) { return load_bytes(load_src); } @@ -1442,7 +1486,7 @@ private: // without any encoding/decoding attempt). For other C++ char sizes this is a no-op. // which supports loading a unicode from a str, doesn't take this path. template <typename C = CharT> - bool load_bytes(enable_if_t<sizeof(C) == 1, handle> src) + bool load_bytes(enable_if_t<std::is_same<C, char>::value, handle> src) { if (PYBIND11_BYTES_CHECK(src.ptr())) { // We were passed a Python 3 raw bytes; accept it into a std::string or char* @@ -1458,7 +1502,7 @@ private: } template <typename C = CharT> - bool load_bytes(enable_if_t<sizeof(C) != 1, handle>) + bool load_bytes(enable_if_t<!std::is_same<C, char>::value, handle>) { return false; } @@ -1637,9 +1681,14 @@ protected: template <size_t... Is> bool load_impl(const sequence& seq, bool convert, index_sequence<Is...>) { +#ifdef __cpp_fold_expressions + if ((... || !std::get<Is>(subcasters).load(seq[Is], convert))) + return false; +#else for (bool r : {std::get<Is>(subcasters).load(seq[Is], convert)...}) if (!r) return false; +#endif return true; } @@ -2352,14 +2401,19 @@ private: template <size_t... Is> bool load_impl_sequence(function_call& call, index_sequence<Is...>) { +#ifdef __cpp_fold_expressions + if ((... || !std::get<Is>(argcasters).load(call.args[Is], call.args_convert[Is]))) + return false; +#else for (bool r : {std::get<Is>(argcasters).load(call.args[Is], call.args_convert[Is])...}) if (!r) return false; +#endif return true; } template <typename Return, typename Func, size_t... Is, typename Guard> - Return call_impl(Func&& f, index_sequence<Is...>, Guard&&) + Return call_impl(Func&& f, index_sequence<Is...>, Guard&&) && { return std::forward<Func>(f)(cast_op<Args>(std::move(std::get<Is>(argcasters)))...); } diff --git a/dune/pybindxi/chrono.h b/dune/pybindxi/chrono.h index df72db32f6c1dfac5f708bf794857de2f9261aa7..9744d171cd1f25bb63c983b4faf43a81d15aa458 100644 --- a/dune/pybindxi/chrono.h +++ b/dune/pybindxi/chrono.h @@ -1,4 +1,3 @@ -#pragma GCC system_header /* pybind11/chrono.h: Transparent conversion between std::chrono and python's datetime @@ -125,8 +124,11 @@ public: 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()); @@ -134,11 +136,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, diff --git a/dune/pybindxi/common.h b/dune/pybindxi/common.h index 3dfa83604d10f8cbbc7f220fec47d2986fac3df9..6c8a4f1e88e493ee08d24e668639c8d495fd49b1 100644 --- a/dune/pybindxi/common.h +++ b/dune/pybindxi/common.h @@ -1,3 +1,2 @@ -#pragma GCC system_header #include "detail/common.h" #warning "Including 'common.h' is deprecated. It will be removed in v3.0. Use 'pybind11.h'." diff --git a/dune/pybindxi/complex.h b/dune/pybindxi/complex.h index 97e839be39a1066adf07a995bd212ed8763995fb..cd496ccfd8262361bae0d14b9544ba85766f82bd 100644 --- a/dune/pybindxi/complex.h +++ b/dune/pybindxi/complex.h @@ -1,4 +1,3 @@ -#pragma GCC system_header /* pybind11/complex.h: Complex number support diff --git a/dune/pybindxi/detail/class.h b/dune/pybindxi/detail/class.h index 2f2945b5f3ce8b3d8488382546a1541cf86eeecf..49c0921753d9c9bc2c52554b3d6537adaa54055a 100644 --- a/dune/pybindxi/detail/class.h +++ b/dune/pybindxi/detail/class.h @@ -1,4 +1,3 @@ -#pragma GCC system_header /* pybind11/detail/class.h: Python C API implementation details for py::class_ @@ -374,6 +373,7 @@ extern "C" inline void pybind11_object_dealloc(PyObject* self) auto type = Py_TYPE(self); type->tp_free(self); +#if PY_VERSION_HEX < 0x03080000 // `type->tp_dealloc != pybind11_object_dealloc` means that we're being called // as part of a derived type's dealloc, in which case we're not allowed to decref // the type here. For cross-module compatibility, we shouldn't compare directly @@ -381,6 +381,11 @@ extern "C" inline void pybind11_object_dealloc(PyObject* self) auto pybind11_object_type = (PyTypeObject*)get_internals().instance_base; if (type->tp_dealloc == pybind11_object_type->tp_dealloc) Py_DECREF(type); +#else + // This was not needed before Python 3.8 (Python issue 35810) + // https://github.com/pybind/pybind11/issues/1946 + Py_DECREF(type); +#endif } /** Create the type which can be used as a common base for all classes. This is @@ -515,6 +520,13 @@ extern "C" inline int pybind11_getbuffer(PyObject* obj, Py_buffer* view, int fla view->len = view->itemsize; for (auto s : info->shape) view->len *= s; + view->readonly = info->readonly; + if ((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE && info->readonly) { + if (view) + view->obj = nullptr; + PyErr_SetString(PyExc_BufferError, "Writable buffer requested for readonly storage"); + return -1; + } if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) view->format = const_cast<char*>(info->format.c_str()); if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) { @@ -617,6 +629,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; diff --git a/dune/pybindxi/detail/common.h b/dune/pybindxi/detail/common.h index ed9476d97bb2372026bbbfcad2a5d6211d2c67c5..5a4c8514ef0eb42ace0b1ce8ef2559f8705123d0 100644 --- a/dune/pybindxi/detail/common.h +++ b/dune/pybindxi/detail/common.h @@ -1,4 +1,3 @@ -#pragma GCC system_header /* pybind11/detail/common.h -- Basic macros @@ -94,8 +93,8 @@ #endif #define PYBIND11_VERSION_MAJOR 2 -#define PYBIND11_VERSION_MINOR 3 -#define PYBIND11_VERSION_PATCH dev1 +#define PYBIND11_VERSION_MINOR 5 +#define PYBIND11_VERSION_PATCH 0 /// Include Python header, disable linking to pythonX_d.lib on Windows in debug mode #if defined(_MSC_VER) @@ -104,7 +103,7 @@ # endif # pragma warning(push) # pragma warning(disable : 4510 4610 4512 4005) -# if defined(_DEBUG) +# if defined(_DEBUG) && !defined(Py_DEBUG) # define PYBIND11_DEBUG_MARKER # undef _DEBUG # endif @@ -114,10 +113,9 @@ #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 - +/* Python #defines overrides on all sorts of core functions, which + tends to weak havok in C++ codebases that expect these to work + like regular functions (potentially with several overloads) */ #if defined(isalnum) # undef isalnum # undef isalpha @@ -128,6 +126,10 @@ # undef toupper #endif +#if defined(copysign) +# undef copysign +#endif + #if defined(_MSC_VER) # if defined(PYBIND11_DEBUG_MARKER) # define _DEBUG @@ -169,7 +171,10 @@ # define PYBIND11_STR_TYPE ::pybind11::str # define PYBIND11_BOOL_ATTR "__bool__" # define PYBIND11_NB_BOOL(ptr) ((ptr)->nb_bool) -# define PYBIND11_PLUGIN_IMPL(name) extern "C" PYBIND11_EXPORT PyObject* PyInit_##name() +// 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 # define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyMethod_New(ptr, nullptr, class_) @@ -192,8 +197,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(); \ @@ -216,6 +223,7 @@ extern "C" #define PYBIND11_STRINGIFY(x) #x #define PYBIND11_TOSTRING(x) PYBIND11_STRINGIFY(x) #define PYBIND11_CONCAT(first, second) first##second +#define PYBIND11_ENSURE_INTERNALS_READY pybind11::detail::get_internals(); #define PYBIND11_CHECK_PYTHON_VERSION \ { \ @@ -265,6 +273,7 @@ extern "C" PYBIND11_PLUGIN_IMPL(name) \ { \ PYBIND11_CHECK_PYTHON_VERSION \ + PYBIND11_ENSURE_INTERNALS_READY \ try { \ return pybind11_init(); \ } \ @@ -294,6 +303,7 @@ extern "C" PYBIND11_PLUGIN_IMPL(name) \ { \ PYBIND11_CHECK_PYTHON_VERSION \ + PYBIND11_ENSURE_INTERNALS_READY \ auto m = pybind11::module(PYBIND11_TOSTRING(name)); \ try { \ PYBIND11_CONCAT(pybind11_init_, name)(m); \ @@ -840,6 +850,8 @@ 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(import_error, PyExc_ImportError) 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 @@ -922,10 +934,6 @@ struct nodelete {} }; -// 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 @@ -952,19 +960,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 { diff --git a/dune/pybindxi/detail/descr.h b/dune/pybindxi/detail/descr.h index e6b65fd0496bc1cbc3edf8f0b53060b5e0acfc1b..630e937a23363366f0e989470d291e220611ddee 100644 --- a/dune/pybindxi/detail/descr.h +++ b/dune/pybindxi/detail/descr.h @@ -1,4 +1,3 @@ -#pragma GCC system_header /* pybind11/detail/descr.h: Helper type for concatenating type signatures at compile time diff --git a/dune/pybindxi/detail/init.h b/dune/pybindxi/detail/init.h index b20657d5823ffb55d22990e934542433e60a4550..fda1b48912537159ebd53171b5cf646f1e8ee7e9 100644 --- a/dune/pybindxi/detail/init.h +++ b/dune/pybindxi/detail/init.h @@ -1,4 +1,3 @@ -#pragma GCC system_header /* pybind11/detail/init.h: init factory function implementation and support code. diff --git a/dune/pybindxi/detail/internals.h b/dune/pybindxi/detail/internals.h index 7ddaf73f2161c21682d3b5bc004f33022ac527a9..3712da057723bb07358234f5a5e2b8f0a3404d09 100644 --- a/dune/pybindxi/detail/internals.h +++ b/dune/pybindxi/detail/internals.h @@ -1,4 +1,3 @@ -#pragma GCC system_header /* pybind11/detail/internals.h: Internal data structure and related functions @@ -26,6 +25,7 @@ inline PyObject* make_object_base_type(PyTypeObject* metaclass); # 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) +# define PYBIND11_TLS_FREE(key) PyThread_tss_free(key) #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 @@ -41,6 +41,7 @@ inline PyObject* make_object_base_type(PyTypeObject* metaclass); # 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 +# define PYBIND11_TLS_FREE(key) (void)key #endif // Python loads modules by default with dlopen with the RTLD_LOCAL flag; under libc++ and possibly @@ -117,6 +118,17 @@ struct internals #if defined(WITH_THREAD) PYBIND11_TLS_KEY_INIT(tstate); PyInterpreterState* istate = nullptr; + ~internals() + { + // This destructor is called *after* Py_Finalize() in finalize_interpreter(). + // That *SHOULD BE* fine. The following details what happens whe PyThread_tss_free is called. + // PYBIND11_TLS_FREE is PyThread_tss_free on python 3.7+. On older python, it does nothing. + // PyThread_tss_free calls PyThread_tss_delete and PyMem_RawFree. + // PyThread_tss_delete just calls TlsFree (on Windows) or pthread_key_delete (on *NIX). Neither + // of those have anything to do with CPython internals. + // PyMem_RawFree *requires* that the `tstate` be allocated with the CPython allocator. + PYBIND11_TLS_FREE(tstate); + } #endif }; @@ -148,14 +160,49 @@ struct type_info }; /// Tracks the `internals` and `type_info` ABI version independent of the main library version -#define PYBIND11_INTERNALS_VERSION 3 +#define PYBIND11_INTERNALS_VERSION 4 -#if defined(_DEBUG) +/// 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 "" #else @@ -163,12 +210,12 @@ struct type_info #endif #define PYBIND11_INTERNALS_ID \ - "__pybind11_internals_v" PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) PYBIND11_INTERNALS_KIND PYBIND11_BUILD_TYPE \ - "__" + "__pybind11_internals_v" 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_BUILD_TYPE "__" + 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`. @@ -178,6 +225,63 @@ inline internals**& get_internals_pp() 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::overflow_error& e) { + PyErr_SetString(PyExc_OverflowError, 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() { @@ -185,6 +289,20 @@ PYBIND11_NOINLINE inline internals& get_internals() 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])) { @@ -196,18 +314,7 @@ PYBIND11_NOINLINE inline internals& get_internals() // // libstdc++ doesn't require this (types there are identified only by name) #if !defined(__GLIBCXX__) - (*internals_pp)->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) @@ -231,42 +338,7 @@ PYBIND11_NOINLINE inline internals& get_internals() internals_ptr->istate = tstate->interp; #endif builtins[id] = capsule(internals_pp); - 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; - } - }); + 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); diff --git a/dune/pybindxi/detail/typeid.h b/dune/pybindxi/detail/typeid.h index f2d5d631111810216c241d7c6a7c3da372fe2d94..010d0e22c8011b88ae2bfded22e875af878ce31a 100644 --- a/dune/pybindxi/detail/typeid.h +++ b/dune/pybindxi/detail/typeid.h @@ -1,4 +1,3 @@ -#pragma GCC system_header /* pybind11/detail/typeid.h: Compiler-independent access to type identifiers diff --git a/dune/pybindxi/eigen.h b/dune/pybindxi/eigen.h index 56ecd9797faa0ea0e83023e079a369a4b1ae32d1..78066c629274d4e2380d40c2d61aae096715386a 100644 --- a/dune/pybindxi/eigen.h +++ b/dune/pybindxi/eigen.h @@ -1,4 +1,3 @@ -#pragma GCC system_header /* pybind11/eigen.h: Transparent conversion for dense and sparse Eigen matrices diff --git a/dune/pybindxi/embed.h b/dune/pybindxi/embed.h index 0aedd584701998d4fd913d9a519555fbaed35f74..5a84e0da213d443d4d62a758775c3b7c119415d8 100644 --- a/dune/pybindxi/embed.h +++ b/dune/pybindxi/embed.h @@ -1,4 +1,3 @@ -#pragma GCC system_header /* pybind11/embed.h: Support for embedding the interpreter @@ -19,12 +18,14 @@ #if PY_MAJOR_VERSION >= 3 # define PYBIND11_EMBEDDED_MODULE_IMPL(name) \ + extern "C" PyObject* pybind11_init_impl_##name(); \ extern "C" PyObject* pybind11_init_impl_##name() \ { \ return pybind11_init_wrapper_##name(); \ } #else # define PYBIND11_EMBEDDED_MODULE_IMPL(name) \ + extern "C" void pybind11_init_impl_##name(); \ extern "C" void pybind11_init_impl_##name() \ { \ pybind11_init_wrapper_##name(); \ diff --git a/dune/pybindxi/eval.h b/dune/pybindxi/eval.h index 6cf02abb8bf926409f62e5e9c5a8d01b05347eca..e58f6c7af1adee0ca54acda452c7336d8929acc0 100644 --- a/dune/pybindxi/eval.h +++ b/dune/pybindxi/eval.h @@ -1,4 +1,3 @@ -#pragma GCC system_header /* pybind11/exec.h: Support for evaluating Python expressions and statements from strings and files diff --git a/dune/pybindxi/functional.h b/dune/pybindxi/functional.h index 6e515584529cd3c43e308c5533567469e2191150..54e8199e5938882d089d3eda41ce2b5c2b00af6a 100644 --- a/dune/pybindxi/functional.h +++ b/dune/pybindxi/functional.h @@ -1,4 +1,3 @@ -#pragma GCC system_header /* pybind11/functional.h: std::function<> support @@ -76,12 +75,23 @@ public: } }; - value = [hfunc = func_handle(std::move(func))](Args... args) -> Return { - 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>()); + // 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; } diff --git a/dune/pybindxi/iostream.h b/dune/pybindxi/iostream.h index 60c98dce87e12d5b56a8e1589943a7728ae7205e..f393629b912633bc434e1fc51965068f5514452e 100644 --- a/dune/pybindxi/iostream.h +++ b/dune/pybindxi/iostream.h @@ -1,4 +1,3 @@ -#pragma GCC system_header /* pybind11/iostream.h -- Tools to assist with redirecting cout and cerr to Python @@ -68,6 +67,8 @@ public: setp(d_buffer.get(), d_buffer.get() + buf_size - 1); } + pythonbuf(pythonbuf&&) = default; + /// Sync before destroy ~pythonbuf() { diff --git a/dune/pybindxi/numpy.h b/dune/pybindxi/numpy.h index 042101e52495f8a7f0a0c6351ba2a2cdb916a69d..284abbbbe169dc2fc881b2dcf3956f520aa8a082 100644 --- a/dune/pybindxi/numpy.h +++ b/dune/pybindxi/numpy.h @@ -1,4 +1,3 @@ -#pragma GCC system_header /* pybind11/numpy.h: Basic NumPy support, vectorize() wrapper @@ -15,6 +14,7 @@ #include <numeric> #include <algorithm> #include <array> +#include <cstdint> #include <cstdlib> #include <cstring> #include <sstream> @@ -117,6 +117,26 @@ 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)>; +}; + +template <typename Concrete> +constexpr int platform_lookup() +{ + return -1; +} + +// Lookup a type according to its size, and return a value corresponding to the NumPy typenum. +template <typename Concrete, typename T, typename... Ts, typename... Ints> +constexpr int platform_lookup(int I, Ints... Is) +{ + return sizeof(Concrete) == sizeof(T) ? I : platform_lookup<Concrete, Ts...>(Is...); +} + struct npy_api { enum constants @@ -148,7 +168,21 @@ struct npy_api NPY_OBJECT_ = 17, NPY_STRING_, NPY_UNICODE_, - NPY_VOID_ + 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 @@ -1241,12 +1275,12 @@ private: 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_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_, @@ -1260,7 +1294,7 @@ 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!"); } }; @@ -1334,8 +1368,15 @@ inline PYBIND11_NOINLINE void register_structured_dtype(any_container<field_desc 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()); names.append(PYBIND11_STR_TYPE(field.name)); @@ -1351,10 +1392,6 @@ inline PYBIND11_NOINLINE void register_structured_dtype(any_container<field_desc // - 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(std::move(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 diff --git a/dune/pybindxi/operators.h b/dune/pybindxi/operators.h index b226e5530cdd23e35637469778268afa6364de16..232cc332323427a27b25f9f590b0591b3d6514e8 100644 --- a/dune/pybindxi/operators.h +++ b/dune/pybindxi/operators.h @@ -1,4 +1,3 @@ -#pragma GCC system_header /* pybind11/operator.h: Metatemplates for operator overloading diff --git a/dune/pybindxi/options.h b/dune/pybindxi/options.h index 68b19364e17bf52681bc4f1d5540e1dfcf82d275..055d6dfc03d9a834fe507148ecc0bd8fc1e1183f 100644 --- a/dune/pybindxi/options.h +++ b/dune/pybindxi/options.h @@ -1,4 +1,3 @@ -#pragma GCC system_header /* pybind11/options.h: global settings that are configurable at runtime. diff --git a/dune/pybindxi/pybind11.h b/dune/pybindxi/pybind11.h index 119899ed05c18ee47c9472f10797454cdeabc91a..820490c8274edc7b82c031b42b7dde4a3b2eabbc 100644 --- a/dune/pybindxi/pybind11.h +++ b/dune/pybindxi/pybind11.h @@ -1,4 +1,3 @@ -#pragma GCC system_header /* pybind11/pybind11.h: Main header file of the C++11 python binding generator library @@ -521,7 +520,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 @@ -1061,11 +1060,18 @@ 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__) +#if defined(__cpp_aligned_new) && (!defined(_MSC_VER) || _MSC_VER >= 1912) + if (a > __STDCPP_DEFAULT_NEW_ALIGNMENT__) { +# ifdef __cpp_sized_deallocation ::operator delete(p, s, std::align_val_t(a)); - else - ::operator delete(p, s); +# else + ::operator delete(p, std::align_val_t(a)); +# endif + return; + } +#endif +#ifdef __cpp_sized_deallocation + ::operator delete(p, s); #else ::operator delete(p); #endif @@ -1602,9 +1608,17 @@ struct enum_base }, \ 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("__eq__", !b.is_none() && a.equal(b)); - PYBIND11_ENUM_OP_CONV("__ne__", b.is_none() || !a.equal(b)); + 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); @@ -1617,6 +1631,7 @@ struct enum_base 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); @@ -1632,6 +1647,7 @@ struct enum_base } } +#undef PYBIND11_ENUM_OP_CONV_LHS #undef PYBIND11_ENUM_OP_CONV #undef PYBIND11_ENUM_OP_STRICT @@ -1693,6 +1709,10 @@ public: #if PY_MAJOR_VERSION < 3 def("__long__", [](Type value) { return (Scalar)value; }); #endif +#if PY_MAJOR_VERSION > 3 || (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; } @@ -2205,8 +2225,8 @@ class gil_scoped_release error_already_set::~error_already_set() { if (m_type) { - error_scope scope; gil_scoped_acquire gil; + error_scope scope; m_type.release().dec_ref(); m_value.release().dec_ref(); m_trace.release().dec_ref(); diff --git a/dune/pybindxi/pytypes.h b/dune/pybindxi/pytypes.h index 65bd1d1faa2e8631d4aa243d6e464a5d8672af29..9d52eff494a360459af077bd9d80abd8c38e81a6 100644 --- a/dune/pybindxi/pytypes.h +++ b/dune/pybindxi/pytypes.h @@ -1,4 +1,3 @@ -#pragma GCC system_header /* pybind11/pytypes.h: Convenience wrapper classes for basic Python types @@ -1733,6 +1732,10 @@ public: { return (size_t)PyTuple_Size(m_ptr); } + bool empty() const + { + return size() == 0; + } detail::tuple_accessor operator[](size_t index) const { return {*this, index}; @@ -1773,6 +1776,10 @@ public: { return (size_t)PyDict_Size(m_ptr); } + bool empty() const + { + return size() == 0; + } detail::dict_iterator begin() const { return {*this, 0}; @@ -1785,13 +1792,10 @@ public: { PyDict_Clear(ptr()); } - bool contains(handle key) const - { - return PyDict_Contains(ptr(), key.ptr()) == 1; - } - bool contains(const char* key) const + template <typename T> + bool contains(T&& key) const { - return PyDict_Contains(ptr(), pybind11::str(key).ptr()) == 1; + return PyDict_Contains(m_ptr, detail::object_or_cast(std::forward<T>(key)).ptr()) == 1; } private: @@ -1812,6 +1816,10 @@ public: { return (size_t)PySequence_Size(m_ptr); } + bool empty() const + { + return size() == 0; + } detail::sequence_accessor operator[](size_t index) const { return {*this, index}; @@ -1844,6 +1852,10 @@ public: { return (size_t)PyList_Size(m_ptr); } + bool empty() const + { + return size() == 0; + } detail::list_accessor operator[](size_t index) const { return {*this, index}; @@ -1865,6 +1877,11 @@ public: { 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 @@ -1890,6 +1907,10 @@ public: { return (size_t)PySet_Size(m_ptr); } + bool empty() const + { + return size() == 0; + } template <typename T> bool add(T&& val) const { @@ -1899,6 +1920,11 @@ public: { 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 @@ -1929,7 +1955,7 @@ 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) @@ -1966,7 +1992,7 @@ public: buf.strides = py_strides.data(); buf.shape = py_shape.data(); buf.suboffsets = nullptr; - buf.readonly = false; + buf.readonly = info.readonly; buf.internal = nullptr; m_ptr = PyMemoryView_FromBuffer(&buf); diff --git a/dune/pybindxi/stl.h b/dune/pybindxi/stl.h index 9272e6daf57b863a4873de6bddd0eb4edb16a748..a11e756447b91c6dadfd3e7e5e04fda5ee4a1ea9 100644 --- a/dune/pybindxi/stl.h +++ b/dune/pybindxi/stl.h @@ -1,4 +1,3 @@ -#pragma GCC system_header /* pybind11/stl.h: Transparent conversion for STL data types diff --git a/dune/pybindxi/stl_bind.h b/dune/pybindxi/stl_bind.h index 9d48d19c6f8acf98744a40dd134c9cfe5ce57c2c..f200de62e6bafcee1de7eee761a162b1d220085f 100644 --- a/dune/pybindxi/stl_bind.h +++ b/dune/pybindxi/stl_bind.h @@ -1,4 +1,3 @@ -#pragma GCC system_header /* pybind11/std_bind.h: Binding generators for STL data types @@ -133,6 +132,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"), "Add an item to the end of the list"); @@ -144,6 +151,9 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t return v.release(); })); + cl.def( + "clear", [](Vector& v) { v.clear(); }, "Clear the contents"); + cl.def( "extend", [](Vector& v, const Vector& src) { v.insert(v.end(), src.begin(), src.end()); }, @@ -174,10 +184,13 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t 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"), @@ -196,20 +209,18 @@ 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"), "Remove and return the item at index ``i``"); - cl.def("__setitem__", [](Vector& v, SizeType i, const T& t) { - if (i >= v.size()) - throw index_error(); - v[i] = t; + cl.def("__setitem__", [wrap_i](Vector& v, DiffType i, const T& t) { + i = wrap_i(i, v.size()); + v[(SizeType)i] = t; }); /// Slicing protocol @@ -252,10 +263,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``"); @@ -291,14 +301,22 @@ 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 ); @@ -318,11 +336,14 @@ 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()) + cl.def("__getitem__", [](const Vector& v, DiffType i) -> T { + if (i < 0 && (i += v.size()) < 0) + throw index_error(); + if ((SizeType)i >= v.size()) throw index_error(); - return v[i]; + return v[(SizeType)i]; }); cl.def( @@ -514,7 +535,7 @@ void map_assignment(const Args&...) // Map assignment when copy-assignable: just copy the value template <typename Map, typename Class_> -void map_assignment(enable_if_t<std::is_copy_assignable<typename Map::mapped_type>::value, Class_>& cl) +void map_assignment(enable_if_t<is_copy_assignable<typename Map::mapped_type>::value, Class_>& cl) { using KeyType = typename Map::key_type; using MappedType = typename Map::mapped_type; @@ -530,7 +551,7 @@ void map_assignment(enable_if_t<std::is_copy_assignable<typename Map::mapped_typ // Not copy-assignable, but still copy-constructible: we can update the value by erasing and reinserting template <typename Map, typename Class_> -void map_assignment(enable_if_t<!std::is_copy_assignable<typename Map::mapped_type>::value +void map_assignment(enable_if_t<!is_copy_assignable<typename Map::mapped_type>::value && is_copy_constructible<typename Map::mapped_type>::value, Class_>& cl) {