2
0
mirror of https://github.com/boostorg/python.git synced 2026-01-24 18:12:43 +00:00

Rationalized conversion registry

Better error reporting


[SVN r14412]
This commit is contained in:
Dave Abrahams
2002-07-11 21:04:33 +00:00
parent c0ecde90bc
commit b8aaf7d7b1
13 changed files with 241 additions and 233 deletions

View File

@@ -14,8 +14,8 @@
# include <boost/python/converter/rvalue_from_python_data.hpp>
# include <boost/mpl/select_type.hpp>
# include <boost/python/converter/registry.hpp>
# include <boost/python/converter/lvalue_from_python_chain.hpp>
# include <boost/python/converter/rvalue_from_python_chain.hpp>
# include <boost/python/converter/from_python.hpp>
# include <boost/python/converter/pointee_from_python.hpp>
# include <boost/python/detail/void_ptr.hpp>
# include <boost/python/back_reference.hpp>
# include <boost/python/detail/referent_storage.hpp>
@@ -229,7 +229,7 @@ inline pointer_cref_arg_from_python<T>::pointer_cref_arg_from_python(PyObject* p
// a U object.
python::detail::write_void_ptr_reference(
m_result.bytes
, p == Py_None ? p : find(p, lvalue_from_python_chain<T>::value)
, p == Py_None ? p : converter::get_lvalue_from_python(p, pointee_from_python<T>::converters)
, (T(*)())0);
}
@@ -252,7 +252,7 @@ inline T pointer_cref_arg_from_python<T>::operator()(PyObject* p) const
template <class T>
inline pointer_arg_from_python<T>::pointer_arg_from_python(PyObject* p)
: arg_lvalue_from_python_base(
p == Py_None ? p : find(p, lvalue_from_python_chain<T>::value))
p == Py_None ? p : converter::get_lvalue_from_python(p, pointee_from_python<T>::converters))
{
}
@@ -266,7 +266,7 @@ inline T pointer_arg_from_python<T>::operator()(PyObject* p) const
//
template <class T>
inline reference_arg_from_python<T>::reference_arg_from_python(PyObject* p)
: arg_lvalue_from_python_base(find(p,lvalue_from_python_chain<T>::value))
: arg_lvalue_from_python_base(converter::get_lvalue_from_python(p,from_python<T>::converters))
{
}
@@ -281,7 +281,7 @@ inline T reference_arg_from_python<T>::operator()(PyObject*) const
//
template <class T>
inline arg_rvalue_from_python<T>::arg_rvalue_from_python(PyObject* obj)
: m_data(find(obj, rvalue_from_python_chain<T>::value))
: m_data(converter::rvalue_from_python_stage1(obj, from_python<T>::converters))
{
}

View File

@@ -8,16 +8,14 @@
namespace boost { namespace python { namespace converter {
struct rvalue_from_python_stage1_data;
struct from_python_registration;
namespace detail
{
// Throw an exception
BOOST_PYTHON_DECL void throw_if_not_registered(rvalue_from_python_stage1_data const&);
BOOST_PYTHON_DECL void* convert_rvalue(PyObject*, rvalue_from_python_stage1_data&, void* storage);
BOOST_PYTHON_DECL void throw_if_not_registered(lvalue_from_python_registration*const&);
BOOST_PYTHON_DECL void* callback_convert_reference(PyObject*, lvalue_from_python_registration*const&);
BOOST_PYTHON_DECL void* callback_convert_pointer(PyObject*, lvalue_from_python_registration*const&);
BOOST_PYTHON_DECL void* callback_convert_reference(PyObject*, from_python_registration const&);
BOOST_PYTHON_DECL void* callback_convert_pointer(PyObject*, from_python_registration const&);
BOOST_PYTHON_DECL void absorb_result(PyObject*);
}

View File

@@ -12,17 +12,17 @@
namespace boost { namespace python { namespace converter {
struct lvalue_from_python_registration;
struct rvalue_from_python_registration;
struct from_python_registration;
struct rvalue_from_python_chain;
BOOST_PYTHON_DECL void* find(
PyObject* source, lvalue_from_python_registration const*);
BOOST_PYTHON_DECL void* get_lvalue_from_python(
PyObject* source, from_python_registration const&);
BOOST_PYTHON_DECL rvalue_from_python_stage1_data find(
PyObject* source, rvalue_from_python_registration const*);
BOOST_PYTHON_DECL rvalue_from_python_stage1_data rvalue_from_python_stage1(
PyObject* source, from_python_registration const&);
BOOST_PYTHON_DECL rvalue_from_python_registration const* find_chain(
PyObject* source, rvalue_from_python_registration const*);
BOOST_PYTHON_DECL rvalue_from_python_chain const* implicit_conversion_chain(
PyObject* source, from_python_registration const&);
}}} // namespace boost::python::converter

View File

@@ -3,8 +3,8 @@
// 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 RVALUE_FROM_PYTHON_CHAIN_DWA200237_HPP
# define RVALUE_FROM_PYTHON_CHAIN_DWA200237_HPP
#ifndef FROM_PYTHON_DWA2002710_HPP
# define FROM_PYTHON_DWA2002710_HPP
# include <boost/python/type_id.hpp>
# include <boost/python/converter/registry.hpp>
# include <boost/type_traits/transform_traits.hpp>
@@ -12,29 +12,42 @@
namespace boost { namespace python { namespace converter {
struct from_python_registration;
namespace detail
{
template <class T>
struct rvalue_from_python_chain_impl
struct from_python_base
{
static rvalue_from_python_registration*const& value;
static from_python_registration const& converters;
};
template <class T>
rvalue_from_python_registration*const& rvalue_from_python_chain_impl<T>::value
= registry::rvalue_converters(type_id<T>());
}
template <class T>
struct rvalue_from_python_chain
: detail::rvalue_from_python_chain_impl<
struct from_python
: detail::from_python_base<
typename add_reference<
typename add_cv<T>::type
typename add_cv<T>::type
>::type
>
>
{
};
# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
// collapses a few more types to the same static instance
template <class T>
struct from_python<T&> : from_python<T> {};
# endif
//
// implementations
//
namespace detail
{
template <class T>
from_python_registration const& from_python_base<T>::converters
= registry::from_python_converters(type_id<T>());
}
}}} // namespace boost::python::converter
#endif // RVALUE_FROM_PYTHON_CHAIN_DWA200237_HPP
#endif // FROM_PYTHON_DWA2002710_HPP

View File

@@ -16,16 +16,18 @@ struct implicit
static void* convertible(PyObject* obj)
{
// Find a converter registration which can produce a Source
// instance from obj
return const_cast<rvalue_from_python_registration*>(
find_chain(obj, rvalue_from_python_chain<Source>::value));
// instance from obj. The user has told us that Source can be
// converted to Target, and instantiating construct() below,
// ensures that at compile-time.
return const_cast<rvalue_from_python_chain*>(
converter::implicit_conversion_chain(obj, from_python<Source>::converters));
}
static void construct(PyObject* obj, rvalue_from_python_stage1_data* data)
{
// This is the registration we got from the convertible step
rvalue_from_python_registration const* registration
= static_cast<rvalue_from_python_registration*>(data->convertible);
rvalue_from_python_chain const* registration
= static_cast<rvalue_from_python_chain*>(data->convertible);
// Call the convertible function again
rvalue_from_python_data<Source> intermediate_data(registration->convertible(obj));

View File

@@ -1,72 +0,0 @@
// Copyright David Abrahams 2002. 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 LVALUE_FROM_PYTHON_CHAIN_DWA200237_HPP
# define LVALUE_FROM_PYTHON_CHAIN_DWA200237_HPP
# include <boost/python/type_id.hpp>
# include <boost/python/converter/pointer_type_id.hpp>
# include <boost/python/converter/registry.hpp>
# include <boost/type_traits/cv_traits.hpp>
# include <boost/python/detail/indirect_traits.hpp>
namespace boost { namespace python { namespace converter {
// Given T == U*cv&, T == U*, or T == U&, lvalue_from_python_chain<T>
// declares a "templated global reference" to the lvalue from_python
// converter chain for U. The optional bool second argument is_return,
// when true, removes the usual special treatment which causes the
// converter for U* to bve used when T == U*cv&
namespace detail
{
template <class T>
struct ptr_or_ptr_ref_lvalue_from_python_chain
{
static lvalue_from_python_registration*const& value;
};
template <class T>
lvalue_from_python_registration*const&
ptr_or_ptr_ref_lvalue_from_python_chain<T>::value
= registry::lvalue_converters(pointer_type_id<T>());
template <class T>
struct ref_lvalue_from_python_chain
{
static lvalue_from_python_registration*const& value;
};
template <class T>
lvalue_from_python_registration*const&
ref_lvalue_from_python_chain<T>::value
= registry::lvalue_converters(type_id<T>());
template <class T, bool is_return>
struct select_lvalue_from_python_chain
{
BOOST_STATIC_CONSTANT(
bool, ptr
= !is_return && boost::python::detail::is_reference_to_pointer<T>::value
|| is_pointer<T>::value);
typedef typename add_reference<typename add_cv<T>::type>::type normalized;
typedef typename mpl::select_type<
ptr
, ptr_or_ptr_ref_lvalue_from_python_chain<normalized>
, ref_lvalue_from_python_chain<normalized>
>::type type;
};
}
template <class T, bool is_return = false>
struct lvalue_from_python_chain
: detail::select_lvalue_from_python_chain<T,is_return>::type
{
};
}}} // namespace boost::python::converter
#endif // LVALUE_FROM_PYTHON_CHAIN_DWA200237_HPP

View File

@@ -0,0 +1,63 @@
// Copyright David Abrahams 2002. 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 POINTEE_FROM_PYTHON_DWA2002710_HPP
# define POINTEE_FROM_PYTHON_DWA2002710_HPP
# include <boost/python/converter/from_python.hpp>
# include <boost/python/converter/pointer_type_id.hpp>
# include <boost/python/converter/registry.hpp>
# include <boost/type_traits/transform_traits.hpp>
# include <boost/type_traits/cv_traits.hpp>
namespace boost { namespace python { namespace converter {
struct from_python_registration;
# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
template <class T>
struct pointee_from_python
: from_python<
typename remove_pointer<
typename remove_cv<
typename remove_reference<T>::type
>::type
>::type
>
{
};
# else
namespace detail
{
template <class T>
struct pointee_from_python_base
{
static from_python_registration const& converters;
};
}
template <class T>
struct pointee_from_python
: detail::pointee_from_python_base<
typename add_reference<
typename add_cv<T>::type
>::type
>
{
};
//
// implementations
//
namespace detail
{
template <class T>
from_python_registration const& pointee_from_python_base<T>::converters
= registry::from_python_converters(pointer_type_id<T>());
}
# endif
}}} // namespace boost::python::converter
#endif // POINTEE_FROM_PYTHON_DWA2002710_HPP

View File

@@ -8,22 +8,41 @@
# include <boost/python/converter/convertible_function.hpp>
# include <boost/python/converter/constructor_function.hpp>
# include <boost/python/type_id.hpp>
namespace boost { namespace python { namespace converter {
struct lvalue_from_python_registration
struct lvalue_from_python_chain
{
convertible_function convert;
lvalue_from_python_registration* next;
lvalue_from_python_chain* next;
};
struct rvalue_from_python_registration
struct rvalue_from_python_chain
{
convertible_function convertible;
constructor_function construct;
rvalue_from_python_registration* next;
rvalue_from_python_chain* next;
};
struct from_python_registration
{
explicit from_python_registration(type_info);
const python::type_info target_type;
lvalue_from_python_chain* lvalue_chain;
rvalue_from_python_chain* rvalue_chain;
};
//
// implementations
//
inline from_python_registration::from_python_registration(type_info target_type)
: target_type(target_type)
, lvalue_chain(0)
, rvalue_chain(0)
{}
}}} // namespace boost::python::converter
#endif // REGISTRATIONS_DWA2002223_HPP

View File

@@ -15,14 +15,12 @@
namespace boost { namespace python { namespace converter {
struct lvalue_from_python_registration;
struct rvalue_from_python_registration;
struct from_python_registration;
// This namespace acts as a sort of singleton
namespace registry
{
BOOST_PYTHON_DECL lvalue_from_python_registration*& lvalue_converters(type_info);
BOOST_PYTHON_DECL rvalue_from_python_registration*& rvalue_converters(type_info);
BOOST_PYTHON_DECL from_python_registration const& from_python_converters(type_info);
BOOST_PYTHON_DECL to_python_function_t const&
get_to_python_function(type_info);

View File

@@ -8,11 +8,12 @@
# include <boost/python/converter/callback_from_python_base.hpp>
# include <boost/python/converter/rvalue_from_python_data.hpp>
# include <boost/python/converter/rvalue_from_python_chain.hpp>
# include <boost/python/converter/lvalue_from_python_chain.hpp>
# include <boost/python/converter/from_python.hpp>
# include <boost/python/detail/void_ptr.hpp>
# include <boost/call_traits.hpp>
# include <boost/python/detail/void_return.hpp>
# include <boost/python/converter/from_python.hpp>
# include <boost/python/converter/pointee_from_python.hpp>
namespace boost { namespace python { namespace converter {
@@ -22,7 +23,6 @@ namespace detail
struct return_pointer_from_python
{
typedef T result_type;
return_pointer_from_python();
T operator()(PyObject*) const;
};
@@ -30,7 +30,6 @@ namespace detail
struct return_reference_from_python
{
typedef T result_type;
return_reference_from_python();
T operator()(PyObject*) const;
};
@@ -93,9 +92,10 @@ namespace detail
{
template <class T>
inline return_rvalue_from_python<T>::return_rvalue_from_python()
: m_data(rvalue_from_python_chain<T>::value)
: m_data(
const_cast<from_python_registration*>(&from_python<T>::converters)
)
{
throw_if_not_registered(m_data.stage1);
}
template <class T>
@@ -105,30 +105,18 @@ namespace detail
return *(T*)convert_rvalue(obj, m_data.stage1, m_data.storage.bytes);
}
template <class T>
inline return_reference_from_python<T>::return_reference_from_python()
{
detail::throw_if_not_registered(lvalue_from_python_chain<T,true>::value);
}
template <class T>
inline T return_reference_from_python<T>::operator()(PyObject* obj) const
{
return python::detail::void_ptr_to_reference(
callback_convert_reference(obj, lvalue_from_python_chain<T,true>::value)
callback_convert_reference(obj, from_python<T>::converters)
, (T(*)())0);
}
template <class T>
inline return_pointer_from_python<T>::return_pointer_from_python()
{
detail::throw_if_not_registered(lvalue_from_python_chain<T,true>::value);
}
template <class T>
inline T return_pointer_from_python<T>::operator()(PyObject* obj) const
{
return T(callback_convert_pointer(obj, lvalue_from_python_chain<T,true>::value));
return T(callback_convert_pointer(obj, pointee_from_python<T>::converters));
}
}

View File

@@ -7,8 +7,10 @@
#include <boost/python/converter/arg_to_python_base.hpp>
#include <boost/python/errors.hpp>
#include <boost/python/converter/find_from_python.hpp>
#include <boost/python/converter/registrations.hpp>
#include <boost/python/handle.hpp>
#include <boost/python/detail/none.hpp>
#include <boost/python/object.hpp>
namespace boost { namespace python { namespace converter {
@@ -43,46 +45,30 @@ namespace detail
{
}
BOOST_PYTHON_DECL void throw_if_not_registered(rvalue_from_python_stage1_data const& data)
{
if (!data.convertible)
{
PyErr_SetString(
PyExc_TypeError
, const_cast<char*>("no from_python rvalue or lvalue converters found for type"));
throw_error_already_set();
}
}
BOOST_PYTHON_DECL void throw_if_not_registered(lvalue_from_python_registration*const& x)
{
if (!x)
{
PyErr_SetString(
PyExc_TypeError
, const_cast<char*>("no from_python lvalue converters found for type"));
throw_error_already_set();
}
}
BOOST_PYTHON_DECL void* callback_convert_reference(
PyObject* source
, lvalue_from_python_registration*const& converters)
, from_python_registration const& converters)
{
handle<> holder(source);
if (source->ob_refcnt <= 2)
{
PyErr_SetString(
PyErr_SetObject(
PyExc_ReferenceError
, const_cast<char*>("Attempt to return dangling internal reference"));
, (object("Attempt to return dangling pointer/reference to object of type ")
+ converters.target_type.name()).ptr()
);
throw_error_already_set();
}
void* result = find(source, converters);
void* result = get_lvalue_from_python(source, converters);
if (!result)
{
PyErr_SetString(
handle<> repr(PyObject_Repr(source));
PyErr_SetObject(
PyExc_TypeError
, const_cast<char*>("no registered from_python lvalue converter was able to convert object"));
, (object("no registered converter was able to convert ")
+ repr + " to a C++ lvalue of type "
+ converters.target_type.name()).ptr()
);
throw_error_already_set();
}
return result;
@@ -90,7 +76,7 @@ namespace detail
BOOST_PYTHON_DECL void* callback_convert_pointer(
PyObject* source
, lvalue_from_python_registration*const& converters)
, from_python_registration const& converters)
{
if (source == Py_None)
{
@@ -112,7 +98,8 @@ namespace detail
{
handle<> holder(src);
data = find(src, static_cast<rvalue_from_python_registration*>(data.convertible));
data = rvalue_from_python_stage1(
src, *static_cast<from_python_registration const*>(data.convertible));
if (!data.convertible)
{

View File

@@ -14,10 +14,12 @@
namespace boost { namespace python { namespace converter {
BOOST_PYTHON_DECL rvalue_from_python_stage1_data find(
BOOST_PYTHON_DECL rvalue_from_python_stage1_data rvalue_from_python_stage1(
PyObject* source
, rvalue_from_python_registration const* chain)
, from_python_registration const& converters)
{
rvalue_from_python_chain const* chain = converters.rvalue_chain;
rvalue_from_python_stage1_data data;
data.convertible = 0;
for (;chain != 0; chain = chain->next)
@@ -33,23 +35,54 @@ BOOST_PYTHON_DECL rvalue_from_python_stage1_data find(
return data;
}
BOOST_PYTHON_DECL void* get_lvalue_from_python(
PyObject* source
, from_python_registration const& converters)
{
lvalue_from_python_chain const* chain = converters.lvalue_chain;
for (;chain != 0; chain = chain->next)
{
void* r = chain->convert(source);
if (r != 0)
return r;
}
return 0;
}
namespace
{
// Prevent looping in implicit conversions. This could/should be
// much more efficient, but will work for now.
typedef std::vector<rvalue_from_python_registration const*> visited_t;
typedef std::vector<rvalue_from_python_chain const*> visited_t;
static visited_t visited;
inline bool visit(rvalue_from_python_chain const* chain)
{
visited_t::iterator const p = std::lower_bound(visited.begin(), visited.end(), chain);
if (p != visited.end() && *p == chain)
return false;
visited.insert(p, chain);
return true;
}
void unvisit(rvalue_from_python_chain const* chain)
{
visited_t::iterator const p = std::lower_bound(visited.begin(), visited.end(), chain);
assert(p != visited.end());
visited.erase(p);
}
}
BOOST_PYTHON_DECL rvalue_from_python_registration const* find_chain(
BOOST_PYTHON_DECL rvalue_from_python_chain const* implicit_conversion_chain(
PyObject* source
, rvalue_from_python_registration const* chain)
, from_python_registration const& converters)
{
visited_t::iterator p = std::lower_bound(visited.begin(), visited.end(), chain);
if (p != visited.end() && *p == chain)
rvalue_from_python_chain const* chain = converters.rvalue_chain;
if (!visit(chain))
return 0;
visited.insert(p, chain);
try
{
for (;chain != 0; chain = chain->next)
@@ -60,25 +93,11 @@ BOOST_PYTHON_DECL rvalue_from_python_registration const* find_chain(
}
catch(...)
{
visited.erase(p);
unvisit(chain);
throw;
}
p = std::lower_bound(visited.begin(), visited.end(), chain);
visited.erase(p);
unvisit(chain);
return chain;
}
BOOST_PYTHON_DECL void* find(
PyObject* source
, lvalue_from_python_registration const* chain)
{
for (;chain != 0; chain = chain->next)
{
void* r = chain->convert(source);
if (r != 0)
return r;
}
return 0;
}
}}} // namespace boost::python::converter

View File

@@ -6,7 +6,7 @@
#include <boost/python/converter/registry.hpp>
#include <boost/python/converter/registrations.hpp>
#include <boost/python/converter/builtin_converters.hpp>
#include <map>
#include <set>
#include <stdexcept>
namespace boost { namespace python { namespace converter {
@@ -16,21 +16,23 @@ namespace // <unnamed>
// These are the elements stored in the registry
struct entry
{
entry();
entry(type_info target);
from_python_registration m_from_python;
// The unique to_python converter for the associated C++ type.
to_python_function_t m_to_python_converter;
// The collection of from_python converters for the associated
// C++ type.
lvalue_from_python_registration* m_lvalue_from_python;
rvalue_from_python_registration* m_rvalue_from_python;
// The class object associated with this type
PyTypeObject* m_class_object;
};
inline bool operator<(entry const& lhs, entry const& rhs)
{
return lhs.m_from_python.target_type < rhs.m_from_python.target_type;
}
typedef std::map<type_info, entry> registry_t;
typedef std::set<entry> registry_t;
registry_t& entries()
{
@@ -50,19 +52,16 @@ namespace // <unnamed>
return registry;
}
entry* find(type_info type)
entry* get(type_info type)
{
registry_t& assoc = entries();
registry_t::iterator p = assoc.find(type);
return p != assoc.end()
? &p->second
: &assoc[type];
return const_cast<entry*>(
&*entries().insert(entry(type)).first
);
}
entry::entry()
: m_to_python_converter(0)
, m_lvalue_from_python(0)
, m_rvalue_from_python(0)
entry::entry(type_info target)
: m_from_python(target)
, m_to_python_converter(0)
, m_class_object(0)
{
}
@@ -73,12 +72,12 @@ namespace registry
to_python_function_t const& get_to_python_function(
type_info key)
{
return find(key)->m_to_python_converter;
return get(key)->m_to_python_converter;
}
void insert(to_python_function_t f, type_info source_t)
{
to_python_function_t& slot = find(source_t)->m_to_python_converter;
to_python_function_t& slot = get(source_t)->m_to_python_converter;
assert(slot == 0); // we have a problem otherwise
if (slot != 0)
{
@@ -89,13 +88,13 @@ namespace registry
}
// Insert an lvalue from_python converter
void insert(void* (*convert)(PyObject*), type_info key)
void insert(convertible_function convert, type_info key)
{
entry* found = find(key);
lvalue_from_python_registration *registration = new lvalue_from_python_registration;
entry* found = get(key);
lvalue_from_python_chain *registration = new lvalue_from_python_chain;
registration->convert = convert;
registration->next = found->m_lvalue_from_python;
found->m_lvalue_from_python = registration;
registration->next = found->m_from_python.lvalue_chain;
found->m_from_python.lvalue_chain = registration;
insert(convert, 0, key);
}
@@ -105,12 +104,12 @@ namespace registry
, constructor_function construct
, type_info key)
{
entry* found = find(key);
rvalue_from_python_registration *registration = new rvalue_from_python_registration;
entry* found = get(key);
rvalue_from_python_chain *registration = new rvalue_from_python_chain;
registration->convertible = convertible;
registration->construct = construct;
registration->next = found->m_rvalue_from_python;
found->m_rvalue_from_python = registration;
registration->next = found->m_from_python.rvalue_chain;
found->m_from_python.rvalue_chain = registration;
}
// Insert an rvalue from_python converter
@@ -118,11 +117,11 @@ namespace registry
, constructor_function construct
, type_info key)
{
rvalue_from_python_registration** found = &find(key)->m_rvalue_from_python;
rvalue_from_python_chain** found = &get(key)->m_from_python.rvalue_chain;
while (*found != 0)
found = &(*found)->next;
rvalue_from_python_registration *registration = new rvalue_from_python_registration;
rvalue_from_python_chain *registration = new rvalue_from_python_chain;
registration->convertible = convertible;
registration->construct = construct;
registration->next = 0;
@@ -131,19 +130,13 @@ namespace registry
PyTypeObject*& class_object(type_info key)
{
return find(key)->m_class_object;
return get(key)->m_class_object;
}
lvalue_from_python_registration*& lvalue_converters(type_info key)
from_python_registration const& from_python_converters(type_info key)
{
return find(key)->m_lvalue_from_python;
return get(key)->m_from_python;
}
rvalue_from_python_registration*& rvalue_converters(type_info key)
{
return find(key)->m_rvalue_from_python;
}
} // namespace registry
}}} // namespace boost::python::converter