// Copyright (c) 2003 Raoul M. Gough // // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy // at http://www.boost.org/LICENSE_1_0.txt) // // Header file visitor.hpp: // // def_visitor implementation to install the container_suite's Python // methods in an object of a boost::python::class_<> instance. // // History // ======= // 2003/ 9/11 rmg File creation from container_suite.hpp // 2008/12/08 Roman Change indexing suite layout // // $Id: visitor.hpp,v 1.1.2.16 2004/02/08 18:57:42 raoulgough Exp $ // #ifndef BOOST_PYTHON_INDEXING_VISITOR_HPP #define BOOST_PYTHON_INDEXING_VISITOR_HPP #include <indexing_suite/slice_handler.hpp> #include <indexing_suite/suite_utils.hpp> // Get index_style_t #include <boost/python/def_visitor.hpp> #include <boost/python/iterator.hpp> #include <boost/python/default_call_policies.hpp> #include <boost/type_traits/ice.hpp> #include <boost/bind.hpp> #include <functional> namespace boost { namespace python { namespace indexing { ////////////////////////////////////////////////////////////////////////// // Policy override template that masks everything except the precall // functions. i.e. it uses default policies for everything except // precall, which must be provided by the template argument. ////////////////////////////////////////////////////////////////////////// namespace detail { template<typename PrecallPolicy> struct precall_only : public boost::python::default_call_policies { precall_only () : m_precall () { } explicit precall_only (PrecallPolicy const ©) : m_precall (copy) { } bool precall (PyObject *args) { return m_precall.precall (args); } bool precall (PyObject *args) const { return m_precall.precall (args); } private: PrecallPolicy m_precall; }; } ////////////////////////////////////////////////////////////////////////// // Ugly macro to define a template that optionally adds a method to // a Python class. This version (OPTIONAL_ALGO_SUPPORT) works with // static functions in an Algorithms class. // // This macro is #undef'd at the end of this header ////////////////////////////////////////////////////////////////////////// #define OPTIONAL_ALGO_SUPPORT(ADDER_NAME, METHOD_NAME, ALGO_FN) \ template<bool doit> \ struct ADDER_NAME { \ template<class PythonClass, class Algorithms, class Policy> \ static void apply (PythonClass &, Algorithms const &, Policy const &) \ { \ } \ }; \ \ template<> \ struct ADDER_NAME<true> { \ template<class PythonClass, class Algorithms, class Policy> \ static void apply( \ PythonClass &pyClass, \ Algorithms const &, \ Policy const &policy) \ { \ pyClass.def (METHOD_NAME, &Algorithms::ALGO_FN, policy); \ } \ } ////////////////////////////////////////////////////////////////////////// // Ugly macro to define a template that optionally adds a method to // a Python class. This version (OPTIONAL_SLICE_SUPPORT) works with // static functions in the slice_handler template. // // This macro is #undef'd at the end of this header ////////////////////////////////////////////////////////////////////////// #define OPTIONAL_SLICE_SUPPORT(ADDER_NAME, METHOD_NAME, SLICE_HANDLER_FN) \ template<bool doit> \ struct ADDER_NAME { \ template<class PythonClass, class Algorithms, class Policy> \ static void apply (PythonClass &, Algorithms const &, Policy const &) \ { \ } \ }; \ \ template<> \ struct ADDER_NAME<true> { \ template<class PythonClass, class Algorithms, class Policy> \ static void apply( \ PythonClass &pyClass, \ Algorithms const &, \ Policy const &policy) \ { \ pyClass.def ( \ METHOD_NAME, \ slice_handler<Algorithms, Policy>::SLICE_HANDLER_FN (policy)); \ } \ } ////////////////////////////////////////////////////////////////////////// // __iter__ is a special case not handled by the above macros. First // the unspecialized (do-nothing) version ////////////////////////////////////////////////////////////////////////// template<bool doit> struct maybe_add_iter { template<class PythonClass, class Algorithms, class Policy> static void apply (PythonClass &, Algorithms const &, Policy const &) { } }; ////////////////////////////////////////////////////////////////////////// // Specialization with the real implementation of __iter__ ////////////////////////////////////////////////////////////////////////// template<> struct maybe_add_iter<true> { template<class PythonClass, class Algorithms, class Policy> static void apply( PythonClass &pyClass, Algorithms const &, Policy const &) { // Should maybe separate precall and postcall portions of the // policy (precall when generating the range object, postcall // when returing from range.next())? pyClass.def( "__iter__", boost::python::range<Policy>( Algorithms::begin, Algorithms::end)); } }; ////////////////////////////////////////////////////////////////////////// // All other optional methods are covered by the two OPTIONAL_* // macros ////////////////////////////////////////////////////////////////////////// OPTIONAL_ALGO_SUPPORT (maybe_add_len, "__len__", size); OPTIONAL_ALGO_SUPPORT (maybe_add_getitem, "__getitem__", get); OPTIONAL_ALGO_SUPPORT (maybe_add_setitem, "__setitem__", assign); OPTIONAL_ALGO_SUPPORT (maybe_add_delitem, "__delitem__", erase_one); OPTIONAL_SLICE_SUPPORT (maybe_add_getslice, "__getitem__", make_getitem); OPTIONAL_SLICE_SUPPORT (maybe_add_setslice, "__setitem__", make_setitem); OPTIONAL_SLICE_SUPPORT (maybe_add_delslice, "__delitem__", make_delitem); OPTIONAL_ALGO_SUPPORT (maybe_add_sort, "sort", sort); OPTIONAL_ALGO_SUPPORT (maybe_add_reverse, "reverse", reverse); OPTIONAL_ALGO_SUPPORT (maybe_add_append, "append", push_back); OPTIONAL_ALGO_SUPPORT (maybe_add_insert, "insert", insert); OPTIONAL_SLICE_SUPPORT (maybe_add_extend, "extend", make_extend); OPTIONAL_ALGO_SUPPORT (maybe_add_index, "index", get_index); OPTIONAL_ALGO_SUPPORT (maybe_add_count, "count", count); OPTIONAL_ALGO_SUPPORT (maybe_add_contains, "__contains__", contains); OPTIONAL_ALGO_SUPPORT (maybe_add_has_key, "has_key", contains); ////////////////////////////////////////////////////////////////////////// // Do-all visitor ////////////////////////////////////////////////////////////////////////// template<class Algorithms, class Policy, method_set_type MethodMask> class visitor : public def_visitor< visitor< Algorithms, Policy, MethodMask > > { Policy m_policy; BOOST_STATIC_CONSTANT ( method_set_type, enabled_methods = Algorithms::supported_methods & MethodMask); public: typedef Algorithms algorithms_type; explicit visitor (Policy const &policy = Policy()) : m_policy (policy) { } public: template <class PythonClass> void visit (PythonClass &pyClass) const { detail::precall_only<Policy> precallPolicy (m_policy); maybe_add_len<detail::is_member<enabled_methods, method_len>::value> ::apply(pyClass, algorithms_type(), precallPolicy); maybe_add_getitem< detail::is_member<enabled_methods, method_getitem>::value >::apply(pyClass, algorithms_type(), m_policy); maybe_add_getslice< detail::is_member<enabled_methods, method_getitem_slice>::value >::apply(pyClass, algorithms_type(), m_policy); maybe_add_setitem< detail::is_member<enabled_methods, method_setitem>::value >::apply(pyClass, algorithms_type(), m_policy); maybe_add_setslice< detail::is_member<enabled_methods, method_setitem_slice>::value >::apply(pyClass, algorithms_type(), m_policy); maybe_add_delitem< detail::is_member<enabled_methods, method_delitem>::value >::apply(pyClass, algorithms_type(), m_policy); maybe_add_delslice< detail::is_member<enabled_methods, method_delitem_slice>::value >::apply(pyClass, algorithms_type(), m_policy); maybe_add_iter< detail::is_member<enabled_methods, method_iter>::value >::apply (pyClass, algorithms_type(), m_policy); maybe_add_sort< detail::is_member<enabled_methods, method_sort>::value >::apply (pyClass, algorithms_type(), precallPolicy); maybe_add_reverse< detail::is_member<enabled_methods, method_reverse>::value >::apply (pyClass, algorithms_type(), precallPolicy); maybe_add_append< detail::is_member<enabled_methods, method_append>::value >::apply (pyClass, algorithms_type(), precallPolicy); maybe_add_insert< detail::is_member<enabled_methods, method_insert>::value >::apply (pyClass, algorithms_type(), precallPolicy); maybe_add_extend< detail::is_member<enabled_methods, method_extend>::value >::apply (pyClass, algorithms_type(), precallPolicy); maybe_add_index< detail::is_member<enabled_methods, method_index>::value >::apply (pyClass, algorithms_type(), precallPolicy); maybe_add_count< detail::is_member<enabled_methods, method_count>::value >::apply (pyClass, algorithms_type(), precallPolicy); maybe_add_contains< detail::is_member<enabled_methods, method_contains>::value >::apply (pyClass, algorithms_type(), precallPolicy); maybe_add_has_key< detail::is_member<enabled_methods, method_has_key>::value >::apply (pyClass, algorithms_type(), precallPolicy); Algorithms::visit_container_class (pyClass, m_policy); } }; } } } #undef OPTIONAL_SLICE_SUPPORT #undef OPTIONAL_ALGO_SUPPORT #endif // BOOST_PYTHON_INDEXING_VISITOR_HPP