Nektar++
Public Member Functions | Static Public Member Functions | List of all members
PythonToOneDArray< T > Struct Template Reference

Public Member Functions

 PythonToOneDArray ()
 

Static Public Member Functions

static void * convertible (PyObject *objPtr)
 
static void decrement (void *objPtr)
 
static void construct (PyObject *objPtr, py::converter::rvalue_from_python_stage1_data *data)
 

Detailed Description

template<typename T>
struct PythonToOneDArray< T >

Definition at line 82 of file SharedArray.cpp.

Constructor & Destructor Documentation

◆ PythonToOneDArray()

template<typename T >
PythonToOneDArray< T >::PythonToOneDArray ( )
inline

Definition at line 84 of file SharedArray.cpp.

85 {
86 py::converter::registry::push_back(&convertible, &construct,
87 py::type_id<Array<OneD, T>>());
88 }
static void construct(PyObject *objPtr, py::converter::rvalue_from_python_stage1_data *data)
static void * convertible(PyObject *objPtr)
Definition: SharedArray.cpp:89

References PythonToOneDArray< T >::construct(), and PythonToOneDArray< T >::convertible().

Member Function Documentation

◆ construct()

template<typename T >
static void PythonToOneDArray< T >::construct ( PyObject *  objPtr,
py::converter::rvalue_from_python_stage1_data *  data 
)
inlinestatic

Definition at line 134 of file SharedArray.cpp.

136 {
137 // This has to be a _borrowed_ reference, otherwise at the end of this
138 // scope it seems memory gets deallocated
139 py::object obj((py::handle<>(py::borrowed(objPtr))));
140 np::ndarray array = py::extract<np::ndarray>(obj);
141
142 // If this array came from C++, extract the C++ array from PyCObject or
143 // PyCapsule and ensure that we set up the C++ array to have a reference
144 // to that object, so that it can be decremented as appropriate.
145 py::object base = array.get_base();
146 Array<OneD, T> *ptr = nullptr;
147
148#if PY_MAJOR_VERSION == 2
149 if (PyCObject_Check(base.ptr()))
150 {
151 ptr = reinterpret_cast<Array<OneD, T> *>(
152 PyCObject_AsVoidPtr(base.ptr()));
153 }
154#else
155 if (PyCapsule_CheckExact(base.ptr()))
156 {
157 ptr = reinterpret_cast<Array<OneD, T> *>(
158 PyCapsule_GetPointer(base.ptr(), nullptr));
159 }
160#endif
161
162 void *storage =
163 ((py::converter::rvalue_from_python_storage<Array<OneD, T>> *)data)
164 ->storage.bytes;
165 data->convertible = storage;
166
167 // If array originated in C++, then we need to be careful to avoid
168 // circular references. We therefore take a step to 'convert' this to a
169 // Python array so that essentially the reference counting and memory
170 // cleanup is done from the Python side.
171 //
172 // 1) Calling ToPythonArray to point to this numpy array. This ensures
173 // that any C++ arrays that share this memory also know to call the
174 // appropriate decrement function.
175 // 2) Creating a new Array from ptr, since ptr will shortly be deleted.
176 // 3) We call set_base to let the numpy array own its own data. This
177 // will, at the end of the function and after `base` goes out of
178 // scope, lead to ptr being deleted.
179 //
180 // After all of this references should be consistent between the C++
181 // side and the Python side.
182 if (ptr != nullptr)
183 {
184 ptr->ToPythonArray((void *)objPtr, &decrement);
185 new (storage) Array<OneD, T>(*ptr);
186 array.set_base(py::object());
187 }
188 else
189 {
190 // Otherwise, construct OneD array from numpy array
191 using nonconst_t = typename std::remove_const<T>::type;
192 new (storage)
193 Array<OneD, T>(array.shape(0), (nonconst_t *)array.get_data(),
194 (void *)objPtr, &decrement);
195 }
196
197 py::incref(objPtr);
198 }
static void decrement(void *objPtr)

References PythonToOneDArray< T >::decrement().

Referenced by PythonToOneDArray< T >::PythonToOneDArray().

◆ convertible()

template<typename T >
static void * PythonToOneDArray< T >::convertible ( PyObject *  objPtr)
inlinestatic

Definition at line 89 of file SharedArray.cpp.

90 {
91 try
92 {
93 py::object obj((py::handle<>(py::borrowed(objPtr))));
94 np::ndarray array = py::extract<np::ndarray>(obj);
95
96 // Check data types match
97 np::dtype dtype =
98 np::dtype::get_builtin<typename boost::remove_const<T>::type>();
99 if (dtype != array.get_dtype())
100 {
101 return nullptr;
102 }
103
104 // Check shape is 1D
105 if (array.get_nd() != 1)
106 {
107 return nullptr;
108 }
109 }
110 catch (boost::python::error_already_set &)
111 {
112 py::handle_exception();
113 PyErr_Clear();
114 return nullptr;
115 }
116
117 return objPtr;
118 }

Referenced by PythonToOneDArray< T >::PythonToOneDArray().

◆ decrement()

template<typename T >
static void PythonToOneDArray< T >::decrement ( void *  objPtr)
inlinestatic

Definition at line 120 of file SharedArray.cpp.

121 {
122 if (!Py_IsInitialized())
123 {
124 // In deinitialisation phase, reference counters are not terribly
125 // robust; decremementing counters here can lead to segfaults during
126 // program exit in some cases.
127 return;
128 }
129
130 // Otherwise decrement reference counter.
131 py::decref((PyObject *)objPtr);
132 }

Referenced by PythonToOneDArray< T >::construct().