diff --git a/include/boost/python/opaque_pointer_converter.hpp b/include/boost/python/opaque_pointer_converter.hpp new file mode 100644 index 00000000..ea635e0a --- /dev/null +++ b/include/boost/python/opaque_pointer_converter.hpp @@ -0,0 +1,129 @@ +// Copyright Gottfried Ganßauge 2003. 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. +/* + * Generic Conversion of opaque C++-pointers to a Python-Wrapper. + */ +# ifndef OPAQUE_POINTER_CONVERTER_HPP_ +# define OPAQUE_POINTER_CONVERTER_HPP_ +# include +# include +# include +# include +# include + +// opaque_pointer_converter -- +// +// usage: opaque_pointer_converter("name") +// +// registers to- and from- python conversions for a type Pointer, +// and a corresponding Python type called "name". +// +// Note: +// In addition you need to define specializations for type_id +// on the type pointed to by Pointer using +// BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(Pointee) +// +// For an example see libs/python/test/opaque.cpp +// +namespace boost { namespace python { + namespace detail { + template + struct opaque_pointer_converter_requires_a_pointer_type +# if defined(__GNUC__) && __GNUC__ >= 3 || defined(__EDG__) + {} +# endif + ; + } + +template +struct opaque_pointer_converter + : to_python_converter< + Pointer, opaque_pointer_converter > +{ + BOOST_STATIC_CONSTANT( + bool, ok = is_pointer::value); + + typedef typename mpl::if_c< + ok + , Pointer + , detail::opaque_pointer_converter_requires_a_pointer_type + >::type ptr_type; + + struct instance; + + explicit opaque_pointer_converter(char const* name) + { + type_object.tp_name = const_cast (name); + + lvalue_from_pytype< + opaque_pointer_converter, + &opaque_pointer_converter::type_object + >(); + } + + static PyObject* convert(ptr_type x) + { + PyObject *result = 0; + + if (x != 0) { + instance *o = PyObject_New (instance, &type_object); + + o->x = x; + result = &o->base_; + } else { + result = detail::none(); + } + + return (result); + } + + static typename ::boost::remove_pointer::type& + execute(instance &p_) + { + return *p_.x; + } + +private: + static PyTypeObject type_object; + + // This is a POD so we can use PyObject_Del on it, for example. + struct instance + { + PyObject base_; + ptr_type x; + }; +}; + +template +PyTypeObject opaque_pointer_converter::type_object = +{ + PyObject_HEAD_INIT(NULL) + 0, + 0, + sizeof(typename opaque_pointer_converter::instance), + 0, + ::boost::python::detail::dealloc +}; +}} // namespace boost::python +# ifdef BOOST_MSVC +// MSC works without this workaround, but needs another one ... +# define BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(Pointee) \ +BOOST_BROKEN_COMPILER_TYPE_TRAITS_SPECIALIZATION(Pointee) +# else +# define BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(Pointee) \ +namespace boost { namespace python { \ + template<> \ + inline type_info type_id(boost::type*) { \ + return type_info (typeid (Pointee *)); \ + } \ + template<> \ + inline type_info type_id( \ + boost::type*) { \ + return type_info (typeid (Pointee *)); \ + } \ +}} +# endif +# endif // OPAQUE_POINTER_CONVERTER_HPP_ diff --git a/include/boost/python/return_opaque_pointer.hpp b/include/boost/python/return_opaque_pointer.hpp new file mode 100644 index 00000000..29fb8672 --- /dev/null +++ b/include/boost/python/return_opaque_pointer.hpp @@ -0,0 +1,51 @@ +// Copyright Gottfried Ganßauge 2003. 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. +/* + * Generic Return value converter generator for opaque C++-pointers + */ +# ifndef RETURN_OPAQUE_POINTER_HPP_ +# define RETURN_OPAQUE_POINTER_HPP_ +# include +# include +# include + +namespace boost { namespace python { + namespace detail { + template + struct opaque_conversion_holder { + inline PyObject *operator () (Pointer p) { + static opaque_pointer_converter converter ( + typeid (Pointer).name()); + + return converter.convert(p); + } + }; + + template + struct return_opaque_pointer_requires_a_pointer_type +# if defined(__GNUC__) && __GNUC__ >= 3 || defined(__EDG__) + {} +# endif + ; + } + + struct return_opaque_pointer + { + template + struct apply + { + BOOST_STATIC_CONSTANT( + bool, ok = is_pointer::value); + + typedef typename mpl::if_c< + ok + , detail::opaque_conversion_holder + , detail::return_opaque_pointer_requires_a_pointer_type + >::type type; + }; + }; +}} // namespace boost::python +# endif // RETURN_OPAQUE_POINTER_HPP_ diff --git a/test/opaque.py b/test/opaque.py new file mode 100644 index 00000000..55afa11f --- /dev/null +++ b/test/opaque.py @@ -0,0 +1,77 @@ +# Copyright Gottfried Ganßauge 2003. 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. +""" +>>> from opaque_ext import * +>>> # +>>> # Check for correct conversion +>>> use(get()) + +# Check that None is converted to a NULL opaque pointer +>>> useany(get()) +1 +>>> useany(None) +0 + +# check that we don't lose type information by converting NULL opaque +# pointers to None +>>> assert getnull() is None +>>> useany(getnull()) +0 + +>>> failuse(get()) +Traceback (most recent call last): + ... +RuntimeError: success +>>> # +>>> # Check that there is no conversion from integers ... +>>> use(0) +Traceback (most recent call last): + ... +TypeError: bad argument type for built-in operation +>>> # +>>> # ... and from strings to opaque objects +>>> use("") +Traceback (most recent call last): + ... +TypeError: bad argument type for built-in operation +>>> # +>>> # Now check the same for another opaque pointer type +>>> use2(get2()) +>>> failuse2(get2()) +Traceback (most recent call last): + ... +RuntimeError: success +>>> use2(0) +Traceback (most recent call last): + ... +TypeError: bad argument type for built-in operation +>>> use2("") +Traceback (most recent call last): + ... +TypeError: bad argument type for built-in operation +>>> # +>>> # Check that opaque types are distinct +>>> use(get2()) +Traceback (most recent call last): + ... +TypeError: bad argument type for built-in operation +>>> use2(get()) +Traceback (most recent call last): + ... +TypeError: bad argument type for built-in operation +""" +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + sys.exit(run()[0])