Skip to content

Commit dabb22b

Browse files
committed
added class wrapping
[SVN r12384]
1 parent 3d03ca3 commit dabb22b

File tree

5 files changed

+150
-30
lines changed

5 files changed

+150
-30
lines changed

include/boost/python/object/class.hpp

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,44 @@
66
#ifndef CLASS_DWA20011214_HPP
77
# define CLASS_DWA20011214_HPP
88

9+
# include <boost/python/module.hpp>
910
# include <boost/python/detail/wrap_python.hpp>
1011
# include <boost/python/detail/config.hpp>
1112
# include <boost/utility.hpp>
1213
# include <boost/python/converter/type_id.hpp>
14+
# include <boost/python/reference.hpp>
1315
# include <boost/iterator_adaptors.hpp>
16+
# include <cstddef>
1417

15-
namespace boost { namespace python { namespace objects {
18+
namespace boost { namespace python {
19+
20+
class module;
21+
22+
namespace objects {
1623

1724
template <class T> struct holder;
1825

26+
// To identify a class, we don't need cv/reference decorations
27+
typedef converter::undecorated_type_id_t class_id;
28+
29+
struct BOOST_PYTHON_DECL class_base : noncopyable
30+
{
31+
// constructor
32+
class_base(
33+
module& name_space // Which name space the class will live in
34+
, char const* name // The name of the class
35+
36+
, std::size_t num_types // A list of class_ids. The first is the type
37+
, class_id const*const types // this is wrapping. The rest are the types of
38+
// any bases.
39+
);
40+
41+
// Retrieve a pointer to the underlying object
42+
PyObject* object() const { return m_object.get(); }
43+
private:
44+
ref m_object;
45+
};
46+
1947
// Base class for all holders
2048
struct BOOST_PYTHON_DECL instance_holder : noncopyable
2149
{
@@ -28,7 +56,7 @@ struct BOOST_PYTHON_DECL instance_holder : noncopyable
2856

2957
virtual void* holds(converter::type_id_t) = 0;
3058

31-
void install(PyObject* inst);
59+
void install(PyObject* inst) throw();
3260

3361
struct iterator_policies : default_iterator_policies
3462
{
@@ -58,6 +86,8 @@ struct instance
5886
instance_holder* objects;
5987
};
6088

89+
// Given a type_id, find the instance data which corresponds to it, or
90+
// return 0 in case no such type is held.
6191
BOOST_PYTHON_DECL void* find_instance_impl(PyObject*, converter::type_id_t);
6292

6393
template <class T>
@@ -66,8 +96,8 @@ T* find_instance(PyObject* p, T* = 0)
6696
return static_cast<T*>(find_instance_impl(p, converter::type_id<T>()));
6797
}
6898

69-
BOOST_PYTHON_DECL PyTypeObject* class_metatype();
70-
BOOST_PYTHON_DECL PyTypeObject* class_type();
99+
BOOST_PYTHON_DECL ref class_metatype();
100+
BOOST_PYTHON_DECL ref class_type();
71101

72102
//
73103
// implementation

include/boost/python/object/class_unwrapper.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@ struct class_unwrapper
1818
template <class Target>
1919
struct reference_unwrapper : converter::unwrapper<Target>
2020
{
21-
bool convertible(PyObject* p) const
21+
void* can_convert(PyObject* p) const
2222
{
23-
return find_holder<T>(p) != 0;
23+
return find_instance<T>(p);
2424
}
2525

26-
Target convert(PyObject* p, void*&) const
26+
Target convert(PyObject* p, void* data, ) const
2727
{
28-
return *find_holder<T>(p)->target();
28+
return *find_instance<T>(p)->target();
2929
}
3030
};
3131

include/boost/python/object/function.hpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,16 @@ struct BOOST_PYTHON_DECL function : PyObject
2222
~function();
2323

2424
PyObject* call(PyObject*, PyObject*) const;
25-
void add_overload(function* overload);
25+
26+
// Add an attributeto the name_space with the given name. If it is
27+
// a function object (this class), and an existing function is
28+
// already there, add it as an overload.
29+
static void add_to_namespace(
30+
PyObject* name_space, char const* name, PyObject* attribute);
2631

2732
private: // helper functions
2833
void argument_error(PyObject* args, PyObject* keywords) const;
34+
void add_overload(function* overload);
2935

3036
private: // data members
3137
py_function m_fn;

include/boost/python/object/value_holder.hpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
# include <boost/python/object/class.hpp>
1010
# include <boost/python/converter/type_id.hpp>
11+
# include <boost/python/object/inheritance.hpp>
12+
# include <boost/ref.hpp>
1113

1214
namespace boost { namespace python { namespace objects {
1315

@@ -76,9 +78,11 @@ struct value_holder_generator
7678
};
7779

7880
template <class Held>
79-
void* value_holder<Held>::holds(converter::type_id_t x)
81+
void* value_holder<Held>::holds(converter::type_id_t dst_t)
8082
{
81-
return x == converter::type_id<Held>() ? &m_held : 0;
83+
converter::type_id_t src_t = converter::type_id<Held>();
84+
return src_t == dst_t ? &m_held
85+
: find_static_type(&m_held, src_t, dst_t);
8286
}
8387

8488
}}} // namespace boost::python::objects

src/object/class.cpp

Lines changed: 99 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,14 @@
66
#include <boost/python/detail/config.hpp>
77
#include <boost/python/detail/wrap_python.hpp>
88
#include <boost/python/object/class.hpp>
9+
#include <boost/python/object/class_wrapper.hpp>
10+
#include <boost/python/objects.hpp>
11+
#include <boost/python/detail/map_entry.hpp>
12+
#include <boost/detail/binary_search.hpp>
913
#include <boost/bind.hpp>
14+
#include <boost/python/detail/wrap_python.hpp>
1015
#include <functional>
16+
#include <vector>
1117

1218
namespace boost { namespace python { namespace objects {
1319

@@ -64,6 +70,20 @@ PyTypeObject class_metatype_object = {
6470
// PyType_GenericNew /* tp_new */
6571
};
6672

73+
// Get the metatype object for all extension classes.
74+
BOOST_PYTHON_DECL ref class_metatype()
75+
{
76+
if (class_metatype_object.tp_dict == 0)
77+
{
78+
class_metatype_object.ob_type = &PyType_Type;
79+
class_metatype_object.tp_base = &PyType_Type;
80+
if (PyType_Ready(&class_metatype_object))
81+
return ref();
82+
}
83+
return ref((PyObject*)&class_metatype_object, ref::increment_count);
84+
}
85+
86+
// Do we really need this? I'm beginning to think we don't!
6787
PyTypeObject class_type_object = {
6888
PyObject_HEAD_INIT(0) //&class_metatype_object)
6989
0,
@@ -107,33 +127,21 @@ PyTypeObject class_type_object = {
107127
PyType_GenericNew
108128
};
109129

110-
BOOST_PYTHON_DECL PyTypeObject* class_metatype()
111-
{
112-
if (class_metatype_object.tp_dict == 0)
113-
{
114-
class_metatype_object.ob_type = &PyType_Type;
115-
class_metatype_object.tp_base = &PyType_Type;
116-
if (PyType_Ready(&class_metatype_object))
117-
return 0;
118-
}
119-
Py_INCREF(&class_metatype_object);
120-
return &class_metatype_object;
121-
}
122-
123-
BOOST_PYTHON_DECL PyTypeObject* class_type()
130+
BOOST_PYTHON_DECL ref class_type()
124131
{
125132
if (class_type_object.tp_dict == 0)
126133
{
127-
class_type_object.ob_type = class_metatype();
134+
class_type_object.ob_type = (PyTypeObject*)class_metatype().release();
128135
class_type_object.tp_base = &PyBaseObject_Type;
129136
if (PyType_Ready(&class_type_object))
130-
return 0;
137+
return ref();
131138
}
132-
Py_INCREF(&class_type_object);
133-
return &class_type_object;
139+
return ref((PyObject*)&class_type_object, ref::increment_count);
134140
}
135141

136-
void instance_holder::install(PyObject* self)
142+
// Install the instance data for a C++ object into a Python instance
143+
// object.
144+
void instance_holder::install(PyObject* self) throw()
137145
{
138146
assert(self->ob_type->ob_type == &class_metatype_object);
139147
m_next = ((instance*)self)->objects;
@@ -157,4 +165,76 @@ find_instance_impl(PyObject* inst, converter::type_id_t type)
157165
return 0;
158166
}
159167

168+
namespace
169+
{
170+
struct class_registry
171+
{
172+
public:
173+
ref get(class_id id) const;
174+
void set(class_id, ref class_object);
175+
private:
176+
typedef detail::map_entry<class_id,ref> entry;
177+
std::vector<entry> m_impl;
178+
};
179+
180+
class_registry& registry()
181+
{
182+
static class_registry x;
183+
return x;
184+
}
185+
186+
ref class_registry::get(class_id id) const
187+
{
188+
std::vector<entry>::const_iterator start = m_impl.begin();
189+
std::vector<entry>::const_iterator finish = m_impl.end();
190+
191+
std::vector<entry>::const_iterator p
192+
= boost::detail::lower_bound(start, finish, id);
193+
194+
if (p == finish && p->key != id)
195+
{
196+
string report("extension class wrapper for base class ");
197+
(report += id.name()) += "has not been created yet";
198+
PyErr_SetObject(PyExc_RuntimeError, report.get());
199+
throw error_already_set();
200+
}
201+
return p->value;
202+
}
203+
204+
void class_registry::set(class_id id, ref object)
205+
{
206+
std::vector<entry>::iterator start = m_impl.begin();
207+
std::vector<entry>::iterator finish = m_impl.end();
208+
m_impl.insert(
209+
boost::detail::lower_bound(start, finish, id)
210+
, entry(id, object));
211+
}
212+
}
213+
214+
class_base::class_base(
215+
module& m, char const* name, std::size_t num_types, class_id const* const types)
216+
{
217+
class_registry& r = registry();
218+
assert(num_types >= 1);
219+
tuple bases(std::max(num_types - 1, static_cast<std::size_t>(1)));
220+
if (num_types > 1)
221+
{
222+
for (std::size_t i = 1; i < num_types; ++i)
223+
bases.set_item(i - 1, r.get(types[i]));
224+
}
225+
else
226+
{
227+
bases.set_item(0, class_type());
228+
}
229+
230+
tuple args(3);
231+
args.set_item(0, string(name).reference());
232+
args.set_item(1, bases.reference());
233+
args.set_item(2, dictionary().reference());
234+
235+
m_object = ref(PyObject_CallObject(class_metatype().get(), args.get()));
236+
r.set(types[0], m_object);
237+
m.add(m_object, name);
238+
}
239+
160240
}}} // namespace boost::python::objects

0 commit comments

Comments
 (0)