2
0
mirror of https://github.com/boostorg/python.git synced 2026-01-27 07:02:15 +00:00

Major simplification of from_python conversion avoids registering

converters for every class.


[SVN r16669]
This commit is contained in:
Dave Abrahams
2002-12-20 00:04:40 +00:00
parent b8edd99dbd
commit 3d874d1618
12 changed files with 177 additions and 151 deletions

View File

@@ -77,21 +77,21 @@ namespace detail
template <detail::operator_id, class L, class R>
struct operator_;
// Register a to_python converter for a class T, depending on the
// type of the first (tag) argument. The 2nd argument is a pointer
// to the type of holder that must be created. The 3rd argument is a
// Register to_python converters for a class T. The first argument
// will be mpl::true_c unless noncopyable was specified as a
// class_<...> template parameter. The 2nd argument is a pointer to
// the type of holder that must be created. The 3rd argument is a
// reference to the Python type object to be created.
template <class T, class SelectHolder>
static inline void register_copy_constructor(mpl::bool_c<true> const&, SelectHolder const& , T* = 0)
inline void register_class_to_python(mpl::true_c copyable, SelectHolder selector, T* = 0)
{
typedef typename SelectHolder::type holder;
force_instantiate(objects::class_cref_wrapper<T, objects::make_instance<T,holder> >());
SelectHolder::register_();
}
// Tag dispatched to have no effect.
template <class T, class SelectHolder>
static inline void register_copy_constructor(mpl::bool_c<false> const&, SelectHolder const&, T* = 0)
inline void register_class_to_python(mpl::false_c copyable, SelectHolder selector, T* = 0)
{
SelectHolder::register_();
}
@@ -125,20 +125,14 @@ namespace detail
template <class T, class Fn>
struct virtual_function_default
# if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
: assertion<is_polymorphic<T> >::failed
, assertion<is_member_function_pointer<Fn> >::failed
# endif
{
template <class Default>
static void
must_be_derived_class_member(Default const&)
{
typedef typename assertion<mpl::logical_not<is_same<Default,Fn> > >::failed test0;
# if defined(BOOST_MSVC) && BOOST_MSVC <= 1300
typedef typename assertion<is_polymorphic<T> >::failed test1;
typedef typename assertion<is_member_function_pointer<Fn> >::failed test2;
# endif
not_a_derived_class_member<Default>(Fn());
}
};
@@ -473,7 +467,7 @@ inline void class_<T,X1,X2,X3>::register_() const
{
objects::register_class_from_python<T,bases>();
detail::register_copy_constructor<T>(
detail::register_class_to_python<T>(
mpl::bool_c<is_copyable>()
, holder_selector::execute((held_type*)0)
);

View File

@@ -18,7 +18,7 @@ struct rvalue_from_python_chain;
BOOST_PYTHON_DECL void* get_lvalue_from_python(
PyObject* source, registration const&);
BOOST_PYTHON_DECL rvalue_from_python_chain const* implicit_conversion_chain(
BOOST_PYTHON_DECL bool implicit_rvalue_convertible_from_python(
PyObject* source, registration const&);
BOOST_PYTHON_DECL rvalue_from_python_stage1_data rvalue_from_python_stage1(

View File

@@ -5,10 +5,13 @@
// to its suitability for any purpose.
#ifndef IMPLICIT_DWA2002326_HPP
# define IMPLICIT_DWA2002326_HPP
# include <boost/python/converter/rvalue_from_python_data.hpp>
# include <boost/python/converter/registrations.hpp>
# include <boost/python/converter/registered.hpp>
# include <boost/python/extract.hpp>
namespace boost { namespace python { namespace converter {
template <class Source, class Target>
@@ -16,39 +19,22 @@ struct implicit
{
static void* convertible(PyObject* obj)
{
// Find a converter chain which can produce a Source 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, registered<Source>::converters));
// Find a converter which can produce a Source 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 implicit_rvalue_convertible_from_python(obj, registered<Source>::converters)
? obj : 0;
}
static void construct(PyObject* obj, rvalue_from_python_stage1_data* data)
{
// This is the chain we got from the convertible step
rvalue_from_python_chain const* chain
= static_cast<rvalue_from_python_chain*>(data->convertible);
// Call the convertible function again
rvalue_from_python_data<Source> intermediate_data(chain->convertible(obj));
// Use the result to construct the source type if the first
// converter was an rvalue converter.
if (chain->construct != 0)
chain->construct(obj, &intermediate_data.stage1);
void* storage = ((rvalue_from_python_storage<Target>*)data)->storage.bytes;
# if !defined(BOOST_MSVC) || _MSC_FULL_VER != 13012108 // vc7.01 alpha workaround
new (storage) Target(*static_cast<Source*>(intermediate_data.stage1.convertible));
# else
Target x(*static_cast<Source*>(intermediate_data.stage1.convertible));
new (storage) Target(x);
# endif
new (storage) Target(extract<Source>(obj)());
// record successful construction
data->convertible = storage;
}
};

View File

@@ -6,11 +6,15 @@
#ifndef REGISTRATIONS_DWA2002223_HPP
# define REGISTRATIONS_DWA2002223_HPP
# include <boost/python/detail/wrap_python.hpp>
# include <boost/python/type_id.hpp>
# include <boost/python/converter/convertible_function.hpp>
# include <boost/python/converter/constructor_function.hpp>
# include <boost/python/converter/to_python_function_type.hpp>
# include <boost/python/type_id.hpp>
# include <boost/python/detail/wrap_python.hpp>
# include <boost/detail/workaround.hpp>
namespace boost { namespace python { namespace converter {
@@ -54,7 +58,7 @@ struct BOOST_PYTHON_DECL registration
// The unique to_python converter for the associated C++ type.
to_python_function_t m_to_python;
# if defined(__MWERKS__) && __MWERKS__ <= 0x3003
# if BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3003))
private:
void operator=(registration); // This is not defined, and just keeps MWCW happy.
# endif

View File

@@ -9,7 +9,6 @@
# include <boost/python/converter/registry.hpp>
# include <boost/python/converter/shared_ptr_from_python.hpp>
# include <boost/python/object/find_instance.hpp>
# include <boost/python/object/inheritance.hpp>
# include <boost/python/detail/force_instantiate.hpp>
@@ -72,8 +71,6 @@ struct register_base_of
template <class Derived, class Bases>
inline void register_class_from_python(Derived* = 0, Bases* = 0)
{
// cause the static registration to be instantiated.
python::detail::force_instantiate(instance_finder<Derived>::registration);
python::detail::force_instantiate(converter::shared_ptr_from_python<Derived>::registration);
// register all up/downcasts here

View File

@@ -7,7 +7,6 @@
# define FIND_INSTANCE_DWA2002312_HPP
# include <boost/python/type_id.hpp>
# include <boost/python/converter/registry.hpp>
namespace boost { namespace python { namespace objects {
@@ -15,26 +14,6 @@ namespace boost { namespace python { namespace objects {
// return 0 in case no such type is held.
BOOST_PYTHON_DECL void* find_instance_impl(PyObject*, type_info);
// This produces a function with the right signature for use in from_python conversions
template <class T>
struct instance_finder
{
instance_finder()
{
converter::registry::insert(&execute, python::type_id<T>());
}
static instance_finder const registration;
private:
static inline void* execute(PyObject* p)
{
return find_instance_impl(p, python::type_id<T>());
}
};
template <class T>
instance_finder<T> const instance_finder<T>::registration;
}}} // namespace boost::python::objects
#endif // FIND_INSTANCE_DWA2002312_HPP

View File

@@ -11,6 +11,15 @@
namespace boost { namespace python { namespace objects {
struct decref_guard
{
decref_guard(PyObject* o) : obj(o) {}
~decref_guard() { Py_XDECREF(obj); }
void cancel() { obj = 0; }
private:
PyObject* obj;
};
template <class T, class Holder>
struct make_instance
{
@@ -28,22 +37,20 @@ struct make_instance
if (raw_result != 0)
{
instance_t* result = (instance_t*)raw_result;
try
{
// construct the new C++ object and install the pointer
// in the Python object.
construct(result, x)->install(raw_result);
}
catch(...)
{
Py_DECREF(raw_result); // reclaim the Python object
throw;
}
decref_guard protect(raw_result);
instance_t* instance = (instance_t*)raw_result;
// construct the new C++ object and install the pointer
// in the Python object.
construct(instance, x)->install(raw_result);
// Note the position of the internally-stored Holder,
// for the sake of destruction
result->ob_size = offsetof(instance_t, storage);
instance->ob_size = offsetof(instance_t, storage);
// Release ownership of the python object
protect.cancel();
}
return raw_result;
}

View File

@@ -14,7 +14,6 @@
# include <boost/python/instance_holder.hpp>
# include <boost/python/type_id.hpp>
# include <boost/python/object/inheritance.hpp>
# include <boost/python/object/find_instance.hpp>
# include <boost/python/object/forward.hpp>
# include <boost/python/pointee.hpp>
# include <boost/python/detail/force_instantiate.hpp>

View File

@@ -12,7 +12,6 @@
# include <boost/python/object/value_holder.hpp>
# include <boost/python/object/pointer_holder.hpp>
# include <boost/python/object/class_wrapper.hpp>
# include <boost/python/object/find_instance.hpp>
# include <boost/python/object/make_instance.hpp>
# include <boost/python/object/instance.hpp>
# include <boost/python/detail/force_instantiate.hpp>
@@ -27,11 +26,22 @@ namespace boost { namespace python { namespace objects {
namespace detail
{
// check_default_constructible --
//
// Used to give a clean error message when the user doesn't specify
// any __init__ functions, but when the class being wrapped doesn't
// have an appropriate default constructor (or if
// has_back_reference<T> is true, a constructor taking PyObject*).
// A helpful compile-time assertion which gives a reasonable error
// message if T can't be default-constructed.
template <class T>
static int specify_init_arguments_or_no_init_for_class_(T const&);
// U is expected to take an initial hidden PyObject* in its
// constructor. Normally this means U is a virtual function
// dispatcher subclass for T.
template <class T, class U>
void check_default_constructible(T*, U*, mpl::bool_c<true>)
{
@@ -39,7 +49,9 @@ namespace detail
sizeof(specify_init_arguments_or_no_init_for_class_<T>(U((::PyObject*)0)))
);
}
// Handles the "normal" case where T is held directly and
// has_back_reference<T> is not specialized.
template <class T>
void check_default_constructible(T*, T*, mpl::bool_c<false>)
{
@@ -47,76 +59,76 @@ namespace detail
sizeof(specify_init_arguments_or_no_init_for_class_<T>(T()))
);
}
//
// select_value_holder/select_pointer_holder --
//
// An instantiation of one of these data-free class templates is
// returned by select_holder::execute(), below. Each provides the
// following public interface:
//
// static void assert_default_constructible() -- called when no
// init<...> arguments are specified in class_<T, ...>'s
// constructor; causes a compile-time error when T has no
// corresponding default constructor.
//
// typedef ... type -- the class derived from instance_holder
// which will manage a Held object in Python class instances
//
// static type* get() { return 0; } -- just a way to access the
// computed type at runtime.
//
// static void register_() -- forces registration of any
// to_python converters corresponding to Held.
template <class T, class Held>
struct select_value_holder
{
BOOST_STATIC_CONSTANT(bool, selector = (!is_same<T,Held>::value) | has_back_reference<T>::value);
BOOST_STATIC_CONSTANT(bool, back_ref = (!is_same<T,Held>::value) | has_back_reference<T>::value);
static void assert_default_constructible()
{
detail::check_default_constructible((T*)0,(Held*)0,mpl::bool_c<selector>());
detail::check_default_constructible((T*)0,(Held*)0,mpl::bool_c<back_ref>());
}
typedef typename mpl::if_c<
selector
back_ref
, value_holder_back_reference<T,Held>
, value_holder<T>
>::type type;
static inline void register_()
{
select_value_holder::register_(mpl::bool_c<selector>());
}
static inline void register_() {}
static type* get() { return 0; }
private:
static inline void register_(mpl::bool_c<true>)
{
python::detail::force_instantiate(instance_finder<Held>::registration);
}
static inline void register_(mpl::bool_c<false>)
{
}
};
template <class T,class Ptr>
struct select_pointer_holder
{
typedef typename python::pointee<Ptr>::type pointee;
BOOST_STATIC_CONSTANT(bool, selector = (!is_same<T,pointee>::value) | has_back_reference<T>::value);
BOOST_STATIC_CONSTANT(bool, back_ref = (!is_same<T,pointee>::value) | has_back_reference<T>::value);
static void assert_default_constructible()
{
detail::check_default_constructible((T*)0,(pointee*)0,mpl::bool_c<selector>());
detail::check_default_constructible((T*)0,(pointee*)0,mpl::bool_c<back_ref>());
}
typedef typename mpl::if_c<
selector
back_ref
, pointer_holder_back_reference<Ptr,T>
, pointer_holder<Ptr,T>
>::type type;
static inline void register_()
{
select_pointer_holder::register_(mpl::bool_c<selector>());
select_pointer_holder::register_(mpl::bool_c<back_ref>());
}
static type* get() { return 0; }
private:
static inline void register_(mpl::bool_c<true>)
static inline void register_(mpl::true_c)
{
// not implemented at least until we solve the back
// reference issue mentioned in pointer_holder.hpp.
//
// python::detail::force_instantiate(
// class_wrapper<Pointer,pointer_holder_back_reference<Pointer,Value> >());
python::detail::force_instantiate(instance_finder<Ptr>::registration);
python::detail::force_instantiate(instance_finder<pointee>::registration);
}
struct construct_from_pointer
@@ -127,37 +139,56 @@ namespace detail
}
};
static inline void register_(mpl::bool_c<false>)
static inline void register_(mpl::false_c)
{
python::detail::force_instantiate(
objects::class_value_wrapper<Ptr, make_instance<T,type> >());
python::detail::force_instantiate(
instance_finder<Ptr>::registration);
}
};
}
// select_holder<T,Held>::execute((Held*)0)
//
// implements a compile-time returns an instantiation of
// detail::select_value_holder or detail::select_pointer_holder, as
// appropriate for class_<T,Held>
template <class T, class Held>
struct select_holder
{
// Return the additional size to allocate in Python class
// instances to hold the C++ instance data.
static inline std::size_t additional_size()
{
return additional_size_helper(execute((Held*)0));
}
// These overloads are an elaborate workaround for deficient
// compilers:
//
// They are meant to be called with a null pointer to the class_'s
// Held template argument. The selected overload will create an
// appropriate instantiation of select_value_holder or
// select_pointer_holder, which is itself an empty class that is
// ultimately used to create the class_'s instance_holder subclass
// object.
// No Held was specified; T is held directly by-value
static inline detail::select_value_holder<T,T>
execute(python::detail::not_specified*)
{
return detail::select_value_holder<T,T>();
}
// A type derived from T was specified; it is assumed to be a
// virtual function dispatcher class, and T is held as Held.
static inline detail::select_value_holder<T, Held>
execute(T*)
{
return detail::select_value_holder<T, Held>();
}
// Some other type was specified; Held is assumed to be a (smart)
// pointer to T or a class derived from T.
static inline detail::select_pointer_holder<T,Held>
execute(void*)
{

View File

@@ -10,11 +10,13 @@
# define VALUE_HOLDER_DWA20011215_HPP
# include <boost/python/object/value_holder_fwd.hpp>
# include <boost/python/instance_holder.hpp>
# include <boost/python/type_id.hpp>
# include <boost/python/object/inheritance.hpp>
# include <boost/python/object/find_instance.hpp>
# include <boost/python/object/forward.hpp>
# include <boost/python/detail/force_instantiate.hpp>
# include <boost/python/detail/preprocessor.hpp>

View File

@@ -37,7 +37,9 @@ namespace detail
template <class T>
static result_type execute(T* p)
{
// can't use auto_ptr with Intel 5 for some reason
// can't use auto_ptr with Intel 5 and VC6 Dinkum library
// for some reason. We get link errors against the auto_ptr
// copy constructor.
# if defined(__ICL) && __ICL < 600
typedef boost::shared_ptr<T> smart_pointer;
# else

View File

@@ -7,11 +7,15 @@
#include <boost/python/converter/from_python.hpp>
#include <boost/python/converter/registrations.hpp>
#include <boost/python/converter/rvalue_from_python_data.hpp>
#include <boost/python/object/find_instance.hpp>
#include <boost/python/handle.hpp>
#include <boost/python/detail/raw_pyobject.hpp>
#include <boost/python/cast.hpp>
#include <boost/lexical_cast.hpp>
#include <vector>
#include <algorithm>
@@ -38,18 +42,28 @@ BOOST_PYTHON_DECL rvalue_from_python_stage1_data rvalue_from_python_stage1(
PyObject* source
, 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)
// First check to see if it's embedded in an extension class
// instance, as a special case.
data.convertible = objects::find_instance_impl(source, converters.target_type);
if (data.convertible)
{
void* r = chain->convertible(source);
if (r != 0)
data.construct = 0;
}
else
{
for (rvalue_from_python_chain const* chain = converters.rvalue_chain;
chain != 0;
chain = chain->next)
{
data.convertible = r;
data.construct = chain->construct;
break;
void* r = chain->convertible(source);
if (r != 0)
{
data.convertible = r;
data.construct = chain->construct;
break;
}
}
}
return data;
@@ -111,8 +125,12 @@ BOOST_PYTHON_DECL void* get_lvalue_from_python(
PyObject* source
, registration const& converters)
{
// Check to see if it's embedded in a class instance
void* x = objects::find_instance_impl(source, converters.target_type);
if (x)
return x;
lvalue_from_python_chain const* chain = converters.lvalue_chain;
for (;chain != 0; chain = chain->next)
{
void* r = chain->convert(source);
@@ -138,38 +156,45 @@ namespace
return true;
}
void unvisit(rvalue_from_python_chain const* chain)
// RAII class for managing global visited marks.
struct unvisit
{
visited_t::iterator const p = std::lower_bound(visited.begin(), visited.end(), chain);
assert(p != visited.end());
visited.erase(p);
}
unvisit(rvalue_from_python_chain const* chain)
: chain(chain) {}
~unvisit()
{
visited_t::iterator const p = std::lower_bound(visited.begin(), visited.end(), chain);
assert(p != visited.end());
visited.erase(p);
}
private:
rvalue_from_python_chain const* chain;
};
}
BOOST_PYTHON_DECL rvalue_from_python_chain const* implicit_conversion_chain(
BOOST_PYTHON_DECL bool implicit_rvalue_convertible_from_python(
PyObject* source
, registration const& converters)
{
if (objects::find_instance_impl(source, converters.target_type))
return true;
rvalue_from_python_chain const* chain = converters.rvalue_chain;
if (!visit(chain))
return 0;
return false;
unvisit protect(chain);
try
for (;chain != 0; chain = chain->next)
{
for (;chain != 0; chain = chain->next)
{
if (chain->convertible(source))
break;
}
if (chain->convertible(source))
return true;
}
catch(...)
{
unvisit(chain);
throw;
}
unvisit(chain);
return chain;
return false;
}
namespace