diff --git a/include/boost/python/converter/registry.hpp b/include/boost/python/converter/registry.hpp index e7e9f739..b71c949a 100644 --- a/include/boost/python/converter/registry.hpp +++ b/include/boost/python/converter/registry.hpp @@ -20,7 +20,11 @@ struct registration; // This namespace acts as a sort of singleton namespace registry { + // Get the registration corresponding to the type, creating it if neccessary BOOST_PYTHON_DECL registration const& lookup(type_info); + + // Return a pointer to the corresponding registration, if one exists + BOOST_PYTHON_DECL registration const* query(type_info); BOOST_PYTHON_DECL void insert(to_python_function_t, type_info); @@ -41,8 +45,6 @@ namespace registry , constructor_function , type_info ); - - BOOST_PYTHON_DECL PyTypeObject*& class_object(type_info key); } }}} // namespace boost::python::converter diff --git a/include/boost/python/object/class_object.hpp b/include/boost/python/object/class_object.hpp deleted file mode 100644 index 57a8ee5d..00000000 --- a/include/boost/python/object/class_object.hpp +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright David Abrahams 2002. Permission to copy, use, -// modify, sell and distribute this software is granted provided this -// copyright notice appears in all copies. This software is provided -// "as is" without express or implied warranty, and with no claim as -// to its suitability for any purpose. -#ifndef CLASS_OBJECT_DWA200222_HPP -# define CLASS_OBJECT_DWA200222_HPP - -# include -# include - -namespace boost { namespace python { namespace objects { - -template -struct class_object -{ - static PyTypeObject*& reference; -}; - -template -PyTypeObject*& class_object::reference - = converter::registry::class_object(python::type_id()); - -}}} // namespace boost::python::objects - -#endif // CLASS_OBJECT_DWA200222_HPP diff --git a/include/boost/python/to_python_indirect.hpp b/include/boost/python/to_python_indirect.hpp index 6aaa2ab0..60b861b1 100644 --- a/include/boost/python/to_python_indirect.hpp +++ b/include/boost/python/to_python_indirect.hpp @@ -8,7 +8,7 @@ # include # include -# include +# include # include # include # include @@ -65,7 +65,7 @@ namespace detail static result_type execute(T* p) { BOOST_STATIC_ASSERT(is_class::value); - return python::objects::class_object::reference; + return converter::registered::converters.class_object; } }; diff --git a/src/converter/registry.cpp b/src/converter/registry.cpp index b74f8bd8..60db3bb8 100644 --- a/src/converter/registry.cpp +++ b/src/converter/registry.cpp @@ -50,8 +50,11 @@ namespace // entry* get(type_info type) { # ifdef BOOST_PYTHON_TRACE_REGISTRY + registry_t::iterator p = entries().find(entry(type)); + std::cout << "looking up " << type - << (entries().find(entry(type)) == entries().end() ? ": not found\n" : ": found\n"); + << (p == entries().end() || p->target_type != type + ? "...NOT found\n" : "...found\n"); # endif return const_cast( &*entries().insert(entry(type)).first @@ -127,15 +130,21 @@ namespace registry *found = registration; } - PyTypeObject*& class_object(type_info key) - { - return get(key)->class_object; - } - registration const& lookup(type_info key) { return *get(key); } + + registration const* query(type_info type) + { + registry_t::iterator p = entries().find(entry(type)); +# ifdef BOOST_PYTHON_TRACE_REGISTRY + std::cout << "querying " << type + << (p == entries().end() || p->target_type != type + ? "...NOT found\n" : "...found\n"); +# endif + return (p == entries().end() || p->target_type != type) ? 0 : &*p; + } } // namespace registry }}} // namespace boost::python::converter diff --git a/src/object/class.cpp b/src/object/class.cpp index 43a6ef46..e49df96f 100644 --- a/src/object/class.cpp +++ b/src/object/class.cpp @@ -204,37 +204,22 @@ namespace objects namespace { - struct class_registry + // Find a registered class object corresponding to id. Return a + // null handle if no such class is registered. + inline type_handle query_class(class_id id) { - public: - type_handle get(class_id id) const; - type_handle query(class_id id) const; - void set(class_id, type_handle class_object); - private: - typedef python::detail::map_entry entry; - std::vector m_impl; - }; - - class_registry& registry() - { - static class_registry x; - return x; + converter::registration const* p = converter::registry::query(id); + return type_handle( + python::borrowed( + python::allow_null(p ? p->class_object : 0)) + ); } - inline type_handle class_registry::query(class_id id) const + // Find a registered class corresponding to id. If not found, + // throw an appropriate exception. + type_handle get_class(class_id id) { - 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); - - return (p == finish || p->key != id) ? type_handle() : p->value; - } - - inline type_handle class_registry::get(class_id id) const - { - type_handle result(this->query(id)); + type_handle result(query_class(id)); if (result.get() == 0) { @@ -245,48 +230,54 @@ namespace objects } return result; } - - inline void class_registry::set(class_id id, type_handle 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)); - converter::registry::class_object(id) = (PyTypeObject*)object.get(); - } } + // class_base constructor + // + // name - the name of the new Python class + // + // num_types - one more than the number of declared bases + // + // types - array of python::type_info, the first item + // corresponding to the class being created, and the + // rest corresponding to its declared bases. + // class_base::class_base( char const* name, std::size_t num_types, class_id const* const types) { - class_registry& r = registry(); assert(num_types >= 1); - handle<> bases( - PyTuple_New(std::max(num_types - 1, static_cast(1))) - ); - - if (num_types > 1) + // Build a tuple of the base Python type objects. If no bases + // were declared, we'll use our class_type() as the single base + // class. + std::size_t const num_bases = std::max(num_types - 1, static_cast(1)); + handle<> bases(PyTuple_New(num_bases)); + + for (std::size_t i = 1; i <= num_bases; ++i) { - for (std::size_t i = 1; i < num_types; ++i) - PyTuple_SET_ITEM(bases.get(), i - 1, upcast(r.get(types[i]).release())); + type_handle c = (i >= num_types) ? class_type() : get_class(types[i]); + // PyTuple_SET_ITEM steals this reference + PyTuple_SET_ITEM(bases.get(), i - 1, upcast(c.release())); } - else - { - PyTuple_SET_ITEM(bases.get(), 0, upcast(class_type().release())); - } - + + // Build the (name, bases, dict) tuple for creating the new class handle<> args(PyTuple_New(3)); PyTuple_SET_ITEM(args.get(), 0, incref(python::object(name).ptr())); PyTuple_SET_ITEM(args.get(), 1, bases.release()); handle<> d(PyDict_New()); PyTuple_SET_ITEM(args.get(), 2, d.release()); + // Call the class metatype to create a new class PyObject* c = PyObject_CallObject(upcast(class_metatype().get()), args.get()); assert(PyType_IsSubtype(c->ob_type, &PyType_Type)); m_object = type_handle((PyTypeObject*)c); - r.set(types[0], m_object); + + // Insert the new class object in the registry + converter::registration& converters = const_cast( + converter::registry::lookup(types[0])); + + // Class object is leaked, for now + converters.class_object = (PyTypeObject*)incref(m_object.get()); } extern "C" @@ -315,7 +306,7 @@ namespace objects BOOST_PYTHON_DECL type_handle registered_class_object(class_id id) { - return registry().query(id); + return objects::query_class(id); } } // namespace objects