• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 
3 // Copyright (c) 2014, Oracle and/or its affiliates.
4 
5 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
6 
7 // Licensed under the Boost Software License version 1.0.
8 // http://www.boost.org/users/license.html
9 
10 #ifndef BOOST_GEOMETRY_ITERATORS_FLATTEN_ITERATOR_HPP
11 #define BOOST_GEOMETRY_ITERATORS_FLATTEN_ITERATOR_HPP
12 
13 #include <boost/mpl/assert.hpp>
14 #include <boost/type_traits/is_convertible.hpp>
15 #include <boost/iterator/iterator_facade.hpp>
16 #include <boost/iterator/iterator_categories.hpp>
17 
18 #include <boost/geometry/core/assert.hpp>
19 
20 namespace boost { namespace geometry
21 {
22 
23 
24 
25 template
26 <
27     typename OuterIterator,
28     typename InnerIterator,
29     typename Value,
30     typename AccessInnerBegin,
31     typename AccessInnerEnd,
32     typename Reference = Value&
33 >
34 class flatten_iterator
35     : public boost::iterator_facade
36         <
37             flatten_iterator
38                 <
39                     OuterIterator,
40                     InnerIterator,
41                     Value,
42                     AccessInnerBegin,
43                     AccessInnerEnd,
44                     Reference
45                 >,
46             Value,
47             boost::bidirectional_traversal_tag,
48             Reference
49         >
50 {
51 private:
52     OuterIterator m_outer_it, m_outer_end;
53     InnerIterator m_inner_it;
54 
55 public:
56     typedef OuterIterator outer_iterator_type;
57     typedef InnerIterator inner_iterator_type;
58 
59     // default constructor
flatten_iterator()60     flatten_iterator() {}
61 
62     // for begin
flatten_iterator(OuterIterator outer_it,OuterIterator outer_end)63     flatten_iterator(OuterIterator outer_it, OuterIterator outer_end)
64         : m_outer_it(outer_it), m_outer_end(outer_end)
65     {
66         advance_through_empty();
67     }
68 
69     // for end
flatten_iterator(OuterIterator outer_end)70     flatten_iterator(OuterIterator outer_end)
71         : m_outer_it(outer_end), m_outer_end(outer_end)
72     {}
73 
74     template
75     <
76         typename OtherOuterIterator, typename OtherInnerIterator,
77         typename OtherValue,
78         typename OtherAccessInnerBegin, typename OtherAccessInnerEnd,
79         typename OtherReference
80     >
flatten_iterator(flatten_iterator<OtherOuterIterator,OtherInnerIterator,OtherValue,OtherAccessInnerBegin,OtherAccessInnerEnd,OtherReference> const & other)81     flatten_iterator(flatten_iterator
82                      <
83                          OtherOuterIterator,
84                          OtherInnerIterator,
85                          OtherValue,
86                          OtherAccessInnerBegin,
87                          OtherAccessInnerEnd,
88                          OtherReference
89                      > const& other)
90         : m_outer_it(other.m_outer_it),
91           m_outer_end(other.m_outer_end),
92           m_inner_it(other.m_inner_it)
93     {
94         static const bool are_conv
95             = boost::is_convertible
96                 <
97                     OtherOuterIterator, OuterIterator
98                 >::value
99            && boost::is_convertible
100                 <
101                     OtherInnerIterator, InnerIterator
102                 >::value;
103 
104         BOOST_MPL_ASSERT_MSG((are_conv),
105                              NOT_CONVERTIBLE,
106                              (types<OtherOuterIterator, OtherInnerIterator>));
107     }
108 
operator =(flatten_iterator const & other)109     flatten_iterator& operator=(flatten_iterator const& other)
110     {
111         m_outer_it = other.m_outer_it;
112         m_outer_end = other.m_outer_end;
113         // avoid assigning an iterator having singular value
114         if ( other.m_outer_it != other.m_outer_end )
115         {
116             m_inner_it = other.m_inner_it;
117         }
118         return *this;
119     }
120 
121 private:
122     friend class boost::iterator_core_access;
123 
124     template
125     <
126         typename Outer,
127         typename Inner,
128         typename V,
129         typename InnerBegin,
130         typename InnerEnd,
131         typename R
132     >
133     friend class flatten_iterator;
134 
empty(OuterIterator outer_it)135     static inline bool empty(OuterIterator outer_it)
136     {
137         return AccessInnerBegin::apply(*outer_it)
138             == AccessInnerEnd::apply(*outer_it);
139     }
140 
advance_through_empty()141     inline void advance_through_empty()
142     {
143         while ( m_outer_it != m_outer_end && empty(m_outer_it) )
144         {
145             ++m_outer_it;
146         }
147 
148         if ( m_outer_it != m_outer_end )
149         {
150             m_inner_it = AccessInnerBegin::apply(*m_outer_it);
151         }
152     }
153 
dereference() const154     inline Reference dereference() const
155     {
156         BOOST_GEOMETRY_ASSERT( m_outer_it != m_outer_end );
157         BOOST_GEOMETRY_ASSERT( m_inner_it != AccessInnerEnd::apply(*m_outer_it) );
158         return *m_inner_it;
159     }
160 
161 
162     template
163     <
164         typename OtherOuterIterator,
165         typename OtherInnerIterator,
166         typename OtherValue,
167         typename OtherAccessInnerBegin,
168         typename OtherAccessInnerEnd,
169         typename OtherReference
170     >
equal(flatten_iterator<OtherOuterIterator,OtherInnerIterator,OtherValue,OtherAccessInnerBegin,OtherAccessInnerEnd,OtherReference> const & other) const171     inline bool equal(flatten_iterator
172                       <
173                           OtherOuterIterator,
174                           OtherInnerIterator,
175                           OtherValue,
176                           OtherAccessInnerBegin,
177                           OtherAccessInnerEnd,
178                           OtherReference
179                       > const& other) const
180     {
181         if ( m_outer_it != other.m_outer_it )
182         {
183             return false;
184         }
185 
186         if ( m_outer_it == m_outer_end )
187         {
188             return true;
189         }
190 
191         return m_inner_it == other.m_inner_it;
192     }
193 
increment()194     inline void increment()
195     {
196         BOOST_GEOMETRY_ASSERT( m_outer_it != m_outer_end );
197         BOOST_GEOMETRY_ASSERT( m_inner_it != AccessInnerEnd::apply(*m_outer_it) );
198 
199         ++m_inner_it;
200         if ( m_inner_it == AccessInnerEnd::apply(*m_outer_it) )
201         {
202             ++m_outer_it;
203             advance_through_empty();
204         }
205     }
206 
decrement()207     inline void decrement()
208     {
209         if ( m_outer_it == m_outer_end
210              || m_inner_it == AccessInnerBegin::apply(*m_outer_it) )
211         {
212             do
213             {
214                 --m_outer_it;
215             }
216             while ( empty(m_outer_it) );
217             m_inner_it = AccessInnerEnd::apply(*m_outer_it);
218         }
219         --m_inner_it;
220     }
221 };
222 
223 
224 
225 }} // namespace boost::geometry
226 
227 
228 #endif // BOOST_GEOMETRY_ITERATORS_FLATTEN_ITERATOR_HPP
229