summaryrefslogtreecommitdiff
path: root/venv/lib/python3.11/site-packages/greenlet/greenlet_refs.hpp
diff options
context:
space:
mode:
authorcyfraeviolae <cyfraeviolae>2024-04-03 03:10:44 -0400
committercyfraeviolae <cyfraeviolae>2024-04-03 03:10:44 -0400
commit6d7ba58f880be618ade07f8ea080fe8c4bf8a896 (patch)
treeb1c931051ffcebd2bd9d61d98d6233ffa289bbce /venv/lib/python3.11/site-packages/greenlet/greenlet_refs.hpp
parent4f884c9abc32990b4061a1bb6997b4b37e58ea0b (diff)
venv
Diffstat (limited to 'venv/lib/python3.11/site-packages/greenlet/greenlet_refs.hpp')
-rw-r--r--venv/lib/python3.11/site-packages/greenlet/greenlet_refs.hpp1100
1 files changed, 1100 insertions, 0 deletions
diff --git a/venv/lib/python3.11/site-packages/greenlet/greenlet_refs.hpp b/venv/lib/python3.11/site-packages/greenlet/greenlet_refs.hpp
new file mode 100644
index 0000000..72ee68b
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/greenlet/greenlet_refs.hpp
@@ -0,0 +1,1100 @@
+#ifndef GREENLET_REFS_HPP
+#define GREENLET_REFS_HPP
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+//#include "greenlet_internal.hpp"
+#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
+ {
+ // Type checkers throw a TypeError if the argument is not
+ // null, and isn't of the required Python type.
+ // (We can't use most of the defined type checkers
+ // like PyList_Check, etc, directly, because they are
+ // implemented as macros.)
+ typedef void (*TypeChecker)(void*);
+
+ G_FP_TMPL_STATIC inline void
+ NoOpChecker(void*)
+ {
+ return;
+ }
+
+ G_FP_TMPL_STATIC inline void
+ GreenletChecker(void *p)
+ {
+ if (!p) {
+ return;
+ }
+
+ PyTypeObject* typ = Py_TYPE(p);
+ // fast, common path. (PyObject_TypeCheck is a macro or
+ // static inline function, and it also does a
+ // direct comparison of the type pointers, but its fast
+ // path only handles one type)
+ 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);
+ }
+ }
+
+ G_FP_TMPL_STATIC inline 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;
+
+ G_FP_TMPL_STATIC inline 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 {
+ // A set of classes to make reference counting rules in python
+ // code explicit.
+ //
+ // Rules of use:
+ // (1) Functions returning a new reference that the caller of the
+ // function is expected to dispose of should return a
+ // ``OwnedObject`` object. This object automatically releases its
+ // reference when it goes out of scope. It works like a ``std::shared_ptr``
+ // and can be copied or used as a function parameter (but don't do
+ // that). Note that constructing a ``OwnedObject`` from a
+ // PyObject* steals the reference.
+ // (2) Parameters to functions should be either a
+ // ``OwnedObject&``, or, more generally, a ``PyObjectPointer&``.
+ // If the function needs to create its own new reference, it can
+ // do so by copying to a local ``OwnedObject``.
+ // (3) Functions returning an existing pointer that is NOT
+ // incref'd, and which the caller MUST NOT decref,
+ // should return a ``BorrowedObject``.
+
+ //
+ // For a class with a single pointer member, whose constructor
+ // does nothing but copy a pointer parameter into the member, and
+ // which can then be converted back to the pointer type, compilers
+ // generate code that's the same as just passing the pointer.
+ // That is, func(BorrowedObject x) called like ``PyObject* p =
+ // ...; f(p)`` has 0 overhead. Similarly, they "unpack" to the
+ // pointer type with 0 overhead.
+ //
+ // If there are no virtual functions, no complex inheritance (maybe?) and
+ // no destructor, these can be directly used as parameters in
+ // Python callbacks like tp_init: the layout is the same as a
+ // single pointer. Only subclasses with trivial constructors that
+ // do nothing but set the single pointer member are safe to use
+ // that way.
+
+
+ // This is the base class for things that can be done with a
+ // PyObject pointer. It assumes nothing about memory management.
+ // NOTE: Nothing is virtual, so subclasses shouldn't add new
+ // storage fields or try to override these methods.
+ template <typename T=PyObject, TypeChecker TC=NoOpChecker>
+ class PyObjectPointer
+ {
+ public:
+ typedef T PyType;
+ protected:
+ T* p;
+ public:
+ explicit PyObjectPointer(T* it=nullptr) : p(it)
+ {
+ TC(p);
+ }
+
+ // We don't allow automatic casting to PyObject* at this
+ // level, because then we could be passed to Py_DECREF/INCREF,
+ // but we want nothing to do with memory management. If you
+ // know better, then you can use the get() method, like on a
+ // std::shared_ptr. Except we name it borrow() to clarify that
+ // if this is a reference-tracked object, the pointer you get
+ // back will go away when the object does.
+ // TODO: This should probably not exist here, but be moved
+ // down to relevant sub-types.
+
+ inline T* borrow() const noexcept
+ {
+ return this->p;
+ }
+
+ PyObject* borrow_o() const noexcept
+ {
+ return reinterpret_cast<PyObject*>(this->p);
+ }
+
+ inline T* operator->() const noexcept
+ {
+ return this->p;
+ }
+
+ bool is_None() const noexcept
+ {
+ return this->p == Py_None;
+ }
+
+ inline 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 p != nullptr;
+ }
+
+ inline Py_ssize_t REFCNT() const noexcept
+ {
+ return p ? Py_REFCNT(p) : -42;
+ }
+
+ inline 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 ;
+ // PyObject_Call(this, args, kwargs);
+ 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 void* const rhs) noexcept
+ {
+ return lhs.borrow_o() == 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:
+
+ // Constructors
+
+ 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);
+ }
+
+ // It would be good to make use of the C++11 distinction
+ // between move and copy operations, e.g., constructing from a
+ // pointer should be a move operation.
+ // In the common case of ``OwnedObject x = Py_SomeFunction()``,
+ // the call to the copy constructor will be elided completely.
+ 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);
+ }
+
+ // We can assign from exactly our type without any extra checking
+ 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;
+ }
+
+ // We can assign from an arbitrary reference type
+ // if it passes our check.
+ 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
+ {
+ // Return a new reference.
+ // TODO: This may go away when we have reference objects
+ // throughout the code.
+ Py_XINCREF(this->p);
+ return this->p;
+ }
+
+ // Nothing else declares a destructor, we're the leaf, so we
+ // should be able to get away without virtual.
+ ~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:
+ // Consumes the reference. Only use this
+ // for API return values.
+ 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);
+ // Steals a reference.
+ 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:
+ // Allow implicit creation from PyObject* pointers as we
+ // transition to using these classes. Also allow automatic
+ // conversion to PyObject* for passing to C API calls and even
+ // for Py_INCREF/DECREF, because we ourselves do no memory management.
+ 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;
+ //typedef BorrowedReference<PyGreenlet> BorrowedGreenlet;
+
+ 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);
+
+ // We get one of these for PyGreenlet, but one for PyObject
+ // is handy as well
+ operator PyObject*() const
+ {
+ return reinterpret_cast<PyObject*>(this->p);
+ }
+ inline Greenlet* operator->() const noexcept;
+ inline 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)
+ {
+
+ }
+
+ /**
+ * Become the new owner of the object. Does not change the
+ * reference count.
+ */
+ 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
+ // Python 2.7 isn't const correct
+ ? 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
+ {
+ // NOTE: This is not Python exception safe.
+ if (this->p) {
+ // The Python APIs return a cached char* value that's only valid
+ // as long as the original object stays around, and we're
+ // about to (probably) toss it. Hence the copy to std::string.
+ 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()));
+ }
+
+ G_FP_TMPL_STATIC 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:
+ // TODO: Would like to use move.
+ explicit OwnedList(const OwnedObject& other)
+ : OwnedReference<PyObject, ListChecker>(other)
+ {
+ }
+
+ OwnedList& operator=(const OwnedObject& other)
+ {
+ if (other && PyList_Check(other.p)) {
+ // Valid list. Own a new reference to it, discard the
+ // reference to what we did own.
+ PyObject* new_ptr = other.p;
+ Py_INCREF(new_ptr);
+ Py_XDECREF(this->p);
+ this->p = new_ptr;
+ }
+ else {
+ // Either the other object was NULL (an error) or it
+ // wasn't a list. Either way, we're now invalidated.
+ 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);
+ }
+ };
+
+ // Use this to represent the module object used at module init
+ // time.
+ // This could either be a borrowed (Py2) or new (Py3) reference;
+ // either way, we don't want to do any memory management
+ // on it here, Python itself will handle that.
+ // XXX: Actually, that's not quite right. On Python 3, if an
+ // exception occurs before we return to the interpreter, this will
+ // leak; but all previous versions also had that problem.
+ class CreatedModule : public PyObjectPointer<>
+ {
+ private:
+ G_NO_COPIES_OF_CLS(CreatedModule);
+ public:
+ CreatedModule(PyModuleDef& mod_def) : PyObjectPointer<>(
+ Require(PyModule_Create(&mod_def)))
+ {
+ }
+
+ // PyAddObject(): Add a reference to the object to the module.
+ // On return, the reference count of the object is unchanged.
+ //
+ // The docs warn that PyModule_AddObject only steals the
+ // reference on success, so if it fails after we've incref'd
+ // or allocated, we're responsible for the decref.
+ 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)
+ {
+ // The caller already owns a reference they will decref
+ // when their variable goes out of scope, we still need to
+ // incref/decref.
+ 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<>
+ {
+ // Not an owned object, because we can't be initialized with
+ // one, and we only sometimes acquire ownership.
+ private:
+ G_NO_COPIES_OF_CLS(PyErrFetchParam);
+ public:
+ // To allow declaring these and passing them to
+ // PyErr_Fetch we implement the empty constructor,
+ // and the address operator.
+ PyErrFetchParam() : PyObjectPointer<>(nullptr)
+ {
+ }
+
+ PyObject** operator&()
+ {
+ return &this->p;
+ }
+
+ // This allows us to pass one directly without the &,
+ // BUT it has higher precedence than the bool operator
+ // if it's not explicit.
+ operator PyObject**()
+ {
+ return &this->p;
+ }
+
+ // We don't want to be able to pass these to Py_DECREF and
+ // such so we don't have the implicit PyObject* conversion.
+
+ inline PyObject* relinquish_ownership()
+ {
+ PyObject* result = this->p;
+ this->p = nullptr;
+ return result;
+ }
+
+ ~PyErrFetchParam()
+ {
+ Py_XDECREF(p);
+ }
+ };
+
+ class OwnedErrPiece : public OwnedObject
+ {
+ private:
+
+ public:
+ // Unlike OwnedObject, this increments the refcount.
+ 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:
+ // Takes new references; if we're destroyed before
+ // restoring the error, we drop the references.
+ PyErrPieces(PyObject* t, PyObject* v, PyObject* tb) :
+ type(t),
+ instance(v),
+ traceback(tb),
+ restored(0)
+ {
+ this->normalize();
+ }
+
+ PyErrPieces() :
+ restored(0)
+ {
+ // PyErr_Fetch transfers ownership to us, so
+ // we don't actually need to INCREF; but we *do*
+ // need to DECREF if we're not restored.
+ 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()
+ {
+ // can only do this once
+ 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()
+ {
+ // First, check the traceback argument, replacing None,
+ // with NULL
+ 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)) {
+ // If we just had a type, we'll now have a type and
+ // instance.
+ // The type's refcount will have gone up by one
+ // because of the instance and the instance will have
+ // a refcount of one. Either way, we owned, and still
+ // do own, exactly one reference.
+ PyErr_NormalizeException(&type, &instance, &traceback);
+
+ }
+ else if (PyExceptionInstance_Check(type)) {
+ /* Raising an instance --- usually that means an
+ object that is a subclass of BaseException, but on
+ Python 2, that can also mean an arbitrary old-style
+ object. The value should be a dummy. */
+ if (instance && !instance.is_None()) {
+ throw PyErrOccurred(
+ PyExc_TypeError,
+ "instance exception may not have a separate value");
+ }
+ /* Normalize to raise <class>, <instance> */
+ this->instance = this->type;
+ this->type = PyExceptionInstance_Class(instance.borrow());
+
+ /*
+ It would be tempting to do this:
+
+ Py_ssize_t type_count = Py_REFCNT(Py_TYPE(instance.borrow()));
+ this->type = PyExceptionInstance_Class(instance.borrow());
+ assert(this->type.REFCNT() == type_count + 1);
+
+ But that doesn't work on Python 2 in the case of
+ old-style instances: The result of Py_TYPE is going to
+ be the global shared <type instance> that all
+ old-style classes have, while the return of Instance_Class()
+ will be the Python-level class object. The two are unrelated.
+ */
+ }
+ else {
+ /* Not something you can raise. throw() fails. */
+ PyErr_Format(PyExc_TypeError,
+ "exceptions must be classes, or instances, not %s",
+ Py_TYPE(type.borrow())->tp_name);
+ throw PyErrOccurred();
+ }
+ }
+ };
+
+ // PyArg_Parse's O argument returns a borrowed reference.
+ 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