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
1218namespace 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!
6787PyTypeObject 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