From 76926159194e180003aa78de97e5f287bf4325a5 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Mon, 15 Apr 2024 20:07:41 +0200 Subject: Adding upstream version 2.7.6. Signed-off-by: Daniel Baumann --- python/generic.h | 336 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 336 insertions(+) create mode 100644 python/generic.h (limited to 'python/generic.h') diff --git a/python/generic.h b/python/generic.h new file mode 100644 index 0000000..60f9531 --- /dev/null +++ b/python/generic.h @@ -0,0 +1,336 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: generic.h,v 1.4 2002/03/10 05:45:34 mdz Exp $ +/* ###################################################################### + + generic - Some handy functions to make integration a tad simpler + + Python needs this little _HEAD tacked onto the front of the object.. + This complicates the integration with C++. We use some templates to + make that quite transparent to us. It would have been nice if Python + internally used a page from the C++ ref counting book to hide its little + header from the world, but it doesn't. + + The CppPyObject has the target object and the Python header, this is + needed to ensure proper alignment. + GetCpp returns the C++ object from a PyObject. + CppPyObject_NEW creates the Python object and then uses placement new + to init the C++ class.. This is good for simple situations and as an + example on how to do it in other more specific cases. + CppPyObject_Dealloc should be used in the Type as the destructor + function. + HandleErrors converts errors from the internal _error stack into Python + exceptions and makes sure the _error stack is empty. + + ##################################################################### */ + /*}}}*/ +#ifndef GENERIC_H +#define GENERIC_H + +#include +#include +#include +#include +#include + +/** + * Exception class for almost all Python errors + */ +extern PyObject *PyAptError; +extern PyObject *PyAptWarning; +/** + * Exception class for invalidated cache objects. + */ +extern PyObject *PyAptCacheMismatchError; + +#if PYTHON_API_VERSION < 1013 +typedef int Py_ssize_t; +#endif + +/* Define compatibility for Python 3. + * + * We will use the names PyString_* to refer to the default string type + * of the current Python version (PyString on 2.X, PyUnicode on 3.X). + * + * When we really need unicode strings, we will use PyUnicode_* directly, as + * long as it exists in Python 2 and Python 3. + * + * When we want bytes in Python 3, we use PyBytes*_ instead of PyString_* and + * define aliases from PyBytes_* to PyString_* for Python 2. + */ + +#if PY_MAJOR_VERSION >= 3 +#define PyString_Check PyUnicode_Check +#define PyString_FromString PyUnicode_FromString +#define PyString_FromStringAndSize PyUnicode_FromStringAndSize +#define PyString_AsString PyUnicode_AsString +#define PyString_FromFormat PyUnicode_FromFormat +#define PyString_Type PyUnicode_Type +#define PyInt_Check PyLong_Check +#define PyInt_AsLong PyLong_AsLong +#define PyInt_FromLong PyLong_FromLong +#endif + +static inline const char *PyUnicode_AsString(PyObject *op) { + // Convert to bytes object, using the default encoding. +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3 + return PyUnicode_AsUTF8(op); +#else + // Use Python-internal API, there is no other way to do this + // without a memory leak. + PyObject *bytes = _PyUnicode_AsDefaultEncodedString(op, 0); + return bytes ? PyBytes_AS_STRING(bytes) : 0; +#endif +} + +// Convert any type of string based object to a const char. +#if PY_MAJOR_VERSION < 3 +static inline const char *PyObject_AsString(PyObject *object) { + if (PyBytes_Check(object)) + return PyBytes_AsString(object); + else if (PyUnicode_Check(object)) + return PyUnicode_AsString(object); + else + PyErr_SetString(PyExc_TypeError, "Argument must be str."); + return 0; +} +#else +static inline const char *PyObject_AsString(PyObject *object) { + if (PyUnicode_Check(object) == 0) { + PyErr_SetString(PyExc_TypeError, "Argument must be str."); + return 0; + } + return PyUnicode_AsString(object); +} +#endif + +template struct CppPyObject : public PyObject +{ + // We are only using CppPyObject and friends as dumb structs only, ie the + // c'tor is never called. + // However if T doesn't have a default c'tor C++ doesn't generate one for + // CppPyObject (since it can't know how it should initialize Object). + // + // This causes problems then in CppPyObject, for which C++ can't create + // a c'tor that calls the base class c'tor (which causes a compilation + // error). + // So basically having the c'tor here removes the need for T to have a + // default c'tor, which is not always desireable. + CppPyObject() { }; + + // The owner of the object. The object keeps a reference to it during its + // lifetime. + PyObject *Owner; + + // Flag which causes the underlying object to not be deleted. + bool NoDelete; + + // The underlying C++ object. + T Object; +}; + +template +inline T &GetCpp(PyObject *Obj) +{ + return ((CppPyObject *)Obj)->Object; +} + +template +inline PyObject *GetOwner(PyObject *Obj) +{ + return ((CppPyObject *)Obj)->Owner; +} + + +template +inline CppPyObject *CppPyObject_NEW(PyObject *Owner,PyTypeObject *Type) +{ + #ifdef ALLOC_DEBUG + std::cerr << "=== ALLOCATING " << Type->tp_name << "+ ===\n"; + #endif + CppPyObject *New = (CppPyObject*)Type->tp_alloc(Type, 0); + new (&New->Object) T; + New->Owner = Owner; + Py_XINCREF(Owner); + return New; +} + +template +inline CppPyObject *CppPyObject_NEW(PyObject *Owner, PyTypeObject *Type,A const &Arg) +{ + #ifdef ALLOC_DEBUG + std::cerr << "=== ALLOCATING " << Type->tp_name << "+ ===\n"; + #endif + CppPyObject *New = (CppPyObject*)Type->tp_alloc(Type, 0); + new (&New->Object) T(Arg); + New->Owner = Owner; + Py_XINCREF(Owner); + return New; +} + +// Traversal and Clean for objects +template +int CppTraverse(PyObject *self, visitproc visit, void* arg) { + Py_VISIT(((CppPyObject *)self)->Owner); + return 0; +} + +template +int CppClear(PyObject *self) { + Py_CLEAR(((CppPyObject *)self)->Owner); + return 0; +} + +template +void CppDealloc(PyObject *iObj) +{ + #ifdef ALLOC_DEBUG + std::cerr << "=== DEALLOCATING " << iObj->ob_type->tp_name << "+ ===\n"; + #endif + if (iObj->ob_type->tp_flags & Py_TPFLAGS_HAVE_GC) + PyObject_GC_UnTrack(iObj); + CppPyObject *Obj = (CppPyObject *)iObj; + if (!((CppPyObject*)Obj)->NoDelete) + Obj->Object.~T(); + CppClear(iObj); + iObj->ob_type->tp_free(iObj); +} + + +template +void CppDeallocPtr(PyObject *iObj) +{ + #ifdef ALLOC_DEBUG + std::cerr << "=== DEALLOCATING " << iObj->ob_type->tp_name << "*+ ===\n"; + #endif + if (iObj->ob_type->tp_flags & Py_TPFLAGS_HAVE_GC) + PyObject_GC_UnTrack(iObj); + CppPyObject *Obj = (CppPyObject *)iObj; + if (!((CppPyObject*)Obj)->NoDelete) { + delete Obj->Object; + Obj->Object = NULL; + } + CppClear(iObj); + iObj->ob_type->tp_free(iObj); +} + +inline PyObject *CppPyString(const std::string &Str) +{ + return PyString_FromStringAndSize(Str.c_str(),Str.length()); +} + +inline PyObject *CppPyString(const char *Str) +{ + if (Str == 0) + return PyString_FromString(""); + return PyString_FromString(Str); +} + +inline PyObject *CppPyLocaleString(const std::string &Str) +{ + char const * const codeset = nl_langinfo(CODESET); + return PyUnicode_Decode(Str.c_str(), Str.length(), codeset, "replace"); +} + +#if PY_MAJOR_VERSION >= 3 +static inline PyObject *CppPyPath(const std::string &path) +{ + return PyUnicode_DecodeFSDefaultAndSize(path.c_str(), path.length()); +} + +static inline PyObject *CppPyPath(const char *path) +{ + if (path == nullptr) + path = ""; + return PyUnicode_DecodeFSDefault(path); +} +#else +template static inline PyObject *CppPyPath(T path) { + return CppPyString(path); +} +#endif + +// Convert _error into Python exceptions +PyObject *HandleErrors(PyObject *Res = 0); + +// Convert a list of strings to a char ** +const char **ListToCharChar(PyObject *List,bool NullTerm = false); +PyObject *CharCharToList(const char **List,unsigned long Size = 0); + +/* Happy number conversion, thanks to overloading */ +inline PyObject *MkPyNumber(unsigned long long o) { return PyLong_FromUnsignedLongLong(o); } +inline PyObject *MkPyNumber(unsigned long o) { return PyLong_FromUnsignedLong(o); } +inline PyObject *MkPyNumber(unsigned int o) { return PyLong_FromUnsignedLong(o); } +inline PyObject *MkPyNumber(unsigned short o) { return PyInt_FromLong(o); } +inline PyObject *MkPyNumber(unsigned char o) { return PyInt_FromLong(o); } + +inline PyObject *MkPyNumber(long long o) { return PyLong_FromLongLong(o); } +inline PyObject *MkPyNumber(long o) { return PyInt_FromLong(o); } +inline PyObject *MkPyNumber(int o) { return PyInt_FromLong(o); } +inline PyObject *MkPyNumber(short o) { return PyInt_FromLong(o); } +inline PyObject *MkPyNumber(signed char o) { return PyInt_FromLong(o); } + +inline PyObject *MkPyNumber(double o) { return PyFloat_FromDouble(o); } + +# define _PyAptObject_getattro 0 + + +/** + * Magic class for file name handling + * + * This manages decoding file names from Python objects; bytes and unicode + * objects. On Python 2, this does the same conversion as PyObject_AsString, + * on Python3, it uses PyUnicode_EncodeFSDefault for unicode objects. + */ +class PyApt_Filename { +public: + PyObject *object; + const char *path; + + PyApt_Filename() { + object = NULL; + path = NULL; + } + + int init(PyObject *object); + + ~PyApt_Filename() { + Py_XDECREF(object); + } + + static int Converter(PyObject *object, void *out) { + return static_cast(out)->init(object); + } + + operator const char *() { + return path; + } + operator const std::string() { + return path; + } + + const char *operator=(const char *path) { + return this->path = path; + } +}; + + +/** + * Basic smart pointer to hold initial objects. + * + * This is like a std::unique_ptr to some extend, + * but it is for initialization only, and hence will also clear out any members + * in case it deletes the instance (the error case). + */ +template struct PyApt_UniqueObject { + T *self; + explicit PyApt_UniqueObject(T *self) : self(self) { } + ~PyApt_UniqueObject() { reset(NULL); } + void reset(T *newself) { if (clear && self && Py_TYPE(self)->tp_clear) Py_TYPE(self)->tp_clear(self); Py_XDECREF(self); self = newself; } + PyApt_UniqueObject operator =(PyApt_UniqueObject) = delete; + bool operator ==(void *other) { return self == other; } + T *operator ->() { return self; } + T *get() { return self; } + T *release() { T *ret = self; self = NULL; return ret; } +}; +#endif -- cgit v1.2.3