diff --git a/PyTools/Embed/PyObjectPtr.cpp b/PyTools/Embed/PyObjectPtr.cpp new file mode 100644 index 0000000000000000000000000000000000000000..55390c99ab52ed8a8d7932c86c3661e78e1f6387 --- /dev/null +++ b/PyTools/Embed/PyObjectPtr.cpp @@ -0,0 +1,83 @@ +#include "PyObjectPtr.h" +#include "PythonInterpreter.h" + +#include <string> +#include <sstream> // stringstream +#include <exception> + +PyObjectPtr::PyObjectPtr(PyObject* pyobject_ptr, + const Status& status): + ptr{pyobject_ptr}, + status{status} +{ + // if PyObject pointer is null but result type is not `None` or `Error`, + // then that will be an `Error` case. + if(!ptr && status.type != Status::Type::None + && status.type != Status::Type::Error) + { + this->status.type = Status::Type::Error; + } +} + + +PyObjectPtr::PyObjectPtr(PyObject* pyobject_ptr): + PyObjectPtr(pyobject_ptr, Status(Status::Type::Info)) {} + + +PyObjectPtr::PyObjectPtr(const Status& status): + PyObjectPtr(nullptr, status) {} + + +PyObjectPtr::~PyObjectPtr() +{ + discard(); +} + + +PyObjectPtr::PyObjectPtr(PyObjectPtr&& other): + PyObjectPtr(other.ptr, other.status) +{ + // reset the moved object + other.reset(); +} + + +PyObject* PyObjectPtr::release() +{ + PyObject* pyobject_ptr {ptr}; + reset(); + return pyobject_ptr; +} + + +void PyObjectPtr::reset() +{ + ptr = nullptr; + status = Status(); +} + + +void PyObjectPtr::discard() +{ + if (!PythonInterpreter::isInitialized()) { + throw(std::runtime_error( + "Decrementing Python reference-count without " + "Python initialized leads to memory access violation " + "(segmentation fault)")); + } + + PythonInterpreter::DecRef(ptr); + reset(); +} + + +bool PyObjectPtr::valid() const +{ + return (ptr && (status.isOK() || status.isWarning())); +} + + +bool PyObjectPtr::isSet() const +{ + return (ptr && status.isSet()); +} diff --git a/PyTools/Embed/PyObjectPtr.h b/PyTools/Embed/PyObjectPtr.h new file mode 100644 index 0000000000000000000000000000000000000000..2165b64770a5a49be936607051778204e627cd3e --- /dev/null +++ b/PyTools/Embed/PyObjectPtr.h @@ -0,0 +1,72 @@ +#ifndef PYOBJECTPTR_H +#define PYOBJECTPTR_H + +#include "PyObjectDecl.h" +#include "Result.h" // Status +#include <vector> + +//======================================== + +// safe container for PyObjects +/* +The class `PyObjectPtr` contains a `PyObject*` (or `NULL`) and a `Status` which denotes the status of the value (OK/Warning/Error). +Decrementing Python reference-count is performed automatically when a +`PyObjectPtr` expires. +*/ + +class PyObjectPtr +{ + +public: + // raw pointer to the PyObject + PyObject* ptr = nullptr; + + // status of the PyObject + Status status; + + PyObjectPtr(PyObject* pyobject_ptr, const Status& status); + + PyObjectPtr(PyObject* pyobject_ptr); + + PyObjectPtr(const Status& status); + + ~PyObjectPtr(); + + // disallow copy constructor + PyObjectPtr(const PyObjectPtr&) = delete; + // disallow copy assignment + PyObjectPtr& operator=(const PyObjectPtr&) = delete; + // allow move constructor + PyObjectPtr(PyObjectPtr&& other); + // reset the container to the initial status (does _not_ release the Python resource) + void reset(); + // reset 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 validity of the PyObjectPtr + bool valid() const; + // check if the PyObjectPtr is set + bool isSet() const; +}; + + +// Numpy array descriptor +struct NpArrayDescr +{ + // Numpy array descriptors + bool C_contiguous = false; + bool F_contiguous = false; + // whether the data area of arr is aligned and in machine byte-order + bool wellbehaved = false; + // number of dimensions + int n_dims = 0; + // sizes of dimensions + std::vector<np_size_t> dims; + // character code indicating the data type + char dtype = '\0'; + // whether Numpy array owns its data + bool owns_data = false; +}; + +#endif // PYOBJECTPTR_H