14
14
15
15
#include < algorithm>
16
16
#include < array>
17
+ #include < cassert>
17
18
#include < cstdint>
18
19
#include < cstdlib>
19
20
#include < cstring>
20
21
#include < functional>
21
22
#include < numeric>
22
23
#include < sstream>
24
+ #include < stdalign.h>
23
25
#include < string>
24
26
#include < type_traits>
25
27
#include < typeindex>
@@ -42,6 +44,30 @@ class array; // Forward declaration
42
44
43
45
PYBIND11_NAMESPACE_BEGIN (detail)
44
46
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
+
45
71
template <>
46
72
struct handle_type_name <array> {
47
73
static constexpr auto name = const_name(" numpy.ndarray" );
@@ -206,8 +232,8 @@ struct npy_api {
206
232
};
207
233
208
234
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) ;
211
237
}
212
238
213
239
bool PyArray_Check_ (PyObject *obj) const {
@@ -643,10 +669,11 @@ class dtype : public object {
643
669
char flags () const { return detail::array_descriptor_proxy (m_ptr)->flags ; }
644
670
645
671
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
+ });
650
677
}
651
678
652
679
dtype strip_padding (ssize_t itemsize) {
0 commit comments