|
#ifndef GREENLET_REFS_HPP |
|
#define GREENLET_REFS_HPP |
|
|
|
#define PY_SSIZE_T_CLEAN |
|
#include <Python.h> |
|
|
|
#include <string> |
|
|
|
|
|
#include "greenlet_compiler_compat.hpp" |
|
#include "greenlet_cpython_compat.hpp" |
|
#include "greenlet_exceptions.hpp" |
|
|
|
struct _greenlet; |
|
struct _PyMainGreenlet; |
|
|
|
typedef struct _greenlet PyGreenlet; |
|
extern PyTypeObject PyGreenlet_Type; |
|
|
|
|
|
#ifdef GREENLET_USE_STDIO |
|
#include <iostream> |
|
using std::cerr; |
|
using std::endl; |
|
#endif |
|
|
|
namespace greenlet |
|
{ |
|
class Greenlet; |
|
|
|
namespace refs |
|
{ |
|
|
|
|
|
|
|
|
|
|
|
typedef void (*TypeChecker)(void*); |
|
|
|
void |
|
NoOpChecker(void*) |
|
{ |
|
return; |
|
} |
|
|
|
void |
|
GreenletChecker(void *p) |
|
{ |
|
if (!p) { |
|
return; |
|
} |
|
|
|
PyTypeObject* typ = Py_TYPE(p); |
|
|
|
|
|
|
|
|
|
if (typ == &PyGreenlet_Type) { |
|
return; |
|
} |
|
|
|
if (!PyObject_TypeCheck(p, &PyGreenlet_Type)) { |
|
std::string err("GreenletChecker: Expected any type of greenlet, not "); |
|
err += Py_TYPE(p)->tp_name; |
|
throw TypeError(err); |
|
} |
|
} |
|
|
|
void |
|
MainGreenletExactChecker(void *p); |
|
|
|
template <typename T, TypeChecker> |
|
class PyObjectPointer; |
|
|
|
template<typename T, TypeChecker> |
|
class OwnedReference; |
|
|
|
|
|
template<typename T, TypeChecker> |
|
class BorrowedReference; |
|
|
|
typedef BorrowedReference<PyObject, NoOpChecker> BorrowedObject; |
|
typedef OwnedReference<PyObject, NoOpChecker> OwnedObject; |
|
|
|
class ImmortalObject; |
|
class ImmortalString; |
|
|
|
template<typename T, TypeChecker TC> |
|
class _OwnedGreenlet; |
|
|
|
typedef _OwnedGreenlet<PyGreenlet, GreenletChecker> OwnedGreenlet; |
|
typedef _OwnedGreenlet<PyGreenlet, MainGreenletExactChecker> OwnedMainGreenlet; |
|
|
|
template<typename T, TypeChecker TC> |
|
class _BorrowedGreenlet; |
|
|
|
typedef _BorrowedGreenlet<PyGreenlet, GreenletChecker> BorrowedGreenlet; |
|
|
|
void |
|
ContextExactChecker(void *p) |
|
{ |
|
if (!p) { |
|
return; |
|
} |
|
if (!PyContext_CheckExact(p)) { |
|
throw TypeError( |
|
"greenlet context must be a contextvars.Context or None" |
|
); |
|
} |
|
} |
|
|
|
typedef OwnedReference<PyObject, ContextExactChecker> OwnedContext; |
|
} |
|
} |
|
|
|
namespace greenlet { |
|
|
|
|
|
namespace refs { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <typename T=PyObject, TypeChecker TC=NoOpChecker> |
|
class PyObjectPointer |
|
{ |
|
public: |
|
typedef T PyType; |
|
protected: |
|
T* p; |
|
public: |
|
PyObjectPointer(T* it=nullptr) : p(it) |
|
{ |
|
TC(p); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
T* borrow() const noexcept |
|
{ |
|
return this->p; |
|
} |
|
|
|
PyObject* borrow_o() const noexcept |
|
{ |
|
return reinterpret_cast<PyObject*>(this->p); |
|
} |
|
|
|
T* operator->() const noexcept |
|
{ |
|
return this->p; |
|
} |
|
|
|
bool is_None() const noexcept |
|
{ |
|
return this->p == Py_None; |
|
} |
|
|
|
PyObject* acquire_or_None() const noexcept |
|
{ |
|
PyObject* result = this->p ? reinterpret_cast<PyObject*>(this->p) : Py_None; |
|
Py_INCREF(result); |
|
return result; |
|
} |
|
|
|
explicit operator bool() const noexcept |
|
{ |
|
return this->p != nullptr; |
|
} |
|
|
|
bool operator!() const noexcept |
|
{ |
|
return this->p == nullptr; |
|
} |
|
|
|
Py_ssize_t REFCNT() const noexcept |
|
{ |
|
return p ? Py_REFCNT(p) : -42; |
|
} |
|
|
|
PyTypeObject* TYPE() const noexcept |
|
{ |
|
return p ? Py_TYPE(p) : nullptr; |
|
} |
|
|
|
inline OwnedObject PyStr() const noexcept; |
|
inline const std::string as_str() const noexcept; |
|
inline OwnedObject PyGetAttr(const ImmortalObject& name) const noexcept; |
|
inline OwnedObject PyRequireAttr(const char* const name) const; |
|
inline OwnedObject PyRequireAttr(const ImmortalString& name) const; |
|
inline OwnedObject PyCall(const BorrowedObject& arg) const; |
|
inline OwnedObject PyCall(PyGreenlet* arg) const ; |
|
inline OwnedObject PyCall(PyObject* arg) const ; |
|
|
|
inline OwnedObject PyCall(const BorrowedObject args, |
|
const BorrowedObject kwargs) const; |
|
inline OwnedObject PyCall(const OwnedObject& args, |
|
const OwnedObject& kwargs) const; |
|
|
|
protected: |
|
void _set_raw_pointer(void* t) |
|
{ |
|
TC(t); |
|
p = reinterpret_cast<T*>(t); |
|
} |
|
void* _get_raw_pointer() const |
|
{ |
|
return p; |
|
} |
|
}; |
|
|
|
#ifdef GREENLET_USE_STDIO |
|
template<typename T, TypeChecker TC> |
|
std::ostream& operator<<(std::ostream& os, const PyObjectPointer<T, TC>& s) |
|
{ |
|
const std::type_info& t = typeid(s); |
|
os << t.name() |
|
<< "(addr=" << s.borrow() |
|
<< ", refcnt=" << s.REFCNT() |
|
<< ", value=" << s.as_str() |
|
<< ")"; |
|
|
|
return os; |
|
} |
|
#endif |
|
|
|
template<typename T, TypeChecker TC> |
|
inline bool operator==(const PyObjectPointer<T, TC>& lhs, const PyObject* const rhs) noexcept |
|
{ |
|
return static_cast<const void*>(lhs.borrow_o()) == static_cast<const void*>(rhs); |
|
} |
|
|
|
template<typename T, TypeChecker TC, typename X, TypeChecker XC> |
|
inline bool operator==(const PyObjectPointer<T, TC>& lhs, const PyObjectPointer<X, XC>& rhs) noexcept |
|
{ |
|
return lhs.borrow_o() == rhs.borrow_o(); |
|
} |
|
|
|
template<typename T, TypeChecker TC, typename X, TypeChecker XC> |
|
inline bool operator!=(const PyObjectPointer<T, TC>& lhs, |
|
const PyObjectPointer<X, XC>& rhs) noexcept |
|
{ |
|
return lhs.borrow_o() != rhs.borrow_o(); |
|
} |
|
|
|
template<typename T=PyObject, TypeChecker TC=NoOpChecker> |
|
class OwnedReference : public PyObjectPointer<T, TC> |
|
{ |
|
private: |
|
friend class OwnedList; |
|
|
|
protected: |
|
explicit OwnedReference(T* it) : PyObjectPointer<T, TC>(it) |
|
{ |
|
} |
|
|
|
public: |
|
|
|
|
|
|
|
static OwnedReference<T, TC> consuming(PyObject* p) |
|
{ |
|
return OwnedReference<T, TC>(reinterpret_cast<T*>(p)); |
|
} |
|
|
|
static OwnedReference<T, TC> owning(T* p) |
|
{ |
|
OwnedReference<T, TC> result(p); |
|
Py_XINCREF(result.p); |
|
return result; |
|
} |
|
|
|
OwnedReference() : PyObjectPointer<T, TC>(nullptr) |
|
{} |
|
|
|
explicit OwnedReference(const PyObjectPointer<>& other) |
|
: PyObjectPointer<T, TC>(nullptr) |
|
{ |
|
T* op = other.borrow(); |
|
TC(op); |
|
this->p = other.borrow(); |
|
Py_XINCREF(this->p); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
OwnedReference(const OwnedReference<T, TC>& other) |
|
: PyObjectPointer<T, TC>(other.p) |
|
{ |
|
Py_XINCREF(this->p); |
|
} |
|
|
|
static OwnedReference<PyObject> None() |
|
{ |
|
Py_INCREF(Py_None); |
|
return OwnedReference<PyObject>(Py_None); |
|
} |
|
|
|
|
|
OwnedReference<T, TC>& operator=(const OwnedReference<T, TC>& other) |
|
{ |
|
Py_XINCREF(other.p); |
|
const T* tmp = this->p; |
|
this->p = other.p; |
|
Py_XDECREF(tmp); |
|
return *this; |
|
} |
|
|
|
OwnedReference<T, TC>& operator=(const BorrowedReference<T, TC> other) |
|
{ |
|
return this->operator=(other.borrow()); |
|
} |
|
|
|
OwnedReference<T, TC>& operator=(T* const other) |
|
{ |
|
TC(other); |
|
Py_XINCREF(other); |
|
T* tmp = this->p; |
|
this->p = other; |
|
Py_XDECREF(tmp); |
|
return *this; |
|
} |
|
|
|
|
|
|
|
template<typename X, TypeChecker XC> |
|
OwnedReference<T, TC>& operator=(const OwnedReference<X, XC>& other) |
|
{ |
|
X* op = other.borrow(); |
|
TC(op); |
|
return this->operator=(reinterpret_cast<T*>(op)); |
|
} |
|
|
|
inline void steal(T* other) |
|
{ |
|
assert(this->p == nullptr); |
|
TC(other); |
|
this->p = other; |
|
} |
|
|
|
T* relinquish_ownership() |
|
{ |
|
T* result = this->p; |
|
this->p = nullptr; |
|
return result; |
|
} |
|
|
|
T* acquire() const |
|
{ |
|
|
|
|
|
|
|
Py_XINCREF(this->p); |
|
return this->p; |
|
} |
|
|
|
|
|
|
|
~OwnedReference() |
|
{ |
|
Py_CLEAR(this->p); |
|
} |
|
|
|
void CLEAR() |
|
{ |
|
Py_CLEAR(this->p); |
|
assert(this->p == nullptr); |
|
} |
|
}; |
|
|
|
static inline |
|
void operator<<=(PyObject*& target, OwnedObject& o) |
|
{ |
|
target = o.relinquish_ownership(); |
|
} |
|
|
|
|
|
class NewReference : public OwnedObject |
|
{ |
|
private: |
|
G_NO_COPIES_OF_CLS(NewReference); |
|
public: |
|
|
|
|
|
NewReference(PyObject* it) : OwnedObject(it) |
|
{ |
|
} |
|
}; |
|
|
|
class NewDictReference : public NewReference |
|
{ |
|
private: |
|
G_NO_COPIES_OF_CLS(NewDictReference); |
|
public: |
|
NewDictReference() : NewReference(PyDict_New()) |
|
{ |
|
if (!this->p) { |
|
throw PyErrOccurred(); |
|
} |
|
} |
|
|
|
void SetItem(const char* const key, PyObject* value) |
|
{ |
|
Require(PyDict_SetItemString(this->p, key, value)); |
|
} |
|
|
|
void SetItem(const PyObjectPointer<>& key, PyObject* value) |
|
{ |
|
Require(PyDict_SetItem(this->p, key.borrow_o(), value)); |
|
} |
|
}; |
|
|
|
template<typename T=PyGreenlet, TypeChecker TC=GreenletChecker> |
|
class _OwnedGreenlet: public OwnedReference<T, TC> |
|
{ |
|
private: |
|
protected: |
|
_OwnedGreenlet(T* it) : OwnedReference<T, TC>(it) |
|
{} |
|
|
|
public: |
|
_OwnedGreenlet() : OwnedReference<T, TC>() |
|
{} |
|
|
|
_OwnedGreenlet(const _OwnedGreenlet<T, TC>& other) : OwnedReference<T, TC>(other) |
|
{ |
|
} |
|
_OwnedGreenlet(OwnedMainGreenlet& other) : |
|
OwnedReference<T, TC>(reinterpret_cast<T*>(other.acquire())) |
|
{ |
|
} |
|
_OwnedGreenlet(const BorrowedGreenlet& other); |
|
|
|
static _OwnedGreenlet<T, TC> consuming(PyGreenlet* it) |
|
{ |
|
return _OwnedGreenlet<T, TC>(reinterpret_cast<T*>(it)); |
|
} |
|
|
|
inline _OwnedGreenlet<T, TC>& operator=(const OwnedGreenlet& other) |
|
{ |
|
return this->operator=(other.borrow()); |
|
} |
|
|
|
inline _OwnedGreenlet<T, TC>& operator=(const BorrowedGreenlet& other); |
|
|
|
_OwnedGreenlet<T, TC>& operator=(const OwnedMainGreenlet& other) |
|
{ |
|
PyGreenlet* owned = other.acquire(); |
|
Py_XDECREF(this->p); |
|
this->p = reinterpret_cast<T*>(owned); |
|
return *this; |
|
} |
|
|
|
_OwnedGreenlet<T, TC>& operator=(T* const other) |
|
{ |
|
OwnedReference<T, TC>::operator=(other); |
|
return *this; |
|
} |
|
|
|
T* relinquish_ownership() |
|
{ |
|
T* result = this->p; |
|
this->p = nullptr; |
|
return result; |
|
} |
|
|
|
PyObject* relinquish_ownership_o() |
|
{ |
|
return reinterpret_cast<PyObject*>(relinquish_ownership()); |
|
} |
|
|
|
inline Greenlet* operator->() const noexcept; |
|
inline operator Greenlet*() const noexcept; |
|
}; |
|
|
|
template <typename T=PyObject, TypeChecker TC=NoOpChecker> |
|
class BorrowedReference : public PyObjectPointer<T, TC> |
|
{ |
|
public: |
|
|
|
|
|
|
|
|
|
BorrowedReference(T* it) : PyObjectPointer<T, TC>(it) |
|
{} |
|
|
|
BorrowedReference(const PyObjectPointer<T>& ref) : PyObjectPointer<T, TC>(ref.borrow()) |
|
{} |
|
|
|
BorrowedReference() : PyObjectPointer<T, TC>(nullptr) |
|
{} |
|
|
|
operator T*() const |
|
{ |
|
return this->p; |
|
} |
|
}; |
|
|
|
typedef BorrowedReference<PyObject> BorrowedObject; |
|
|
|
|
|
template<typename T=PyGreenlet, TypeChecker TC=GreenletChecker> |
|
class _BorrowedGreenlet : public BorrowedReference<T, TC> |
|
{ |
|
public: |
|
_BorrowedGreenlet() : |
|
BorrowedReference<T, TC>(nullptr) |
|
{} |
|
|
|
_BorrowedGreenlet(T* it) : |
|
BorrowedReference<T, TC>(it) |
|
{} |
|
|
|
_BorrowedGreenlet(const BorrowedObject& it); |
|
|
|
_BorrowedGreenlet(const OwnedGreenlet& it) : |
|
BorrowedReference<T, TC>(it.borrow()) |
|
{} |
|
|
|
_BorrowedGreenlet<T, TC>& operator=(const BorrowedObject& other); |
|
|
|
|
|
|
|
operator PyObject*() const |
|
{ |
|
return reinterpret_cast<PyObject*>(this->p); |
|
} |
|
Greenlet* operator->() const noexcept; |
|
operator Greenlet*() const noexcept; |
|
}; |
|
|
|
typedef _BorrowedGreenlet<PyGreenlet> BorrowedGreenlet; |
|
|
|
template<typename T, TypeChecker TC> |
|
_OwnedGreenlet<T, TC>::_OwnedGreenlet(const BorrowedGreenlet& other) |
|
: OwnedReference<T, TC>(reinterpret_cast<T*>(other.borrow())) |
|
{ |
|
Py_XINCREF(this->p); |
|
} |
|
|
|
|
|
class BorrowedMainGreenlet |
|
: public _BorrowedGreenlet<PyGreenlet, MainGreenletExactChecker> |
|
{ |
|
public: |
|
BorrowedMainGreenlet(const OwnedMainGreenlet& it) : |
|
_BorrowedGreenlet<PyGreenlet, MainGreenletExactChecker>(it.borrow()) |
|
{} |
|
BorrowedMainGreenlet(PyGreenlet* it=nullptr) |
|
: _BorrowedGreenlet<PyGreenlet, MainGreenletExactChecker>(it) |
|
{} |
|
}; |
|
|
|
template<typename T, TypeChecker TC> |
|
_OwnedGreenlet<T, TC>& _OwnedGreenlet<T, TC>::operator=(const BorrowedGreenlet& other) |
|
{ |
|
return this->operator=(other.borrow()); |
|
} |
|
|
|
|
|
class ImmortalObject : public PyObjectPointer<> |
|
{ |
|
private: |
|
G_NO_ASSIGNMENT_OF_CLS(ImmortalObject); |
|
public: |
|
explicit ImmortalObject(PyObject* it) : PyObjectPointer<>(it) |
|
{ |
|
} |
|
|
|
ImmortalObject(const ImmortalObject& other) |
|
: PyObjectPointer<>(other.p) |
|
{ |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
ImmortalObject& operator=(PyObject* it) |
|
{ |
|
assert(this->p == nullptr); |
|
this->p = it; |
|
return *this; |
|
} |
|
|
|
static ImmortalObject consuming(PyObject* it) |
|
{ |
|
return ImmortalObject(it); |
|
} |
|
|
|
inline operator PyObject*() const |
|
{ |
|
return this->p; |
|
} |
|
}; |
|
|
|
class ImmortalString : public ImmortalObject |
|
{ |
|
private: |
|
G_NO_COPIES_OF_CLS(ImmortalString); |
|
const char* str; |
|
public: |
|
ImmortalString(const char* const str) : |
|
ImmortalObject(str ? Require(PyUnicode_InternFromString(str)) : nullptr) |
|
{ |
|
this->str = str; |
|
} |
|
|
|
inline ImmortalString& operator=(const char* const str) |
|
{ |
|
if (!this->p) { |
|
this->p = Require(PyUnicode_InternFromString(str)); |
|
this->str = str; |
|
} |
|
else { |
|
assert(this->str == str); |
|
} |
|
return *this; |
|
} |
|
|
|
inline operator std::string() const |
|
{ |
|
return this->str; |
|
} |
|
|
|
}; |
|
|
|
class ImmortalEventName : public ImmortalString |
|
{ |
|
private: |
|
G_NO_COPIES_OF_CLS(ImmortalEventName); |
|
public: |
|
ImmortalEventName(const char* const str) : ImmortalString(str) |
|
{} |
|
}; |
|
|
|
class ImmortalException : public ImmortalObject |
|
{ |
|
private: |
|
G_NO_COPIES_OF_CLS(ImmortalException); |
|
public: |
|
ImmortalException(const char* const name, PyObject* base=nullptr) : |
|
ImmortalObject(name |
|
|
|
? Require(PyErr_NewException((char*)name, base, nullptr)) |
|
: nullptr) |
|
{} |
|
|
|
inline bool PyExceptionMatches() const |
|
{ |
|
return PyErr_ExceptionMatches(this->p) > 0; |
|
} |
|
|
|
}; |
|
|
|
template<typename T, TypeChecker TC> |
|
inline OwnedObject PyObjectPointer<T, TC>::PyStr() const noexcept |
|
{ |
|
if (!this->p) { |
|
return OwnedObject(); |
|
} |
|
return OwnedObject::consuming(PyObject_Str(reinterpret_cast<PyObject*>(this->p))); |
|
} |
|
|
|
template<typename T, TypeChecker TC> |
|
inline const std::string PyObjectPointer<T, TC>::as_str() const noexcept |
|
{ |
|
|
|
if (this->p) { |
|
|
|
|
|
|
|
OwnedObject py_str = this->PyStr(); |
|
if (!py_str) { |
|
return "(nil)"; |
|
} |
|
return PyUnicode_AsUTF8(py_str.borrow()); |
|
} |
|
return "(nil)"; |
|
} |
|
|
|
template<typename T, TypeChecker TC> |
|
inline OwnedObject PyObjectPointer<T, TC>::PyGetAttr(const ImmortalObject& name) const noexcept |
|
{ |
|
assert(this->p); |
|
return OwnedObject::consuming(PyObject_GetAttr(reinterpret_cast<PyObject*>(this->p), name)); |
|
} |
|
|
|
template<typename T, TypeChecker TC> |
|
inline OwnedObject PyObjectPointer<T, TC>::PyRequireAttr(const char* const name) const |
|
{ |
|
assert(this->p); |
|
return OwnedObject::consuming(Require(PyObject_GetAttrString(this->p, name), name)); |
|
} |
|
|
|
template<typename T, TypeChecker TC> |
|
inline OwnedObject PyObjectPointer<T, TC>::PyRequireAttr(const ImmortalString& name) const |
|
{ |
|
assert(this->p); |
|
return OwnedObject::consuming(Require( |
|
PyObject_GetAttr( |
|
reinterpret_cast<PyObject*>(this->p), |
|
name |
|
), |
|
name |
|
)); |
|
} |
|
|
|
template<typename T, TypeChecker TC> |
|
inline OwnedObject PyObjectPointer<T, TC>::PyCall(const BorrowedObject& arg) const |
|
{ |
|
return this->PyCall(arg.borrow()); |
|
} |
|
|
|
template<typename T, TypeChecker TC> |
|
inline OwnedObject PyObjectPointer<T, TC>::PyCall(PyGreenlet* arg) const |
|
{ |
|
return this->PyCall(reinterpret_cast<PyObject*>(arg)); |
|
} |
|
|
|
template<typename T, TypeChecker TC> |
|
inline OwnedObject PyObjectPointer<T, TC>::PyCall(PyObject* arg) const |
|
{ |
|
assert(this->p); |
|
return OwnedObject::consuming(PyObject_CallFunctionObjArgs(this->p, arg, NULL)); |
|
} |
|
|
|
template<typename T, TypeChecker TC> |
|
inline OwnedObject PyObjectPointer<T, TC>::PyCall(const BorrowedObject args, |
|
const BorrowedObject kwargs) const |
|
{ |
|
assert(this->p); |
|
return OwnedObject::consuming(PyObject_Call(this->p, args, kwargs)); |
|
} |
|
|
|
template<typename T, TypeChecker TC> |
|
inline OwnedObject PyObjectPointer<T, TC>::PyCall(const OwnedObject& args, |
|
const OwnedObject& kwargs) const |
|
{ |
|
assert(this->p); |
|
return OwnedObject::consuming(PyObject_Call(this->p, args.borrow(), kwargs.borrow())); |
|
} |
|
|
|
inline void |
|
ListChecker(void * p) |
|
{ |
|
if (!p) { |
|
return; |
|
} |
|
if (!PyList_Check(p)) { |
|
throw TypeError("Expected a list"); |
|
} |
|
} |
|
|
|
class OwnedList : public OwnedReference<PyObject, ListChecker> |
|
{ |
|
private: |
|
G_NO_ASSIGNMENT_OF_CLS(OwnedList); |
|
public: |
|
|
|
explicit OwnedList(const OwnedObject& other) |
|
: OwnedReference<PyObject, ListChecker>(other) |
|
{ |
|
} |
|
|
|
OwnedList& operator=(const OwnedObject& other) |
|
{ |
|
if (other && PyList_Check(other.p)) { |
|
|
|
|
|
PyObject* new_ptr = other.p; |
|
Py_INCREF(new_ptr); |
|
Py_XDECREF(this->p); |
|
this->p = new_ptr; |
|
} |
|
else { |
|
|
|
|
|
Py_XDECREF(this->p); |
|
this->p = nullptr; |
|
} |
|
return *this; |
|
} |
|
|
|
inline bool empty() const |
|
{ |
|
return PyList_GET_SIZE(p) == 0; |
|
} |
|
|
|
inline Py_ssize_t size() const |
|
{ |
|
return PyList_GET_SIZE(p); |
|
} |
|
|
|
inline BorrowedObject at(const Py_ssize_t index) const |
|
{ |
|
return PyList_GET_ITEM(p, index); |
|
} |
|
|
|
inline void clear() |
|
{ |
|
PyList_SetSlice(p, 0, PyList_GET_SIZE(p), NULL); |
|
} |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CreatedModule : public PyObjectPointer<> |
|
{ |
|
private: |
|
G_NO_COPIES_OF_CLS(CreatedModule); |
|
public: |
|
CreatedModule(PyModuleDef& mod_def) : PyObjectPointer<>( |
|
Require(PyModule_Create(&mod_def))) |
|
{ |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void PyAddObject(const char* name, const long new_bool) |
|
{ |
|
OwnedObject p = OwnedObject::consuming(Require(PyBool_FromLong(new_bool))); |
|
this->PyAddObject(name, p); |
|
} |
|
|
|
void PyAddObject(const char* name, const OwnedObject& new_object) |
|
{ |
|
|
|
|
|
|
|
this->PyAddObject(name, new_object.borrow()); |
|
} |
|
|
|
void PyAddObject(const char* name, const ImmortalObject& new_object) |
|
{ |
|
this->PyAddObject(name, new_object.borrow()); |
|
} |
|
|
|
void PyAddObject(const char* name, PyTypeObject& type) |
|
{ |
|
this->PyAddObject(name, reinterpret_cast<PyObject*>(&type)); |
|
} |
|
|
|
void PyAddObject(const char* name, PyObject* new_object) |
|
{ |
|
Py_INCREF(new_object); |
|
try { |
|
Require(PyModule_AddObject(this->p, name, new_object)); |
|
} |
|
catch (const PyErrOccurred&) { |
|
Py_DECREF(p); |
|
throw; |
|
} |
|
} |
|
}; |
|
|
|
class PyErrFetchParam : public PyObjectPointer<> |
|
{ |
|
|
|
|
|
private: |
|
G_NO_COPIES_OF_CLS(PyErrFetchParam); |
|
public: |
|
|
|
|
|
|
|
PyErrFetchParam() : PyObjectPointer<>(nullptr) |
|
{ |
|
} |
|
|
|
PyObject** operator&() |
|
{ |
|
return &this->p; |
|
} |
|
|
|
|
|
|
|
|
|
operator PyObject**() |
|
{ |
|
return &this->p; |
|
} |
|
|
|
|
|
|
|
|
|
inline PyObject* relinquish_ownership() |
|
{ |
|
PyObject* result = this->p; |
|
this->p = nullptr; |
|
return result; |
|
} |
|
|
|
~PyErrFetchParam() |
|
{ |
|
Py_XDECREF(p); |
|
} |
|
}; |
|
|
|
class OwnedErrPiece : public OwnedObject |
|
{ |
|
private: |
|
|
|
public: |
|
|
|
OwnedErrPiece(PyObject* p=nullptr) : OwnedObject(p) |
|
{ |
|
this->acquire(); |
|
} |
|
|
|
PyObject** operator&() |
|
{ |
|
return &this->p; |
|
} |
|
|
|
inline operator PyObject*() const |
|
{ |
|
return this->p; |
|
} |
|
|
|
operator PyTypeObject*() const |
|
{ |
|
return reinterpret_cast<PyTypeObject*>(this->p); |
|
} |
|
}; |
|
|
|
class PyErrPieces |
|
{ |
|
private: |
|
OwnedErrPiece type; |
|
OwnedErrPiece instance; |
|
OwnedErrPiece traceback; |
|
bool restored; |
|
public: |
|
|
|
|
|
PyErrPieces(PyObject* t, PyObject* v, PyObject* tb) : |
|
type(t), |
|
instance(v), |
|
traceback(tb), |
|
restored(0) |
|
{ |
|
this->normalize(); |
|
} |
|
|
|
PyErrPieces() : |
|
restored(0) |
|
{ |
|
|
|
|
|
|
|
PyErrFetchParam t, v, tb; |
|
PyErr_Fetch(&t, &v, &tb); |
|
type.steal(t.relinquish_ownership()); |
|
instance.steal(v.relinquish_ownership()); |
|
traceback.steal(tb.relinquish_ownership()); |
|
} |
|
|
|
void PyErrRestore() |
|
{ |
|
|
|
assert(!this->restored); |
|
this->restored = true; |
|
PyErr_Restore( |
|
this->type.relinquish_ownership(), |
|
this->instance.relinquish_ownership(), |
|
this->traceback.relinquish_ownership()); |
|
assert(!this->type && !this->instance && !this->traceback); |
|
} |
|
|
|
private: |
|
void normalize() |
|
{ |
|
|
|
|
|
if (traceback.is_None()) { |
|
traceback = nullptr; |
|
} |
|
|
|
if (traceback && !PyTraceBack_Check(traceback.borrow())) { |
|
throw PyErrOccurred(PyExc_TypeError, |
|
"throw() third argument must be a traceback object"); |
|
} |
|
|
|
if (PyExceptionClass_Check(type)) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
PyErr_NormalizeException(&type, &instance, &traceback); |
|
|
|
} |
|
else if (PyExceptionInstance_Check(type)) { |
|
|
|
|
|
|
|
|
|
if (instance && !instance.is_None()) { |
|
throw PyErrOccurred( |
|
PyExc_TypeError, |
|
"instance exception may not have a separate value"); |
|
} |
|
|
|
this->instance = this->type; |
|
this->type = PyExceptionInstance_Class(instance.borrow()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
else { |
|
|
|
PyErr_Format(PyExc_TypeError, |
|
"exceptions must be classes, or instances, not %s", |
|
Py_TYPE(type.borrow())->tp_name); |
|
throw PyErrOccurred(); |
|
} |
|
} |
|
}; |
|
|
|
|
|
class PyArgParseParam : public BorrowedObject |
|
{ |
|
private: |
|
G_NO_COPIES_OF_CLS(PyArgParseParam); |
|
public: |
|
explicit PyArgParseParam(PyObject* p=nullptr) : BorrowedObject(p) |
|
{ |
|
} |
|
|
|
inline PyObject** operator&() |
|
{ |
|
return &this->p; |
|
} |
|
}; |
|
|
|
};}; |
|
|
|
#endif |
|
|