source: NonGTP/Boost/boost/python/object/iterator.hpp @ 857

Revision 857, 8.0 KB checked in by igarcia, 19 years ago (diff)
RevLine 
[857]1// Copyright David Abrahams 2002.
2// Distributed under the Boost Software License, Version 1.0. (See
3// accompanying file LICENSE_1_0.txt or copy at
4// http://www.boost.org/LICENSE_1_0.txt)
5#ifndef ITERATOR_DWA2002510_HPP
6# define ITERATOR_DWA2002510_HPP
7
8# include <boost/python/detail/prefix.hpp>
9
10# include <boost/python/class.hpp>
11# include <boost/python/return_value_policy.hpp>
12# include <boost/python/return_by_value.hpp>
13# include <boost/python/handle.hpp>
14# include <boost/python/make_function.hpp>
15
16# include <boost/python/object/iterator_core.hpp>
17# include <boost/python/object/class_detail.hpp>
18# include <boost/python/object/function_object.hpp>
19
20# include <boost/mpl/vector/vector10.hpp>
21# include <boost/mpl/if.hpp>
22
23# include <boost/python/detail/raw_pyobject.hpp>
24
25# include <boost/type.hpp>
26
27# include <boost/type_traits/is_same.hpp>
28# include <boost/type_traits/add_reference.hpp>
29# include <boost/type_traits/add_const.hpp>
30
31# include <boost/detail/iterator.hpp>
32
33namespace boost { namespace python { namespace objects {
34
35// CallPolicies for the next() method of iterators. We don't want
36// users to have to explicitly specify that the references returned by
37// iterators are copied, so we just replace the result_converter from
38// the default_iterator_call_policies with a permissive one which
39// always copies the result.
40typedef return_value_policy<return_by_value> default_iterator_call_policies;
41
42// Instantiations of these are wrapped to produce Python iterators.
43template <class NextPolicies, class Iterator>
44struct iterator_range
45{
46    iterator_range(object sequence, Iterator start, Iterator finish);
47
48    typedef boost::detail::iterator_traits<Iterator> traits_t;
49
50    struct next
51    {
52        typedef typename mpl::if_<
53            is_reference<
54                typename traits_t::reference
55            >
56          , typename traits_t::reference
57          , typename traits_t::value_type
58        >::type result_type;
59       
60        result_type
61        operator()(iterator_range<NextPolicies,Iterator>& self)
62        {
63            if (self.m_start == self.m_finish)
64                stop_iteration_error();
65            return *self.m_start++;
66        }
67
68# if BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3003))
69        // CWPro8 has a codegen problem when this is an empty class
70        int garbage;
71# endif
72    };
73   
74# ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
75    // for compilers which can't deduce the value_type of pointers, we
76    // have a special implementation of next.  This takes advantage of
77    // the fact that T* results are treated like T& results by
78    // Boost.Python's function wrappers.
79    struct next_ptr
80    {
81        typedef Iterator result_type;
82       
83        result_type
84        operator()(iterator_range<NextPolicies,Iterator>& self)
85        {
86            if (self.m_start == self.m_finish)
87                stop_iteration_error();
88            return self.m_start++;
89        }
90    };
91   
92    typedef mpl::if_<
93        is_same<
94            boost::detail::please_invoke_BOOST_TT_BROKEN_COMPILER_SPEC_on_cv_unqualified_pointee<Iterator>
95          , typename traits_t::value_type
96        >
97      , next_ptr
98      , next
99    >::type next_fn;
100# else
101    typedef next next_fn;
102# endif
103   
104    object m_sequence; // Keeps the sequence alive while iterating.
105    Iterator m_start;
106    Iterator m_finish;
107};
108
109namespace detail
110{
111  // Get a Python class which contains the given iterator and
112  // policies, creating it if necessary. Requires: NextPolicies is
113  // default-constructible.
114  template <class Iterator, class NextPolicies>
115  object demand_iterator_class(char const* name, Iterator* = 0, NextPolicies const& policies = NextPolicies())
116  {
117      typedef iterator_range<NextPolicies,Iterator> range_;
118
119      // Check the registry. If one is already registered, return it.
120      handle<> class_obj(
121          objects::registered_class_object(python::type_id<range_>()));
122       
123      if (class_obj.get() != 0)
124          return object(class_obj);
125
126      typedef typename range_::next_fn next_fn;
127      typedef typename next_fn::result_type result_type;
128     
129      return class_<range_>(name, no_init)
130          .def("__iter__", identity_function())
131          .def(
132              "next"
133            , make_function(
134                next_fn()
135              , policies
136              , mpl::vector2<result_type,range_&>()
137            ));
138  }
139
140  // A function object which builds an iterator_range.
141  template <
142      class Target
143    , class Iterator
144    , class Accessor1
145    , class Accessor2
146    , class NextPolicies
147  >
148  struct py_iter_
149  {
150      py_iter_(Accessor1 const& get_start, Accessor2 const& get_finish)
151        : m_get_start(get_start)
152        , m_get_finish(get_finish)
153      {}
154     
155      // Extract an object x of the Target type from the first Python
156      // argument, and invoke get_start(x)/get_finish(x) to produce
157      // iterators, which are used to construct a new iterator_range<>
158      // object that gets wrapped into a Python iterator.
159      iterator_range<NextPolicies,Iterator>
160      operator()(back_reference<Target&> x) const
161      {
162          // Make sure the Python class is instantiated.
163          detail::demand_iterator_class("iterator", (Iterator*)0, NextPolicies());
164         
165          return iterator_range<NextPolicies,Iterator>(
166              x.source()
167            , m_get_start(x.get())
168            , m_get_finish(x.get())
169          );
170      }
171   private:
172      Accessor1 m_get_start;
173      Accessor2 m_get_finish;
174  };
175
176  template <class Target, class Iterator, class NextPolicies, class Accessor1, class Accessor2>
177  inline object make_iterator_function(
178      Accessor1 const& get_start
179    , Accessor2 const& get_finish
180    , NextPolicies const& next_policies
181    , Iterator const& (*)()
182    , boost::type<Target>*
183    , int
184  )
185  {
186      return make_function(
187          py_iter_<Target,Iterator,Accessor1,Accessor2,NextPolicies>(get_start, get_finish)
188        , default_call_policies()
189        , mpl::vector2<iterator_range<NextPolicies,Iterator>, back_reference<Target&> >()
190      );
191  }
192
193  template <class Target, class Iterator, class NextPolicies, class Accessor1, class Accessor2>
194  inline object make_iterator_function(
195      Accessor1 const& get_start
196    , Accessor2 const& get_finish
197    , NextPolicies const& next_policies
198    , Iterator& (*)()
199    , boost::type<Target>*
200    , ...)
201  {
202      return make_iterator_function(
203          get_start
204        , get_finish
205        , next_policies
206        , (Iterator const&(*)())0
207        , (boost::type<Target>*)0
208        , 0
209      );
210  }
211
212}
213
214// Create a Python callable object which accepts a single argument
215// convertible to the C++ Target type and returns a Python
216// iterator. The Python iterator uses get_start(x) and get_finish(x)
217// (where x is an instance of Target) to produce begin and end
218// iterators for the range, and an instance of NextPolicies is used as
219// CallPolicies for the Python iterator's next() function.
220template <class Target, class NextPolicies, class Accessor1, class Accessor2>
221inline object make_iterator_function(
222    Accessor1 const& get_start
223  , Accessor2 const& get_finish
224  , NextPolicies const& next_policies
225  , boost::type<Target>* = 0
226)
227{
228    typedef typename Accessor1::result_type iterator;
229    typedef typename add_const<iterator>::type iterator_const;
230    typedef typename add_reference<iterator_const>::type iterator_cref;
231     
232    return detail::make_iterator_function(
233        get_start
234      , get_finish
235      , next_policies
236      , (iterator_cref(*)())0
237      , (boost::type<Target>*)0
238      , 0
239    );
240}
241
242//
243// implementation
244//
245template <class NextPolicies, class Iterator>
246inline iterator_range<NextPolicies,Iterator>::iterator_range(
247    object sequence, Iterator start, Iterator finish)
248    : m_sequence(sequence), m_start(start), m_finish(finish)
249{
250}
251
252}}} // namespace boost::python::objects
253
254#endif // ITERATOR_DWA2002510_HPP
Note: See TracBrowser for help on using the repository browser.