LazyInitializeAtLeastOnceDestroyNever v1

This commit is contained in:
Ralf W. Grosse-Kunstleve 2023-10-08 22:22:37 -07:00
parent 6c77208561
commit 38317c3139

View File

@ -14,12 +14,14 @@
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <cassert>
#include <cstdint> #include <cstdint>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <functional> #include <functional>
#include <numeric> #include <numeric>
#include <sstream> #include <sstream>
#include <stdalign.h>
#include <string> #include <string>
#include <type_traits> #include <type_traits>
#include <typeindex> #include <typeindex>
@ -42,6 +44,30 @@ class array; // Forward declaration
PYBIND11_NAMESPACE_BEGIN(detail) PYBIND11_NAMESPACE_BEGIN(detail)
// Main author of this class: jbms@
template <typename T>
class LazyInitializeAtLeastOnceDestroyNever {
public:
template <typename Initialize>
T &Get(Initialize &&initialize) {
if (!initialized_) {
assert(PyGILState_Check());
// Multiple threads may run this concurrently, but that is fine.
auto value = initialize(); // May release and re-acquire the GIL.
if (!initialized_) { // This runs with the GIL held,
new // therefore this is reached only once.
(reinterpret_cast<T *>(value_storage_)) T(std::move(value));
initialized_ = true;
}
}
return *reinterpret_cast<T *>(value_storage_);
}
private:
alignas(T) char value_storage_[sizeof(T)];
bool initialized_ = false;
};
template <> template <>
struct handle_type_name<array> { struct handle_type_name<array> {
static constexpr auto name = const_name("numpy.ndarray"); static constexpr auto name = const_name("numpy.ndarray");
@ -206,8 +232,8 @@ struct npy_api {
}; };
static npy_api &get() { static npy_api &get() {
static npy_api api = lookup(); static LazyInitializeAtLeastOnceDestroyNever<npy_api> api_init;
return api; return api_init.Get(lookup);
} }
bool PyArray_Check_(PyObject *obj) const { bool PyArray_Check_(PyObject *obj) const {
@ -643,10 +669,11 @@ public:
char flags() const { return detail::array_descriptor_proxy(m_ptr)->flags; } char flags() const { return detail::array_descriptor_proxy(m_ptr)->flags; }
private: private:
static object _dtype_from_pep3118() { static object &_dtype_from_pep3118() {
module_ m = detail::import_numpy_core_submodule("_internal"); static detail::LazyInitializeAtLeastOnceDestroyNever<object> imported_obj;
static PyObject *obj = m.attr("_dtype_from_pep3118").cast<object>().release().ptr(); return imported_obj.Get([]() {
return reinterpret_borrow<object>(obj); return detail::import_numpy_core_submodule("_internal").attr("_dtype_from_pep3118");
});
} }
dtype strip_padding(ssize_t itemsize) { dtype strip_padding(ssize_t itemsize) {