// Copyright David Abrahams 2001. 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. #include #include #include #include #include #include #include #include #include namespace boost { namespace python { namespace objects { instance_holder::instance_holder() : m_next(0) { } instance_holder::~instance_holder() { } PyTypeObject class_metatype_object = { PyObject_HEAD_INIT(0)//&PyType_Type) 0, "Boost.Python.class", PyType_Type.tp_basicsize, 0, 0, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT // | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, /* tp_flags */ 0, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ 0, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, //&PyType_Type, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ 0, // 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); } extern "C" { static void instance_dealloc(PyObject* inst) { instance* kill_me = (instance*)inst; for (instance_holder* p = kill_me->objects, *next; p != 0; p = next) { next = p->next(); delete p; } inst->ob_type->tp_free(inst); } } // 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, "Boost.Python.instance", sizeof(instance), 0, instance_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT // | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, /* tp_flags */ 0, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ 0, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, //&PyBaseObject_Type, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ PyType_GenericNew }; BOOST_PYTHON_DECL ref class_type() { if (class_type_object.tp_dict == 0) { class_type_object.ob_type = (PyTypeObject*)class_metatype().release(); class_type_object.tp_base = &PyBaseObject_Type; if (PyType_Ready(&class_type_object)) return ref(); } return ref((PyObject*)&class_type_object, ref::increment_count); } // 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; ((instance*)self)->objects = this; } BOOST_PYTHON_DECL void* find_instance_impl(PyObject* inst, converter::undecorated_type_id_t type) { if (inst->ob_type->ob_type != &class_metatype_object) return 0; instance* self = reinterpret_cast(inst); for (instance_holder::iterator match(self->objects), end(0); match != end; ++match) { void* const found = (*match).holds(type); if (found) return found; } 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)); converter::registry::class_object(id) = (PyTypeObject*)object.get(); } } 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); 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); } }}} // namespace boost::python::objects