about summary refs log tree commit diff
path: root/.venv/lib/python3.12/site-packages/greenlet/greenlet_refs.hpp
diff options
context:
space:
mode:
authorS. Solomon Darnell2025-03-28 21:52:21 -0500
committerS. Solomon Darnell2025-03-28 21:52:21 -0500
commit4a52a71956a8d46fcb7294ac71734504bb09bcc2 (patch)
treeee3dc5af3b6313e921cd920906356f5d4febc4ed /.venv/lib/python3.12/site-packages/greenlet/greenlet_refs.hpp
parentcc961e04ba734dd72309fb548a2f97d67d578813 (diff)
downloadgn-ai-master.tar.gz
two version of R2R are here HEAD master
Diffstat (limited to '.venv/lib/python3.12/site-packages/greenlet/greenlet_refs.hpp')
-rw-r--r--.venv/lib/python3.12/site-packages/greenlet/greenlet_refs.hpp1118
1 files changed, 1118 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/greenlet/greenlet_refs.hpp b/.venv/lib/python3.12/site-packages/greenlet/greenlet_refs.hpp
new file mode 100644
index 00000000..b7e5e3f2
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/greenlet/greenlet_refs.hpp
@@ -0,0 +1,1118 @@
+#ifndef GREENLET_REFS_HPP
+#define GREENLET_REFS_HPP
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+
+#include <string>
+
+//#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*);
+
+        void
+        NoOpChecker(void*)
+        {
+            return;
+        }
+
+        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);
+            }
+        }
+
+        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 {
+    // 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``.
+
+    // XXX: The following two paragraphs do not hold for all platforms.
+    // Notably, 32-bit PPC Linux passes structs by reference, not by
+    // value, so this actually doesn't work. (Although that's the only
+    // platform that doesn't work on.) DO NOT ATTEMPT IT. The
+    // unfortunate consequence of that is that the slots which we
+    // *know* are already type safe will wind up calling the type
+    // checker function (when we had the slots accepting
+    // BorrowedGreenlet, this was bypassed), so this slows us down.
+    // TODO: Optimize this again.
+
+    // 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:
+        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.
+
+        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 ;
+        // 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 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:
+
+        // 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);
+        }
+        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)
+        {
+
+        }
+
+        /**
+         * 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()));
+    }
+
+    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