Skip to content

Commit 38317c3

Browse files
committed
LazyInitializeAtLeastOnceDestroyNever v1
1 parent 6c77208 commit 38317c3

File tree

1 file changed

+33
-6
lines changed

1 file changed

+33
-6
lines changed

include/pybind11/numpy.h

+33-6
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,14 @@
1414

1515
#include <algorithm>
1616
#include <array>
17+
#include <cassert>
1718
#include <cstdint>
1819
#include <cstdlib>
1920
#include <cstring>
2021
#include <functional>
2122
#include <numeric>
2223
#include <sstream>
24+
#include <stdalign.h>
2325
#include <string>
2426
#include <type_traits>
2527
#include <typeindex>
@@ -42,6 +44,30 @@ class array; // Forward declaration
4244

4345
PYBIND11_NAMESPACE_BEGIN(detail)
4446

47+
// Main author of this class: jbms@
48+
template <typename T>
49+
class LazyInitializeAtLeastOnceDestroyNever {
50+
public:
51+
template <typename Initialize>
52+
T &Get(Initialize &&initialize) {
53+
if (!initialized_) {
54+
assert(PyGILState_Check());
55+
// Multiple threads may run this concurrently, but that is fine.
56+
auto value = initialize(); // May release and re-acquire the GIL.
57+
if (!initialized_) { // This runs with the GIL held,
58+
new // therefore this is reached only once.
59+
(reinterpret_cast<T *>(value_storage_)) T(std::move(value));
60+
initialized_ = true;
61+
}
62+
}
63+
return *reinterpret_cast<T *>(value_storage_);
64+
}
65+
66+
private:
67+
alignas(T) char value_storage_[sizeof(T)];
68+
bool initialized_ = false;
69+
};
70+
4571
template <>
4672
struct handle_type_name<array> {
4773
static constexpr auto name = const_name("numpy.ndarray");
@@ -206,8 +232,8 @@ struct npy_api {
206232
};
207233

208234
static npy_api &get() {
209-
static npy_api api = lookup();
210-
return api;
235+
static LazyInitializeAtLeastOnceDestroyNever<npy_api> api_init;
236+
return api_init.Get(lookup);
211237
}
212238

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

645671
private:
646-
static object _dtype_from_pep3118() {
647-
module_ m = detail::import_numpy_core_submodule("_internal");
648-
static PyObject *obj = m.attr("_dtype_from_pep3118").cast<object>().release().ptr();
649-
return reinterpret_borrow<object>(obj);
672+
static object &_dtype_from_pep3118() {
673+
static detail::LazyInitializeAtLeastOnceDestroyNever<object> imported_obj;
674+
return imported_obj.Get([]() {
675+
return detail::import_numpy_core_submodule("_internal").attr("_dtype_from_pep3118");
676+
});
650677
}
651678

652679
dtype strip_padding(ssize_t itemsize) {

0 commit comments

Comments
 (0)