diff --git a/include/boost/python/object/class.hpp b/include/boost/python/object/class.hpp index bc8f40d1..808e3669 100644 --- a/include/boost/python/object/class.hpp +++ b/include/boost/python/object/class.hpp @@ -6,16 +6,44 @@ #ifndef CLASS_DWA20011214_HPP # define CLASS_DWA20011214_HPP +# include # include # include # include # include +# include # include +# include -namespace boost { namespace python { namespace objects { +namespace boost { namespace python { + +class module; + +namespace objects { template struct holder; +// To identify a class, we don't need cv/reference decorations +typedef converter::undecorated_type_id_t class_id; + +struct BOOST_PYTHON_DECL class_base : noncopyable +{ + // constructor + class_base( + module& name_space // Which name space the class will live in + , char const* name // The name of the class + + , std::size_t num_types // A list of class_ids. The first is the type + , class_id const*const types // this is wrapping. The rest are the types of + // any bases. + ); + + // Retrieve a pointer to the underlying object + PyObject* object() const { return m_object.get(); } + private: + ref m_object; +}; + // Base class for all holders struct BOOST_PYTHON_DECL instance_holder : noncopyable { @@ -28,7 +56,7 @@ struct BOOST_PYTHON_DECL instance_holder : noncopyable virtual void* holds(converter::type_id_t) = 0; - void install(PyObject* inst); + void install(PyObject* inst) throw(); struct iterator_policies : default_iterator_policies { @@ -58,6 +86,8 @@ struct instance instance_holder* objects; }; +// Given a type_id, find the instance data which corresponds to it, or +// return 0 in case no such type is held. BOOST_PYTHON_DECL void* find_instance_impl(PyObject*, converter::type_id_t); template @@ -66,8 +96,8 @@ T* find_instance(PyObject* p, T* = 0) return static_cast(find_instance_impl(p, converter::type_id())); } -BOOST_PYTHON_DECL PyTypeObject* class_metatype(); -BOOST_PYTHON_DECL PyTypeObject* class_type(); +BOOST_PYTHON_DECL ref class_metatype(); +BOOST_PYTHON_DECL ref class_type(); // // implementation diff --git a/include/boost/python/object/class_unwrapper.hpp b/include/boost/python/object/class_unwrapper.hpp index 666c6e93..0877ff24 100644 --- a/include/boost/python/object/class_unwrapper.hpp +++ b/include/boost/python/object/class_unwrapper.hpp @@ -18,14 +18,14 @@ struct class_unwrapper template struct reference_unwrapper : converter::unwrapper { - bool convertible(PyObject* p) const + void* can_convert(PyObject* p) const { - return find_holder(p) != 0; + return find_instance(p); } - Target convert(PyObject* p, void*&) const + Target convert(PyObject* p, void* data, ) const { - return *find_holder(p)->target(); + return *find_instance(p)->target(); } }; diff --git a/include/boost/python/object/function.hpp b/include/boost/python/object/function.hpp index ed7dd319..cc2695d8 100644 --- a/include/boost/python/object/function.hpp +++ b/include/boost/python/object/function.hpp @@ -22,10 +22,16 @@ struct BOOST_PYTHON_DECL function : PyObject ~function(); PyObject* call(PyObject*, PyObject*) const; - void add_overload(function* overload); + + // Add an attributeto the name_space with the given name. If it is + // a function object (this class), and an existing function is + // already there, add it as an overload. + static void add_to_namespace( + PyObject* name_space, char const* name, PyObject* attribute); private: // helper functions void argument_error(PyObject* args, PyObject* keywords) const; + void add_overload(function* overload); private: // data members py_function m_fn; diff --git a/include/boost/python/object/value_holder.hpp b/include/boost/python/object/value_holder.hpp index be7247da..d6e38a79 100644 --- a/include/boost/python/object/value_holder.hpp +++ b/include/boost/python/object/value_holder.hpp @@ -8,6 +8,8 @@ # include # include +# include +# include namespace boost { namespace python { namespace objects { @@ -76,9 +78,11 @@ struct value_holder_generator }; template -void* value_holder::holds(converter::type_id_t x) +void* value_holder::holds(converter::type_id_t dst_t) { - return x == converter::type_id() ? &m_held : 0; + converter::type_id_t src_t = converter::type_id(); + return src_t == dst_t ? &m_held + : find_static_type(&m_held, src_t, dst_t); } }}} // namespace boost::python::objects diff --git a/src/object/class.cpp b/src/object/class.cpp index 8e85f38b..5ebabba1 100644 --- a/src/object/class.cpp +++ b/src/object/class.cpp @@ -6,8 +6,14 @@ #include #include #include +#include +#include +#include +#include #include +#include #include +#include namespace boost { namespace python { namespace objects { @@ -64,6 +70,20 @@ PyTypeObject class_metatype_object = { // PyType_GenericNew /* tp_new */ }; +// Get the metatype object for all extension classes. +BOOST_PYTHON_DECL ref class_metatype() +{ + if (class_metatype_object.tp_dict == 0) + { + class_metatype_object.ob_type = &PyType_Type; + class_metatype_object.tp_base = &PyType_Type; + if (PyType_Ready(&class_metatype_object)) + return ref(); + } + return ref((PyObject*)&class_metatype_object, ref::increment_count); +} + +// Do we really need this? I'm beginning to think we don't! PyTypeObject class_type_object = { PyObject_HEAD_INIT(0) //&class_metatype_object) 0, @@ -107,33 +127,21 @@ PyTypeObject class_type_object = { PyType_GenericNew }; -BOOST_PYTHON_DECL PyTypeObject* class_metatype() -{ - if (class_metatype_object.tp_dict == 0) - { - class_metatype_object.ob_type = &PyType_Type; - class_metatype_object.tp_base = &PyType_Type; - if (PyType_Ready(&class_metatype_object)) - return 0; - } - Py_INCREF(&class_metatype_object); - return &class_metatype_object; -} - -BOOST_PYTHON_DECL PyTypeObject* class_type() +BOOST_PYTHON_DECL ref class_type() { if (class_type_object.tp_dict == 0) { - class_type_object.ob_type = class_metatype(); + class_type_object.ob_type = (PyTypeObject*)class_metatype().release(); class_type_object.tp_base = &PyBaseObject_Type; if (PyType_Ready(&class_type_object)) - return 0; + return ref(); } - Py_INCREF(&class_type_object); - return &class_type_object; + return ref((PyObject*)&class_type_object, ref::increment_count); } -void instance_holder::install(PyObject* self) +// Install the instance data for a C++ object into a Python instance +// object. +void instance_holder::install(PyObject* self) throw() { assert(self->ob_type->ob_type == &class_metatype_object); m_next = ((instance*)self)->objects; @@ -157,4 +165,76 @@ find_instance_impl(PyObject* inst, converter::type_id_t type) return 0; } +namespace +{ + struct class_registry + { + public: + ref get(class_id id) const; + void set(class_id, ref class_object); + private: + typedef detail::map_entry entry; + std::vector m_impl; + }; + + class_registry& registry() + { + static class_registry x; + return x; + } + + ref class_registry::get(class_id id) const + { + std::vector::const_iterator start = m_impl.begin(); + std::vector::const_iterator finish = m_impl.end(); + + std::vector::const_iterator p + = boost::detail::lower_bound(start, finish, id); + + if (p == finish && p->key != id) + { + string report("extension class wrapper for base class "); + (report += id.name()) += "has not been created yet"; + PyErr_SetObject(PyExc_RuntimeError, report.get()); + throw error_already_set(); + } + return p->value; + } + + void class_registry::set(class_id id, ref object) + { + std::vector::iterator start = m_impl.begin(); + std::vector::iterator finish = m_impl.end(); + m_impl.insert( + boost::detail::lower_bound(start, finish, id) + , entry(id, object)); + } +} + +class_base::class_base( + module& m, char const* name, std::size_t num_types, class_id const* const types) +{ + class_registry& r = registry(); + assert(num_types >= 1); + tuple bases(std::max(num_types - 1, static_cast(1))); + if (num_types > 1) + { + for (std::size_t i = 1; i < num_types; ++i) + bases.set_item(i - 1, r.get(types[i])); + } + else + { + bases.set_item(0, class_type()); + } + + tuple args(3); + args.set_item(0, string(name).reference()); + args.set_item(1, bases.reference()); + args.set_item(2, dictionary().reference()); + + m_object = ref(PyObject_CallObject(class_metatype().get(), args.get())); + r.set(types[0], m_object); + m.add(m_object, name); +} + }}} // namespace boost::python::objects