from gen_function import * import string def gen_extclass(args): held_instance = """%{ template <%(class A%n%:, %)>%} HeldInstance(PyObject* p%(, const A%n%& a%n%)) : T(%(a%n%:, %)), m_self(p) {}""" instance_value_holder = """%{ template <%(class A%n%:, %)>%} InstanceValueHolder(ExtensionInstance* p%(, const A%n& a%n%)) : m_held(p%(, a%n%)) {}""" return ( """// (C) Copyright David Abrahams 2000. 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. // // The author gratefully acknowleges the support of Dragon Systems, Inc., in // producing this work. // // This file automatically generated for %d-argument constructors by // gen_extclass.py #ifndef EXTENSION_CLASS_DWA052000_H_ # define EXTENSION_CLASS_DWA052000_H_ # include "pyconfig.h" # include "subclass.h" # include # include "none.h" # include "objects.h" # include "functions.h" # include # include "init_function.h" # include # include namespace py { // forward declarations class ExtensionInstance; template class InstanceHolder; template class InstanceValueHolder; template class InstancePtrHolder; MetaClass* extension_meta_class(); ExtensionInstance* get_extension_instance(PyObject* p); void report_missing_instance_data(ExtensionInstance*, Class*, const std::type_info&); void report_missing_ptr_data(ExtensionInstance*, Class*, const std::type_info&); void report_missing_class_object(const std::type_info&); void report_released_smart_pointer(const std::type_info&); template struct ExtensionClassFromPython { }; template T* check_non_null(T* p) { if (p == 0) report_released_smart_pointer(typeid(T)); return p; } template class HeldInstance; class ExtensionClassBase : public Class { public: ExtensionClassBase(const char* name); protected: void add_method(PyPtr method, const char* name); void add_default_method(PyPtr method, const char* name); void add_method(Function* method, const char* name); void add_default_method(Function* method, const char* name); void add_constructor_object(Function*); void add_setter_method(Function*, const char* name); void add_getter_method(Function*, const char* name); }; template class ClassRegistry { public: static Class* class_object() { return static_class_object; } static void register_class(py::Class*); static void unregister_class(py::Class*); private: static py::Class* static_class_object; }; #ifdef PY_NO_INLINE_FRIENDS_IN_NAMESPACE // back to global namespace for this GCC bug } #endif // This class' only job is to define from_python and to_python converters for T // and U. T is the class the user really intends to wrap. U is a class derived // from T with some virtual function overriding boilerplate, or if there are no // virtual functions, U = HeldInstance. template > class PyExtensionClassConverters { public: #ifdef BOOST_MSVC // Convert return values of type T to python objects. What happens if T is // not copyable? Apparently there is no problem with g++ or MSVC unless this // is actually used. With a conforming compiler we will have a problem. friend PyObject* to_python(const T& x) { py::PyPtr result(create_instance(false)); result->add_implementation( std::auto_ptr( new py::InstanceValueHolder(result.get(), x))); return result.release(); } #else friend py::Type py_holder_type(const T&) { return py::Type(); } #endif PyExtensionClassConverters() {} // Convert to T* friend T* from_python(PyObject* obj, py::Type) { // Downcast to an ExtensionInstance, then find the actual T py::ExtensionInstance* self = py::get_extension_instance(obj); typedef std::vector::const_iterator Iterator; for (Iterator p = self->wrapped_objects().begin(); p != self->wrapped_objects().end(); ++p) { py::InstanceHolder* held = dynamic_cast*>(*p); if (held != 0) return held->target(); } py::report_missing_instance_data(self, py::ClassRegistry::class_object(), typeid(T)); throw py::ArgumentError(); } // Convert to PtrType, where PtrType can be dereferenced to obtain a T. template static PtrType& ptr_from_python(PyObject* obj, py::Type) { // Downcast to an ExtensionInstance, then find the actual T py::ExtensionInstance* self = py::get_extension_instance(obj); typedef std::vector::const_iterator Iterator; for (Iterator p = self->wrapped_objects().begin(); p != self->wrapped_objects().end(); ++p) { py::InstancePtrHolder* held = dynamic_cast*>(*p); if (held != 0) return held->ptr(); } py::report_missing_ptr_data(self, py::ClassRegistry::class_object(), typeid(T)); throw py::ArgumentError(); } template static PyObject* ptr_to_python(PtrType x) { py::PyPtr result(create_instance(true)); result->add_implementation( std::auto_ptr( new py::InstancePtrHolder(x))); return result.release(); } static py::PyPtr create_instance(bool seek_base) { if (py::ClassRegistry::class_object() == 0) py::report_missing_class_object(typeid(T)); py::Class* class_ = seek_base && py::ClassRegistry::class_object()->bases().size() > 0 ? py::Downcast >( py::ClassRegistry::class_object()->bases()[0].get()).get() : py::ClassRegistry::class_object(); 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()); } // Convert to T& friend T& from_python(PyObject* p, py::Type) { return *py::check_non_null(from_python(p, py::Type())); } // Convert to const T& friend const T& from_python(PyObject* p, py::Type) { return from_python(p, py::Type()); } // Convert to T friend const T& from_python(PyObject* p, py::Type) { return from_python(p, py::Type()); } friend std::auto_ptr& from_python(PyObject* p, py::Type&>) { return ptr_from_python(p, py::Type >()); } friend std::auto_ptr& from_python(PyObject* p, py::Type >) { return ptr_from_python(p, py::Type >()); } friend const std::auto_ptr& from_python(PyObject* p, py::Type&>) { return ptr_from_python(p, py::Type >()); } friend PyObject* to_python(std::auto_ptr x) { return ptr_to_python(x); } friend boost::shared_ptr& from_python(PyObject* p, py::Type&>) { return ptr_from_python(p, py::Type >()); } friend boost::shared_ptr& from_python(PyObject* p, py::Type >) { return ptr_from_python(p, py::Type >()); } friend const boost::shared_ptr& from_python(PyObject* p, py::Type&>) { return ptr_from_python(p, py::Type >()); } friend PyObject* to_python(boost::shared_ptr x) { return ptr_to_python(x); } }; #ifndef BOOST_MSVC template py::InstanceHolderBase* py_copy_to_new_value_holder(py::ExtensionInstance* p, const T& x, py::Type) { return new py::InstanceValueHolder(p, x); } template PyObject* to_python(const T& x) { py::PyPtr result( PyExtensionClassConverters::create_instance(false)); result->add_implementation( std::auto_ptr( py_copy_to_new_value_holder(result.get(), x, py_holder_type(x)))); return result.release(); } #endif #ifdef PY_NO_INLINE_FRIENDS_IN_NAMESPACE // back from global namespace for this GCC bug namespace py { using ::PyExtensionClassConverters; #endif template class InstanceHolder; class ReadOnlySetattrFunction : public Function { public: ReadOnlySetattrFunction(const char* name); PyObject* do_call(PyObject* args, PyObject* keywords) const; const char* description() const; private: String m_name; }; // An easy way to make an extension base class which wraps T. Note that Python // subclasses of this class will simply be Class objects. // // U should be a class derived from T which overrides virtual functions with // boilerplate code to call back into Python. See extclass_demo.h for examples. // // U is optional, but you won't be able to override any member functions in // Python which are called from C++ if you don't supply it. If you just want to // be able to use T in python without overriding member functions, you can omit // U. template > class ExtensionClass : public PyExtensionClassConverters, // This generates the to_python/from_python functions public ExtensionClassBase { public: typedef T WrappedType; typedef U CallbackType; // Construct with a name that comes from typeid(T).name(). The name only // affects the objects of this class are represented through repr() ExtensionClass(); // Construct with the given name. The name only affects the objects of this // class are represented through repr() ExtensionClass(const char* name); ~ExtensionClass(); // define constructors """ % args + gen_function( """ template <%(class A%n%:, %)> void def(Constructor<%(A%n%:, %)>) // The following incantation builds a Signature1, Signature2,... object. It // should _all_ get optimized away. { add_constructor( %(prepend(Type::Id(), %) Signature0()%()%)); } """, args) + """ // define member functions. In fact this works for free functions, too - // they act like static member functions, or if they start with the // appropriate self argument (as a pointer), they can be used just like // ordinary member functions -- just like Python! template void def(Fn fn, const char* name) { this->add_method(new_wrapped_function(fn), name); } // Define a virtual member function with a default implementation. // default_fn should be a function which provides the default implementation. // Be careful that default_fn does not in fact call fn virtually! template void def(Fn fn, const char* name, DefaultFn default_fn) { this->add_default_method(new_wrapped_function(default_fn), name); this->add_method(new_wrapped_function(fn), name); } // Provide a function which implements x., reading from the given // member (pm) of the T instance template void def_getter(MemberType T::*pm, const char* name) { this->add_getter_method(new GetterFunction(pm), name); } // Provide a function which implements assignment to x., writing to // the given member (pm) of the T instance template void def_setter(MemberType T::*pm, const char* name) { this->add_setter_method(new SetterFunction(pm), name); } // Expose the given member (pm) of the T instance as a read-only attribute template void def_readonly(MemberType T::*pm, const char* name) { this->add_setter_method(new ReadOnlySetattrFunction(name), name); this->def_getter(pm, name); } // Expose the given member (pm) of the T instance as a read/write attribute template void def_read_write(MemberType T::*pm, const char* name) { this->def_getter(pm, name); this->def_setter(pm, name); } private: typedef InstanceValueHolder Holder; template void add_constructor(Signature sig) { this->add_constructor_object(InitFunction::create(sig)); } }; // A simple wrapper over a T which allows us to use ExtensionClass with a // single template parameter only. See ExtensionClass, above. template class HeldInstance : public T { // There are no member functions: we want to avoid inadvertently overriding // any virtual functions in T. public:""" + gen_functions(held_instance, args) + """ protected: PyObject* m_self; // Not really needed; doesn't really hurt. }; class InstanceHolderBase { public: virtual ~InstanceHolderBase() {} }; template class InstanceHolder : public InstanceHolderBase { public: virtual Held *target() = 0; }; template class InstanceValueHolder : public InstanceHolder { public: Held* target() { return &m_held; } Wrapper* value_target() { return &m_held; } """ + gen_functions(instance_value_holder, args) + """ private: Wrapper m_held; }; """ + """ template class InstancePtrHolder : public InstanceHolder { public: HeldType* target() { return &*m_ptr; } PtrType& ptr() { return m_ptr; } InstancePtrHolder(PtrType ptr) : m_ptr(ptr) {} private: PtrType m_ptr; }; class ExtensionInstance : public Instance { public: ExtensionInstance(PyTypeObject* class_); ~ExtensionInstance(); void add_implementation(std::auto_ptr holder); typedef std::vector WrappedObjects; const WrappedObjects& wrapped_objects() const { return m_wrapped_objects; } private: WrappedObjects m_wrapped_objects; }; // // Template function implementations // template ExtensionClass::ExtensionClass() : ExtensionClassBase(typeid(T).name()) { ClassRegistry::register_class(this); } template ExtensionClass::ExtensionClass(const char* name) : ExtensionClassBase(name) { ClassRegistry::register_class(this); } template ExtensionClass::~ExtensionClass() { ClassRegistry::unregister_class(this); } template inline void ClassRegistry::register_class(Class* p) { // You're not expected to create more than one of these! assert(static_class_object == 0); static_class_object = p; } template inline void ClassRegistry::unregister_class(Class* p) { // The user should be destroying the same object they created. assert(static_class_object == p); (void)p; // unused in shipping version static_class_object = 0; } // // Static data member declaration. // template Class* ClassRegistry::static_class_object; } // namespace py #endif // EXTENSION_CLASS_DWA052000_H_ """) if __name__ == '__main__': import sys if len(sys.argv) == 1: args = 5 else: args = int(sys.argv[1]) print gen_extclass(args)