// (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. #ifndef FUNCTIONS_DWA051400_H_ # define FUNCTIONS_DWA051400_H_ # include "pyconfig.h" # include "wrap_python.h" # include "pyptr.h" # include "signatures.h" # include "caller.h" # include # include "objects.h" # include "base_object.h" # include # include namespace py { // forward declaration class ExtensionInstance; // Function -- // the common base class for all overloadable function and method objects // supplied by the library. class Function : public PythonObject { public: Function(); // Function objects are reasonably rare, so we guess we can afford a virtual table. // This cuts down on the number of distinct type objects which need to be defined. virtual ~Function() {} PyObject* call(PyObject* args, PyObject* keywords) const; static void add_to_namespace(PyPtr f, const char* name, PyObject* dict); private: virtual PyObject* do_call(PyObject* args, PyObject* keywords) const = 0; virtual const char* description() const = 0; private: struct TypeObject; private: PyPtr m_overloads; }; // WrappedFunctionPointer<> -- // A single function or member function pointer wrapped and presented to // Python as a callable object. // // Template parameters: // R - the return type of the function pointer // F - the complete type of the wrapped function pointer template struct WrappedFunctionPointer : Function { typedef F PtrFun; // pointer-to--function or pointer-to-member-function WrappedFunctionPointer(PtrFun pf) : m_pf(pf) {} private: PyObject* do_call(PyObject* args, PyObject* keywords) const { return Caller::call(m_pf, args, keywords); } const char* description() const { return typeid(F).name(); } private: const PtrFun m_pf; }; // raw_arguments_function // A function that passes the Python argument tuple and keyword dictionary // verbatim to C++ (useful for customized argument parsing and variable // argument lists) template struct raw_arguments_function : Function { typedef Ret (*PtrFun)(Args, Keywords); raw_arguments_function(PtrFun pf) : m_pf(pf) {} private: PyObject* do_call(PyObject* args, PyObject* keywords) const { Ptr dict(keywords ? Ptr(keywords, Ptr::new_ref) : Ptr(PyDict_New())); return to_python( (*m_pf)(from_python(args, py::Type()), from_python(dict.get(), py::Type()))); } const char* description() const { return typeid(PtrFun).name(); } private: const PtrFun m_pf; }; // virtual_function<> -- // A virtual function with a default implementation wrapped and presented // to Python as a callable object. // // Template parameters: // T - the type of the target class // R - the return type of the function pointer // V - the virtual function pointer being wrapped // (should be of the form R(T::*)(), or R (*)(T, )) // D - a function which takes a T&, const T&, T*, or const T* first // parameter and calls T::f on it /non-virtually/, where V // approximates &T::f. template class virtual_function : public Function { public: virtual_function(V virtual_function_ptr, D default_implementation) : m_virtual_function_ptr(virtual_function_ptr), m_default_implementation(default_implementation) {} private: PyObject* do_call(PyObject* args, PyObject* keywords) const; const char* description() const { return typeid(V).name(); } private: const V m_virtual_function_ptr; const D m_default_implementation; }; // A helper function for new_member_function(), below. Implements the core // functionality once the return type has already been deduced. R is expected to // be Type, where X is the actual return type of pmf. template Function* new_wrapped_function_aux(R, F pmf) { // We can't just use "typename R::Type" below because MSVC (incorrectly) pukes. typedef typename R::Type ReturnType; return new WrappedFunctionPointer(pmf); } // Create and return a new member function object wrapping the given // pointer-to-member function template inline Function* new_wrapped_function(F pmf) { // Deduce the return type and pass it off to the helper function above return new_wrapped_function_aux(return_value(pmf), pmf); } namespace detail { template Function* new_raw_arguments_function(R (*pmf)(Args, Keywords)) { return new raw_arguments_function(pmf); } // A helper function for new_virtual_function(), below. Implements the core // functionality once the return type has already been deduced. R is expected to // be Type, where X is the actual return type of V. template inline Function* new_virtual_function_aux( Type, R, V virtual_function_ptr, D default_implementation ) { // We can't just use "typename R::Type" below because MSVC (incorrectly) pukes. typedef typename R::Type ReturnType; return new virtual_function( virtual_function_ptr, default_implementation); } // Create and return a new virtual_function object wrapping the given // virtual_function_ptr and default_implementation template inline Function* new_virtual_function( Type, V virtual_function_ptr, D default_implementation ) { // Deduce the return type and pass it off to the helper function above return new_virtual_function_aux( Type(), return_value(virtual_function_ptr), virtual_function_ptr, default_implementation); } } // namespace detail // A function with a bundled "bound target" object. This is what is produced by // the expression a.b where a is an Instance or ExtensionInstance object and b // is a callable object not found in the instance namespace but on its class or // a base class. class BoundFunction : public PythonObject { public: static BoundFunction* create(const Ptr& target, const Ptr& fn); BoundFunction(const Ptr& target, const Ptr& fn); PyObject* call(PyObject*args, PyObject* keywords) const; PyObject* getattr(const char* name) const; private: struct TypeObject; friend struct TypeObject; Ptr m_target; Ptr m_unbound_function; private: // data members for allocation/deallocation optimization BoundFunction* m_free_list_link; static BoundFunction* free_list; }; // Special functions designed to access data members of a wrapped C++ object. template class GetterFunction : public Function { public: typedef MemberType ClassType::* PointerToMember; GetterFunction(PointerToMember pm) : m_pm(pm) {} private: PyObject* do_call(PyObject* args, PyObject* keywords) const; const char* description() const { return typeid(MemberType (*)(const ClassType&)).name(); } private: PointerToMember m_pm; }; template class SetterFunction : public Function { public: typedef MemberType ClassType::* PointerToMember; SetterFunction(PointerToMember pm) : m_pm(pm) {} private: PyObject* do_call(PyObject* args, PyObject* keywords) const; const char* description() const { return typeid(void (*)(const ClassType&, const MemberType&)).name(); } private: PointerToMember m_pm; }; template PyObject* GetterFunction::do_call( PyObject* args, PyObject* /* keywords */) const { PyObject* self; if (!PyArg_ParseTuple(args, const_cast("O"), &self)) return 0; return to_python( from_python(self, Type())->*m_pm); } template PyObject* SetterFunction::do_call( PyObject* args, PyObject* /* keywords */) const { PyObject* self; PyObject* value; if (!PyArg_ParseTuple(args, const_cast("OO"), &self, &value)) return 0; typedef typename boost::call_traits::const_reference ExtractType; from_python(self, Type())->*m_pm = from_python(value, Type()); return none(); } template PyObject* virtual_function::do_call(PyObject* args, PyObject* keywords) const { // If the target object is held by pointer, we must call through the virtual // function pointer to the most-derived override. PyObject* target = PyTuple_GetItem(args, 0); if (target != 0) { ExtensionInstance* self = get_extension_instance(target); if (self->wrapped_objects().size() == 1 && !self->wrapped_objects()[0]->held_by_value()) { return Caller::call(m_virtual_function_ptr, args, keywords); } } return Caller::call(m_default_implementation, args, keywords); } } #endif // FUNCTIONS_DWA051400_H_