Chris@16: // Copyright David Abrahams 2002. Chris@16: // Distributed under the Boost Software License, Version 1.0. (See Chris@16: // accompanying file LICENSE_1_0.txt or copy at Chris@16: // http://www.boost.org/LICENSE_1_0.txt) Chris@16: #ifndef ITERATOR_DWA2002510_HPP Chris@16: # define ITERATOR_DWA2002510_HPP Chris@16: Chris@16: # include Chris@16: Chris@16: # include Chris@16: # include Chris@16: # include Chris@16: # include Chris@16: # include Chris@16: Chris@16: # include Chris@16: # include Chris@16: # include Chris@16: Chris@16: # include Chris@16: # include Chris@16: Chris@16: # include Chris@16: Chris@16: # include Chris@16: Chris@16: # include Chris@16: # include Chris@16: # include Chris@16: Chris@16: # include Chris@16: Chris@16: namespace boost { namespace python { namespace objects { Chris@16: Chris@16: // CallPolicies for the next() method of iterators. We don't want Chris@16: // users to have to explicitly specify that the references returned by Chris@16: // iterators are copied, so we just replace the result_converter from Chris@16: // the default_iterator_call_policies with a permissive one which Chris@16: // always copies the result. Chris@16: typedef return_value_policy default_iterator_call_policies; Chris@16: Chris@16: // Instantiations of these are wrapped to produce Python iterators. Chris@16: template Chris@16: struct iterator_range Chris@16: { Chris@16: iterator_range(object sequence, Iterator start, Iterator finish); Chris@16: Chris@16: typedef boost::detail::iterator_traits traits_t; Chris@16: Chris@16: struct next Chris@16: { Chris@16: typedef typename mpl::if_< Chris@16: is_reference< Chris@16: typename traits_t::reference Chris@16: > Chris@16: , typename traits_t::reference Chris@16: , typename traits_t::value_type Chris@16: >::type result_type; Chris@16: Chris@16: result_type Chris@16: operator()(iterator_range& self) Chris@16: { Chris@16: if (self.m_start == self.m_finish) Chris@16: stop_iteration_error(); Chris@16: return *self.m_start++; Chris@16: } Chris@16: Chris@16: # if BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3003)) Chris@16: // CWPro8 has a codegen problem when this is an empty class Chris@16: int garbage; Chris@16: # endif Chris@16: }; Chris@16: Chris@16: # ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION Chris@16: // for compilers which can't deduce the value_type of pointers, we Chris@16: // have a special implementation of next. This takes advantage of Chris@16: // the fact that T* results are treated like T& results by Chris@16: // Boost.Python's function wrappers. Chris@16: struct next_ptr Chris@16: { Chris@16: typedef Iterator result_type; Chris@16: Chris@16: result_type Chris@16: operator()(iterator_range& self) Chris@16: { Chris@16: if (self.m_start == self.m_finish) Chris@16: stop_iteration_error(); Chris@16: return self.m_start++; Chris@16: } Chris@16: }; Chris@16: Chris@16: typedef mpl::if_< Chris@16: is_same< Chris@16: boost::detail::please_invoke_BOOST_TT_BROKEN_COMPILER_SPEC_on_cv_unqualified_pointee Chris@16: , typename traits_t::value_type Chris@16: > Chris@16: , next_ptr Chris@16: , next Chris@16: >::type next_fn; Chris@16: # else Chris@16: typedef next next_fn; Chris@16: # endif Chris@16: Chris@16: object m_sequence; // Keeps the sequence alive while iterating. Chris@16: Iterator m_start; Chris@16: Iterator m_finish; Chris@16: }; Chris@16: Chris@16: namespace detail Chris@16: { Chris@16: // Get a Python class which contains the given iterator and Chris@16: // policies, creating it if necessary. Requires: NextPolicies is Chris@16: // default-constructible. Chris@16: template Chris@16: object demand_iterator_class(char const* name, Iterator* = 0, NextPolicies const& policies = NextPolicies()) Chris@16: { Chris@16: typedef iterator_range range_; Chris@16: Chris@16: // Check the registry. If one is already registered, return it. Chris@16: handle<> class_obj( Chris@16: objects::registered_class_object(python::type_id())); Chris@16: Chris@16: if (class_obj.get() != 0) Chris@16: return object(class_obj); Chris@16: Chris@16: typedef typename range_::next_fn next_fn; Chris@16: typedef typename next_fn::result_type result_type; Chris@16: Chris@16: return class_(name, no_init) Chris@16: .def("__iter__", identity_function()) Chris@16: .def( Chris@16: #if PY_VERSION_HEX >= 0x03000000 Chris@16: "__next__" Chris@16: #else Chris@16: "next" Chris@16: #endif Chris@16: , make_function( Chris@16: next_fn() Chris@16: , policies Chris@16: , mpl::vector2() Chris@16: )); Chris@16: } Chris@16: Chris@16: // A function object which builds an iterator_range. Chris@16: template < Chris@16: class Target Chris@16: , class Iterator Chris@16: , class Accessor1 Chris@16: , class Accessor2 Chris@16: , class NextPolicies Chris@16: > Chris@16: struct py_iter_ Chris@16: { Chris@16: py_iter_(Accessor1 const& get_start, Accessor2 const& get_finish) Chris@16: : m_get_start(get_start) Chris@16: , m_get_finish(get_finish) Chris@16: {} Chris@16: Chris@16: // Extract an object x of the Target type from the first Python Chris@16: // argument, and invoke get_start(x)/get_finish(x) to produce Chris@16: // iterators, which are used to construct a new iterator_range<> Chris@16: // object that gets wrapped into a Python iterator. Chris@16: iterator_range Chris@16: operator()(back_reference x) const Chris@16: { Chris@16: // Make sure the Python class is instantiated. Chris@16: detail::demand_iterator_class("iterator", (Iterator*)0, NextPolicies()); Chris@16: Chris@16: return iterator_range( Chris@16: x.source() Chris@16: , m_get_start(x.get()) Chris@16: , m_get_finish(x.get()) Chris@16: ); Chris@16: } Chris@16: private: Chris@16: Accessor1 m_get_start; Chris@16: Accessor2 m_get_finish; Chris@16: }; Chris@16: Chris@16: template Chris@16: inline object make_iterator_function( Chris@16: Accessor1 const& get_start Chris@16: , Accessor2 const& get_finish Chris@16: , NextPolicies const& /*next_policies*/ Chris@16: , Iterator const& (*)() Chris@16: , boost::type* Chris@16: , int Chris@16: ) Chris@16: { Chris@16: return make_function( Chris@16: py_iter_(get_start, get_finish) Chris@16: , default_call_policies() Chris@16: , mpl::vector2, back_reference >() Chris@16: ); Chris@16: } Chris@16: Chris@16: template Chris@16: inline object make_iterator_function( Chris@16: Accessor1 const& get_start Chris@16: , Accessor2 const& get_finish Chris@16: , NextPolicies const& next_policies Chris@16: , Iterator& (*)() Chris@16: , boost::type* Chris@16: , ...) Chris@16: { Chris@16: return make_iterator_function( Chris@16: get_start Chris@16: , get_finish Chris@16: , next_policies Chris@16: , (Iterator const&(*)())0 Chris@16: , (boost::type*)0 Chris@16: , 0 Chris@16: ); Chris@16: } Chris@16: Chris@16: } Chris@16: Chris@16: // Create a Python callable object which accepts a single argument Chris@16: // convertible to the C++ Target type and returns a Python Chris@16: // iterator. The Python iterator uses get_start(x) and get_finish(x) Chris@16: // (where x is an instance of Target) to produce begin and end Chris@16: // iterators for the range, and an instance of NextPolicies is used as Chris@16: // CallPolicies for the Python iterator's next() function. Chris@16: template Chris@16: inline object make_iterator_function( Chris@16: Accessor1 const& get_start Chris@16: , Accessor2 const& get_finish Chris@16: , NextPolicies const& next_policies Chris@16: , boost::type* = 0 Chris@16: ) Chris@16: { Chris@16: typedef typename Accessor1::result_type iterator; Chris@16: typedef typename add_const::type iterator_const; Chris@16: typedef typename add_reference::type iterator_cref; Chris@16: Chris@16: return detail::make_iterator_function( Chris@16: get_start Chris@16: , get_finish Chris@16: , next_policies Chris@16: , (iterator_cref(*)())0 Chris@16: , (boost::type*)0 Chris@16: , 0 Chris@16: ); Chris@16: } Chris@16: Chris@16: // Chris@16: // implementation Chris@16: // Chris@16: template Chris@16: inline iterator_range::iterator_range( Chris@16: object sequence, Iterator start, Iterator finish) Chris@16: : m_sequence(sequence), m_start(start), m_finish(finish) Chris@16: { Chris@16: } Chris@16: Chris@16: }}} // namespace boost::python::objects Chris@16: Chris@16: #endif // ITERATOR_DWA2002510_HPP