Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
greenlet_refs.hpp1200 linesDownload Raw Back to greenlet
1#ifndef GREENLET_REFS_HPP
2#define GREENLET_REFS_HPP
3
4#define PY_SSIZE_T_CLEAN
5#include <Python.h>
6
7#include <string>
8
9//#include "greenlet_internal.hpp"
10#include "greenlet_compiler_compat.hpp"
11#include "greenlet_cpython_compat.hpp"
12#include "greenlet_exceptions.hpp"
13
14struct _greenlet;
15struct _PyMainGreenlet;
16
17typedef struct _greenlet PyGreenlet;
18extern PyTypeObject PyGreenlet_Type;
19
20
21#ifdef  GREENLET_USE_STDIO
22#include <iostream>
23using std::cerr;
24using std::endl;
25#endif
26
27namespace greenlet
28{
29    class Greenlet;
30
31    static inline bool
32    IsShuttingDown()
33    {
34        // This used to check a flag set by an ``atexit`` callback.
35        // This was wrong: the interpreter is still fully functional
36        // while *all* atexit callbacks are run, and it is perfectly
37        // valid for an atexit callback that runs after our atexit
38        // callback (i.e., registered first/before ours) to want to
39        // make use of greenlet services --- this comes up easily with
40        // gevent monkey-patching. Almost immediately after atexit callbacks,
41        // and before any destructive action is taken, Python arranges
42        // for Py_IsFinalizing to become true.
43
44        // It may see me could potentially tighten this check even more (and
45        // eliminate a function call) by setting a flag in a
46        // destructor function for our PyCapsule object (_C_API) to
47        // determine when we're shutting down. ``Py_IsFinalizing``
48        // becomes true relatively early in the shutdown process,
49        // while Capsule destructor functions only run when the module
50        // has actually been torn down --- well, when all of its dicts are
51        // cleared and collected; recall that because we use
52        // single-phase init, there is a "hidden" copy of the module
53        // dict kept by CPython internals used to re-populate a module
54        // if greenlet is imported twice, so Python code can't trigger
55        // C_API to get GC'd early without seriously poking at CPython
56        // internals, e.g., by using `gc.get_referrers` to find the
57        // hidden dict. However, C extensions could have INCREF the
58        // capsule object and prevent it from *ever* getting torn
59        // down, so this isn't reliable.
60
61        // We could probably be even "smarter" and replace values in
62        // _PyGreenlet_API with different values at destruction time.
63        // For the PyObject* returning APIs, we could replace them
64        // with versions that set an exception and return null --- the
65        // benefit being that we don't have to include a
66        // Py_IsFinalizing() call in the normal path; int returning
67        // APIs would be handled on a case-by-case basis; unclear what
68        // to do with the types. This is of questionable benefit
69        // though because by the time our destructor is called, our
70        // module is about to be destroyed which may take our
71        // allocated storage with it (if CPython ever dynamically
72        // unloads loaded shared libraries, which as of 3.14 it never
73        // does).
74
75        return Py_IsFinalizing();
76    }
77
78    namespace refs
79    {
80        // Type checkers throw a TypeError if the argument is not
81        // null, and isn't of the required Python type.
82        // (We can't use most of the defined type checkers
83        // like PyList_Check, etc, directly, because they are
84        // implemented as macros.)
85        typedef void (*TypeChecker)(void*);
86
87        void
88        NoOpChecker(void*)
89        {
90            return;
91        }
92
93        void
94        GreenletChecker(void *p)
95        {
96            if (!p) {
97                return;
98            }
99            if (IsShuttingDown()) {
100                return;
101            }
102
103            PyTypeObject* typ = Py_TYPE(p);
104            // fast, common path. (PyObject_TypeCheck is a macro or
105            // static inline function, and it also does a
106            // direct comparison of the type pointers, but its fast
107            // path only handles one type)
108            if (typ == &PyGreenlet_Type) {
109                return;
110            }
111
112            if (!PyObject_TypeCheck(p, &PyGreenlet_Type)) {
113                std::string err("GreenletChecker: Expected any type of greenlet, not ");
114                err += Py_TYPE(p)->tp_name;
115                throw TypeError(err);
116            }
117        }
118
119        void
120        MainGreenletExactChecker(void *p);
121
122        template <typename T, TypeChecker>
123        class PyObjectPointer;
124
125        template<typename T, TypeChecker>
126        class OwnedReference;
127
128
129        template<typename T, TypeChecker>
130        class BorrowedReference;
131
132        typedef BorrowedReference<PyObject, NoOpChecker> BorrowedObject;
133        typedef OwnedReference<PyObject, NoOpChecker> OwnedObject;
134
135        class ImmortalObject;
136        class ImmortalString;
137
138        template<typename T, TypeChecker TC>
139        class _OwnedGreenlet;
140
141        typedef _OwnedGreenlet<PyGreenlet, GreenletChecker> OwnedGreenlet;
142        typedef _OwnedGreenlet<PyGreenlet, MainGreenletExactChecker> OwnedMainGreenlet;
143
144        template<typename T, TypeChecker TC>
145        class _BorrowedGreenlet;
146
147        typedef _BorrowedGreenlet<PyGreenlet, GreenletChecker> BorrowedGreenlet;
148
149        void
150        ContextExactChecker(void *p)
151        {
152            if (!p) {
153                return;
154            }
155            if (IsShuttingDown()) {
156                return;
157            }
158            if (!PyContext_CheckExact(p)) {
159                throw TypeError(
160                    "greenlet context must be a contextvars.Context or None"
161                );
162            }
163        }
164
165        typedef OwnedReference<PyObject, ContextExactChecker> OwnedContext;
166    }
167}
168
169namespace greenlet {
170
171
172    namespace refs {
173    // A set of classes to make reference counting rules in python
174    // code explicit.
175    //
176    // Rules of use:
177    // (1) Functions returning a new reference that the caller of the
178    // function is expected to dispose of should return a
179    // ``OwnedObject`` object. This object automatically releases its
180    // reference when it goes out of scope. It works like a ``std::shared_ptr``
181    // and can be copied or used as a function parameter (but don't do
182    // that). Note that constructing a ``OwnedObject`` from a
183    // PyObject* steals the reference.
184    // (2) Parameters to functions should be either a
185    // ``OwnedObject&``, or, more generally, a ``PyObjectPointer&``.
186    // If the function needs to create its own new reference, it can
187    // do so by copying to a local ``OwnedObject``.
188    // (3) Functions returning an existing pointer that is NOT
189    // incref'd, and which the caller MUST NOT decref,
190    // should return a ``BorrowedObject``.
191
192    // XXX: The following two paragraphs do not hold for all platforms.
193    // Notably, 32-bit PPC Linux passes structs by reference, not by
194    // value, so this actually doesn't work. (Although that's the only
195    // platform that doesn't work on.) DO NOT ATTEMPT IT. The
196    // unfortunate consequence of that is that the slots which we
197    // *know* are already type safe will wind up calling the type
198    // checker function (when we had the slots accepting
199    // BorrowedGreenlet, this was bypassed), so this slows us down.
200    // TODO: Optimize this again.
201
202    // For a class with a single pointer member, whose constructor
203    // does nothing but copy a pointer parameter into the member, and
204    // which can then be converted back to the pointer type, compilers
205    // generate code that's the same as just passing the pointer.
206    // That is, func(BorrowedObject x) called like ``PyObject* p =
207    // ...; f(p)`` has 0 overhead. Similarly, they "unpack" to the
208    // pointer type with 0 overhead.
209    //
210    // If there are no virtual functions, no complex inheritance (maybe?) and
211    // no destructor, these can be directly used as parameters in
212    // Python callbacks like tp_init: the layout is the same as a
213    // single pointer. Only subclasses with trivial constructors that
214    // do nothing but set the single pointer member are safe to use
215    // that way.
216
217
218    // This is the base class for things that can be done with a
219    // PyObject pointer. It assumes nothing about memory management.
220    // NOTE: Nothing is virtual, so subclasses shouldn't add new
221    // storage fields or try to override these methods.
222    template <typename T=PyObject, TypeChecker TC=NoOpChecker>
223    class PyObjectPointer
224    {
225    public:
226        typedef T PyType;
227    protected:
228        T* p;
229    public:
230        PyObjectPointer(T* it=nullptr) : p(it)
231        {
232            TC(p);
233        }
234
235        // We don't allow automatic casting to PyObject* at this
236        // level, because then we could be passed to Py_DECREF/INCREF,
237        // but we want nothing to do with memory management. If you
238        // know better, then you can use the get() method, like on a
239        // std::shared_ptr. Except we name it borrow() to clarify that
240        // if this is a reference-tracked object, the pointer you get
241        // back will go away when the object does.
242        // TODO: This should probably not exist here, but be moved
243        // down to relevant sub-types.
244
245        T* borrow() const noexcept
246        {
247            return this->p;
248        }
249
250        PyObject* borrow_o() const noexcept
251        {
252            return reinterpret_cast<PyObject*>(this->p);
253        }
254
255         T* operator->() const noexcept
256        {
257            return this->p;
258        }
259
260        bool is_None() const noexcept
261        {
262            return this->p == Py_None;
263        }
264
265        PyObject* acquire_or_None() const noexcept
266        {
267            PyObject* result = this->p ? reinterpret_cast<PyObject*>(this->p) : Py_None;
268            Py_INCREF(result);
269            return result;
270        }
271
272        explicit operator bool() const noexcept
273        {
274            return this->p != nullptr;
275        }
276
277        bool operator!() const noexcept
278        {
279            return this->p == nullptr;
280        }
281
282        Py_ssize_t REFCNT() const noexcept
283        {
284            return p ? Py_REFCNT(p) : -42;
285        }
286
287        PyTypeObject* TYPE() const noexcept
288        {
289            return p ? Py_TYPE(p) : nullptr;
290        }
291
292        inline OwnedObject PyStr() const noexcept;
293        inline const std::string as_str() const noexcept;
294        inline OwnedObject PyGetAttr(const ImmortalObject& name) const noexcept;
295        inline OwnedObject PyRequireAttr(const char* const name) const;
296        inline OwnedObject PyRequireAttr(const ImmortalString& name) const;
297        inline OwnedObject PyCall(const BorrowedObject& arg) const;
298        inline OwnedObject PyCall(PyGreenlet* arg) const ;
299        inline OwnedObject PyCall(PyObject* arg) const ;
300        // PyObject_Call(this, args, kwargs);
301        inline OwnedObject PyCall(const BorrowedObject args,
302                                  const BorrowedObject kwargs) const;
303        inline OwnedObject PyCall(const OwnedObject& args,
304                                  const OwnedObject& kwargs) const;
305
306    protected:
307        void _set_raw_pointer(void* t)
308        {
309            TC(t);
310            p = reinterpret_cast<T*>(t);
311        }
312        void* _get_raw_pointer() const
313        {
314            return p;
315        }
316    };
317
318#ifdef GREENLET_USE_STDIO
319        template<typename T, TypeChecker TC>
320        std::ostream& operator<<(std::ostream& os, const PyObjectPointer<T, TC>& s)
321        {
322            const std::type_info& t = typeid(s);
323            os << t.name()
324               << "(addr=" << s.borrow()
325               << ", refcnt=" << s.REFCNT()
326               << ", value=" << s.as_str()
327               << ")";
328
329            return os;
330        }
331#endif
332
333    template<typename T, TypeChecker TC>
334    inline bool operator==(const PyObjectPointer<T, TC>& lhs, const PyObject* const rhs) noexcept
335    {
336        return static_cast<const void*>(lhs.borrow_o()) == static_cast<const void*>(rhs);
337    }
338
339    template<typename T, TypeChecker TC, typename X, TypeChecker XC>
340    inline bool operator==(const PyObjectPointer<T, TC>& lhs, const PyObjectPointer<X, XC>& rhs) noexcept
341    {
342        return lhs.borrow_o() == rhs.borrow_o();
343    }
344
345    template<typename T, TypeChecker TC, typename X, TypeChecker XC>
346    inline bool operator!=(const PyObjectPointer<T, TC>& lhs,
347                           const PyObjectPointer<X, XC>& rhs) noexcept
348    {
349        return lhs.borrow_o() != rhs.borrow_o();
350    }
351
352    template<typename T=PyObject, TypeChecker TC=NoOpChecker>
353    class OwnedReference : public PyObjectPointer<T, TC>
354    {
355    private:
356        friend class OwnedList;
357
358    protected:
359        explicit OwnedReference(T* it) : PyObjectPointer<T, TC>(it)
360        {
361        }
362
363    public:
364
365        // Constructors
366
367        static OwnedReference<T, TC> consuming(PyObject* p)
368        {
369            return OwnedReference<T, TC>(reinterpret_cast<T*>(p));
370        }
371
372        static OwnedReference<T, TC> owning(T* p)
373        {
374            OwnedReference<T, TC> result(p);
375            Py_XINCREF(result.p);
376            return result;
377        }
378
379        OwnedReference() : PyObjectPointer<T, TC>(nullptr)
380        {}
381
382        explicit OwnedReference(const PyObjectPointer<>& other)
383            : PyObjectPointer<T, TC>(nullptr)
384        {
385            T* op = other.borrow();
386            TC(op);
387            this->p = other.borrow();
388            Py_XINCREF(this->p);
389        }
390
391        // It would be good to make use of the C++11 distinction
392        // between move and copy operations, e.g., constructing from a
393        // pointer should be a move operation.
394        // In the common case of ``OwnedObject x = Py_SomeFunction()``,
395        // the call to the copy constructor will be elided completely.
396        OwnedReference(const OwnedReference<T, TC>& other)
397            : PyObjectPointer<T, TC>(other.p)
398        {
399            Py_XINCREF(this->p);
400        }
401
402        static OwnedReference<PyObject> None()
403        {
404            Py_INCREF(Py_None);
405            return OwnedReference<PyObject>(Py_None);
406        }
407
408        // We can assign from exactly our type without any extra checking
409        OwnedReference<T, TC>& operator=(const OwnedReference<T, TC>& other)
410        {
411            Py_XINCREF(other.p);
412            const T* tmp = this->p;
413            this->p = other.p;
414            Py_XDECREF(tmp);
415            return *this;
416        }
417
418        OwnedReference<T, TC>& operator=(const BorrowedReference<T, TC> other)
419        {
420            return this->operator=(other.borrow());
421        }
422
423        OwnedReference<T, TC>& operator=(T* const other)
424        {
425            TC(other);
426            Py_XINCREF(other);
427            T* tmp = this->p;
428            this->p = other;
429            Py_XDECREF(tmp);
430            return *this;
431        }
432
433        // We can assign from an arbitrary reference type
434        // if it passes our check.
435        template<typename X, TypeChecker XC>
436        OwnedReference<T, TC>& operator=(const OwnedReference<X, XC>& other)
437        {
438            X* op = other.borrow();
439            TC(op);
440            return this->operator=(reinterpret_cast<T*>(op));
441        }
442
443        inline void steal(T* other)
444        {
445            assert(this->p == nullptr);
446            TC(other);
447            this->p = other;
448        }
449
450        T* relinquish_ownership()
451        {
452            T* result = this->p;
453            this->p = nullptr;
454            return result;
455        }
456
457        T* acquire() const
458        {
459            // Return a new reference.
460            // TODO: This may go away when we have reference objects
461            // throughout the code.
462            Py_XINCREF(this->p);
463            return this->p;
464        }
465
466        // Nothing else declares a destructor, we're the leaf, so we
467        // should be able to get away without virtual.
468        ~OwnedReference()
469        {
470            Py_CLEAR(this->p);
471        }
472
473        void CLEAR()
474        {
475            Py_CLEAR(this->p);
476            assert(this->p == nullptr);
477        }
478    };
479
480    static inline
481    void operator<<=(PyObject*& target, OwnedObject& o)
482    {
483        target = o.relinquish_ownership();
484    }
485
486
487    class NewReference : public OwnedObject
488    {
489    private:
490        G_NO_COPIES_OF_CLS(NewReference);
491    public:
492        // Consumes the reference. Only use this
493        // for API return values.
494        NewReference(PyObject* it) : OwnedObject(it)
495        {
496        }
497    };
498
499    class NewDictReference : public NewReference
500    {
501    private:
502        G_NO_COPIES_OF_CLS(NewDictReference);
503    public:
504        NewDictReference() : NewReference(PyDict_New())
505        {
506            if (!this->p) {
507                throw PyErrOccurred();
508            }
509        }
510
511        void SetItem(const char* const key, PyObject* value)
512        {
513            Require(PyDict_SetItemString(this->p, key, value));
514        }
515
516        void SetItem(const PyObjectPointer<>& key, PyObject* value)
517        {
518            Require(PyDict_SetItem(this->p, key.borrow_o(), value));
519        }
520    };
521
522    template<typename T=PyGreenlet, TypeChecker TC=GreenletChecker>
523    class _OwnedGreenlet: public OwnedReference<T, TC>
524    {
525    private:
526    protected:
527        _OwnedGreenlet(T* it) : OwnedReference<T, TC>(it)
528        {}
529
530    public:
531        _OwnedGreenlet() : OwnedReference<T, TC>()
532        {}
533
534        _OwnedGreenlet(const _OwnedGreenlet<T, TC>& other) : OwnedReference<T, TC>(other)
535        {
536        }
537        _OwnedGreenlet(OwnedMainGreenlet& other) :
538            OwnedReference<T, TC>(reinterpret_cast<T*>(other.acquire()))
539        {
540        }
541        _OwnedGreenlet(const BorrowedGreenlet& other);
542        // Steals a reference.
543        static _OwnedGreenlet<T, TC> consuming(PyGreenlet* it)
544        {
545            return _OwnedGreenlet<T, TC>(reinterpret_cast<T*>(it));
546        }
547
548        inline _OwnedGreenlet<T, TC>& operator=(const OwnedGreenlet& other)
549        {
550            return this->operator=(other.borrow());
551        }
552
553        inline _OwnedGreenlet<T, TC>& operator=(const BorrowedGreenlet& other);
554
555        _OwnedGreenlet<T, TC>& operator=(const OwnedMainGreenlet& other)
556        {
557            PyGreenlet* owned = other.acquire();
558            Py_XDECREF(this->p);
559            this->p = reinterpret_cast<T*>(owned);
560            return *this;
561        }
562
563        _OwnedGreenlet<T, TC>& operator=(T* const other)
564        {
565            OwnedReference<T, TC>::operator=(other);
566            return *this;
567        }
568
569        T* relinquish_ownership()
570        {
571            T* result = this->p;
572            this->p = nullptr;
573            return result;
574        }
575
576        PyObject* relinquish_ownership_o()
577        {
578            return reinterpret_cast<PyObject*>(relinquish_ownership());
579        }
580
581        inline Greenlet* operator->() const noexcept;
582        inline operator Greenlet*() const noexcept;
583    };
584
585    template <typename T=PyObject, TypeChecker TC=NoOpChecker>
586    class BorrowedReference : public PyObjectPointer<T, TC>
587    {
588    public:
589        // Allow implicit creation from PyObject* pointers as we
590        // transition to using these classes. Also allow automatic
591        // conversion to PyObject* for passing to C API calls and even
592        // for Py_INCREF/DECREF, because we ourselves do no memory management.
593        BorrowedReference(T* it) : PyObjectPointer<T, TC>(it)
594        {}
595
596        BorrowedReference(const PyObjectPointer<T>& ref) : PyObjectPointer<T, TC>(ref.borrow())
597        {}
598
599        BorrowedReference() : PyObjectPointer<T, TC>(nullptr)
600        {}
601
602        operator T*() const
603        {
604            return this->p;
605        }
606    };
607
608    typedef BorrowedReference<PyObject> BorrowedObject;
609    //typedef BorrowedReference<PyGreenlet> BorrowedGreenlet;
610
611    template<typename T=PyGreenlet, TypeChecker TC=GreenletChecker>
612    class _BorrowedGreenlet : public BorrowedReference<T, TC>
613    {
614    public:
615        _BorrowedGreenlet() :
616            BorrowedReference<T, TC>(nullptr)
617        {}
618
619        _BorrowedGreenlet(T* it) :
620            BorrowedReference<T, TC>(it)
621        {}
622
623        _BorrowedGreenlet(const BorrowedObject& it);
624
625        _BorrowedGreenlet(const OwnedGreenlet& it) :
626            BorrowedReference<T, TC>(it.borrow())
627        {}
628
629        _BorrowedGreenlet<T, TC>& operator=(const BorrowedObject& other);
630
631        // We get one of these for PyGreenlet, but one for PyObject
632        // is handy as well
633        operator PyObject*() const
634        {
635            return reinterpret_cast<PyObject*>(this->p);
636        }
637        Greenlet* operator->() const noexcept;
638        operator Greenlet*() const noexcept;
639    };
640
641    typedef _BorrowedGreenlet<PyGreenlet> BorrowedGreenlet;
642
643    template<typename T, TypeChecker TC>
644    _OwnedGreenlet<T, TC>::_OwnedGreenlet(const BorrowedGreenlet& other)
645        : OwnedReference<T, TC>(reinterpret_cast<T*>(other.borrow()))
646    {
647        Py_XINCREF(this->p);
648    }
649
650
651     class BorrowedMainGreenlet
652            : public _BorrowedGreenlet<PyGreenlet, MainGreenletExactChecker>
653    {
654    public:
655        BorrowedMainGreenlet(const OwnedMainGreenlet& it) :
656            _BorrowedGreenlet<PyGreenlet, MainGreenletExactChecker>(it.borrow())
657        {}
658        BorrowedMainGreenlet(PyGreenlet* it=nullptr)
659            : _BorrowedGreenlet<PyGreenlet, MainGreenletExactChecker>(it)
660        {}
661    };
662
663    template<typename T, TypeChecker TC>
664    _OwnedGreenlet<T, TC>& _OwnedGreenlet<T, TC>::operator=(const BorrowedGreenlet& other)
665    {
666        return this->operator=(other.borrow());
667    }
668
669
670    class ImmortalObject : public PyObjectPointer<>
671    {
672    private:
673        G_NO_ASSIGNMENT_OF_CLS(ImmortalObject);
674    public:
675        explicit ImmortalObject(PyObject* it) : PyObjectPointer<>(it)
676        {
677        }
678
679        ImmortalObject(const ImmortalObject& other)
680            : PyObjectPointer<>(other.p)
681        {
682
683        }
684
685        /**
686         * Become the new owner of the object. Does not change the
687         * reference count.
688         */
689        ImmortalObject& operator=(PyObject* it)
690        {
691            assert(this->p == nullptr);
692            this->p = it;
693            return *this;
694        }
695
696        static ImmortalObject consuming(PyObject* it)
697        {
698            return ImmortalObject(it);
699        }
700
701        inline operator PyObject*() const
702        {
703            return this->p;
704        }
705    };
706
707    class ImmortalString : public ImmortalObject
708    {
709    private:
710        G_NO_COPIES_OF_CLS(ImmortalString);
711        const char* str;
712    public:
713        ImmortalString(const char* const str) :
714            ImmortalObject(str ? Require(PyUnicode_InternFromString(str)) : nullptr)
715        {
716            this->str = str;
717        }
718
719        inline ImmortalString& operator=(const char* const str)
720        {
721            if (!this->p) {
722                this->p = Require(PyUnicode_InternFromString(str));
723                this->str = str;
724            }
725            else {
726                assert(this->str == str);
727            }
728            return *this;
729        }
730
731        inline operator std::string() const
732        {
733            return this->str;
734        }
735
736    };
737
738    class ImmortalEventName : public ImmortalString
739    {
740    private:
741        G_NO_COPIES_OF_CLS(ImmortalEventName);
742    public:
743        ImmortalEventName(const char* const str) : ImmortalString(str)
744        {}
745    };
746
747    class ImmortalException : public ImmortalObject
748    {
749    private:
750        G_NO_COPIES_OF_CLS(ImmortalException);
751    public:
752        ImmortalException(const char* const name, PyObject* base=nullptr) :
753            ImmortalObject(name
754                           // Python 2.7 isn't const correct
755                           ? Require(PyErr_NewException((char*)name, base, nullptr))
756                           : nullptr)
757        {}
758
759        inline bool PyExceptionMatches() const
760        {
761            return PyErr_ExceptionMatches(this->p) > 0;
762        }
763
764    };
765
766    template<typename T, TypeChecker TC>
767    inline OwnedObject PyObjectPointer<T, TC>::PyStr() const noexcept
768    {
769        if (!this->p) {
770            return OwnedObject();
771        }
772        return OwnedObject::consuming(PyObject_Str(reinterpret_cast<PyObject*>(this->p)));
773    }
774
775    template<typename T, TypeChecker TC>
776    inline const std::string PyObjectPointer<T, TC>::as_str() const noexcept
777    {
778        // NOTE: This is not Python exception safe.
779        if (this->p) {
780            // The Python APIs return a cached char* value that's only valid
781            // as long as the original object stays around, and we're
782            // about to (probably) toss it. Hence the copy to std::string.
783            OwnedObject py_str = this->PyStr();
784            if (!py_str) {
785                return "(nil)";
786            }
787            return PyUnicode_AsUTF8(py_str.borrow());
788        }
789        return "(nil)";
790    }
791
792    template<typename T, TypeChecker TC>
793    inline OwnedObject PyObjectPointer<T, TC>::PyGetAttr(const ImmortalObject& name) const noexcept
794    {
795        assert(this->p);
796        return OwnedObject::consuming(PyObject_GetAttr(reinterpret_cast<PyObject*>(this->p), name));
797    }
798
799    template<typename T, TypeChecker TC>
800    inline OwnedObject PyObjectPointer<T, TC>::PyRequireAttr(const char* const name) const
801    {
802        assert(this->p);
803        return OwnedObject::consuming(Require(PyObject_GetAttrString(this->p, name), name));
804    }
805
806    template<typename T, TypeChecker TC>
807    inline OwnedObject PyObjectPointer<T, TC>::PyRequireAttr(const ImmortalString& name) const
808    {
809        assert(this->p);
810        return OwnedObject::consuming(Require(
811                   PyObject_GetAttr(
812                      reinterpret_cast<PyObject*>(this->p),
813                      name
814                   ),
815                   name
816               ));
817    }
818
819    template<typename T, TypeChecker TC>
820    inline OwnedObject PyObjectPointer<T, TC>::PyCall(const BorrowedObject& arg) const
821    {
822        return this->PyCall(arg.borrow());
823    }
824
825    template<typename T, TypeChecker TC>
826    inline OwnedObject PyObjectPointer<T, TC>::PyCall(PyGreenlet* arg) const
827    {
828        return this->PyCall(reinterpret_cast<PyObject*>(arg));
829    }
830
831    template<typename T, TypeChecker TC>
832    inline OwnedObject PyObjectPointer<T, TC>::PyCall(PyObject* arg) const
833    {
834        assert(this->p);
835        return OwnedObject::consuming(PyObject_CallFunctionObjArgs(this->p, arg, NULL));
836    }
837
838    template<typename T, TypeChecker TC>
839    inline OwnedObject PyObjectPointer<T, TC>::PyCall(const BorrowedObject args,
840                                                  const BorrowedObject kwargs) const
841    {
842        assert(this->p);
843        return OwnedObject::consuming(PyObject_Call(this->p, args, kwargs));
844    }
845
846    template<typename T, TypeChecker TC>
847    inline OwnedObject PyObjectPointer<T, TC>::PyCall(const OwnedObject& args,
848                                                  const OwnedObject& kwargs) const
849    {
850        assert(this->p);
851        return OwnedObject::consuming(PyObject_Call(this->p, args.borrow(), kwargs.borrow()));
852    }
853
854    inline void
855    ListChecker(void * p)
856    {
857        if (!p) {
858            return;
859        }
860        if (!PyList_Check(p)) {
861            throw TypeError("Expected a list");
862        }
863    }
864
865    class OwnedList : public OwnedReference<PyObject, ListChecker>
866    {
867    private:
868        G_NO_ASSIGNMENT_OF_CLS(OwnedList);
869    public:
870        // TODO: Would like to use move.
871        explicit OwnedList(const OwnedObject& other)
872            : OwnedReference<PyObject, ListChecker>(other)
873        {
874        }
875
876        OwnedList& operator=(const OwnedObject& other)
877        {
878            if (other && PyList_Check(other.p)) {
879                // Valid list. Own a new reference to it, discard the
880                // reference to what we did own.
881                PyObject* new_ptr = other.p;
882                Py_INCREF(new_ptr);
883                Py_XDECREF(this->p);
884                this->p = new_ptr;
885            }
886            else {
887                // Either the other object was NULL (an error) or it
888                // wasn't a list. Either way, we're now invalidated.
889                Py_XDECREF(this->p);
890                this->p = nullptr;
891            }
892            return *this;
893        }
894
895        inline bool empty() const
896        {
897            return PyList_GET_SIZE(p) == 0;
898        }
899
900        inline Py_ssize_t size() const
901        {
902            return PyList_GET_SIZE(p);
903        }
904
905        inline BorrowedObject at(const Py_ssize_t index) const
906        {
907            return PyList_GET_ITEM(p, index);
908        }
909
910        inline void clear()
911        {
912            PyList_SetSlice(p, 0, PyList_GET_SIZE(p), NULL);
913        }
914    };
915
916    // Use this to represent the module object used at module init
917    // time.
918    // This could either be a borrowed (Py2) or new (Py3) reference;
919    // either way, we don't want to do any memory management
920    // on it here, Python itself will handle that.
921    // XXX: Actually, that's not quite right. On Python 3, if an
922    // exception occurs before we return to the interpreter, this will
923    // leak; but all previous versions also had that problem.
924    class CreatedModule : public PyObjectPointer<>
925    {
926    private:
927        G_NO_COPIES_OF_CLS(CreatedModule);
928    public:
929        CreatedModule(PyModuleDef& mod_def) : PyObjectPointer<>(
930            Require(PyModule_Create(&mod_def)))
931        {
932        }
933
934        // PyAddObject(): Add a new reference to the object to the module.
935        void PyAddObject(const char* name, const long new_bool)
936        {
937            Require(PyModule_AddIntConstant(this->p, name, new_bool));
938        }
939
940        // It is safe to pass a null value to this API because we use
941        // PyModule_AddObjectRef under the covers which allows null.
942        void PyAddObject(const char* name, const OwnedObject& new_object)
943        {
944            // The caller already owns a reference they will decref
945            // when their variable goes out of scope, we still need to
946            // incref/decref.
947            this->PyAddObject(name, new_object.borrow());
948        }
949
950        void PyAddObject(const char* name, const ImmortalObject& new_object)
951        {
952            this->PyAddObject(name, new_object.borrow());
953        }
954
955        void PyAddObject(const char* name, PyTypeObject& type)
956        {
957            this->PyAddObject(name, reinterpret_cast<PyObject*>(&type));
958        }
959
960    private:
961
962        void PyAddObject(const char* name, PyObject* new_object)
963        {
964            Require(PyModule_AddObjectRef(this->p, name, new_object));
965        }
966    };
967
968    class PyErrFetchParam : public PyObjectPointer<>
969    {
970        // Not an owned object, because we can't be initialized with
971        // one, and we only sometimes acquire ownership.
972    private:
973        G_NO_COPIES_OF_CLS(PyErrFetchParam);
974    public:
975        // To allow declaring these and passing them to
976        // PyErr_Fetch we implement the empty constructor,
977        // and the address operator.
978        PyErrFetchParam() : PyObjectPointer<>(nullptr)
979        {
980        }
981
982        PyObject** operator&()
983        {
984            return &this->p;
985        }
986
987        // This allows us to pass one directly without the &,
988        // BUT it has higher precedence than the bool operator
989        // if it's not explicit.
990        operator PyObject**()
991        {
992            return &this->p;
993        }
994
995        // We don't want to be able to pass these to Py_DECREF and
996        // such so we don't have the implicit PyObject* conversion.
997
998        inline PyObject* relinquish_ownership()
999        {
1000            PyObject* result = this->p;
1001            this->p = nullptr;
1002            return result;
1003        }
1004
1005        ~PyErrFetchParam()
1006        {
1007            Py_XDECREF(p);
1008        }
1009    };
1010
1011    class OwnedErrPiece : public OwnedObject
1012    {
1013    private:
1014
1015    public:
1016        // Unlike OwnedObject, this increments the refcount.
1017        OwnedErrPiece(PyObject* p=nullptr) : OwnedObject(p)
1018        {
1019            this->acquire();
1020        }
1021
1022        PyObject** operator&()
1023        {
1024            return &this->p;
1025        }
1026
1027        inline operator PyObject*() const
1028        {
1029            return this->p;
1030        }
1031
1032        operator PyTypeObject*() const
1033        {
1034            return reinterpret_cast<PyTypeObject*>(this->p);
1035        }
1036    };
1037
1038    // TODO: When we run on 3.12+ only (GREENLET_312), switch to the
1039    // ``PyErr_GetRaisedException`` family of functions. The
1040    // ``PyErr_Fetch`` family is deprecated on 3.12+, but is part
1041    // of the stable ABI so it's not going anywhere.
1042    class PyErrPieces
1043    {
1044    private:
1045        OwnedErrPiece type;
1046        OwnedErrPiece instance;
1047        OwnedErrPiece traceback;
1048        bool restored;
1049    public:
1050        // Takes new references; if we're destroyed before
1051        // restoring the error, we drop the references.
1052        PyErrPieces(PyObject* t, PyObject* v, PyObject* tb) :
1053            type(t),
1054            instance(v),
1055            traceback(tb),
1056            restored(0)
1057        {
1058            this->normalize();
1059        }
1060
1061        PyErrPieces() :
1062            restored(0)
1063        {
1064            // PyErr_Fetch transfers ownership to us, so
1065            // we don't actually need to INCREF; but we *do*
1066            // need to DECREF if we're not restored.
1067            PyErrFetchParam t, v, tb;
1068            PyErr_Fetch(&t, &v, &tb);
1069            type.steal(t.relinquish_ownership());
1070            instance.steal(v.relinquish_ownership());
1071            traceback.steal(tb.relinquish_ownership());
1072        }
1073
1074        void PyErrRestore()
1075        {
1076            // can only do this once
1077            assert(!this->restored);
1078            this->restored = true;
1079            PyErr_Restore(
1080                this->type.relinquish_ownership(),
1081                this->instance.relinquish_ownership(),
1082                this->traceback.relinquish_ownership());
1083            assert(!this->type && !this->instance && !this->traceback);
1084        }
1085
1086    private:
1087        void normalize()
1088        {
1089            // First, check the traceback argument, replacing None,
1090            // with NULL
1091            if (traceback.is_None()) {
1092                traceback = nullptr;
1093            }
1094
1095            if (traceback && !PyTraceBack_Check(traceback.borrow())) {
1096                throw PyErrOccurred(PyExc_TypeError,
1097                                    "throw() third argument must be a traceback object");
1098            }
1099
1100            if (PyExceptionClass_Check(type)) {
1101                // If we just had a type, we'll now have a type and
1102                // instance.
1103                // The type's refcount will have gone up by one
1104                // because of the instance and the instance will have
1105                // a refcount of one. Either way, we owned, and still
1106                // do own, exactly one reference.
1107                PyErr_NormalizeException(&type, &instance, &traceback);
1108
1109            }
1110            else if (PyExceptionInstance_Check(type)) {
1111                /* Raising an instance --- usually that means an
1112                   object that is a subclass of BaseException, but on
1113                   Python 2, that can also mean an arbitrary old-style
1114                   object. The value should be a dummy. */
1115                if (instance && !instance.is_None()) {
1116                    throw PyErrOccurred(
1117                                    PyExc_TypeError,
1118                                    "instance exception may not have a separate value");
1119                }
1120                /* Normalize to raise <class>, <instance> */
1121                this->instance = this->type;
1122                this->type = PyExceptionInstance_Class(instance.borrow());
1123
1124                /*
1125                  It would be tempting to do this:
1126
1127                Py_ssize_t type_count = Py_REFCNT(Py_TYPE(instance.borrow()));
1128                this->type = PyExceptionInstance_Class(instance.borrow());
1129                assert(this->type.REFCNT() == type_count + 1);
1130
1131                But that doesn't work on Python 2 in the case of
1132                old-style instances: The result of Py_TYPE is going to
1133                be the global shared <type instance> that all
1134                old-style classes have, while the return of Instance_Class()
1135                will be the Python-level class object. The two are unrelated.
1136                */
1137            }
1138            else {
1139                /* Not something you can raise. throw() fails. */
1140                PyErr_Format(PyExc_TypeError,
1141                     "exceptions must be classes, or instances, not %s",
1142                             Py_TYPE(type.borrow())->tp_name);
1143                throw PyErrOccurred();
1144            }
1145        }
1146    };
1147
1148    // PyArg_Parse's O argument returns a borrowed reference.
1149    class PyArgParseParam : public BorrowedObject
1150    {
1151    private:
1152        G_NO_COPIES_OF_CLS(PyArgParseParam);
1153    public:
1154        explicit PyArgParseParam(PyObject* p=nullptr) : BorrowedObject(p)
1155        {
1156        }
1157
1158        inline PyObject** operator&()
1159        {
1160            return &this->p;
1161        }
1162    };
1163
1164#ifdef Py_GIL_DISABLED
1165        // building on 3.13 or newer, free-threaded
1166        class PyCriticalObjectSection {
1167        private:
1168            G_NO_COPIES_OF_CLS(PyCriticalObjectSection);
1169            PyCriticalSection _py_cs;
1170        public:
1171            explicit PyCriticalObjectSection(PyObject* p)
1172            {
1173                PyCriticalSection_Begin(&this->_py_cs, p);
1174            }
1175            explicit PyCriticalObjectSection(const PyGreenlet* p)
1176            : PyCriticalObjectSection(
1177                  reinterpret_cast<PyObject*>(
1178                      const_cast<PyGreenlet*>(p)))
1179            {}
1180            ~PyCriticalObjectSection()
1181            {
1182                PyCriticalSection_End(&this->_py_cs);
1183            }
1184        };
1185#else
1186        class PyCriticalObjectSection {
1187        public:
1188            explicit PyCriticalObjectSection(PyObject* UNUSED(p))
1189            {}
1190            explicit PyCriticalObjectSection(const PyGreenlet* UNUSED(p))
1191            {}
1192        };
1193
1194#endif
1195
1196
1197};};
1198
1199#endif
1200 
codekingpro/portable-devtools · Team Ai