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