blob: 23c1db035407fa486e429762ab5b7d9283fdde70 [file] [log] [blame]
// Copyright Gottfried Ganßauge 2003..2006.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
/*
* Generic Conversion of opaque C++-pointers to a Python-Wrapper.
*/
# ifndef OPAQUE_POINTER_CONVERTER_HPP_
# define OPAQUE_POINTER_CONVERTER_HPP_
# include <boost/python/detail/prefix.hpp>
# include <boost/python/lvalue_from_pytype.hpp>
# include <boost/python/to_python_converter.hpp>
# include <boost/python/converter/registrations.hpp>
# include <boost/python/detail/dealloc.hpp>
# include <boost/python/detail/none.hpp>
# include <boost/python/type_id.hpp>
# include <boost/python/errors.hpp>
# include <boost/type_traits/remove_pointer.hpp>
# include <boost/type_traits/is_pointer.hpp>
# include <boost/type_traits/is_void.hpp>
# include <boost/implicit_cast.hpp>
# include <boost/mpl/eval_if.hpp>
# include <boost/mpl/identity.hpp>
# include <boost/mpl/assert.hpp>
// opaque --
//
// registers to- and from- python conversions for a type Pointee.
//
// 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 {
template <class Pointee>
struct opaque
{
opaque()
{
if (type_object.tp_name == 0)
{
type_object.tp_name = const_cast<char*>(type_id<Pointee*>().name());
if (PyType_Ready (&type_object) < 0)
{
throw error_already_set();
}
this->register_self();
}
}
static opaque instance;
private:
static void* extract(PyObject* op)
{
return PyObject_TypeCheck(op, &type_object)
? static_cast<python_instance*>(implicit_cast<void*>(op))->x
: 0
;
}
static PyObject* wrap(void const* px)
{
Pointee* x = *static_cast<Pointee*const*>(px);
if (x == 0)
return detail::none();
if ( python_instance *o = PyObject_New(python_instance, &type_object) )
{
o->x = x;
return static_cast<PyObject*>(implicit_cast<void*>(o));
}
else
{
throw error_already_set();
}
}
void register_self()
{
converter::registration const *existing =
converter::registry::query (type_id<Pointee*>());
if ((existing == 0) || (existing->m_to_python == 0))
{
#ifndef BOOST_PYTHON_NO_PY_SIGNATURES
converter::registry::insert(&extract, type_id<Pointee>(), &get_pytype);
converter::registry::insert(&wrap, type_id<Pointee*>(), &get_pytype);
#else
converter::registry::insert(&extract, type_id<Pointee>());
converter::registry::insert(&wrap, type_id<Pointee*>());
#endif
}
}
struct python_instance
{
PyObject_HEAD
Pointee* x;
};
static PyTypeObject type_object;
#ifndef BOOST_PYTHON_NO_PY_SIGNATURES
static PyTypeObject const *get_pytype(){return &type_object; }
#endif
};
template <class Pointee>
opaque<Pointee> opaque<Pointee>::instance;
template <class Pointee>
PyTypeObject opaque<Pointee>::type_object =
{
PyVarObject_HEAD_INIT(NULL, 0)
0,
sizeof( BOOST_DEDUCED_TYPENAME opaque<Pointee>::python_instance ),
0,
::boost::python::detail::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 */
0, /* 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 */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
0, /* tp_new */
0, /* tp_free */
0, /* tp_is_gc */
0, /* tp_bases */
0, /* tp_mro */
0, /* tp_cache */
0, /* tp_subclasses */
0, /* tp_weaklist */
#if PYTHON_API_VERSION >= 1012
0 /* tp_del */
#endif
};
}} // namespace boost::python
# if BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
# define BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(Pointee)
# else
// If you change the below, don't forget to alter the end of type_id.hpp
# define BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(Pointee) \
namespace boost { namespace python { \
template<> \
inline type_info type_id<Pointee>(BOOST_PYTHON_EXPLICIT_TT_DEF(Pointee)) \
{ \
return type_info (typeid (Pointee *)); \
} \
template<> \
inline type_info type_id<const volatile Pointee&>( \
BOOST_PYTHON_EXPLICIT_TT_DEF(const volatile Pointee&)) \
{ \
return type_info (typeid (Pointee *)); \
} \
}}
# endif
# endif // OPAQUE_POINTER_CONVERTER_HPP_