-
-
Save geogreff/f6947877da23e07dab094ebd4fecf574 to your computer and use it in GitHub Desktop.
A very simple example of holding a C++ class in Python.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <Python.h> | |
struct MyClass { | |
int val; | |
MyClass(void) : val(42) {} | |
}; | |
#ifdef __cplusplus | |
extern "C" { | |
#endif // __cplusplus | |
void destroy_funkster(PyObject* funkster) { | |
delete (MyClass*)PyCapsule_GetPointer(funkster, "val"); | |
} | |
static PyObject* get_funkster_val(PyObject *self, PyObject *args) { | |
PyObject* pf = NULL; | |
if(!PyArg_UnpackTuple(args, "funk", 1, 1, &pf)) return NULL; | |
MyClass* f = (MyClass*)PyCapsule_GetPointer(pf, "val"); | |
return PyLong_FromLong(f->val); | |
} | |
static PyObject* make_funkster(PyObject *self, PyObject *args) { | |
return PyCapsule_New((void*)new MyClass(), "val", destroy_funkster); | |
} | |
static PyMethodDef FunksterMethods[] = { | |
{"make_funkster", make_funkster, METH_NOARGS, "Make a Funkster."}, | |
{"get_funkster_val", get_funkster_val, METH_VARARGS, "Get val from Funkster"}, | |
{NULL, NULL, 0, NULL} /* Sentinel */ | |
}; | |
PyMODINIT_FUNC initfunkster(void) { | |
PyObject *m; | |
m = Py_InitModule("funkster", FunksterMethods); | |
if (m == NULL) return; | |
} | |
#ifdef __cplusplus | |
} // end extern "C" | |
#endif // __cplusplus |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* This is an example of how one could hold a templated | |
* class polymorphically in python. | |
* | |
* THIS IS A VERY BAD IMPLEMENTATION THAT DOES NO ERROR | |
* CHECKING AND WOULD CAUSE PYTHON TO CRASH IF A USER DID | |
* SOME PRETTY BENIGN THINGS... YOU HAVE BEEN WARNED. | |
*/ | |
#include <Python.h> | |
enum IDS { ZERO, ONE, TWO, THREE }; | |
template<int ID> | |
struct MyClass { | |
enum { value=ID }; | |
long get(void) const { return ID; } | |
}; | |
struct Wrapper; // forward def | |
static void doDelete(Wrapper*); // forward def | |
struct Wrapper { | |
Wrapper(int id, void* instance) : id(id), instance(instance) {} | |
~Wrapper(void) { doDelete(this); } | |
long id; | |
void* instance; | |
}; | |
static void* makeWrapper(long id) { | |
switch(static_cast<IDS>(id)) { | |
case ZERO: | |
return static_cast<void*>(new Wrapper(id, static_cast<void*>(new MyClass<ZERO>()))); | |
case ONE: | |
return static_cast<void*>(new Wrapper(id, static_cast<void*>(new MyClass<ONE>()))); | |
case TWO: | |
return static_cast<void*>(new Wrapper(id, static_cast<void*>(new MyClass<TWO>()))); | |
case THREE: | |
return static_cast<void*>(new Wrapper(id, static_cast<void*>(new MyClass<THREE>()))); | |
} | |
}; | |
static long doJobby(Wrapper* wrapper) { | |
switch(static_cast<IDS>(wrapper->id)) { | |
case ZERO: | |
return static_cast<MyClass<ZERO>*>(wrapper->instance)->get(); | |
case ONE: | |
return static_cast<MyClass<ONE>*>(wrapper->instance)->get(); | |
case TWO: | |
return static_cast<MyClass<TWO>*>(wrapper->instance)->get(); | |
case THREE: | |
return static_cast<MyClass<THREE>*>(wrapper->instance)->get(); | |
default: | |
return -1; | |
} | |
} | |
static void doDelete(Wrapper* wrapper) { | |
switch(static_cast<IDS>(wrapper->id)) { | |
case ZERO: | |
delete static_cast<MyClass<ZERO>*>(wrapper->instance); | |
break; | |
case ONE: | |
delete static_cast<MyClass<ONE>*>(wrapper->instance); | |
break; | |
case TWO: | |
delete static_cast<MyClass<TWO>*>(wrapper->instance); | |
break; | |
case THREE: | |
delete static_cast<MyClass<THREE>*>(wrapper->instance); | |
break; | |
} | |
} | |
#ifdef __cplusplus | |
extern "C" { | |
#endif // __cplusplus | |
void destroy_funkster(PyObject* funkster) { | |
doDelete((Wrapper*)PyCapsule_GetPointer(funkster, "val")); | |
} | |
static PyObject* make_funkster(PyObject *self, PyObject *args) { | |
PyObject* idp; | |
PyArg_UnpackTuple(args, "funk", 1, 1, &idp); | |
return PyCapsule_New(makeWrapper(PyInt_AsLong(idp)), "val", destroy_funkster); | |
} | |
static PyObject* get_funkster_val(PyObject *self, PyObject *args) { | |
PyObject* pf = NULL; | |
if(!PyArg_UnpackTuple(args, "funk", 1, 1, &pf)) return NULL; | |
Wrapper* w = (Wrapper*)PyCapsule_GetPointer(pf, "val"); | |
return PyLong_FromLong(doJobby(w)); | |
} | |
static PyMethodDef FunksterMethods[] = { | |
{"make_funkster", make_funkster, METH_VARARGS, "Make a Funkster."}, | |
{"get_funkster_val", get_funkster_val, METH_VARARGS, "Get val from Funkster"}, | |
{NULL, NULL, 0, NULL} /* Sentinel */ | |
}; | |
PyMODINIT_FUNC initfunkster(void) { | |
PyObject *m; | |
m = Py_InitModule("funkster", FunksterMethods); | |
if (m == NULL) return; | |
} | |
#ifdef __cplusplus | |
} // end extern "C" | |
#endif // __cplusplus |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* This is an example of how one could hold a templated | |
* class with a polymorphic base polymorphically in python. | |
* | |
* THIS IS A VERY BAD IMPLEMENTATION THAT DOES NO ERROR | |
* CHECKING AND WOULD CAUSE PYTHON TO CRASH IF A USER DID | |
* SOME PRETTY BENIGN THINGS... YOU HAVE BEEN WARNED. | |
*/ | |
#include <Python.h> | |
enum IDS { ZERO, ONE, TWO, THREE }; | |
struct MyBase { | |
virtual ~MyBase(void) {} | |
virtual long get(void) const = 0; | |
virtual MyBase* clone(void) const = 0; | |
}; | |
template<int ID> | |
struct MyClass : MyBase { | |
enum { value=ID }; | |
MyClass(void) {} | |
virtual long get(void) const { return ID; } | |
virtual MyClass* clone(void) const { return new MyClass(); } | |
private: | |
MyClass(MyClass const& other); | |
MyClass& operator=(MyClass const& rhs); | |
}; | |
static void* makeBase(int id) { | |
// note that we could have put the global scope static functions into | |
// instance methods that looked similar to this in funkster2.cpp. | |
switch(static_cast<IDS>(id)) { | |
case ZERO: | |
return static_cast<void*>(new MyClass<ZERO>()); | |
case ONE: | |
return static_cast<void*>(new MyClass<ONE>()); | |
case TWO: | |
return static_cast<void*>(new MyClass<TWO>()); | |
case THREE: | |
return static_cast<void*>(new MyClass<THREE>()); | |
default: | |
// raise an error here. | |
break; | |
} | |
} | |
#ifdef __cplusplus | |
extern "C" { | |
#endif // __cplusplus | |
void destroy_funkster(PyObject* funkster) { | |
delete static_cast<MyBase*>(PyCapsule_GetPointer(funkster, "val")); | |
} | |
static PyObject* make_funkster(PyObject *self, PyObject *args) { | |
PyObject* idp; | |
PyArg_UnpackTuple(args, "funk", 1, 1, &idp); | |
return PyCapsule_New(makeBase(PyInt_AsLong(idp)), "val", destroy_funkster); | |
} | |
static PyObject* get_funkster_val(PyObject *self, PyObject *args) { | |
PyObject* pf = NULL; | |
if(!PyArg_UnpackTuple(args, "funk", 1, 1, &pf)) return NULL; | |
MyBase* b = (MyBase*)PyCapsule_GetPointer(pf, "val"); | |
return PyLong_FromLong(b->get()); | |
} | |
static PyMethodDef FunksterMethods[] = { | |
{"make_funkster", make_funkster, METH_VARARGS, "Make a Funkster."}, | |
{"get_funkster_val", get_funkster_val, METH_VARARGS, "Get val from Funkster"}, | |
{NULL, NULL, 0, NULL} /* Sentinel */ | |
}; | |
PyMODINIT_FUNC initfunkster(void) { | |
PyObject *m; | |
m = Py_InitModule("funkster", FunksterMethods); | |
if (m == NULL) return; | |
} | |
#ifdef __cplusplus | |
} // end extern "C" | |
#endif // __cplusplus |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* This is an example of how one could hold a templated | |
* class with a polymorphic base polymorphically in python. | |
* | |
* While it is slightly more verbose, I prefer this to | |
* the one in funkster3.cpp as this is more straight | |
* forward to wrap using Boost.Python... or at least it | |
* appears to be to a Boost.Python newbie like me! | |
* | |
* THIS IS A VERY BAD IMPLEMENTATION THAT DOES NO ERROR | |
* CHECKING AND WOULD CAUSE PYTHON TO CRASH IF A USER DID | |
* SOME PRETTY BENIGN THINGS... YOU HAVE BEEN WARNED. | |
*/ | |
#include <Python.h> | |
enum IDS { ZERO, ONE, TWO, THREE }; | |
struct MyBase { | |
virtual ~MyBase(void) {} | |
virtual long get(void) const = 0; | |
virtual MyBase* clone(void) const = 0; | |
}; | |
template<int ID> | |
struct MyClass : MyBase { | |
enum { value=ID }; | |
MyClass(void) {} | |
virtual long get(void) const { return ID; } | |
virtual MyClass* clone(void) const { return new MyClass(); } | |
private: | |
MyClass(MyClass const& other); | |
MyClass& operator=(MyClass const& rhs); | |
}; | |
static MyBase* makeBase(int id) { | |
switch(static_cast<IDS>(id)) { | |
case ZERO: | |
return static_cast<MyBase*>(new MyClass<ZERO>()); | |
case ONE: | |
return static_cast<MyBase*>(new MyClass<ONE>()); | |
case TWO: | |
return static_cast<MyBase*>(new MyClass<TWO>()); | |
case THREE: | |
return static_cast<MyBase*>(new MyClass<THREE>()); | |
default: | |
// raise an error here. | |
break; | |
} | |
} | |
struct Wrapper { | |
Wrapper(long id) | |
: instance_(makeBase(id)) { | |
} | |
Wrapper(Wrapper const& other) | |
: instance_(other.instance_->clone()) { | |
} | |
Wrapper& operator=(Wrapper const& rhs) { | |
delete instance_; | |
instance_ = rhs.instance_->clone(); | |
} | |
~Wrapper(void) { | |
delete instance_; | |
} | |
long get(void) { | |
return instance_->get(); | |
} | |
private: | |
MyBase* | |
instance_; | |
}; | |
#ifdef __cplusplus | |
extern "C" { | |
#endif // __cplusplus | |
void destroy_funkster(PyObject* funkster) { | |
delete static_cast<Wrapper*>(PyCapsule_GetPointer(funkster, "val")); | |
} | |
static PyObject* make_funkster(PyObject *self, PyObject *args) { | |
PyObject* idp; | |
PyArg_UnpackTuple(args, "funk", 1, 1, &idp); | |
return PyCapsule_New(new Wrapper(PyInt_AsLong(idp)), "val", destroy_funkster); | |
} | |
static PyObject* get_funkster_val(PyObject *self, PyObject *args) { | |
PyObject* pf = NULL; | |
if(!PyArg_UnpackTuple(args, "funk", 1, 1, &pf)) return NULL; | |
Wrapper* w = (Wrapper*)PyCapsule_GetPointer(pf, "val"); | |
return PyLong_FromLong(w->get()); | |
} | |
static PyMethodDef FunksterMethods[] = { | |
{"make_funkster", make_funkster, METH_VARARGS, "Make a Funkster."}, | |
{"get_funkster_val", get_funkster_val, METH_VARARGS, "Get val from Funkster"}, | |
{NULL, NULL, 0, NULL} /* Sentinel */ | |
}; | |
PyMODINIT_FUNC initfunkster(void) { | |
PyObject *m; | |
m = Py_InitModule("funkster", FunksterMethods); | |
if (m == NULL) return; | |
} | |
#ifdef __cplusplus | |
} // end extern "C" | |
#endif // __cplusplus |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment