1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
|
// ************************************************************************************************
//
// BornAgain: simulate and fit reflection and scattering
//
//! @file PyCore/Embed/PyObjectPtr.h
//! @brief Defines class PyObjectPtr.
//!
//! @homepage http://www.bornagainproject.org
//! @license GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2018
//! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS)
//
// ************************************************************************************************
#ifdef SWIG
#error no need to expose this header to Swig
#endif // SWIG
#ifndef BORNAGAIN_PYTHON
#error this header requires Python support
#endif
#ifndef BORNAGAIN_PYCORE_EMBED_PYOBJECTPTR_H
#define BORNAGAIN_PYCORE_EMBED_PYOBJECTPTR_H
#include "PyCore/Embed/PyObjectDecl.h"
#include <map>
#include <string>
#include <variant>
#include <vector>
// metadata container
using ValueType = std::variant<long int, double, std::string>;
using ArrayMetadata = std::map<std::string, ValueType>;
//! Safe container for PyObjects:
//! The class `PyObjectPtr` contains a `PyObject*` (or `NULL`).
//! Decrementing Python reference-count is performed automatically when
//! the life-time of a `PyObjectPtr` expires.
class PyObjectPtr {
public:
PyObjectPtr(PyObject* pyobject_ptr, const bool borrowed = false)
: m_ptr{pyobject_ptr}
, m_borrowed{borrowed}
{
}
~PyObjectPtr() { discard(); }
PyObjectPtr(const PyObjectPtr&) = delete;
PyObjectPtr(PyObjectPtr&& other);
PyObjectPtr& operator=(const PyObjectPtr&) = delete;
//! Returns the raw pointer to the PyObject
PyObject* get() { return m_ptr; }
//! Resets the container to the initial status (does _not_ release the Python resource)
void reset();
//! Resets the container to the initial status and return the PyObject pointer
//! (does _not_ release the Python resource)
PyObject* release();
//! Discards the Python resource (decrements the Python reference)
void discard();
//! Check the validity of the PyObjectPtr
bool valid() const { return static_cast<bool>(m_ptr); }
private:
//! Raw pointer to the PyObject
PyObject* m_ptr = nullptr;
//! Flag to determine if PyObject is a borrowed reference
// NOTE:
// The Python C-API uses two main types of object references:
// 1) 'Strong' reference (aka. 'new' reference) is a pointer that owns the reference.
// It increases the object's reference count and the caller is responsible for eventually
// calling `Py_DECREF` to release it.
//
// 2) 'Borrowed' reference is a pointer to an object that does _not_ own the reference.
// It does _not_ increase the object's reference count. The caller presumes that
// the referenced object already exists and has a positive refcount.
// The caller should not call `Py_DECREF` on the object (no need to release).
// It can become a dangling pointer if the object is destroyed.
//
// See section "Reference Count Details" in the Python/C API Reference Manual
// <https://docs.python.org/3/c-api/intro.html#reference-count-details>
bool m_borrowed = false;
};
//! Wrapper for a Numpy array to be passed to C++. The class stores the basic information
//! which is required to define a Numpy array: size, rank and shape of the array and its
//! datatype. The C++ code can then access the array data via a raw pointer.
//! The accompanying Python object is also internally managed by the class.
//! NOTE: The array data is not copied.
class NumpyArrayWrapper {
public:
NumpyArrayWrapper(const std::size_t datasize, const std::size_t n_dims, const std::size_t* dims,
const std::string& dtype, const void* array_ptr, PyObject* py_array_ptr,
const ArrayMetadata& metadata = {});
~NumpyArrayWrapper();
//! Total size of the array
std::size_t size() const { return m_datasize; }
//! Rank, number of dimensions of the array
std::size_t rank() const { return m_dims.size(); }
//! Raw pointer to the array which stores the size of the underlying C-Array on each dimension
const std::size_t* dimensions() const { return m_dims.data(); }
//! Raw pointer to the underlying C-array
const void* arrayPtr() const { return m_array_ptr; }
//! Data-type ('dtype') of the array
const std::string dtype() const { return m_dtype; }
//! ArrayMetadata of the array
const ArrayMetadata& metadata() const { return m_metadata; }
private:
std::size_t m_datasize = 0; //!< total size of the array
std::vector<std::size_t> m_dims; //!< dimensions of the arrary
std::string m_dtype; //!< data-type ('dtype') of the array
ArrayMetadata m_metadata; //!< metadata of the array
const void* m_array_ptr = nullptr; //!< raw pointer to the array data
PyObject* m_py_array_ptr = nullptr; //!< raw pointer to the Numpy array (Python object)
};
#endif // BORNAGAIN_PYCORE_EMBED_PYOBJECTPTR_H
|