diff options
Diffstat (limited to 'python/generic.h')
| -rw-r--r-- | python/generic.h | 167 |
1 files changed, 127 insertions, 40 deletions
diff --git a/python/generic.h b/python/generic.h index d2fcf42a..31c1bc2d 100644 --- a/python/generic.h +++ b/python/generic.h @@ -29,12 +29,81 @@ #include <Python.h> #include <string> +#include <iostream> #include <new> #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 +// Force 0.7 compatibility to be off in Python 3 builds +#undef COMPAT_0_7 +#else +// Compatibility for Python 2.5 and previous. +#if (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION <= 5) +#define PyBytes_Check PyString_Check +#define PyBytes_AS_STRING PyString_AS_STRING +#define PyBytes_AsString PyString_AsString +#define PyBytes_AsStringAndSize PyString_AsStringAndSize +#define PyBytes_FromStringAndSize PyString_FromStringAndSize +#define PyVarObject_HEAD_INIT(type, size) PyObject_HEAD_INIT(type) size, +#endif +#endif + +// Hacks to make Python 2.4 build. +#if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION <= 4 +#define PyErr_WarnEx(cat,msg,stacklevel) PyErr_Warn(cat,msg) +#endif + + +static inline const char *PyUnicode_AsString(PyObject *op) { + // Convert to bytes object, using the default encoding. + PyObject *bytes = PyUnicode_AsEncodedString(op,0,0); + return bytes ? PyBytes_AS_STRING(bytes) : 0; +} + +// 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 <class T> struct CppPyObject : public PyObject { // We are only using CppPyObject and friends as dumb structs only, ie the @@ -42,18 +111,22 @@ template <class T> struct CppPyObject : public PyObject // 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 CppOwnedPyObject, for which C++ can't create + // 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() { }; - T Object; -}; -template <class T> struct CppOwnedPyObject : public CppPyObject<T> -{ + // 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 <class T> @@ -65,66 +138,74 @@ inline T &GetCpp(PyObject *Obj) template <class T> inline PyObject *GetOwner(PyObject *Obj) { - return ((CppOwnedPyObject<T> *)Obj)->Owner; + return ((CppPyObject<T> *)Obj)->Owner; } -// Generic 'new' functions + template <class T> -inline CppPyObject<T> *CppPyObject_NEW(PyTypeObject *Type) +inline CppPyObject<T> *CppPyObject_NEW(PyObject *Owner,PyTypeObject *Type) { - CppPyObject<T> *New = PyObject_NEW(CppPyObject<T>,Type); + #ifdef ALLOC_DEBUG + std::cerr << "=== ALLOCATING " << Type->tp_name << "+ ===\n"; + #endif + CppPyObject<T> *New = (CppPyObject<T>*)Type->tp_alloc(Type, 0); new (&New->Object) T; + New->Owner = Owner; + Py_XINCREF(Owner); return New; } template <class T,class A> -inline CppPyObject<T> *CppPyObject_NEW(PyTypeObject *Type,A const &Arg) +inline CppPyObject<T> *CppPyObject_NEW(PyObject *Owner, PyTypeObject *Type,A const &Arg) { - CppPyObject<T> *New = PyObject_NEW(CppPyObject<T>,Type); + #ifdef ALLOC_DEBUG + std::cerr << "=== ALLOCATING " << Type->tp_name << "+ ===\n"; + #endif + CppPyObject<T> *New = (CppPyObject<T>*)Type->tp_alloc(Type, 0); new (&New->Object) T(Arg); + New->Owner = Owner; + Py_XINCREF(Owner); return New; } +// Traversal and Clean for objects template <class T> -inline CppOwnedPyObject<T> *CppOwnedPyObject_NEW(PyObject *Owner, - PyTypeObject *Type) -{ - CppOwnedPyObject<T> *New = PyObject_NEW(CppOwnedPyObject<T>,Type); - new (&New->Object) T; - New->Owner = Owner; - Py_INCREF(Owner); - return New; +int CppTraverse(PyObject *self, visitproc visit, void* arg) { + Py_VISIT(((CppPyObject<T> *)self)->Owner); + return 0; } -template <class T,class A> -inline CppOwnedPyObject<T> *CppOwnedPyObject_NEW(PyObject *Owner, - PyTypeObject *Type,A const &Arg) -{ - CppOwnedPyObject<T> *New = PyObject_NEW(CppOwnedPyObject<T>,Type); - new (&New->Object) T(Arg); - New->Owner = Owner; - if (Owner != 0) - Py_INCREF(Owner); - return New; +template <class T> +int CppClear(PyObject *self) { + Py_CLEAR(((CppPyObject<T> *)self)->Owner); + return 0; } -// Generic Dealloc type functions template <class T> -void CppDealloc(PyObject *Obj) +void CppDealloc(PyObject *iObj) { - GetCpp<T>(Obj).~T(); - PyObject_DEL(Obj); + #ifdef ALLOC_DEBUG + std::cerr << "=== DEALLOCATING " << iObj->ob_type->tp_name << "+ ===\n"; + #endif + CppPyObject<T> *Obj = (CppPyObject<T> *)iObj; + if (!((CppPyObject<T>*)Obj)->NoDelete) + Obj->Object.~T(); + CppClear<T>(iObj); + iObj->ob_type->tp_free(iObj); } + template <class T> -void CppOwnedDealloc(PyObject *iObj) +void CppDeallocPtr(PyObject *iObj) { - CppOwnedPyObject<T> *Obj = (CppOwnedPyObject<T> *)iObj; - Obj->Object.~T(); - if (Obj->Owner != 0) { - Py_DECREF(Obj->Owner); - } - PyObject_DEL(Obj); + #ifdef ALLOC_DEBUG + std::cerr << "=== DEALLOCATING " << iObj->ob_type->tp_name << "*+ ===\n"; + #endif + CppPyObject<T> *Obj = (CppPyObject<T> *)iObj; + if (!((CppPyObject<T>*)Obj)->NoDelete) + delete Obj->Object; + CppClear<T>(iObj); + iObj->ob_type->tp_free(iObj); } inline PyObject *CppPyString(std::string Str) @@ -146,4 +227,10 @@ PyObject *HandleErrors(PyObject *Res = 0); const char **ListToCharChar(PyObject *List,bool NullTerm = false); PyObject *CharCharToList(const char **List,unsigned long Size = 0); +# ifdef COMPAT_0_7 +PyObject *_PyAptObject_getattro(PyObject *self, PyObject *attr); +# else +# define _PyAptObject_getattro 0 +# endif + #endif |
