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 88 of file SharedArray.cpp.

Constructor & Destructor Documentation

◆ PythonToOneDArray()

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

Definition at line 90 of file SharedArray.cpp.

91  {
92  py::converter::registry::push_back(
93  &convertible, &construct, py::type_id<Array<OneD, T> >());
94  }
static void construct(PyObject *objPtr, py::converter::rvalue_from_python_stage1_data *data)
static void * convertible(PyObject *objPtr)
Definition: SharedArray.cpp:95

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 140 of file SharedArray.cpp.

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

◆ convertible()

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

Definition at line 95 of file SharedArray.cpp.

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

◆ decrement()

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

Definition at line 126 of file SharedArray.cpp.

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