summaryrefslogtreecommitdiff
path: root/python/generic.h
diff options
context:
space:
mode:
Diffstat (limited to 'python/generic.h')
-rw-r--r--python/generic.h167
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