Skip to content

Commit 0ce8ab7

Browse files
committed
Full virtual function and abstract base support; new class interface.
[SVN r13253]
1 parent d721281 commit 0ce8ab7

17 files changed

Lines changed: 424 additions & 299 deletions

include/boost/python/class.hpp

Lines changed: 119 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -7,55 +7,50 @@
77
# define CLASS_DWA200216_HPP
88

99
# include <boost/python/class_fwd.hpp>
10+
# include <boost/python/bases.hpp>
11+
# include <boost/python/args.hpp>
1012
# include <boost/python/reference.hpp>
1113
# include <boost/python/object/class.hpp>
12-
# include <boost/python/object/value_holder_fwd.hpp>
1314
# include <boost/python/converter/type_id.hpp>
1415
# include <boost/python/detail/wrap_function.hpp>
1516
# include <boost/python/detail/member_function_cast.hpp>
16-
# include <boost/mpl/type_list.hpp>
1717
# include <boost/python/object/class_converters.hpp>
18+
# include <boost/type_traits/ice.hpp>
19+
# include <boost/type_traits/same_traits.hpp>
1820
# include <boost/mpl/size.hpp>
1921
# include <boost/mpl/for_each.hpp>
20-
# include <boost/python/detail/type_list.hpp>
21-
22-
namespace // put some convenience classes into the unnamed namespace for the user
23-
{
24-
// A type list for specifying bases
25-
template < BOOST_MPL_LIST_DEFAULT_PARAMETERS(typename B, ::boost::mpl::null_argument) >
26-
struct bases : ::boost::mpl::type_list< BOOST_MPL_LIST_PARAMETERS(B) >::type
27-
{};
28-
29-
// A type list for specifying arguments
30-
template < BOOST_MPL_LIST_DEFAULT_PARAMETERS(typename A, ::boost::mpl::null_argument) >
31-
struct args : ::boost::mpl::type_list< BOOST_MPL_LIST_PARAMETERS(A) >::type
32-
{};
33-
}
22+
# include <boost/mpl/bool_t.hpp>
23+
# include <boost/python/object/select_holder.hpp>
24+
# include <boost/python/object/class_wrapper.hpp>
25+
# include <boost/utility.hpp>
3426

3527
namespace boost { namespace python {
3628

3729
namespace detail
3830
{
39-
// This is an mpl BinaryMetaFunction object with a runtime behavior,
40-
// which is to write the id of the type which is passed as its 2nd
41-
// compile-time argument into the iterator pointed to by its runtime
42-
// argument
43-
struct write_type_id
31+
struct write_type_id;
32+
33+
template <class T, class Prev = detail::not_specified>
34+
struct select_held_type;
35+
36+
template <class T1, class T2, class T3>
37+
struct has_noncopyable;
38+
39+
// Register a to_python converter for a class T, depending on the
40+
// type of the first (tag) argument. The 2nd argument is a pointer
41+
// to the type of holder that must be created. The 3rd argument is a
42+
// reference to the Python type object to be created.
43+
template <class T, class Holder>
44+
static inline void register_copy_constructor(mpl::bool_t<true> const&, Holder*, ref const& obj, T* = 0)
4445
{
45-
// The first argument is Ignored because mpl::for_each is still
46-
// currently an accumulate (reduce) implementation.
47-
template <class Ignored, class T> struct apply
48-
{
49-
// also an artifact of accumulate-based for_each
50-
typedef void type;
46+
objects::class_wrapper<T,Holder> x(obj);
47+
}
5148

52-
// Here's the runtime behavior
53-
static void execute(converter::undecorated_type_id_t** p)
54-
{
55-
*(*p)++ = converter::undecorated_type_id<T>();
56-
}
57-
};
58-
};
49+
// Tag dispatched to have no effect.
50+
template <class T, class Holder>
51+
static inline void register_copy_constructor(mpl::bool_t<false> const&, Holder*, ref const&, T* = 0)
52+
{
53+
}
5954
}
6055

6156
//
@@ -64,27 +59,24 @@ namespace detail
6459
// This is the primary mechanism through which users will expose
6560
// C++ classes to Python. The three template arguments are:
6661
//
67-
// T - The class being exposed to Python
68-
//
69-
// Bases - An MPL sequence of base classes
70-
//
71-
// HolderGenerator -
72-
// An optional type generator for the "holder" which
73-
// maintains the C++ object inside the Python instance. The
74-
// default just holds the object "by-value", but other
75-
// holders can be substituted which will hold the C++ object
76-
// by smart pointer, for example.
77-
//
7862
template <
7963
class T // class being wrapped
80-
, class Bases
81-
, class HolderGenerator
64+
, class X1 // = detail::not_specified
65+
, class X2 // = detail::not_specified
66+
, class X3 // = detail::not_specified
8267
>
8368
class class_ : private objects::class_base
8469
{
85-
typedef class_<T,Bases,HolderGenerator> self;
70+
typedef class_<T,X1,X2,X3> self;
71+
BOOST_STATIC_CONSTANT(bool, is_copyable = (!detail::has_noncopyable<X1,X2,X3>::value));
72+
73+
typedef typename detail::select_held_type<
74+
X1, typename detail::select_held_type<
75+
X2, typename detail::select_held_type<
76+
X3
77+
>::type>::type>::type held_type;
78+
8679
public:
87-
8880
// Automatically derive the class name - only works on some
8981
// compilers because type_info::name is sometimes mangled (gcc)
9082
class_();
@@ -130,7 +122,12 @@ class class_ : private objects::class_base
130122
template <class Args>
131123
self& def_init(Args const&)
132124
{
133-
def("__init__", make_constructor<T,Args,HolderGenerator>());
125+
def("__init__",
126+
make_constructor<Args>(
127+
// Using runtime type selection works around a CWPro7 bug.
128+
objects::select_holder<T,held_type>((held_type*)0).get()
129+
)
130+
);
134131
return *this;
135132
}
136133

@@ -147,6 +144,12 @@ class class_ : private objects::class_base
147144
private: // types
148145
typedef objects::class_id class_id;
149146

147+
typedef typename detail::select_bases<X1
148+
, typename detail::select_bases<X2
149+
, typename boost::python::detail::select_bases<X3>::type
150+
>::type
151+
>::type bases;
152+
150153
// A helper class which will contain an array of id objects to be
151154
// passed to the base class constructor
152155
struct id_vector
@@ -159,50 +162,97 @@ class class_ : private objects::class_base
159162

160163
// Write the rest of the elements into succeeding positions.
161164
class_id* p = ids + 1;
162-
mpl::for_each<Bases, void, detail::write_type_id>::execute(&p);
165+
mpl::for_each<bases, void, detail::write_type_id>::execute(&p);
163166
}
164167

165168
BOOST_STATIC_CONSTANT(
166-
std::size_t, size = mpl::size<Bases>::value + 1);
169+
std::size_t, size = mpl::size<bases>::value + 1);
167170
class_id ids[size];
168171
};
169-
170-
private: // helper functions
171-
void initialize_converters();
172172
};
173173

174174

175175
//
176176
// implementations
177177
//
178-
template <class T, class Bases, class HolderGenerator>
179-
inline class_<T, Bases, HolderGenerator>::class_()
178+
template <class T, class X1, class X2, class X3>
179+
inline class_<T,X1,X2,X3>::class_()
180180
: class_base(typeid(T).name(), id_vector::size, id_vector().ids)
181181
{
182-
// Bring the class converters into existence. This static object
183-
// will survive until the shared library this module lives in is
184-
// unloaded (that doesn't happen until Python terminates).
185-
static objects::class_converters<T,Bases> converters(object());
182+
// register converters
183+
objects::register_class_from_python<T,bases>();
184+
185+
detail::register_copy_constructor<T>(
186+
mpl::bool_t<is_copyable>()
187+
, objects::select_holder<T,held_type>((held_type*)0).get()
188+
, this->object());
186189
}
187190

188-
template <class T, class Bases, class HolderGenerator>
189-
inline class_<T, Bases, HolderGenerator>::class_(char const* name)
191+
template <class T, class X1, class X2, class X3>
192+
inline class_<T,X1,X2,X3>::class_(char const* name)
190193
: class_base(name, id_vector::size, id_vector().ids)
191194
{
192-
// Bring the class converters into existence. This static object
193-
// will survive until the shared library this module lives in is
194-
// unloaded (that doesn't happen until Python terminates).
195-
static objects::class_converters<T,Bases> converters(object());
195+
// register converters
196+
objects::register_class_from_python<T,bases>();
197+
198+
detail::register_copy_constructor<T>(
199+
mpl::bool_t<is_copyable>()
200+
, objects::select_holder<T,held_type>((held_type*)0).get()
201+
, this->object());
196202
}
197203

198-
template <class T, class Bases, class HolderGenerator>
199-
inline ref class_<T, Bases, HolderGenerator>::object() const
204+
template <class T, class X1, class X2, class X3>
205+
inline ref class_<T,X1,X2,X3>::object() const
200206
{
201207
typedef objects::class_base base;
202208

203209
return this->base::object();
204210
}
205211

212+
namespace detail
213+
{
214+
// This is an mpl BinaryMetaFunction object with a runtime behavior,
215+
// which is to write the id of the type which is passed as its 2nd
216+
// compile-time argument into the iterator pointed to by its runtime
217+
// argument
218+
struct write_type_id
219+
{
220+
// The first argument is Ignored because mpl::for_each is still
221+
// currently an accumulate (reduce) implementation.
222+
template <class Ignored, class T> struct apply
223+
{
224+
// also an artifact of accumulate-based for_each
225+
typedef void type;
226+
227+
// Here's the runtime behavior
228+
static void execute(converter::undecorated_type_id_t** p)
229+
{
230+
*(*p)++ = converter::undecorated_type_id<T>();
231+
}
232+
};
233+
};
234+
235+
236+
template <class T1, class T2, class T3>
237+
struct has_noncopyable
238+
: type_traits::ice_or<
239+
is_same<T1,noncopyable>::value
240+
, is_same<T2,noncopyable>::value
241+
, is_same<T3,noncopyable>::value>
242+
{};
243+
244+
245+
template <class T, class Prev>
246+
struct select_held_type
247+
: mpl::select_type<
248+
!(specifies_bases<T>::value | is_same<T,noncopyable>::value)
249+
, T
250+
, Prev
251+
>
252+
{
253+
};
254+
}
255+
206256
}} // namespace boost::python
207257

208258
#endif // CLASS_DWA200216_HPP

include/boost/python/class_fwd.hpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
// to its suitability for any purpose.
66
#ifndef CLASS_FWD_DWA200222_HPP
77
# define CLASS_FWD_DWA200222_HPP
8-
# include <boost/python/object/value_holder_fwd.hpp>
8+
# include <boost/python/detail/not_specified.hpp>
99

1010
namespace boost { namespace python {
1111

@@ -16,8 +16,9 @@ namespace detail
1616

1717
template <
1818
class T // class being wrapped
19-
, class Bases = detail::empty_list
20-
, class HolderGenerator = objects::value_holder_generator<>
19+
, class X1 = detail::not_specified
20+
, class X2 = detail::not_specified
21+
, class X3 = detail::not_specified
2122
>
2223
class class_;
2324

include/boost/python/detail/arg_tuple_size.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ struct arg_tuple_size<R (A0::*)(A1, A2, A3, A4, A5)>
103103

104104

105105
// Metrowerks thinks this creates ambiguities
106-
# if !defined(__MWERKS__) || __MWERKS__ > 0x2406
106+
# if !defined(__MWERKS__) || __MWERKS__ > 0x2407
107107

108108
template <class R, class A0>
109109
struct arg_tuple_size<R (A0::*)() const>

include/boost/python/detail/msvc_typeinfo.hpp

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88

99
#include <boost/type.hpp>
1010
#include <typeinfo>
11-
11+
#include <boost/type_traits/array_traits.hpp>
12+
#include <boost/type_traits/reference_traits.hpp>
1213
//
1314
// Fix for MSVC's broken typeid() implementation which doesn't strip
1415
// decoration. This fix doesn't handle cv-qualified array types. It
@@ -62,35 +63,35 @@ inline typeinfo typeid_nonref(boost::type<T>* = 0)
6263
}
6364

6465
template <class T>
65-
inline typeinfo typeid_ref(boost::type<T>*, ...)
66+
inline typeinfo typeid_ref(T&(*)())
6667
{
6768
return typeid_nonref<T>();
6869
}
6970

70-
template <class U, class T>
71-
inline typeinfo typeid_ref(boost::type<U>*, T& (*)())
71+
template <class T>
72+
inline typeinfo array_ref_typeid(bool_t<true>, bool_t<false>, boost::type<T>* = 0)
7273
{
73-
return typeid_nonref<T>();
74+
return typeid_ref((T&(*)())0);
7475
}
7576

7677
template <class T>
77-
inline typeinfo typeid_array(bool_t<false>, boost::type<T>* = 0)
78+
inline typeinfo array_ref_typeid(bool_t<false>, bool_t<true>, boost::type<T>* = 0)
7879
{
79-
typedef T (*x)();
80-
return typeid_ref((boost::type<T>*)0, x(0));
80+
return typeid_ref((T(*)())0);
8181
}
8282

8383
template <class T>
84-
inline typeinfo typeid_array(bool_t<true>, boost::type<T>* = 0)
84+
inline typeinfo array_ref_typeid(bool_t<false>, bool_t<false>, boost::type<T>* = 0)
8585
{
86-
return typeid_nonref<T>();
86+
return typeid_ref((T&(*)())0);
8787
}
8888

8989
template <class T>
9090
inline typeinfo msvc_typeid(boost::type<T>* = 0)
9191
{
92-
typedef bool_t<is_array<T>::value> tag;
93-
return typeid_array(tag(), (boost::type<T>*)0);
92+
typedef bool_t<is_array<T>::value> array_tag;
93+
typedef bool_t<is_reference<T>::value> ref_tag;
94+
return array_ref_typeid(array_tag(), ref_tag(), (boost::type<T>*)0);
9495
}
9596

9697
}}} // namespace boost::python::detail

include/boost/python/make_function.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,16 @@ objects::function* make_function(F f, Policies const& policies)
3535
, detail::arg_tuple_size<F>::value);
3636
}
3737

38-
template <class T, class ArgList, class Generator>
39-
objects::function* make_constructor(T* = 0, ArgList* = 0, Generator* = 0)
38+
template <class ArgList, class Holder>
39+
objects::function* make_constructor(Holder* = 0, ArgList* = 0)
4040
{
4141
enum { nargs = mpl::size<ArgList>::value };
4242

4343
return new objects::function(
4444
objects::py_function(
4545
::boost::bind<PyObject*>(detail::caller(),
4646
objects::make_holder<nargs>
47-
::template apply<T,Generator,ArgList>::execute
47+
::template apply<Holder,ArgList>::execute
4848
, _1, _2, default_call_policies()))
4949
, nargs + 1);
5050
}

0 commit comments

Comments
 (0)