flatten_iterator.hpp 5.7 KB

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