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 * convertible(PyObject *objPtr)
Definition: SharedArray.cpp:89
static void construct(PyObject *objPtr, py::converter::rvalue_from_python_stage1_data *data)

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(), 0));
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)

◆ 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 0;
102  }
103 
104  // Check shape is 1D
105  if (array.get_nd() != 1)
106  {
107  return 0;
108  }
109  }
110  catch (boost::python::error_already_set &)
111  {
112  py::handle_exception();
113  PyErr_Clear();
114  return 0;
115  }
116 
117  return objPtr;
118  }

◆ 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  }