// (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 5-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; class ExtensionClassBase; 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 T* check_non_null(T* p) { if (p == 0) report_released_smart_pointer(typeid(T)); return 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; struct add_operator_base; } 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; void set_attribute(const char* name, PyObject* x); void set_attribute(const char* name, Ptr x); 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: friend struct detail::add_operator_base; void add_method(PyPtr method, const char* name); void add_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 ExtensionClassBase* class_object() { return static_class_object; } // 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 ExtensionClassBase* static_class_object; static std::vector static_base_class_info; static std::vector static_derived_class_info; }; } PY_BEGIN_CONVERSION_NAMESPACE // 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: // Get an object which can be used to convert T to/from python. This is used // as a kind of concept check by the global template // // PyObject* to_python(const T& x) // // below this class, to prevent the confusing messages that would otherwise // pop up. Now, if T hasn't been wrapped as an extension class, the user // will see an error message about the lack of an eligible // py_extension_class_converters() function. friend PyExtensionClassConverters py_extension_class_converters(py::Type) { return PyExtensionClassConverters(); } // This is a member function because in a conforming implementation, friend // funcitons defined inline in the class body are all instantiated as soon // as the enclosing class is instantiated. If T is not copyable, that causes // a compiler error. Instead, we access this function through the global // template // // PyObject* to_python(const T& x) // // defined below this class. Since template functions are instantiated only // on demand, errors will be avoided unless T is noncopyable and the user // writes code which causes us to try to copy a T. PyObject* to_python(const T& x) const { py::PyPtr result(create_instance()); result->add_implementation( std::auto_ptr( new py::InstanceValueHolder(result.get(), x))); return result.release(); } // 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(); // 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(); } // 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()); result->add_implementation( std::auto_ptr( new py::InstancePtrHolder(x))); return result.release(); } static py::PyPtr create_instance() { PyTypeObject* class_object = py::ClassRegistry::class_object(); if (class_object == 0) py::report_missing_class_object(typeid(T)); return py::PyPtr( new py::ExtensionInstance(class_object)); } // Convert to const T* friend const T* from_python(PyObject* p, py::Type) { return from_python(p, py::Type()); } // Convert to const T* const& friend const T* from_python(PyObject* p, py::Type) { return from_python(p, py::Type()); } // Convert to T* const& friend 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); } }; // Convert T to_python, instantiated on demand and only if there isn't a // non-template overload for this function. This version is the one invoked when // T is a wrapped class. See the first 2 functions declared in // PyExtensionClassConverters above for more info. template PyObject* to_python(const T& x) { return py_extension_class_converters(py::Type()).to_python(x); } PY_END_CONVERSION_NAMESPACE namespace py { PY_IMPORT_CONVERSION(PyExtensionClassConverters); 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; }; enum operator_id { op_add = 0x1, op_sub = 0x2, op_mul = 0x4, op_div = 0x8, op_mod = 0x10, op_divmod =0x20, op_pow = 0x40, op_lshift = 0x80, op_rshift = 0x100, op_and = 0x200, op_xor = 0x400, op_or = 0x800, op_neg = 0x1000, op_pos = 0x2000, op_abs = 0x4000, op_invert = 0x8000, op_int = 0x10000, op_long = 0x20000, op_float = 0x40000, op_str = 0x80000, op_cmp = 0x100000 }; namespace detail { struct auto_operand {}; template struct operand_select { template struct wrapped { typedef Specified type; }; }; template <> struct operand_select { template struct wrapped { typedef const WrappedType& type; }; }; template struct define_operator; template struct choose_op; template struct choose_rop; template struct choose_unary_op; } template struct operators {}; template struct left_operand {}; template struct right_operand {}; 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. // // 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 template inline void def(Constructor) // The following incantation builds a Signature1, Signature2,... object. It // should _all_ get optimized away. { add_constructor( prepend(Type::Id(), prepend(Type::Id(), prepend(Type::Id(), prepend(Type::Id(), prepend(Type::Id(), Signature0())))))); } // export homogeneous operators (type of both lhs and rhs is 'operator') // usage: foo_class.def(py::operators<(py::op_add | py::op_sub), Foo>()); // export homogeneous operators (type of both lhs and rhs is 'T const&') // usage: foo_class.def(py::operators<(py::op_add | py::op_sub)>()); template inline void def(operators) { typedef typename detail::operand_select::template wrapped::type true_operand; def_operators(operators()); } // export heterogeneous operators (type of lhs: 'left', of rhs: 'right') // usage: foo_class.def(py::operators<(py::op_add | py::op_sub), Foo>(), // py::right_operand()); // export heterogeneous operators (type of lhs: 'T const&', of rhs: 'right') // usage: foo_class.def(py::operators<(py::op_add | py::op_sub)>(), // py::right_operand()); template inline void def(operators, right_operand r) { typedef typename detail::operand_select::template wrapped::type true_left; def_operators(operators(), r); } // export heterogeneous reverse-argument operators // (type of lhs: 'left', of rhs: 'right') // usage: foo_class.def(py::operators<(py::op_add | py::op_sub), Foo>(), // py::left_operand()); // export heterogeneous reverse-argument operators // (type of lhs: 'left', of rhs: 'T const&') // usage: foo_class.def(py::operators<(py::op_add | py::op_sub)>(), // py::left_operand()); template inline void def(operators, left_operand l) { typedef typename detail::operand_select::template wrapped::type true_right; def_operators(operators(), l); } // define a function that passes Python arguments and keywords // to C++ verbatim (as a 'Tuple const&' and 'Dict const&' // respectively). This is useful for manual argument passing. // It's also the only possibility to pass keyword arguments to C++. // Fn must have a signatur that is compatible to // PyObject* (*)(PyObject* aTuple, PyObject* aDictionary) template inline void def_raw(Fn fn, const char* name) { this->add_method(py::detail::new_raw_arguments_function(fn), name); } // 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 inline 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 inline void def(Fn fn, const char* name, DefaultFn default_fn) { this->add_method(py::detail::new_virtual_function(Type(), fn, default_fn), name); } // Provide a function which implements x., reading from the given // member (pm) of the T instance template inline 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 inline 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 inline 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 inline void def_read_write(MemberType T::*pm, const char* name) { 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: // 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 inline void def_operators(operators) { register_coerce(); detail::choose_op<(which & op_add)>::template args::add(this); detail::choose_op<(which & op_sub)>::template args::add(this); detail::choose_op<(which & op_mul)>::template args::add(this); detail::choose_op<(which & op_div)>::template args::add(this); detail::choose_op<(which & op_mod)>::template args::add(this); detail::choose_op<(which & op_divmod)>::template args::add(this); detail::choose_op<(which & op_pow)>::template args::add(this); detail::choose_op<(which & op_lshift)>::template args::add(this); detail::choose_op<(which & op_rshift)>::template args::add(this); detail::choose_op<(which & op_and)>::template args::add(this); detail::choose_op<(which & op_xor)>::template args::add(this); detail::choose_op<(which & op_or)>::template args::add(this); detail::choose_unary_op<(which & op_neg)>::template args::add(this); detail::choose_unary_op<(which & op_pos)>::template args::add(this); detail::choose_unary_op<(which & op_abs)>::template args::add(this); detail::choose_unary_op<(which & op_invert)>::template args::add(this); detail::choose_unary_op<(which & op_int)>::template args::add(this); detail::choose_unary_op<(which & op_long)>::template args::add(this); detail::choose_unary_op<(which & op_float)>::template args::add(this); detail::choose_op<(which & op_cmp)>::template args::add(this); detail::choose_unary_op<(which & op_str)>::template args::add(this); } template inline void def_operators(operators, right_operand) { register_coerce(); detail::choose_op<(which & op_add)>::template args::add(this); detail::choose_op<(which & op_sub)>::template args::add(this); detail::choose_op<(which & op_mul)>::template args::add(this); detail::choose_op<(which & op_div)>::template args::add(this); detail::choose_op<(which & op_mod)>::template args::add(this); detail::choose_op<(which & op_divmod)>::template args::add(this); detail::choose_op<(which & op_pow)>::template args::add(this); detail::choose_op<(which & op_lshift)>::template args::add(this); detail::choose_op<(which & op_rshift)>::template args::add(this); detail::choose_op<(which & op_and)>::template args::add(this); detail::choose_op<(which & op_xor)>::template args::add(this); detail::choose_op<(which & op_or)>::template args::add(this); detail::choose_op<(which & op_cmp)>::template args::add(this); } template inline void def_operators(operators, left_operand) { register_coerce(); detail::choose_rop<(which & op_add)>::template args::add(this); detail::choose_rop<(which & op_sub)>::template args::add(this); detail::choose_rop<(which & op_mul)>::template args::add(this); detail::choose_rop<(which & op_div)>::template args::add(this); detail::choose_rop<(which & op_mod)>::template args::add(this); detail::choose_rop<(which & op_divmod)>::template args::add(this); detail::choose_rop<(which & op_pow)>::template args::add(this); detail::choose_rop<(which & op_lshift)>::template args::add(this); detail::choose_rop<(which & op_rshift)>::template args::add(this); detail::choose_rop<(which & op_and)>::template args::add(this); detail::choose_rop<(which & op_xor)>::template args::add(this); detail::choose_rop<(which & op_or)>::template args::add(this); detail::choose_rop<(which & op_cmp)>::template args::add(this); } template void add_constructor(Signature sig) { this->add_constructor_object(InitFunction::create(sig)); } void register_coerce(); }; // 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: HeldInstance(PyObject*) : T() {} template HeldInstance(PyObject*, A1 a1) : T(a1) {} template HeldInstance(PyObject*, A1 a1, A2 a2) : T(a1, a2) {} template HeldInstance(PyObject*, A1 a1, A2 a2, A3 a3) : T(a1, a2, a3) {} template HeldInstance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4) : T(a1, a2, a3, a4) {} template HeldInstance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) : T(a1, a2, a3, a4, a5) {} }; // Abstract base class for all instance holders. Base for template class // InstanceHolder<>, below. class InstanceHolderBase { public: virtual ~InstanceHolderBase() {} virtual bool held_by_value() = 0; }; // Abstract base class which holds a Held, somehow. Provides a uniform way to // get a pointer to the held object template class InstanceHolder : public InstanceHolderBase { public: virtual Held*target() = 0; }; // Concrete class which holds a Held by way of a wrapper class Wrapper. If Held // can be constructed with arguments (A1...An), Wrapper must have a // corresponding constructor for arguments (PyObject*, A1...An). Wrapper is // neccessary to implement virtual function callbacks (there must be a // back-pointer to the actual Python object so that we can call any // overrides). HeldInstance (above) is used as a default Wrapper class when // there are no virtual functions. template class InstanceValueHolder : public InstanceHolder { public: Held* target() { return &m_held; } Wrapper* value_target() { return &m_held; } InstanceValueHolder(ExtensionInstance* p) : m_held(p) {} template InstanceValueHolder(ExtensionInstance* p, A1 a1) : m_held(p, a1) {} template InstanceValueHolder(ExtensionInstance* p, A1 a1, A2 a2) : m_held(p, a1, a2) {} template InstanceValueHolder(ExtensionInstance* p, A1 a1, A2 a2, A3 a3) : m_held(p, a1, a2, a3) {} template InstanceValueHolder(ExtensionInstance* p, A1 a1, A2 a2, A3 a3, A4 a4) : m_held(p, a1, a2, a3, a4) {} template InstanceValueHolder(ExtensionInstance* p, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) : m_held(p, a1, a2, a3, a4, a5) {} public: // implementation of InstanceHolderBase required interface bool held_by_value() { return true; } private: Wrapper m_held; }; // Concrete class which holds a HeldType by way of a (possibly smart) pointer // PtrType. By default, these are only generated for PtrType == // std::auto_ptr and PtrType == boost::shared_ptr. template class InstancePtrHolder : public InstanceHolder { public: HeldType* target() { return &*m_ptr; } PtrType& ptr() { return m_ptr; } InstancePtrHolder(PtrType ptr) : m_ptr(ptr) {} public: // implementation of InstanceHolderBase required interface bool held_by_value() { return false; } 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 // namespace detail { Tuple extension_class_coerce(Ptr l, Ptr r); } template ExtensionClass::ExtensionClass() : ExtensionClassBase(typeid(T).name()) { ClassRegistry::register_class(this); } template ExtensionClass::ExtensionClass(const char* name) : ExtensionClassBase(name) { ClassRegistry::register_class(this); } template void ExtensionClass::register_coerce() { Ptr coerce_fct = dict().get_item(String("__coerce__")); if(coerce_fct.get() == 0) // not yet defined this->def(&py::detail::extension_class_coerce, "__coerce__"); } 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() { ClassRegistry::unregister_class(this); } template inline void ClassRegistry::register_class(ExtensionClassBase* 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(ExtensionClassBase* 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; } 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 ExtensionClassBase* ClassRegistry::static_class_object; template std::vector ClassRegistry::static_base_class_info; template std::vector ClassRegistry::static_derived_class_info; } // namespace py #endif // EXTENSION_CLASS_DWA052000_H_