2
0
mirror of https://github.com/boostorg/python.git synced 2026-01-19 16:32:16 +00:00

Make slice work on vc6

Revamp/simplify class registration


[SVN r23823]
This commit is contained in:
Dave Abrahams
2004-07-20 03:16:49 +00:00
parent 2bdb728e87
commit 615adc5fe6
18 changed files with 391 additions and 498 deletions

View File

@@ -8,10 +8,11 @@
# include <boost/python/detail/prefix.hpp>
# include <boost/noncopyable.hpp>
# include <boost/python/class_fwd.hpp>
# include <boost/python/object/class.hpp>
# include <boost/python/bases.hpp>
# include <boost/python/object.hpp>
# include <boost/python/type_id.hpp>
# include <boost/python/data_members.hpp>
@@ -20,12 +21,9 @@
# include <boost/python/init.hpp>
# include <boost/python/args_fwd.hpp>
# include <boost/python/object/select_holder.hpp>
# include <boost/python/object/class_wrapper.hpp>
# include <boost/python/object/make_instance.hpp>
# include <boost/python/object/class_metadata.hpp>
# include <boost/python/object/pickle_support.hpp>
# include <boost/python/object/add_to_namespace.hpp>
# include <boost/python/object/class_converters.hpp>
# include <boost/python/detail/overloads_fwd.hpp>
# include <boost/python/detail/operator_id.hpp>
@@ -33,7 +31,6 @@
# include <boost/python/detail/force_instantiate.hpp>
# include <boost/type_traits/is_same.hpp>
# include <boost/type_traits/is_convertible.hpp>
# include <boost/type_traits/is_member_function_pointer.hpp>
# include <boost/type_traits/is_polymorphic.hpp>
@@ -41,10 +38,7 @@
# include <boost/mpl/for_each.hpp>
# include <boost/mpl/bool.hpp>
# include <boost/mpl/not.hpp>
# include <boost/mpl/or.hpp>
# include <boost/mpl/vector/vector10.hpp>
# include <boost/utility.hpp>
# include <boost/detail/workaround.hpp>
# if BOOST_WORKAROUND(__MWERKS__, <= 0x3004) \
@@ -87,52 +81,6 @@ namespace detail
type_info** p;
};
template <class T, class Prev = detail::not_specified>
struct select_held_type;
template <class T1, class T2, class T3>
struct has_noncopyable;
// Register to_python converters for a class T. The first argument
// will be mpl::true_ 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>
inline void register_class_to_python(mpl::true_, SelectHolder, T* = 0)
{
typedef typename SelectHolder::type holder;
force_instantiate(objects::class_cref_wrapper<T, objects::make_instance<T,holder> >());
SelectHolder::register_();
}
template <class T, class SelectHolder>
inline void register_class_to_python(mpl::false_, SelectHolder, T* = 0)
{
SelectHolder::register_();
}
//
// register_wrapper_class -- register the relationship between a
// virtual function callback wrapper class and the class being
// wrapped.
//
template <class T>
inline void register_wrapper_class_impl(T*, T*, int) {}
template <class Wrapper, class T>
inline void register_wrapper_class_impl(Wrapper*, T*, ...)
{
objects::register_class_from_python<Wrapper, mpl::vector1<T> >();
objects::copy_class_object(type_id<T>(), type_id<Wrapper>());
}
template <class Held, class T>
inline void register_wrapper_class(Held* = 0, T* = 0)
{
register_wrapper_class_impl((Held*)0, (T*)0, 0);
}
template <class T>
struct is_data_member_pointer
: mpl::and_<
@@ -212,34 +160,18 @@ class class_ : public objects::class_base
{
public: // types
typedef objects::class_base base;
typedef class_<T,X1,X2,X3> self;
typedef typename objects::class_metadata<T,X1,X2,X3> metadata;
typedef T wrapped_type;
typedef class_<T,X1,X2,X3> self;
BOOST_STATIC_CONSTANT(bool, is_copyable = (!detail::has_noncopyable<X1,X2,X3>::value));
// held_type - either T, a class derived from T or a smart pointer
// to a (class derived from) T.
typedef typename detail::select_held_type<
X1, typename detail::select_held_type<
X2, typename detail::select_held_type<
X3
>::type>::type>::type held_type;
typedef objects::select_holder<T,held_type> select_holder;
private: // types
typedef typename detail::select_bases<X1
, typename detail::select_bases<X2
, typename boost::python::detail::select_bases<X3>::type
>::type
>::type bases;
// A helper class which will contain an array of id objects to be
// passed to the base class constructor
struct id_vector
{
typedef typename metadata::bases bases;
id_vector()
{
// Stick the derived class id into the first element of the array
@@ -272,8 +204,7 @@ class class_ : public objects::class_base
inline class_(char const* name, init_base<DerivedT> const& i)
: base(name, id_vector::size, id_vector().ids)
{
this->register_holder();
this->def(i);
this->initialize(i);
}
// Construct with class name, docstring and init<> function
@@ -281,8 +212,7 @@ class class_ : public objects::class_base
inline class_(char const* name, char const* doc, init_base<DerivedT> const& i)
: base(name, id_vector::size, id_vector().ids, doc)
{
this->register_holder();
this->def(i);
this->initialize(i);
}
public: // member functions
@@ -510,8 +440,22 @@ class class_ : public objects::class_base
return this->add_static_property(name, python::make_getter(d), python::make_setter(d));
}
inline void register_() const;
inline void register_holder();
template <class DefVisitor>
inline void initialize(DefVisitor const& i)
{
metadata::register_(); // set up runtime metadata/conversions
typedef typename metadata::holder holder;
this->set_instance_size( objects::additional_instance_size<holder>::value );
this->def(i);
}
inline void initialize(no_init_t)
{
metadata::register_(); // set up runtime metadata/conversions
this->def_no_init();
}
//
// These two overloads discriminate between def() as applied to a
@@ -625,80 +569,26 @@ class class_ : public objects::class_base
// implementations
//
// register converters
template <class T, class X1, class X2, class X3>
inline void class_<T,X1,X2,X3>::register_() const
{
objects::register_class_from_python<T,bases>();
typedef BOOST_DEDUCED_TYPENAME select_holder::held_type held_t;
detail::register_wrapper_class<held_t,T>();
detail::register_class_to_python<T>(
mpl::bool_<is_copyable>()
, select_holder()
);
}
template <class T, class X1, class X2, class X3>
inline void class_<T,X1,X2,X3>::register_holder()
{
this->register_();
typedef typename select_holder::type holder;
this->set_instance_size(
objects::additional_instance_size<holder>::value
);
}
template <class T, class X1, class X2, class X3>
inline class_<T,X1,X2,X3>::class_(char const* name, char const* doc)
: base(name, id_vector::size, id_vector().ids, doc)
{
this->register_holder();
select_holder::assert_default_constructible();
this->def(init<>());
this->initialize(init<>());
// select_holder::assert_default_constructible();
}
template <class T, class X1, class X2, class X3>
inline class_<T,X1,X2,X3>::class_(char const* name, no_init_t)
: base(name, id_vector::size, id_vector().ids)
{
this->register_();
this->def_no_init();
this->initialize(no_init);
}
template <class T, class X1, class X2, class X3>
inline class_<T,X1,X2,X3>::class_(char const* name, char const* doc, no_init_t)
: base(name, id_vector::size, id_vector().ids, doc)
{
this->register_();
this->def_no_init();
}
namespace detail
{
template <class T1, class T2, class T3>
struct has_noncopyable
: mpl::or_<
is_same<T1,noncopyable>
, is_same<T2,noncopyable>
, is_same<T3,noncopyable>
>
{};
template <class T, class Prev>
struct select_held_type
: mpl::if_<
mpl::or_<
specifies_bases<T>
, is_same<T,noncopyable>
>
, Prev
, T
>
{
};
this->initialize(no_init);
}
}} // namespace boost::python

View File

@@ -8,6 +8,10 @@
# include <boost/python/handle.hpp>
# include <boost/python/converter/shared_ptr_deleter.hpp>
# include <boost/python/converter/from_python.hpp>
# include <boost/python/converter/rvalue_from_python_data.hpp>
# include <boost/python/converter/registered.hpp>
# include <boost/shared_ptr.hpp>
namespace boost { namespace python { namespace converter {

View File

@@ -328,17 +328,15 @@ namespace detail
, detail::keyword_range const& keywords_
)
{
typedef typename ClassT::select_holder selector_t;
cl.def(
"__init__",
detail::make_keyword_range_constructor<Signature,NArgs>(
policies
, keywords_
, selector_t::get()
)
, doc
);
"__init__"
, detail::make_keyword_range_constructor<Signature,NArgs>(
policies
, keywords_
, (typename ClassT::metadata::holder*)0
)
, doc
);
}
///////////////////////////////////////////////////////////////////////////////

View File

@@ -58,8 +58,6 @@ struct BOOST_PYTHON_DECL class_base : python::api::object
void make_method_static(const char *method_name);
};
BOOST_PYTHON_DECL void copy_class_object(type_info const& src, type_info const& dst);
}}} // namespace boost::python::objects
#endif // CLASS_DWA20011214_HPP

View File

@@ -1,93 +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 CLASS_CONVERTERS_DWA2002119_HPP
# define CLASS_CONVERTERS_DWA2002119_HPP
# include <boost/python/converter/registry.hpp>
# include <boost/python/converter/shared_ptr_from_python.hpp>
# include <boost/python/object/inheritance.hpp>
# include <boost/python/detail/force_instantiate.hpp>
# include <boost/type_traits/add_pointer.hpp>
# include <boost/type_traits/is_polymorphic.hpp>
# include <boost/mpl/for_each.hpp>
# include <boost/detail/workaround.hpp>
namespace boost { namespace python { namespace objects {
//////////////////////////////////////////////////////////////////////
//
// register_base_of<T> -
// A BinaryMetaFunction object which registers a single base
// class of T, and the corresponding cast(s)
//
// register_downcast/do_nothing -
// Helpers for register_base_of<> which take care of registering
// down-casts
template <class Base, class Derived>
struct register_downcast
{
static void execute()
{
register_conversion<Base, Derived>(true);
}
};
struct do_nothing
{
static void execute() { }
};
// Here's where the real work gets done:
template <class Derived>
struct register_base_of
{
// Here's the runtime part:
template <class Base>
void operator()(Base*) const
{
// Register the Base class
register_dynamic_id<Base>();
// Register the up-cast
register_conversion<Derived,Base>(false);
// Register the down-cast, if appropriate.
mpl::if_<
# if BOOST_WORKAROUND(__MWERKS__, <= 0x2407)
mpl::true_
# else
is_polymorphic<Base>
# endif
, register_downcast<Base,Derived>
, do_nothing
>::type::execute();
}
};
// Brings into existence all converters associated with a class. Bases
// is expected to be an mpl sequence of base types.
template <class Derived, class Bases>
inline void register_class_from_python(Derived* = 0, Bases* = 0)
{
// Static object constructor performs registration
static converter::shared_ptr_from_python<Derived> shared_ptr_registration;
// register all up/downcasts here
register_dynamic_id<Derived>();
// register each base in the sequence
mpl::for_each(register_base_of<Derived>(), (Bases*)0, (add_pointer<mpl::_>*)0);
}
}}} // namespace boost::python::object
#endif // CLASS_CONVERTERS_DWA2002119_HPP

View File

@@ -0,0 +1,249 @@
// Copyright David Abrahams 2004. 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)
#ifndef CLASS_METADATA_DWA2004719_HPP
# define CLASS_METADATA_DWA2004719_HPP
# include <boost/python/converter/shared_ptr_from_python.hpp>
# include <boost/python/object/inheritance.hpp>
# include <boost/python/object/class_wrapper.hpp>
# include <boost/python/object/make_instance.hpp>
# include <boost/python/object/value_holder.hpp>
# include <boost/python/object/pointer_holder.hpp>
# include <boost/python/object/make_ptr_instance.hpp>
# include <boost/python/detail/force_instantiate.hpp>
# include <boost/python/detail/not_specified.hpp>
# include <boost/python/has_back_reference.hpp>
# include <boost/python/bases.hpp>
# include <boost/type_traits/add_pointer.hpp>
# include <boost/type_traits/is_convertible.hpp>
# include <boost/type_traits/is_polymorphic.hpp>
# include <boost/mpl/if.hpp>
# include <boost/mpl/apply_if.hpp>
# include <boost/mpl/bool.hpp>
# include <boost/mpl/or.hpp>
# include <boost/mpl/identity.hpp>
# include <boost/mpl/for_each.hpp>
# include <boost/mpl/placeholders.hpp>
# include <boost/mpl/single_view.hpp>
# include <boost/type_traits/is_convertible.hpp>
# include <boost/noncopyable.hpp>
# include <boost/detail/workaround.hpp>
namespace boost { namespace python { namespace objects {
BOOST_PYTHON_DECL
void copy_class_object(type_info const& src, type_info const& dst);
//
// Support for registering base/derived relationships
//
template <class Derived>
struct register_base_of
{
template <class Base>
inline void operator()(Base*) const
{
// Register the Base class
register_dynamic_id<Base>();
// Register the up-cast
register_conversion<Derived,Base>(false);
// Register the down-cast, if appropriate.
this->register_downcast((Base*)0, is_polymorphic<Base>());
}
private:
static inline void register_downcast(void*, mpl::false_) {}
template <class Base>
static inline void register_downcast(Base*, mpl::true_)
{
register_conversion<Base, Derived>(true);
}
};
//
// Preamble of register_class. Also used for callback classes, which
// need some registration of their own.
//
template <class T, class Bases>
void register_shared_ptr_from_python_and_casts(T*, Bases)
{
// Constructor performs registration
python::detail::force_instantiate(converter::shared_ptr_from_python<T>());
//
// register all up/downcasts here. We're using the alternate
// interface to mpl::for_each to avoid an MSVC 6 bug.
//
register_dynamic_id<T>();
mpl::for_each(register_base_of<T>(), (Bases*)0, (add_pointer<mpl::_>*)0);
}
//
// Helper for choosing the unnamed held_type argument
//
template <class T, class Prev>
struct select_held_type
: mpl::if_<
mpl::or_<
python::detail::specifies_bases<T>
, is_same<T,noncopyable>
>
, Prev
, T
>
{
};
template <
class T // class being wrapped
, class X1 // = detail::not_specified
, class X2 // = detail::not_specified
, class X3 // = detail::not_specified
>
struct class_metadata
{
//
// Calculate the unnamed template arguments
//
// held_type_arg -- not_specified, [a class derived from] T or a
// smart pointer to [a class derived from] T. Preserving
// not_specified allows us to give class_<T,T> a back-reference.
typedef typename select_held_type<
X1
, typename select_held_type<
X2
, typename select_held_type<
X3
, python::detail::not_specified
>::type
>::type
>::type held_type_arg;
// bases
typedef typename python::detail::select_bases<
X1
, typename python::detail::select_bases<
X2
, typename python::detail::select_bases<
X3
, python::bases<>
>::type
>::type
>::type bases;
typedef mpl::or_<
is_same<X1,noncopyable>
, is_same<X2,noncopyable>
, is_same<X3,noncopyable>
> is_noncopyable;
//
// Holder computation.
//
// Compute the actual type that will be held in the Holder.
typedef typename mpl::if_<
is_same<held_type_arg,python::detail::not_specified>, T, held_type_arg
>::type held_type;
// Determine if the object will be held by value
typedef is_convertible<held_type*,T*> use_value_holder;
// Compute the "wrapped type", that is, if held_type is a smart
// pointer, we're talking about the pointee.
typedef typename mpl::apply_if<
use_value_holder
, mpl::identity<held_type>
, pointee<held_type>
>::type wrapper;
// Determine whether wrapper needs to be separately registered
typedef is_base_and_derived<T,wrapper> use_callback_class;
// Determine whether to use a holder with a back-reference
typedef mpl::or_<
use_callback_class
, has_back_reference<T>
, is_same<held_type_arg,T>
> use_back_reference;
// Select the holder.
typedef typename mpl::apply_if<
use_back_reference
, mpl::if_<
use_value_holder
, value_holder_back_reference<T, wrapper>
, pointer_holder_back_reference<held_type,T>
>
, mpl::if_<
use_value_holder
, value_holder<T>
, pointer_holder<held_type,T>
>
>::type holder;
inline static void register_() // Register the runtime metadata.
{
objects::register_shared_ptr_from_python_and_casts((T*)0, bases());
class_metadata::maybe_register_callback_class(use_callback_class());
class_metadata::maybe_register_class_to_python(is_noncopyable());
class_metadata::maybe_register_pointer_to_python(
(use_value_holder*)0, (use_back_reference*)0);
}
private:
//
// Support for converting smart pointers to python
//
inline static void maybe_register_pointer_to_python(void*,void*) {}
inline static void maybe_register_pointer_to_python(mpl::false_*, mpl::false_*)
{
python::detail::force_instantiate(
objects::class_value_wrapper<
held_type
, make_ptr_instance<T, pointer_holder<held_type, T> >
>()
);
}
//
// Support for registering to-python converters
//
inline static void maybe_register_class_to_python(mpl::true_) {}
inline static void maybe_register_class_to_python(mpl::false_)
{
python::detail::force_instantiate(class_cref_wrapper<T, make_instance<T, holder> >());
}
//
// Support for registering callback classes
//
inline static void maybe_register_callback_class(mpl::false_) {}
inline static void maybe_register_callback_class(mpl::true_)
{
objects::register_shared_ptr_from_python_and_casts(
(wrapper*)0, mpl::single_view<T>());
// explicit qualification of type_id makes msvc6 happy
objects::copy_class_object(python::type_id<T>(), python::type_id<wrapper>());
}
};
}}} // namespace boost::python::object
#endif // CLASS_METADATA_DWA2004719_HPP

View File

@@ -1,195 +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 SELECT_HOLDER_DWA2002322_HPP
# define SELECT_HOLDER_DWA2002322_HPP
# include <boost/python/has_back_reference.hpp>
# include <boost/python/detail/not_specified.hpp>
# include <boost/python/pointee.hpp>
# 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/make_ptr_instance.hpp>
# include <boost/python/object/instance.hpp>
# include <boost/python/detail/force_instantiate.hpp>
# include <boost/type.hpp>
# include <boost/mpl/bool.hpp>
# include <boost/mpl/if.hpp>
# include <boost/mpl/or.hpp>
# include <boost/mpl/not.hpp>
# include <boost/type_traits/same_traits.hpp>
# include <boost/type_traits/is_base_and_derived.hpp>
# include <boost/type_traits/alignment_traits.hpp>
# include <cstddef>
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::true_)
{
python::detail::force_instantiate(
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::false_)
{
python::detail::force_instantiate(
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
{
private:
typedef mpl::or_<
mpl::not_<is_same<T,Held> >
, has_back_reference<T>
> use_back_ref;
public:
static void assert_default_constructible()
{
detail::check_default_constructible((T*)0,(Held*)0, use_back_ref());
}
typedef typename mpl::if_<
use_back_ref
, value_holder_back_reference<T,Held>
, value_holder<T>
>::type type;
typedef Held held_type;
static inline void register_() {}
static type* get() { return 0; }
};
template <class T,class Ptr>
struct select_pointer_holder
{
private:
typedef typename python::pointee<Ptr>::type wrapper;
typedef mpl::or_<
mpl::not_<is_same<T,wrapper> >
, has_back_reference<T>
> use_back_ref;
public:
static void assert_default_constructible()
{
detail::check_default_constructible((T*)0,(wrapper*)0, use_back_ref());
}
typedef typename mpl::if_<
use_back_ref
, pointer_holder_back_reference<Ptr,T>
, pointer_holder<Ptr,T>
>::type type;
typedef typename pointee<Ptr>::type held_type;
static inline void register_()
{
select_pointer_holder::register_(use_back_ref());
}
static type* get() { return 0; }
private:
static inline void register_(mpl::true_)
{
}
struct construct_from_pointer
{
static type* execute(PyObject*, Ptr x)
{
return new type(x);
}
};
static inline void register_(mpl::false_)
{
python::detail::force_instantiate(
objects::class_value_wrapper<Ptr, make_ptr_instance<T,type> >());
}
};
}
// select_holder<T,Held>::execute((Held*)0)
//
// 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
: mpl::if_<
is_same<Held, python::detail::not_specified>
, detail::select_value_holder<T,T>
, typename mpl::if_<
mpl::or_<
is_same<T,Held>
, is_base_and_derived<T, Held>
>
, detail::select_value_holder<T,Held>
, detail::select_pointer_holder<T, Held>
>::type
>::type
{
};
}}} // namespace boost::python::objects
#endif // SELECT_HOLDER_DWA2002322_HPP

View File

@@ -39,6 +39,8 @@
# include <boost/type_traits/add_pointer.hpp>
# endif
# include <boost/mpl/if.hpp>
namespace boost { namespace python {
namespace converter
@@ -297,7 +299,14 @@ namespace api
// explicit conversion from any C++ object to Python
template <class T>
explicit object(T const& x)
explicit object(
T const& x
# if BOOST_WORKAROUND(BOOST_MSVC, == 1200)
// use some SFINAE to un-confuse MSVC about its
// copy-initialization ambiguity claim.
, typename mpl::if_<is_proxy<T>,int&,int>::type* = 0
# endif
)
: object_base(object_base_initializer(x))
{
}

View File

@@ -91,7 +91,7 @@ namespace detail
, options.policies()
);
typedef BOOST_DEDUCED_TYPENAME C_::select_holder::held_type held_t;
typedef BOOST_DEDUCED_TYPENAME C_::metadata::held_type held_type;
// Add the default implementation which raises the exception
c.def(
@@ -99,7 +99,7 @@ namespace detail
, make_function(
detail::nullary_function_adaptor<void(*)()>(pure_virtual_called)
, default_call_policies()
, detail::error_signature<held_t>(detail::get_signature(m_pmf))
, detail::error_signature<held_type>(detail::get_signature(m_pmf))
)
);
}

View File

@@ -12,45 +12,55 @@
#include <boost/python/extract.hpp>
#include <boost/python/converter/pytype_object_mgr_traits.hpp>
#include <boost/iterator/iterator_traits.hpp>
#include <iterator>
#include <algorithm>
namespace boost { namespace python {
class BOOST_PYTHON_DECL slice : public object
namespace detail
{
private:
// Helper function to work around bugs in MSVC 6
static object new_slice(PyObject*, PyObject*, PyObject*);
class BOOST_PYTHON_DECL slice_base : public object
{
public:
// Get the Python objects associated with the slice. In principle, these
// may be any arbitrary Python type, but in practice they are usually
// integers. If one or more parameter is ommited in the Python expression
// that created this slice, than that parameter is None here, and compares
// equal to a default-constructed boost::python::object.
// If a user-defined type wishes to support slicing, then support for the
// special meaning associated with negative indicies is up to the user.
object start() const;
object stop() const;
object step() const;
protected:
explicit slice_base(PyObject*, PyObject*, PyObject*);
BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(slice_base, object)
};
}
class slice : public detail::slice_base
{
typedef detail::slice_base base;
public:
// Equivalent to slice(::)
slice();
slice() : base(0,0,0) {}
// Each argument must be slice_nil, or implicitly convertable to object.
// They should normally be integers.
template<typename Integer1, typename Integer2>
slice( Integer1 start, Integer2 stop)
: object( new_slice( object(start).ptr(), object(stop).ptr(), NULL))
: base( object(start).ptr(), object(stop).ptr(), 0 )
{}
template<typename Integer1, typename Integer2, typename Integer3>
slice( Integer1 start, Integer2 stop, Integer3 stride)
: object(
new_slice( object(start).ptr(), object(stop).ptr(), object(stride).ptr()))
: base( object(start).ptr(), object(stop).ptr(), object(stride).ptr() )
{}
// Get the Python objects associated with the slice. In principle, these
// may be any arbitrary Python type, but in practice they are usually
// integers. If one or more parameter is ommited in the Python expression
// that created this slice, than that parameter is None here, and compares
// equal to a default-constructed boost::python::object.
// If a user-defined type wishes to support slicing, then support for the
// special meaning associated with negative indicies is up to the user.
object start() const;
object stop() const;
object step() const;
// The following algorithm is intended to automate the process of
// determining a slice range when you want to fully support negative
// indicies and non-singular step sizes. Its functionallity is simmilar to
@@ -90,14 +100,12 @@ class BOOST_PYTHON_DECL slice : public object
// the case where the user fails to catch the exception, it will simply
// be translated to Python by the default exception handling mechanisms.
#ifndef BOOST_NO_MEMBER_TEMPLATES
template<typename RandomAccessIterator>
struct range
{
RandomAccessIterator start;
RandomAccessIterator stop;
int step;
typename iterator_difference<RandomAccessIterator>::type step;
};
template<typename RandomAccessIterator>
@@ -109,9 +117,10 @@ class BOOST_PYTHON_DECL slice : public object
// carefully crafted to ensure that these iterators never fall out of
// the range of the container.
slice::range<RandomAccessIterator> ret;
typename RandomAccessIterator::difference_type max_dist =
std::distance( begin, end);
typedef typename iterator_difference<RandomAccessIterator>::type difference_type;
difference_type max_dist = boost::detail::distance(begin, end);
object slice_start = this->start();
object slice_stop = this->stop();
object slice_step = this->step();
@@ -121,7 +130,7 @@ class BOOST_PYTHON_DECL slice : public object
ret.step = 1;
}
else {
ret.step = extract<int>( slice_step);
ret.step = extract<long>( slice_step);
if (ret.step == 0) {
PyErr_SetString( PyExc_IndexError, "step size cannot be zero.");
throw_error_already_set();
@@ -138,7 +147,7 @@ class BOOST_PYTHON_DECL slice : public object
ret.start = begin;
}
else {
int i = extract<int>( slice_start);
difference_type i = extract<long>( slice_start);
if (i >= max_dist && ret.step > 0)
throw std::invalid_argument( "Zero-length slice");
if (i >= 0) {
@@ -167,7 +176,7 @@ class BOOST_PYTHON_DECL slice : public object
}
}
else {
int i = extract<int>( slice_stop);
difference_type i = extract<long>(slice_stop);
// First, branch on which direction we are going with this.
if (ret.step < 0) {
if (i+1 >= max_dist || i == -1)
@@ -188,8 +197,7 @@ class BOOST_PYTHON_DECL slice : public object
if (i > 0) {
ret.stop = begin;
BOOST_USING_STD_MIN();
std::advance( ret.stop, min BOOST_PREVENT_MACRO_SUBSTITUTION( i-1, max_dist-1));
std::advance( ret.stop, (std::min)( i-1, max_dist-1));
}
else { // i is negative, but not more negative than -max_dist
ret.stop = end;
@@ -203,8 +211,8 @@ class BOOST_PYTHON_DECL slice : public object
// represent the widest possible range that could be traveled
// (inclusive), and final_dist is the maximum distance covered by the
// slice.
typename RandomAccessIterator::difference_type final_dist =
std::distance( ret.start, ret.stop);
typename iterator_difference<RandomAccessIterator>::type final_dist =
boost::detail::distance( ret.start, ret.stop);
// First case, if both ret.start and ret.stop are equal, then step
// is irrelevant and we can return here.
@@ -222,24 +230,23 @@ class BOOST_PYTHON_DECL slice : public object
// I don't remember all of the oolies surrounding negative modulii,
// so I am handling each of these cases separately.
if (final_dist < 0) {
int remainder = -final_dist % -ret.step;
difference_type remainder = -final_dist % -ret.step;
std::advance( ret.stop, remainder);
}
else {
int remainder = final_dist % ret.step;
difference_type remainder = final_dist % ret.step;
std::advance( ret.stop, -remainder);
}
return ret;
}
#endif // !defined BOOST_NO_MEMBER_TEMPLATES
public:
// This declaration, in conjunction with the specialization of
// object_manager_traits<> below, allows C++ functions accepting slice
// arguments to be called from from Python. These constructors should never
// be used in client code.
BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(slice, object)
BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(slice, detail::slice_base)
};

View File

@@ -6,39 +6,32 @@
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
namespace boost { namespace python {
namespace boost { namespace python { namespace detail {
object
slice::new_slice(PyObject* start, PyObject* stop, PyObject* step)
{
return object(detail::new_reference( PySlice_New(start, stop, step)));
}
slice::slice()
: object( boost::python::detail::new_reference(
PySlice_New( NULL, NULL, NULL)))
slice_base::slice_base(PyObject* start, PyObject* stop, PyObject* step)
: object(detail::new_reference( PySlice_New(start, stop, step)))
{
}
object
slice::start() const
slice_base::start() const
{
return object( detail::borrowed_reference(
((PySliceObject*)this->ptr())->start));
}
object
slice::stop() const
slice_base::stop() const
{
return object( detail::borrowed_reference(
((PySliceObject*)this->ptr())->stop));
}
object
slice::step() const
slice_base::step() const
{
return object( detail::borrowed_reference(
((PySliceObject*)this->ptr())->step));
}
} } // !namespace boost::python
} } } // !namespace boost::python::detail

View File

@@ -158,7 +158,11 @@ bpl-test crossmod_exception
[ bpl-test docstring ]
[ bpl-test vector_indexing_suite ]
[ bpl-test map_indexing_suite ]
[ extension map_indexing_suite_ext
: map_indexing_suite.cpp int_map_indexing_suite.cpp <template>../build/extension ]
[ boost-python-runtest
map_indexing_suite : map_indexing_suite.py <pyd>map_indexing_suite_ext ]
# if $(TEST_BIENSTMAN_NON_BUGS)
# {

View File

@@ -29,7 +29,7 @@ BOOST_PYTHON_MODULE(injected_ext)
class_<X>("X", init<int>())
.def("__init__", make_constructor(empty))
.def("__init__", make_constructor(sum))
.def("__init__", make_constructor(product))
.def("__init__", make_constructor(product), "this is product's docstring")
.def("value", &X::value)
;
}

16
test/int_map_indexing_suite.cpp Executable file
View File

@@ -0,0 +1,16 @@
// Copyright David Abrahams 2004. 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)
#include <boost/python/class.hpp>
#include <boost/python/suite/indexing/map_indexing_suite.hpp>
void int_map_indexing_suite()
{
using namespace boost::python;
// Compile check only...
class_<std::map<int, int> >("IntMap")
.def(map_indexing_suite<std::map<int, int> >())
;
}

View File

@@ -40,10 +40,15 @@ BOOST_PYTHON_MODULE(map_indexing_suite_ext)
.def(map_indexing_suite<std::map<std::string, X> >())
;
void int_map_indexing_suite(); // moved to int_map_indexing_suite.cpp to
int_map_indexing_suite(); // avoid MSVC 6/7 internal structure overflow
#if 0
// Compile check only...
class_<std::map<int, int> >("IntMap")
.def(map_indexing_suite<std::map<int, int> >())
;
#endif
// Compile check only...
class_<std::map<std::string, boost::shared_ptr<X> > >("TestMap")

View File

@@ -8,6 +8,7 @@
#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
#include "test_class.hpp"
//#include <boost/python/str.hpp>
#if __GNUC__ != 2
# include <ostream>
#else

View File

@@ -3,7 +3,7 @@
// 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 <boost/python/object/select_holder.hpp>
#include <boost/python/object/class_metadata.hpp>
#include <boost/python/has_back_reference.hpp>
#include <boost/python/detail/not_specified.hpp>
#include <boost/static_assert.hpp>
@@ -41,7 +41,13 @@ void assert_same(U* = 0, T* = 0)
template <class T, class Held, class Holder>
void assert_holder(T* = 0, Held* = 0, Holder* = 0)
{
typedef typename boost::python::objects::select_holder<T,Held>::type h;
using namespace boost::python::detail;
using namespace boost::python::objects;
typedef typename class_metadata<
T,Held,not_specified,not_specified
>::holder h;
assert_same<Holder>(
(h*)0
);
@@ -55,7 +61,7 @@ int test_main(int, char * [])
assert_holder<Base,not_specified,value_holder<Base> >();
assert_holder<BR,not_specified,value_holder_back_reference<BR,BR> >();
assert_holder<Base,Base,value_holder<Base> >();
assert_holder<Base,Base,value_holder_back_reference<Base,Base> >();
assert_holder<BR,BR,value_holder_back_reference<BR,BR> >();
assert_holder<Base,Derived

View File

@@ -76,6 +76,7 @@ bool check_numeric_array_rich_slice()
// Verify functions accepting a slice argument can be called
bool accept_slice( slice) { return true; }
int check_slice_get_indicies(slice index);
int check_slice_get_indicies(const slice index)
{
// A vector of integers from [-5, 5].
@@ -88,7 +89,7 @@ int check_slice_get_indicies(const slice index)
slice::range<std::vector<int>::iterator> bounds;
try {
bounds = index.get_indicies<>(coll.begin(), coll.end());
bounds = index.get_indicies(coll.begin(), coll.end());
}
catch (std::invalid_argument) {
return 0;