diff options
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.hpp | 1100 |
1 files changed, 0 insertions, 1100 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 deleted file mode 100644 index 72ee68b..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/greenlet_refs.hpp +++ /dev/null @@ -1,1100 +0,0 @@ -#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 |