diff --git a/test/m1.cpp b/test/m1.cpp index 809a0d63..db450f77 100644 --- a/test/m1.cpp +++ b/test/m1.cpp @@ -5,7 +5,7 @@ // to its suitability for any purpose. // Seems to be neccessary to suppress an ICE with MSVC -#include "boost/mpl/comparison/less.hpp" +#include #include "simple_type.hpp" #include "complicated.hpp" @@ -21,12 +21,14 @@ #include #include +// Declare some straightforward extension types extern "C" void dealloc(PyObject* self) { PyObject_Del(self); } +// Noddy is a type we got from one of the Python sample files struct NoddyObject : PyObject { int x; @@ -50,6 +52,22 @@ PyTypeObject NoddyType = { 0, /*tp_hash */ }; +// Create a Noddy containing 42 +extern "C" PyObject* +new_noddy(PyObject* self, PyObject* args) +{ + NoddyObject* noddy; + + if (!PyArg_ParseTuple(args,":new_noddy")) + return NULL; + + noddy = PyObject_New(NoddyObject, &NoddyType); + noddy->x = 42; + + return (PyObject*)noddy; +} + +// Simple is a wrapper around a struct simple, which just contains a char* struct SimpleObject : PyObject { simple x; @@ -73,20 +91,7 @@ PyTypeObject SimpleType = { 0, /*tp_hash */ }; -extern "C" PyObject* -new_noddy(PyObject* self, PyObject* args) -{ - NoddyObject* noddy; - - if (!PyArg_ParseTuple(args,":new_noddy")) - return NULL; - - noddy = PyObject_New(NoddyObject, &NoddyType); - noddy->x = 42; - - return (PyObject*)noddy; -} - +// Create a Simple containing "hello, world" extern "C" PyObject* new_simple(PyObject* self, PyObject* args) { @@ -101,12 +106,21 @@ new_simple(PyObject* self, PyObject* args) return (PyObject*)simple; } +// Initial method table for the module static PyMethodDef methods[] = { { "new_noddy", new_noddy, METH_VARARGS }, { "new_simple", new_simple, METH_VARARGS }, {0, 0, 0, 0} }; +// +// Declare some wrappers/unwrappers to test the low-level conversion +// mechanism. See boost/python/converter/source.hpp,target.hpp for a +// description of how the type parameters to wrapper<> and unwrapper<> +// are selected. +// + +// Wrap an int by converting it to a Python Int struct int_wrapper : boost::python::converter::wrapper { @@ -116,6 +130,7 @@ struct int_wrapper } }; +// Wrap a simple by converting it to a Simple struct simple_wrapper : boost::python::converter::wrapper { @@ -127,6 +142,10 @@ struct simple_wrapper } }; +// wrap a mutable reference to a simple by converting it to a +// Simple. Normally we wouldn't do it this way, since modifications to +// the result clearly don't change the original object, but here we're +// just proving that the mechanism works. struct simple_ref_wrapper : boost::python::converter::wrapper { @@ -138,6 +157,9 @@ struct simple_ref_wrapper } }; +// extract an int from a Python Int by converting it to an int. Since +// int is a scalar type, we convert by-value. Since Python Ints are +// immutable, there's no non-const reference converter. struct native_int_unwrapper : boost::python::converter::unwrapper { @@ -152,6 +174,7 @@ struct native_int_unwrapper } }; +// Extract an int from a Noddy struct noddy_int_unwrapper : boost::python::converter::unwrapper { @@ -166,6 +189,7 @@ struct noddy_int_unwrapper } }; +// Extract a mutable reference to an int from a Noddy. struct noddy_int_ref_unwrapper : boost::python::converter::unwrapper { @@ -180,6 +204,7 @@ struct noddy_int_ref_unwrapper } }; +// Extract a mutable reference to a simple from a Simple struct simple_ref_unwrapper : boost::python::converter::unwrapper { @@ -194,6 +219,7 @@ struct simple_ref_unwrapper } }; +// Extract a const reference to a simple from a Simple struct simple_const_ref_unwrapper : boost::python::converter::unwrapper { @@ -208,11 +234,17 @@ struct simple_const_ref_unwrapper } }; +// +// Some C++ functions to expose to Python +// + +// Returns the length of s's held string int f(simple const& s) { return strlen(s.s); } +// A trivial passthru function for simple objects simple const& g(simple const& x) { return x; @@ -222,6 +254,7 @@ BOOST_PYTHON_MODULE_INIT(m1) { PyObject* m1 = Py_InitModule(const_cast("m1"), methods); + // Create the converters; they are self-registering/unregistering. static int_wrapper wrap_int; static simple_wrapper wrap_simple; static native_int_unwrapper unwrap_int1; @@ -233,32 +266,41 @@ BOOST_PYTHON_MODULE_INIT(m1) // These compilers will need additional converters static simple_ref_wrapper wrap_simple_ref; #endif + + // This unwrapper extracts pointers and references to the "complicated" class. static boost::python::converter::class_unwrapper unwrap_complicated; PyObject* d = PyModule_GetDict(m1); if (d == NULL) return; + // Insert the extension metaclass object if (PyDict_SetItemString( d, "xclass", (PyObject *)boost::python::object::class_metatype()) < 0) return; + // Insert the base class for all extension classes if (PyDict_SetItemString( d, "xinst", (PyObject *)boost::python::object::class_type()) < 0) return; + // Expose f() if (PyDict_SetItemString( d, "f", boost::python::make_function(f)) < 0) return; + // Expose g() if (PyDict_SetItemString( d, "g", boost::python::make_function(g)) < 0) return; + // Expose complicated's get_n() member function. See newtest.py + // for how it's used to build an extension class. if (PyDict_SetItemString( d, "get_n", boost::python::make_function(&complicated::get_n)) < 0) return; + // Expose complicated::complicated(simple const&, int) as init1 if (PyDict_SetItemString( d, "init1" , boost::python::make_constructor< @@ -268,6 +310,7 @@ BOOST_PYTHON_MODULE_INIT(m1) ) < 0) return; + // Expose complicated::complicated(simple const&) as init2 if (PyDict_SetItemString( d, "init2" , boost::python::make_constructor< diff --git a/test/m2.cpp b/test/m2.cpp index d2093a20..04750dd7 100644 --- a/test/m2.cpp +++ b/test/m2.cpp @@ -4,6 +4,13 @@ // "as is" without express or implied warranty, and with no claim as // to its suitability for any purpose. +// This module exercises the converters exposed in m1 at a low level +// by exposing raw Python extension functions that use wrap<> and +// unwrap<> objects. + +// Seems to be neccessary to suppress an ICE with MSVC +#include + #include #include #include "simple_type.hpp" @@ -11,7 +18,10 @@ using boost::python::wrap; using boost::python::unwrap; -extern "C" { +extern "C" +{ + // Get a simple (by value) from the argument, and return the + // string it holds. PyObject* unwrap_simple(PyObject* self, PyObject* args) { @@ -28,6 +38,8 @@ extern "C" { return PyString_FromString(x.s); }; + // Likewise, but demands that its possible to get a non-const + // reference to the simple. PyObject* unwrap_simple_ref(PyObject* self, PyObject* args) { @@ -44,6 +56,7 @@ extern "C" { return PyString_FromString(x.s); }; + // Likewise, with a const reference to the simple object. PyObject* unwrap_simple_const_ref(PyObject* self, PyObject* args) { @@ -60,6 +73,8 @@ extern "C" { return PyString_FromString(x.s); }; + // Get an int (by value) from the argument, and convert it to a + // Python Int. PyObject* unwrap_int(PyObject* self, PyObject* args) { @@ -76,6 +91,7 @@ extern "C" { return PyInt_FromLong(x); }; + // Get a non-const reference to an int from the argument PyObject* unwrap_int_ref(PyObject* self, PyObject* args) { @@ -92,6 +108,7 @@ extern "C" { return PyInt_FromLong(x); }; + // Get a const reference to an int from the argument. PyObject* unwrap_int_const_ref(PyObject* self, PyObject* args) { @@ -110,8 +127,12 @@ extern "C" { // ------------------- } + +// MSVC6 bug workaround template struct xxxx; +// rewrap extracts a T from the argument, then converts the T back +// to a PyObject* and returns it. template PyObject* rewrap(PyObject* self, PyObject* args, xxxx* = 0) @@ -134,6 +155,10 @@ rewrap(PyObject* self, PyObject* args, xxxx* = 0) extern "C" { + // + // Use rewrap to test simple, simple&, simple const&, int, + // int&, int const& + // PyObject* wrap_simple(PyObject* self, PyObject* args) { diff --git a/test/newtest.py b/test/newtest.py index 783e2240..b866258c 100644 --- a/test/newtest.py +++ b/test/newtest.py @@ -59,11 +59,17 @@ try: wrap_int_ref(n) >>> f(g(s)) 12 +Create an extension class which wraps "complicated" (init1 and get_n) +are a complicated constructor and member function, respectively. + >>> C = xclass('C', (xinst,), {'__init__': init1, 'get_n': get_n}) >>> c = C(s, 99) >>> c.get_n() 99 +Create another extension class which wraps "complicated" (init2 is a +different constructor -- no overloading yet). + >>> D = xclass('D', (xinst,), {'__init__': init2, 'get_n': get_n}) >>> d = D(s) >>> d.get_n()