diff --git a/src/converter/body.cpp b/src/converter/body.cpp new file mode 100644 index 00000000..637f8c3e --- /dev/null +++ b/src/converter/body.cpp @@ -0,0 +1,18 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#include + +namespace boost { namespace python { namespace converter { + +// default implementation is a no-op. Most handles will not hold any +// data that needs to be managed. Unwrap objects which convert +// by-value are an exception. Fortunately, the concrete body subclass +// has that knowledge. +void body::destroy_handle(handle*) const +{ +} + +}}} // namespace boost::python::converter diff --git a/src/converter/handle.cpp b/src/converter/handle.cpp new file mode 100644 index 00000000..1a2b8c31 --- /dev/null +++ b/src/converter/handle.cpp @@ -0,0 +1,35 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#include +#include + +namespace boost { namespace python { namespace converter { + +bool handle::convertible() const +{ + for (handle const* p = this; p != 0; p = p->m_next) + { + if (p->m_body == 0) + return false; + } + return true; +} + +void handle::destroy() +{ + // Recurse down the chain releasing from tail to head + if (m_next != 0) + m_next->destroy(); + + // Our body knows how to destroy us. If we never got a body, + // there's nothing to do. + if (m_body) + m_body->destroy_handle(this); +} + +// void handle::dummy::nonnull() {} + +}}} // namespace boost::python::converter diff --git a/src/converter/registry.cpp b/src/converter/registry.cpp new file mode 100644 index 00000000..1dd1c7cb --- /dev/null +++ b/src/converter/registry.cpp @@ -0,0 +1,170 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. + +# include +# include +# include +# include +# include +# include +# ifdef BOOST_PYTHON_TRACE +# include +# endif + +namespace boost { namespace python { namespace converter { + +namespace // +{ + typedef std::map registry_t; + + registry_t& entries() + { + static registry_t registry; + return registry; + } +} // namespace + +namespace registry +{ + entry* find(type_id_t type) + { + return &entries()[type]; + } + + entry::entry() + : m_wrapper(0) + { + } + + namespace // + { + // A UnaryFunction type which deletes its argument + struct delete_item + { + template + void operator()(T* x) const + { + delete x; + } + }; + + // A UnaryFunction type which returns true iff its argument is a + // unwrapper which can convert the given Python object. + struct convertible + { + convertible(PyObject* p) + : m_p(p) + {} + + bool operator()(unwrapper_base* converter) const + { + return converter->convertible(m_p); + } + + PyObject* m_p; + }; + } + + entry::~entry() + { + } + + unwrapper_base* entry::unwrapper(PyObject* p) const + { + unwrappers::const_iterator q = + std::find_if(m_unwrappers.begin(), m_unwrappers.end(), convertible(p)); + + return q == m_unwrappers.end() ? 0 : *q; + } + + wrapper_base* entry::wrapper() const + { + return m_wrapper; + } + + entry::unwrappers::iterator entry::find(unwrapper_base const& x) + { + return std::find(m_unwrappers.begin(), m_unwrappers.end(), &x); + } + + void entry::insert(unwrapper_base& x) + { + unwrappers::iterator p = this->find(x); + + assert(p == m_unwrappers.end()); + if (p != m_unwrappers.end()) + { + throw std::runtime_error( + "trying to register unrapper which is already registered"); + } + m_unwrappers.push_back(&x); + } + + void entry::remove(unwrapper_base& x) + { + unwrappers::iterator p = find(x); + + // Be sure we're not removing a converter which hasn't been + // registered. + assert(p != m_unwrappers.end()); + if (p == m_unwrappers.end()) + { + throw std::runtime_error( + "trying to unregister unwrapper which is not registered"); + } + m_unwrappers.erase(p); + } + + void entry::insert(wrapper_base& x) + { + assert(m_wrapper == 0); // we have a problem otherwise + if (m_wrapper != 0) + { + throw std::runtime_error( + "trying to register wrapper for a type which already has a registered wrapper"); + } + m_wrapper = &x; + } + + void entry::remove(wrapper_base& x) + { + assert(m_wrapper == &x); + if (m_wrapper != &x) + { + throw std::runtime_error( + "trying to unregister a wrapper which is not registered"); + } + m_wrapper = 0; + } + + void insert(wrapper_base& w) + { +# ifdef BOOST_PYTHON_TRACE + std::cout << "inserting wrapper for " << w.key() << std::endl; +# endif + find(w.key())->insert(w); + } + + void insert(unwrapper_base& u) + { +# ifdef BOOST_PYTHON_TRACE + std::cout << "inserting unwrapper for " << u.key() << std::endl; +# endif + find(u.key())->insert(u); + } + + void remove(wrapper_base& w) + { + find(w.key())->remove(w); + } + + void remove(unwrapper_base& u) + { + find(u.key())->remove(u); + } +} // namespace registry + +}}} // namespace boost::python::converter diff --git a/src/converter/type_id.cpp b/src/converter/type_id.cpp new file mode 100644 index 00000000..23f6e4bc --- /dev/null +++ b/src/converter/type_id.cpp @@ -0,0 +1,67 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. + +#include +#if !defined(__GNUC__) || __GNUC__ >= 3 || __SGI_STL_PORT +# include +#else +# include +#endif + +namespace boost { namespace python { namespace converter { + +#if 1 +bool type_id_before::operator()(type_id_t const& x, type_id_t const& y) const +{ + return x < y; +} + +BOOST_PYTHON_EXPORT std::ostream& operator<<(std::ostream& os, type_id_t const& x) +{ +# ifdef BOOST_PYTHON_TYPE_ID_NAME + os << x.m_base_type;e +# else + os << x.m_base_type->name(); +# endif + // VC6 mistakenly distinguishes typeid(X) from typeid(X const) + // from typeid(X&)... so the name is already correct. I have it + // from Jason Shirk that VC7.0 has the same bug but it will be + // fixed in 7.1 +# if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 + if (x.m_decoration & type_id_t::const_) + os << " const"; + if (x.m_decoration & type_id_t::volatile_) + os << " volatile"; + if (x.m_decoration & type_id_t::reference) + os << "&"; +# endif + return os; +} + +#else +bool type_id_before::operator()(type_id_t const& x, type_id_t const& y) const +{ + for (;;) + { + if (*y == 0) + { + return 0; + } + else if (*x == 0) + { + return 1; + } + else if (*x != *y) + { + return *x < *y; + } + ++x; + ++y; + } +} +#endif + +}}} // namespace boost::python::converter diff --git a/src/converter/unwrap.cpp b/src/converter/unwrap.cpp new file mode 100644 index 00000000..e0c09db6 --- /dev/null +++ b/src/converter/unwrap.cpp @@ -0,0 +1,35 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. + +#include + +namespace boost { namespace python { namespace converter { + +namespace +{ + struct pyobject_unwrapper : unwrapper_base + { + pyobject_unwrapper(); + bool convertible(PyObject*) const; + }; + + pyobject_unwrapper static_unwrapper; + + pyobject_unwrapper::pyobject_unwrapper() + : unwrapper_base(type_id()) + { + } + + bool pyobject_unwrapper::convertible(PyObject*) const + { + return true; + } +} + +BOOST_PYTHON_EXPORT unwrapper_base* +unwrap_more_::m_unwrapper = &static_unwrapper; + +}}} // namespace boost::python::converter diff --git a/src/converter/unwrapper.cpp b/src/converter/unwrapper.cpp new file mode 100644 index 00000000..0681ea99 --- /dev/null +++ b/src/converter/unwrapper.cpp @@ -0,0 +1,23 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#include +#include +#include + +namespace boost { namespace python { namespace converter { + +unwrapper_base::unwrapper_base(type_id_t key) + : body(key) +{ + registry::insert(*this); +} + +unwrapper_base::~unwrapper_base() +{ + registry::remove(*this); +} + +}}} // namespace boost::python::converter diff --git a/src/converter/wrapper.cpp b/src/converter/wrapper.cpp new file mode 100644 index 00000000..9038cd6d --- /dev/null +++ b/src/converter/wrapper.cpp @@ -0,0 +1,29 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. + +#include +#include + +namespace boost { namespace python { namespace converter { + +wrapper_base::wrapper_base(type_id_t type) + : body(type) +{ + // static assertions for target. These would go in a header, + // but Metrowerks only respects BOOST_STATIC_ASSERT if it is in an + // instantiated function +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +#else +#endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + registry::insert(*this); +} + +wrapper_base::~wrapper_base() +{ + registry::remove(*this); +} + +}}} // namespace boost::python::converter diff --git a/src/gen_call.py b/src/gen_call.py new file mode 100644 index 00000000..dd178648 --- /dev/null +++ b/src/gen_call.py @@ -0,0 +1,82 @@ +# (C) Copyright David Abrahams 2001. Permission to copy, use, modify, sell and +# distribute this software is granted provided this copyright notice appears +# in all copies. This software is provided "as is" without express or implied +# warranty, and with no claim as to its suitability for any purpose. +# +# This work was funded in part by Lawrence Berkeley National Labs + +from gen_function import * +import string + +header = '''// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +// +// This work was funded in part by Lawrence Berkeley National Labs +// +// This file generated for %d-argument member functions and %d-argument free +// functions by gen_call.py + +#ifndef CALL_DWA20011214_HPP +# define CALL_DWA20011214_HPP + +# include + +namespace boost { namespace python { + +''' +_cv_qualifiers = ('', ' const', ' volatile', ' const volatile') + +def gen_call(member_function_args, free_function_args = None): + if free_function_args is None: + free_function_args = member_function_args + 1 + + return (header % (member_function_args, free_function_args) + + gen_functions( +'''template +PyObject* call(R (*f)(%(A%n%:, %)), PyObject* args, PyObject* keywords) +{ + return detail::returning::call(f, args, keywords); +} + +''', free_function_args) + + +'''// Member functions +''' + + reduce(lambda x,y: x+y + , map(lambda cv: + gen_functions( +'''template +PyObject* call(R (A0::*f)(%(A%+%:, %))%1, PyObject* args, PyObject* keywords) +{ + return detail::returning::call(f, args, keywords); +} + +''' + , member_function_args, cv) + , _cv_qualifiers)) + + +''' +}} // namespace boost::python + +#endif // CALL_DWA20011214_HPP +''') + +if __name__ == '__main__': + import sys + + if len(sys.argv) == 1: + member_function_args = 5 + free_function_args = 6 + else: + member_function_args = int(sys.argv[1]) + if len(sys.argv) > 2: + free_function_args = int(sys.argv[2]) + else: + free_function_args = member_function_args + + print gen_call(member_function_args, free_function_args) + + diff --git a/src/gen_returning.py b/src/gen_returning.py new file mode 100644 index 00000000..2b112cc0 --- /dev/null +++ b/src/gen_returning.py @@ -0,0 +1,191 @@ +# (C) Copyright David Abrahams 2001. Permission to copy, use, modify, sell and +# distribute this software is granted provided this copyright notice appears +# in all copies. This software is provided "as is" without express or implied +# warranty, and with no claim as to its suitability for any purpose. +# +# This work was funded in part by Lawrence Berkeley National Labs + +from gen_function import * +import string + +header = '''// (C) Copyright David Abrahams 2001. Permission to copy, use, modify, sell and +// distribute this software is granted provided this copyright notice appears +// in all copies. This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// +// This work was funded in part by Lawrence Berkeley National Labs +// +// This file generated for %d-argument member functions and %d-argument free +// functions by gen_returning.py +''' + +body_sections = ( +''' +#ifndef RETURNING_DWA20011201_HPP +# define RETURNING_DWA20011201_HPP + +//# include +# include +# include +# include +# include + +namespace boost { namespace python { namespace detail { + +// Calling C++ from Python +template +struct returning +{ +''', +''' +''', +''' // Free functions +''', +'''}; + +template <> +struct returning +{ + typedef void R; +''', +''' +''', +''' + // Free functions +''', +'''}; + +}}} // namespace boost::python::detail + +#endif // RETURNING_DWA20011201_HPP +''') + +#' + +member_function = ''' template + static PyObject* call(R (A0::*pmf)(%(A%+%:, %))%1, PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); +%( unwrap_more c%+(PyTuple_GET_ITEM(args, %+), c%n); +%) +%[r%: // find the result converter + wrap_more r(c%n); +%] if (!c0) return 0; + %[r%:return r( %]((*c0).*pmf)(%(*c%+%:, %))%[r%: )%];%[v%: + return detail::none();%] + }; +''' + +free_function = '''%{ template <%(class A%n%:, %)> +%} static PyObject* call(R (*pf)(%(A%n%:, %)), PyObject*%{ args%}, PyObject* /* keywords */ ) + {%{ + // check that each of the arguments is convertible +%}%( unwrap%{_more%} c%n(PyTuple_GET_ITEM(args, %n)%{, c%-%}); +%)%[r%: + // find the result converter + wrap%{_more%} r%{(c%-)%};%]%{ + if (!c0) return 0;%} + %[r%:return r( %](*pf)(%(*c%n%:, %))%[r%: )%];%[v%: + return detail::none();%] + }; +''' + +def _returns_value(key, n, args, value): + if key == 'r': + return value + # pass the value through gen_function again for recursive expansion +# return apply(gen_function, (value, n) + args +# , {'fill': _returns_value}) + else: + assert key == 'v' + return '' + +def _returns_void(key, n, args, value): + if key == 'v': + return value + else: + assert key == 'r' + # return the empty string, ignoring the value + return '' + +_cv_qualifiers = ('', ' const', ' volatile', ' const volatile') + +_prefix = { +# ' const': ''' + +# // missing cv-qualified -> cv-unqualified member pointer conversions +# # if defined(__MWERKS__) && __MWERKS__ <=0x2406 || defined(BOOST_MSVC) && BOOST_MSVC <= 1200 || defined(__BORLANDC__) +# ''', + ' const volatile': ''' +// missing const volatile type traits +# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +'''}; + +def gen_returning(member_function_args, free_function_args = None): + if free_function_args is None: + free_function_args = member_function_args + 1 + + return_none = '''; + return detail::none();''' + + return (header % (member_function_args, free_function_args) + + body_sections[0] + # + # functions returning results + # + + + reduce(lambda x,y: x+y + , map(lambda cv: + _prefix.get(cv,'') + + gen_functions(member_function, + member_function_args, cv, + fill = _returns_value) + '\n' + , _cv_qualifiers)) + + '''# endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + +''' +## endif // missing cv-qualified -> cv-unqualified member pointer conversions +#''' + # free functions + + gen_functions(free_function, free_function_args, fill = _returns_value) + + body_sections[3] + + # + # functions returning void + # + + + reduce(lambda x,y: x+y + , map(lambda cv: + _prefix.get(cv,'') + + gen_functions(member_function, + member_function_args, cv, fill = + _returns_void) + '\n' + , _cv_qualifiers)) + + + '''# endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + +''' +## endif // missing cv-qualified -> cv-unqualified member pointer conversions +#''' + # free functions + + gen_functions(free_function, free_function_args, fill = _returns_void) + + body_sections[6] + ) + +if __name__ == '__main__': + import sys + + if len(sys.argv) == 1: + member_function_args = 5 + free_function_args = 6 + else: + member_function_args = int(sys.argv[1]) + if len(sys.argv) > 2: + free_function_args = int(sys.argv[2]) + else: + free_function_args = member_function_args + + print gen_returning(member_function_args, free_function_args) + + diff --git a/src/object/class.cpp b/src/object/class.cpp new file mode 100644 index 00000000..ead43b60 --- /dev/null +++ b/src/object/class.cpp @@ -0,0 +1,117 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. + +#include +#include +#include + +namespace boost { namespace python { namespace object { + +holder_base::holder_base(converter::type_id_t id) + : m_type(id) + , m_next(0) +{ +} + +holder_base::~holder_base() +{ +} + +BOOST_PYTHON_EXPORT PyTypeObject class_metatype = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "Boost.Python.class", + PyType_Type.tp_basicsize, + 0, + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + &PyType_Type, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, + // PyType_GenericNew /* tp_new */ +}; + +BOOST_PYTHON_EXPORT PyTypeObject class_type = { + PyObject_HEAD_INIT(&class_metatype) + 0, + "Boost.Python.instance", + sizeof(instance), + 0, + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + &PyBaseObject_Type, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + PyType_GenericNew +}; + +void holder_base::install(PyObject* self) +{ + assert(self->ob_type->ob_type == &class_metatype); + m_next = ((instance*)self)->objects; + ((instance*)self)->objects = this; +} + +}}} // namespace boost::python::object diff --git a/src/object/function.cpp b/src/object/function.cpp new file mode 100644 index 00000000..4c2de3c7 --- /dev/null +++ b/src/object/function.cpp @@ -0,0 +1,95 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. + +#include + +namespace boost { namespace python { namespace object { + + +function::function(py_function implementation) + : m_fn(implementation) +{ + PyObject* p = this; + PyObject_INIT(p, &function_type); +} + +function::~function() +{ +} + +PyObject* function::call(PyObject* args, PyObject* keywords) const +{ + return m_fn(args, keywords); +} + +extern "C" +{ + // Stolen from Python's funcobject.c + static PyObject * + function_descr_get(PyObject *func, PyObject *obj, PyObject *type) + { + if (obj == Py_None) + obj = NULL; + return PyMethod_New(func, obj, type); + } + + static void + function_dealloc(PyObject* p) + { + delete static_cast(p); + } + + static PyObject * + function_call(PyObject *func, PyObject *arg, PyObject *kw) + { + return static_cast(func)->call(arg, kw); + } +} + +PyTypeObject function_type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "Boost.Python.function", + sizeof(function), + 0, + (destructor)function_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, //(reprfunc)func_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + function_call, /* tp_call */ + 0, /* tp_str */ + 0, // PyObject_GenericGetAttr, /* tp_getattro */ + 0, // PyObject_GenericSetAttr, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT /* | Py_TPFLAGS_HAVE_GC */,/* tp_flags */ + 0, /* tp_doc */ + 0, // (traverseproc)func_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, //offsetof(PyFunctionObject, func_weakreflist), /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, // func_memberlist, /* tp_members */ + 0, //func_getsetlist, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + function_descr_get, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, //offsetof(PyFunctionObject, func_dict), /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, + 0 /* tp_new */ +}; + +}}} // namespace boost::python::object diff --git a/test/complicated.hpp b/test/complicated.hpp new file mode 100644 index 00000000..123c53fe --- /dev/null +++ b/test/complicated.hpp @@ -0,0 +1,39 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef COMPLICATED_DWA20011215_HPP +# define COMPLICATED_DWA20011215_HPP +# include + +# include "simple_type.hpp" + +struct complicated +{ + complicated(simple const&, int = 0); + ~complicated(); + + int get_n() const; + + char* s; + int n; +}; + +inline complicated::complicated(simple const&s, int n) + : s(s.s), n(n) +{ + std::cout << "constructing complicated: " << this->s << ", " << n << std::endl; +} + +inline complicated::~complicated() +{ + std::cout << "destroying complicated: " << this->s << ", " << n << std::endl; +} + +inline int complicated::get_n() const +{ + return n; +} + +#endif // COMPLICATED_DWA20011215_HPP diff --git a/test/m1.cpp b/test/m1.cpp new file mode 100644 index 00000000..f23a525b --- /dev/null +++ b/test/m1.cpp @@ -0,0 +1,286 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. + +// Seems to be neccessary to suppress an ICE with MSVC +#include "boost/mpl/comparison/less.hpp" + +#include "simple_type.hpp" +#include "complicated.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" void +dealloc(PyObject* self) +{ + PyObject_Del(self); +} + +struct NoddyObject : PyObject +{ + int x; +}; + +PyTypeObject NoddyType = { + PyObject_HEAD_INIT(NULL) + 0, + "Noddy", + sizeof(NoddyObject), + 0, + dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ +}; + +struct SimpleObject : PyObject +{ + simple x; +}; + +PyTypeObject SimpleType = { + PyObject_HEAD_INIT(NULL) + 0, + "Simple", + sizeof(SimpleObject), + 0, + dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 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; +} + +extern "C" PyObject* +new_simple(PyObject* self, PyObject* args) +{ + SimpleObject* simple; + + if (!PyArg_ParseTuple(args,":new_simple")) + return NULL; + + simple = PyObject_New(SimpleObject, &SimpleType); + simple->x.s = "hello, world"; + + return (PyObject*)simple; +} + +static PyMethodDef methods[] = { + { "new_noddy", new_noddy, METH_VARARGS }, + { "new_simple", new_simple, METH_VARARGS }, + {NULL, NULL} +}; + +struct int_wrapper + : boost::python::converter::wrapper +{ + PyObject* convert(int const& x) const + { + return PyInt_FromLong(x); + } +}; + +struct simple_wrapper + : boost::python::converter::wrapper +{ + PyObject* convert(simple const& x) const + { + SimpleObject* p = PyObject_New(SimpleObject, &SimpleType); + p->x = x; + return p; + } +}; + +struct simple_ref_wrapper + : boost::python::converter::wrapper +{ + PyObject* convert(simple& x) const + { + SimpleObject* p = PyObject_New(SimpleObject, &SimpleType); + p->x = x; + return p; + } +}; + +struct native_int_unwrapper + : boost::python::converter::unwrapper +{ + bool convertible(PyObject* p) const + { + return PyInt_Check(p); + } + + int convert(PyObject* p, void*&) const + { + return PyInt_AsLong(p); + } +}; + +struct noddy_int_unwrapper + : boost::python::converter::unwrapper +{ + bool convertible(PyObject* p) const + { + return p->ob_type == &NoddyType; + } + + int convert(PyObject* p, void*&) const + { + return static_cast(p)->x; + } +}; + +struct noddy_int_ref_unwrapper + : boost::python::converter::unwrapper +{ + bool convertible(PyObject* p) const + { + return p->ob_type == &NoddyType; + } + + int& convert(PyObject* p, void*&) const + { + return static_cast(p)->x; + } +}; + +struct simple_ref_unwrapper + : boost::python::converter::unwrapper +{ + bool convertible(PyObject* p) const + { + return p->ob_type == &SimpleType; + } + + simple& convert(PyObject* p, void*&) const + { + return static_cast(p)->x; + } +}; + +struct simple_const_ref_unwrapper + : boost::python::converter::unwrapper +{ + bool convertible(PyObject* p) const + { + return p->ob_type == &SimpleType; + } + + simple const& convert(PyObject* p, void*&) const + { + return static_cast(p)->x; + } +}; + +int f(simple const& s) +{ + return strlen(s.s); +} + +simple const& g(simple const& x) +{ + return x; +} + +BOOST_PYTHON_MODULE_INIT(m1) +{ + PyObject* m1 = Py_InitModule(const_cast("m1"), methods); + + static int_wrapper wrap_int; + static simple_wrapper wrap_simple; + static native_int_unwrapper unwrap_int1; + static noddy_int_unwrapper unwrap_int2; + static noddy_int_ref_unwrapper unwrap_int3; + static simple_ref_unwrapper unwrap_simple; +#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + // These compilers will need additional converters + static simple_const_ref_unwrapper unwrap_simple_const_ref; + static simple_ref_wrapper wrap_simple_ref; +#endif + + // Not quite right + if (PyType_Ready(&boost::python::object::class_metatype) < 0) + return; + + if (PyType_Ready(&boost::python::object::class_type) < 0) + return; + + Py_INCREF(&boost::python::object::class_type); + PyObject* d = PyModule_GetDict(m1); + if (d == NULL) + return; + + if (PyDict_SetItemString( + d, "xclass", (PyObject *)&boost::python::object::class_metatype) < 0) + return; + + if (PyDict_SetItemString( + d, "xinst", (PyObject *)&boost::python::object::class_type) < 0) + return; + + if (PyDict_SetItemString( + d, "f", boost::python::make_function(f)) < 0) + return; + + if (PyDict_SetItemString( + d, "g", boost::python::make_function(g)) < 0) + return; + + if (PyDict_SetItemString( + d, "get_n", boost::python::make_function(&complicated::get_n)) < 0) + return; + + if (PyDict_SetItemString( + d, "init1" + , boost::python::make_constructor< + complicated + , boost::mpl::type_list + , boost::python::object::value_holder_generator>() + ) < 0) + return; + + if (PyDict_SetItemString( + d, "init2" + , boost::python::make_constructor< + complicated + , boost::mpl::type_list + , boost::python::object::value_holder_generator>() + ) < 0) + return; +} + +#include "module_tail.cpp" diff --git a/test/m2.cpp b/test/m2.cpp new file mode 100644 index 00000000..d2093a20 --- /dev/null +++ b/test/m2.cpp @@ -0,0 +1,197 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. + +#include +#include +#include "simple_type.hpp" + +using boost::python::wrap; +using boost::python::unwrap; + +extern "C" { + PyObject* + unwrap_simple(PyObject* self, PyObject* args) + { + PyObject* p; + if (!PyArg_ParseTuple(args, "O", &p)) + return 0; + + boost::python::unwrap in(p); + if (!in) + return 0; + + simple x = *in; + + return PyString_FromString(x.s); + }; + + PyObject* + unwrap_simple_ref(PyObject* self, PyObject* args) + { + PyObject* p; + if (!PyArg_ParseTuple(args, "O", &p)) + return 0; + + unwrap in(p); + if (!in) + return 0; + + simple& x = *in; + + return PyString_FromString(x.s); + }; + + PyObject* + unwrap_simple_const_ref(PyObject* self, PyObject* args) + { + PyObject* p; + if (!PyArg_ParseTuple(args, "O", &p)) + return 0; + + unwrap in(p); + if (!in) + return 0; + + simple const& x = *in; + + return PyString_FromString(x.s); + }; + + PyObject* + unwrap_int(PyObject* self, PyObject* args) + { + PyObject* p; + if (!PyArg_ParseTuple(args, "O", &p)) + return 0; + + unwrap in(p); + if (!in) + return 0; + + int x = *in; + + return PyInt_FromLong(x); + }; + + PyObject* + unwrap_int_ref(PyObject* self, PyObject* args) + { + PyObject* p; + if (!PyArg_ParseTuple(args, "O", &p)) + return 0; + + unwrap in(p); + if (!in) + return 0; + + int& x = *in; + + return PyInt_FromLong(x); + }; + + PyObject* + unwrap_int_const_ref(PyObject* self, PyObject* args) + { + PyObject* p; + if (!PyArg_ParseTuple(args, "O", &p)) + return 0; + + unwrap in(p); + if (!in) + return 0; + + int const& x = *in; + + return PyInt_FromLong(x); + }; + + // ------------------- +} +template struct xxxx; + +template +PyObject* +rewrap(PyObject* self, PyObject* args, xxxx* = 0) +{ + PyObject* p; + if (!PyArg_ParseTuple(args, "O", &p)) + return 0; + + boost::python::unwrap in(p); + if (!in) + return 0; + + boost::python::wrap out; + if (!out) + return 0; + + T x = *in; + return out(x); +} + +extern "C" +{ + PyObject* + wrap_simple(PyObject* self, PyObject* args) + { + return rewrap(self, args); + }; + + PyObject* + wrap_simple_ref(PyObject* self, PyObject* args) + { + return rewrap(self, args); + }; + + PyObject* + wrap_simple_const_ref(PyObject* self, PyObject* args) + { + return rewrap(self, args); + }; + + PyObject* + wrap_int(PyObject* self, PyObject* args) + { + return rewrap(self, args); + }; + + PyObject* + wrap_int_ref(PyObject* self, PyObject* args) + { + return rewrap(self, args); + }; + + PyObject* + wrap_int_const_ref(PyObject* self, PyObject* args) + { + return rewrap(self, args); + }; +} + +PyMethodDef initial_methods[] = +{ + { "unwrap_int", unwrap_int, METH_VARARGS, 0 }, + { "unwrap_int_ref", unwrap_int_ref, METH_VARARGS, 0 }, + { "unwrap_int_const_ref", unwrap_int_const_ref, METH_VARARGS, 0 }, + { "unwrap_simple", unwrap_simple, METH_VARARGS, 0 }, + { "unwrap_simple_ref", unwrap_simple_ref, METH_VARARGS, 0 }, + { "unwrap_simple_const_ref", unwrap_simple_const_ref, METH_VARARGS, 0 }, + + { "wrap_int", wrap_int, METH_VARARGS, 0 }, + { "wrap_int_ref", wrap_int_ref, METH_VARARGS, 0 }, + { "wrap_int_const_ref", wrap_int_const_ref, METH_VARARGS, 0 }, + { "wrap_simple", wrap_simple, METH_VARARGS, 0 }, + { "wrap_simple_ref", wrap_simple_ref, METH_VARARGS, 0 }, + { "wrap_simple_const_ref", wrap_simple_const_ref, METH_VARARGS, 0 }, + { 0, 0, 0, 0 } +}; + +BOOST_PYTHON_MODULE_INIT(m2) +{ + Py_InitModule(const_cast("m2"), initial_methods); +} + +#include "module_tail.cpp" diff --git a/test/module_tail.cpp b/test/module_tail.cpp new file mode 100644 index 00000000..6849bf83 --- /dev/null +++ b/test/module_tail.cpp @@ -0,0 +1,39 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. + +#if defined(_WIN32) +# ifdef __MWERKS__ +# pragma ANSI_strict off +# endif +# include +# ifdef __MWERKS__ +# pragma ANSI_strict reset +# endif + +extern "C" BOOL WINAPI DllMain ( HINSTANCE hInst, DWORD wDataSeg, LPVOID lpvReserved ); + +# ifdef BOOST_MSVC +extern "C" void structured_exception_translator(unsigned int, EXCEPTION_POINTERS*) +{ + throw; +} +# endif + +BOOL WINAPI DllMain( + HINSTANCE, //hDllInst + DWORD fdwReason, + LPVOID // lpvReserved + ) +{ +# ifdef BOOST_MSVC + _set_se_translator(structured_exception_translator); +# endif + (void)fdwReason; // warning suppression. + + return 1; +} +#endif // _WIN32 + diff --git a/test/newtest.py b/test/newtest.py new file mode 100644 index 00000000..cd610c6d --- /dev/null +++ b/test/newtest.py @@ -0,0 +1,90 @@ +""" +>>> from m1 import * + +>>> from m2 import * + +>>> n = new_noddy() +>>> s = new_simple() +>>> unwrap_int(n) +42 +>>> unwrap_int_ref(n) +42 +>>> unwrap_int_const_ref(n) +42 +>>> unwrap_simple(s) +'hello, world' +>>> unwrap_simple_ref(s) +'hello, world' +>>> unwrap_simple_const_ref(s) +'hello, world' +>>> unwrap_int(5) +5 + +Can't get a reference to a built-in integer object +>>> try: +... unwrap_int_ref(7) +... except: pass +... else: print 'no exception' + +>>> try: +... unwrap_int_const_ref(9) +... except: pass +... else: print 'no exception' + +>>> wrap_int(n) +42 + +try: wrap_int_ref(n) +... except: pass +... else: print 'no exception' + +>>> wrap_int_const_ref(n) +42 + +>>> unwrap_simple_ref(wrap_simple(s)) +'hello, world' + +>>> unwrap_simple_ref(wrap_simple_ref(s)) +'hello, world' + +>>> unwrap_simple_ref(wrap_simple_const_ref(s)) +'hello, world' + +>>> f(s) +12 + +>>> unwrap_simple(g(s)) +'hello, world' + +>>> f(g(s)) +12 + +>>> C = xclass('C', (xinst,), {'__init__': init1, 'get_n': get_n}) +>>> c = C(s, 99) +>>> c.get_n() +99 + +>>> D = xclass('D', (xinst,), {'__init__': init2, 'get_n': get_n}) +>>> d = D(s) +>>> d.get_n() +0 + +""" + +def run(args = None): + + import m1,m2 + import string + import re + import sys + + if args is not None: + sys.argv = args + import sys + import doctest + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + sys.exit(run()[0]) diff --git a/test/simple_type.hpp b/test/simple_type.hpp new file mode 100644 index 00000000..2df97cfd --- /dev/null +++ b/test/simple_type.hpp @@ -0,0 +1,14 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef SIMPLE_TYPE_DWA2001128_HPP +# define SIMPLE_TYPE_DWA2001128_HPP + +struct simple +{ + char* s; +}; + +#endif // SIMPLE_TYPE_DWA2001128_HPP