Skip to content

Commit

Permalink
LazyInitializeAtLeastOnceDestroyNever v1
Browse files Browse the repository at this point in the history
  • Loading branch information
Ralf W. Grosse-Kunstleve committed Oct 9, 2023
1 parent 6c77208 commit 38317c3
Showing 1 changed file with 33 additions and 6 deletions.
39 changes: 33 additions & 6 deletions include/pybind11/numpy.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@

#include <algorithm>
#include <array>
#include <cassert>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <functional>
#include <numeric>
#include <sstream>
#include <stdalign.h>
#include <string>
#include <type_traits>
#include <typeindex>
Expand All @@ -42,6 +44,30 @@ class array; // Forward declaration

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 <>
struct handle_type_name<array> {
static constexpr auto name = const_name("numpy.ndarray");
Expand Down Expand Up @@ -206,8 +232,8 @@ struct npy_api {
};

static npy_api &get() {
static npy_api api = lookup();
return api;
static LazyInitializeAtLeastOnceDestroyNever<npy_api> api_init;
return api_init.Get(lookup);
}

bool PyArray_Check_(PyObject *obj) const {
Expand Down Expand Up @@ -643,10 +669,11 @@ class dtype : public object {
char flags() const { return detail::array_descriptor_proxy(m_ptr)->flags; }

private:
static object _dtype_from_pep3118() {
module_ m = detail::import_numpy_core_submodule("_internal");
static PyObject *obj = m.attr("_dtype_from_pep3118").cast<object>().release().ptr();
return reinterpret_borrow<object>(obj);
static object &_dtype_from_pep3118() {
static detail::LazyInitializeAtLeastOnceDestroyNever<object> imported_obj;
return imported_obj.Get([]() {
return detail::import_numpy_core_submodule("_internal").attr("_dtype_from_pep3118");
});
}

dtype strip_padding(ssize_t itemsize) {
Expand Down

0 comments on commit 38317c3

Please sign in to comment.