From f5f3277507da78a275ea0d6b0725cdbfe2976f04 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Sat, 28 Oct 2000 21:44:22 +0000 Subject: [PATCH] Factorization [SVN r8047] --- gen_extclass.py | 181 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 169 insertions(+), 12 deletions(-) diff --git a/gen_extclass.py b/gen_extclass.py index 13b84fb4..0ef450e6 100644 --- a/gen_extclass.py +++ b/gen_extclass.py @@ -41,6 +41,7 @@ namespace py { // forward declarations class ExtensionInstance; +class ExtensionClassBase; template class InstanceHolder; template class InstanceValueHolder; template class InstancePtrHolder; @@ -67,10 +68,39 @@ T* check_non_null(T* p) template class HeldInstance; +namespace detail { + typedef void* (*ConversionFunction)(void*); + + struct BaseClassInfo + { + BaseClassInfo(ExtensionClassBase* t, ConversionFunction f) + :class_object(t), convert(f) + {} + + ExtensionClassBase* class_object; + ConversionFunction convert; + }; + + typedef BaseClassInfo DerivedClassInfo; +} + class ExtensionClassBase : public Class { public: ExtensionClassBase(const char* name); + + public: + // the purpose of try_class_conversions() and its related functions + // is explained in extclass.cpp + void* try_class_conversions(InstanceHolderBase*) const; + void* try_base_class_conversions(InstanceHolderBase*) const; + void* try_derived_class_conversions(InstanceHolderBase*) const; + + private: + virtual void* extract_object_from_holder(InstanceHolderBase* v) const = 0; + virtual std::vector const& base_classes() const = 0; + virtual std::vector const& derived_classes() const = 0; + protected: void add_method(PyPtr method, const char* name); void add_default_method(PyPtr method, const char* name); @@ -86,12 +116,24 @@ template class ClassRegistry { public: - static Class* class_object() + static ExtensionClassBase* class_object() { return static_class_object; } - static void register_class(py::Class*); - static void unregister_class(py::Class*); + + // Register/unregister the Python class object corresponding to T + static void register_class(ExtensionClassBase*); + static void unregister_class(ExtensionClassBase*); + + // Establish C++ inheritance relationships + static void register_base_class(py::detail::BaseClassInfo const&); + static void register_derived_class(py::detail::DerivedClassInfo const&); + + // Query the C++ inheritance relationships + static std::vector const& base_classes(); + static std::vector const& derived_classes(); private: - static py::Class* static_class_object; + static ExtensionClassBase* static_class_object; + static std::vector static_base_class_info; + static std::vector static_derived_class_info; }; #ifdef PY_NO_INLINE_FRIENDS_IN_NAMESPACE // back to global namespace for this GCC bug @@ -123,8 +165,6 @@ class PyExtensionClassConverters { return py::Type(); } #endif - PyExtensionClassConverters() {} - // Convert to T* friend T* from_python(PyObject* obj, py::Type) { @@ -137,6 +177,11 @@ class PyExtensionClassConverters py::InstanceHolder* held = dynamic_cast*>(*p); if (held != 0) return held->target(); + + // see extclass.cpp for an explanation of try_class_conversions() + void * target = py::ClassRegistry::class_object()->try_class_conversions(*p); + if(target) + return static_cast(target); } py::report_missing_instance_data(self, py::ClassRegistry::class_object(), typeid(T)); throw py::ArgumentError(); @@ -185,7 +230,6 @@ class PyExtensionClassConverters return py::PyPtr(new py::ExtensionInstance(class_)); } - // Convert to const T* friend const T* from_python(PyObject* p, py::Type) { return from_python(p, py::Type()); } @@ -264,6 +308,27 @@ class ReadOnlySetattrFunction : public Function String m_name; }; +namespace detail +{ + + template + struct DefineConversion + { + static void * upcast_ptr(void * v) + { + return static_cast(static_cast(v)); + } + + static void * downcast_ptr(void * v) + { + return dynamic_cast(static_cast(v)); + } + }; + +} + +enum WithoutDowncast { without_downcast }; + // An easy way to make an extension base class which wraps T. Note that Python // subclasses of this class will simply be Class objects. // @@ -358,10 +423,49 @@ class ExtensionClass this->def_getter(pm, name); this->def_setter(pm, name); } + + // declare the given class a base class of this one and register + // up and down conversion functions + template + void declare_base(ExtensionClass * base) + { + // see extclass.cpp for an explanation of why we need to register + // conversion functions + detail::BaseClassInfo baseInfo(base, + &detail::DefineConversion::downcast_ptr); + ClassRegistry::register_base_class(baseInfo); + add_base(Ptr(as_object(base), Ptr::new_ref)); + + detail::DerivedClassInfo derivedInfo(this, + &detail::DefineConversion::upcast_ptr); + ClassRegistry::register_derived_class(derivedInfo); + } + + // declare the given class a base class of this one and register + // only up conversion function + template + void declare_base(ExtensionClass * base, WithoutDowncast) + { + // see extclass.cpp for an explanation of why we need to register + // conversion functions + detail::BaseClassInfo baseInfo(base, 0); + ClassRegistry::register_base_class(baseInfo); + add_base(Ptr(as_object(base), Ptr::new_ref)); + + detail::DerivedClassInfo derivedInfo(this, + &detail::DefineConversion::upcast_ptr); + ClassRegistry::register_derived_class(derivedInfo); + } - private: + private: // types typedef InstanceValueHolder Holder; - + + private: // ExtensionClassBase virtual function implementations + std::vector const& base_classes() const; + std::vector const& derived_classes() const; + void* extract_object_from_holder(InstanceHolderBase* v) const; + + private: // Utility functions template void add_constructor(Signature sig) { @@ -455,6 +559,31 @@ ExtensionClass::ExtensionClass(const char* name) ClassRegistry::register_class(this); } +template +inline +std::vector const & +ExtensionClass::base_classes() const +{ + return ClassRegistry::base_classes(); +} + +template +inline +std::vector const & +ExtensionClass::derived_classes() const +{ + return ClassRegistry::derived_classes(); +} + +template +void* ExtensionClass::extract_object_from_holder(InstanceHolderBase* v) const +{ + py::InstanceHolder* held = dynamic_cast*>(v); + if(held) + return held->target(); + return 0; +} + template ExtensionClass::~ExtensionClass() { @@ -462,7 +591,7 @@ ExtensionClass::~ExtensionClass() } template -inline void ClassRegistry::register_class(Class* p) +inline void ClassRegistry::register_class(ExtensionClassBase* p) { // You're not expected to create more than one of these! assert(static_class_object == 0); @@ -470,7 +599,7 @@ inline void ClassRegistry::register_class(Class* p) } template -inline void ClassRegistry::unregister_class(Class* p) +inline void ClassRegistry::unregister_class(ExtensionClassBase* p) { // The user should be destroying the same object they created. assert(static_class_object == p); @@ -478,11 +607,39 @@ inline void ClassRegistry::unregister_class(Class* p) static_class_object = 0; } +template +void ClassRegistry::register_base_class(py::detail::BaseClassInfo const & i) +{ + static_base_class_info.push_back(i); +} + +template +void ClassRegistry::register_derived_class(py::detail::DerivedClassInfo const & i) +{ + static_derived_class_info.push_back(i); +} + +template +std::vector const& ClassRegistry::base_classes() +{ + return static_base_class_info; +} + +template +std::vector const& ClassRegistry::derived_classes() +{ + return static_derived_class_info; +} + // // Static data member declaration. // template -Class* ClassRegistry::static_class_object; +ExtensionClassBase* ClassRegistry::static_class_object; +template +std::vector ClassRegistry::static_base_class_info; +template +std::vector ClassRegistry::static_derived_class_info; } // namespace py