Skip to content

Commit 03e9e4c

Browse files
committed
Added class wrapping
[SVN r12387]
1 parent 4a1d077 commit 03e9e4c

9 files changed

Lines changed: 1164 additions & 24 deletions

File tree

Jamfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ dll bpl
2323
src/converter/type_id.cpp
2424
src/object/class.cpp
2525
src/object/function.cpp
26-
# src/object/inheritance.cpp
26+
src/object/inheritance.cpp
2727
src/errors.cpp
2828
src/module.cpp
2929
src/objects.cpp

include/boost/python/class.hpp

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
// Copyright David Abrahams 2002. Permission to copy, use,
2+
// modify, sell and distribute this software is granted provided this
3+
// copyright notice appears in all copies. This software is provided
4+
// "as is" without express or implied warranty, and with no claim as
5+
// to its suitability for any purpose.
6+
#ifndef CLASS_DWA200216_HPP
7+
# define CLASS_DWA200216_HPP
8+
9+
# include <boost/python/module.hpp>
10+
# include <boost/python/reference.hpp>
11+
# include <boost/python/object/class.hpp>
12+
# include <boost/python/converter/type_id.hpp>
13+
# include <boost/python/detail/wrap_function.hpp>
14+
# include <boost/mpl/type_list.hpp>
15+
# include <boost/python/object/class_converters.hpp>
16+
# include <boost/mpl/size.hpp>
17+
# include <boost/mpl/for_each.hpp>
18+
# include <boost/mpl/type_list.hpp>
19+
20+
namespace // put some convenience classes into the unnamed namespace for the user
21+
{
22+
// A type list for specifying bases
23+
template < BOOST_MPL_LIST_DEFAULT_PARAMETERS(typename B, ::boost::mpl::null_argument) >
24+
struct bases : ::boost::mpl::type_list< BOOST_MPL_LIST_PARAMETERS(B) >::type
25+
{};
26+
27+
// A type list for specifying arguments
28+
template < BOOST_MPL_LIST_DEFAULT_PARAMETERS(typename A, ::boost::mpl::null_argument) >
29+
struct args : ::boost::mpl::type_list< BOOST_MPL_LIST_PARAMETERS(A) >::type
30+
{};
31+
}
32+
33+
namespace boost { namespace python {
34+
35+
// Forward declarations
36+
namespace objects
37+
{
38+
struct value_holder_generator;
39+
}
40+
41+
namespace detail
42+
{
43+
// This is an mpl BinaryMetaFunction object with a runtime behavior,
44+
// which is to write the id of the type which is passed as its 2nd
45+
// compile-time argument into the iterator pointed to by its runtime
46+
// argument
47+
struct write_type_id
48+
{
49+
// The first argument is Ignored because mpl::for_each is still
50+
// currently an accumulate (reduce) implementation.
51+
template <class Ignored, class T> struct apply
52+
{
53+
// also an artifact of accumulate-based for_each
54+
typedef void type;
55+
56+
// Here's the runtime behavior
57+
static void execute(converter::undecorated_type_id_t** p)
58+
{
59+
*(*p)++ = converter::undecorated_type_id<T>();
60+
}
61+
};
62+
};
63+
}
64+
65+
//
66+
// class_<T,Bases,HolderGenerator>
67+
//
68+
// This is the primary mechanism through which users will expose
69+
// C++ classes to Python. The three template arguments are:
70+
//
71+
// T - The class being exposed to Python
72+
//
73+
// Bases - An MPL sequence of base classes
74+
//
75+
// HolderGenerator -
76+
// An optional type generator for the "holder" which
77+
// maintains the C++ object inside the Python instance. The
78+
// default just holds the object "by-value", but other
79+
// holders can be substituted which will hold the C++ object
80+
// by smart pointer, for example.
81+
//
82+
template <
83+
class T // class being wrapped
84+
, class Bases = mpl::type_list<>::type
85+
, class HolderGenerator = objects::value_holder_generator
86+
>
87+
class class_ : objects::class_base
88+
{
89+
typedef class_<T,Bases,HolderGenerator> self;
90+
public:
91+
92+
// Construct with the module and class name
93+
class_(module&, char const* name);
94+
95+
// Wrap a member function or a non-member function which can take
96+
// a T, T cv&, or T cv* as its first parameter, or a callable
97+
// python object.
98+
template <class F>
99+
self& def(F f, char const* name)
100+
{
101+
// Use function::add_to_namespace to achieve overloading if
102+
// appropriate.
103+
objects::function::add_to_namespace(this->object(), name, detail::wrap_function(f));
104+
return *this;
105+
}
106+
107+
// Define the constructor with the given Args, which should be an
108+
// MPL sequence of types.
109+
template <class Args>
110+
self& def_init(Args const& = Args())
111+
{
112+
def(make_constructor<T,Args,HolderGenerator>(), "__init__");
113+
return *this;
114+
}
115+
116+
// Define the default constructor.
117+
self& def_init()
118+
{
119+
this->def_init(mpl::type_list<>::type());
120+
return *this;
121+
}
122+
123+
private: // types
124+
typedef objects::class_id class_id;
125+
126+
// A helper class which will contain an array of id objects to be
127+
// passed to the base class constructor
128+
struct id_vector
129+
{
130+
id_vector()
131+
{
132+
// Stick the derived class id into the first element of the array
133+
ids[0] = converter::undecorated_type_id<T>();
134+
135+
// Write the rest of the elements into succeeding positions.
136+
class_id* p = ids + 1;
137+
mpl::for_each<Bases, void, detail::write_type_id>::execute(&p);
138+
}
139+
140+
BOOST_STATIC_CONSTANT(
141+
std::size_t, size = mpl::size<Bases>::value + 1);
142+
class_id ids[size];
143+
};
144+
145+
private: // helper functions
146+
void initialize_converters();
147+
};
148+
149+
150+
//
151+
// implementations
152+
//
153+
template <class T, class Bases, class HolderGenerator>
154+
inline class_<T, Bases, HolderGenerator>::class_(
155+
module& m, char const* name = typeid(T).name())
156+
: class_base(m, name, id_vector::size, id_vector().ids)
157+
{
158+
// Bring the class converters into existence. This static object
159+
// will survive until the shared library this module lives in is
160+
// unloaded (that doesn't happen until Python terminates).
161+
static objects::class_converters<T,Bases> converters(object());
162+
}
163+
164+
}} // namespace boost::python
165+
166+
#endif // CLASS_DWA200216_HPP
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright David Abrahams 2002. Permission to copy, use,
2+
// modify, sell and distribute this software is granted provided this
3+
// copyright notice appears in all copies. This software is provided
4+
// "as is" without express or implied warranty, and with no claim as
5+
// to its suitability for any purpose.
6+
#ifndef MAP_ENTRY_DWA2002118_HPP
7+
# define MAP_ENTRY_DWA2002118_HPP
8+
9+
namespace boost { namespace python { namespace detail {
10+
11+
// A trivial type that works well as the value_type of associative
12+
// vector maps
13+
template <class Key, class Value>
14+
struct map_entry
15+
{
16+
map_entry() {}
17+
map_entry(Key k) : key(k), value() {}
18+
map_entry(Key k, Value v) : key(k), value(v) {}
19+
20+
bool operator<(map_entry const& rhs) const
21+
{
22+
return this->key < rhs.key;
23+
}
24+
25+
Key key;
26+
Value value;
27+
};
28+
29+
template <class Key, class Value>
30+
bool operator<(map_entry<Key,Value> const& e, Key const& k)
31+
{
32+
return e.key < k;
33+
}
34+
35+
template <class Key, class Value>
36+
bool operator<(Key const& k, map_entry<Key,Value> const& e)
37+
{
38+
return k < e.key;
39+
}
40+
41+
42+
}}} // namespace boost::python::detail
43+
44+
#endif // MAP_ENTRY_DWA2002118_HPP
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Copyright David Abrahams 2002. Permission to copy, use,
2+
// modify, sell and distribute this software is granted provided this
3+
// copyright notice appears in all copies. This software is provided
4+
// "as is" without express or implied warranty, and with no claim as
5+
// to its suitability for any purpose.
6+
#ifndef WRAP_FUNCTION_DWA2002118_HPP
7+
# define WRAP_FUNCTION_DWA2002118_HPP
8+
9+
# include <boost/python/make_function.hpp>
10+
# include <boost/type_traits/ice.hpp>
11+
# include <boost/type_traits/composite_traits.hpp>
12+
# include <boost/mpl/select_type.hpp>
13+
14+
namespace boost { namespace python { namespace detail {
15+
16+
// A function which converts its argument into a Python callable
17+
// object. Not very general yet!
18+
19+
// This should eventually be replaced with a mechanism for specialized
20+
// wrap/unwrap objects. In other words, to_python(f), where f is a
21+
// function pointer or function type, should produce a callable Python
22+
// object.
23+
24+
template <bool needs_wrapping>
25+
struct wrap_function_select
26+
{
27+
template <class F>
28+
static objects::function* execute(F f)
29+
{
30+
return make_function(f);
31+
}
32+
};
33+
34+
template<>
35+
struct wrap_function_select<false>
36+
{
37+
template <class F>
38+
static F execute(F f)
39+
{
40+
return f;
41+
}
42+
};
43+
44+
template <class F>
45+
PyObject* wrap_function(F f)
46+
{
47+
return wrap_function_select<
48+
type_traits::ice_or<
49+
is_function<F>::value
50+
, is_member_function_pointer<F>::value
51+
>::value >::execute(f);
52+
}
53+
54+
}}} // namespace boost::python::detail
55+
56+
#endif // WRAP_FUNCTION_DWA2002118_HPP
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
// Copyright David Abrahams 2002. Permission to copy, use,
2+
// modify, sell and distribute this software is granted provided this
3+
// copyright notice appears in all copies. This software is provided
4+
// "as is" without express or implied warranty, and with no claim as
5+
// to its suitability for any purpose.
6+
#ifndef CLASS_CONVERTERS_DWA2002119_HPP
7+
# define CLASS_CONVERTERS_DWA2002119_HPP
8+
9+
# include <boost/python/converter/class.hpp>
10+
# include <boost/python/object/class_wrapper.hpp>
11+
# include <boost/mpl/for_each.hpp>
12+
13+
namespace boost { namespace python { namespace objects {
14+
15+
// Instantiating this class brings into existence all converters
16+
// associated with a class Bases is expected to be an mpl sequence of
17+
// base types.
18+
template <class Derived, class Bases>
19+
struct class_converters
20+
{
21+
public: // member functions
22+
// Constructor takes the python class object associated with T
23+
class_converters(PyObject* python_class);
24+
25+
private: // data members
26+
converter::class_unwrapper<Derived> m_unwrapper;
27+
class_wrapper<Derived> m_wrapper;
28+
};
29+
30+
//
31+
// Implementation details
32+
//
33+
34+
//////////////////////////////////////////////////////////////////////
35+
//
36+
// register_base_of<T> -
37+
// A BinaryMetaFunction object which registers a single base
38+
// class of T, and the corresponding cast(s)
39+
//
40+
41+
42+
// register_downcast/do_nothing -
43+
// Helpers for register_base_of<> which take care of registering
44+
// down-casts
45+
template <class Base, class Derived>
46+
struct register_downcast
47+
{
48+
static void execute()
49+
{
50+
register_conversion<Base, Derived>(true);
51+
}
52+
};
53+
54+
struct do_nothing
55+
{
56+
static void execute() { }
57+
};
58+
59+
// Here's where the real work gets done:
60+
template <class Derived>
61+
struct register_base_of
62+
{
63+
// Ignored is needed because mpl::for_each is still actually
64+
// accumulate. We're not using any state so it just sits there.
65+
template <class Ignored, class Base>
66+
struct apply
67+
{
68+
typedef void type; // 'type' needs to be defined for the same reasons
69+
70+
// Here's the runtime part:
71+
static void execute()
72+
{
73+
// Register the Base class
74+
register_dynamic_id<Base>();
75+
// Register the up-cast
76+
register_conversion<Derived,Base>(false);
77+
78+
// Register the down-cast, if appropriate.
79+
mpl::select_type<
80+
is_polymorphic<Base>::value
81+
, register_downcast<Base,Derived>
82+
, do_nothing
83+
>::type::execute();
84+
}
85+
};
86+
};
87+
88+
template <class Derived, class Bases>
89+
class_converters<Derived,Bases>::class_converters(PyObject* type_object)
90+
: m_wrapper(type_object)
91+
{
92+
// register all up/downcasts here
93+
register_dynamic_id<Derived>();
94+
95+
// register each base in the sequence
96+
mpl::for_each<Bases, void, register_base_of<Derived> >::execute();
97+
}
98+
99+
}}} // namespace boost::python::object
100+
101+
#endif // CLASS_CONVERTERS_DWA2002119_HPP

0 commit comments

Comments
 (0)