range_segment_iterator.hpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2014, Oracle and/or its affiliates.
  3. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
  4. // Licensed under the Boost Software License version 1.0.
  5. // http://www.boost.org/users/license.html
  6. #ifndef BOOST_GEOMETRY_ITERATORS_DETAIL_SEGMENT_ITERATOR_RANGE_SEGMENT_ITERATOR_HPP
  7. #define BOOST_GEOMETRY_ITERATORS_DETAIL_SEGMENT_ITERATOR_RANGE_SEGMENT_ITERATOR_HPP
  8. #include <boost/mpl/assert.hpp>
  9. #include <boost/type_traits/is_convertible.hpp>
  10. #include <boost/iterator/iterator_facade.hpp>
  11. #include <boost/iterator/iterator_categories.hpp>
  12. #include <boost/range.hpp>
  13. #include <boost/geometry/core/closure.hpp>
  14. #include <boost/geometry/iterators/closing_iterator.hpp>
  15. namespace boost { namespace geometry
  16. {
  17. #ifndef DOXYGEN_NO_DETAIL
  18. namespace detail { namespace segment_iterator
  19. {
  20. template <typename Range, closure_selector Closure = closure<Range>::value>
  21. struct range_iterator_type
  22. {
  23. typedef typename boost::range_iterator<Range>::type type;
  24. };
  25. template <typename Range>
  26. struct range_iterator_type<Range, open>
  27. {
  28. typedef closing_iterator<Range> type;
  29. };
  30. template <typename Range, closure_selector Closure = closure<Range>::value>
  31. struct range_iterator_begin
  32. {
  33. static inline typename range_iterator_type<Range, Closure>::type
  34. apply(Range& range)
  35. {
  36. return boost::begin(range);
  37. }
  38. };
  39. template <typename Range>
  40. struct range_iterator_begin<Range, open>
  41. {
  42. static inline typename range_iterator_type<Range, open>::type
  43. apply(Range& range)
  44. {
  45. return closing_iterator<Range>(range);
  46. }
  47. };
  48. template <typename Range, closure_selector Closure = closure<Range>::value>
  49. struct range_iterator_end
  50. {
  51. static inline typename range_iterator_type<Range, Closure>::type
  52. apply(Range& range)
  53. {
  54. return boost::end(range);
  55. }
  56. };
  57. template <typename Range>
  58. struct range_iterator_end<Range, open>
  59. {
  60. static inline typename range_iterator_type<Range, open>::type
  61. apply(Range& range)
  62. {
  63. return closing_iterator<Range>(range, true);
  64. }
  65. };
  66. template <typename Range, typename Value, typename Reference = Value>
  67. class range_segment_iterator
  68. : public boost::iterator_facade
  69. <
  70. range_segment_iterator<Range, Value, Reference>,
  71. Value,
  72. boost::bidirectional_traversal_tag,
  73. Reference
  74. >
  75. {
  76. static inline bool has_less_than_two_elements(Range const& r)
  77. {
  78. return boost::size(r) < ((closure<Range>::value == open) ? 1u : 2u);
  79. }
  80. public:
  81. typedef typename range_iterator_type<Range>::type iterator_type;
  82. // default constructor
  83. range_segment_iterator()
  84. : m_it(), m_has_less_than_two_elements(false)
  85. {}
  86. // for begin
  87. range_segment_iterator(Range& r)
  88. : m_it(range_iterator_begin<Range>::apply(r))
  89. , m_has_less_than_two_elements(has_less_than_two_elements(r))
  90. {}
  91. // for end
  92. range_segment_iterator(Range& r, bool)
  93. : m_it(range_iterator_end<Range>::apply(r))
  94. , m_has_less_than_two_elements(has_less_than_two_elements(r))
  95. {
  96. if (! m_has_less_than_two_elements)
  97. {
  98. // the range consists of at least two items
  99. --m_it;
  100. }
  101. }
  102. template
  103. <
  104. typename OtherRange,
  105. typename OtherValue,
  106. typename OtherReference
  107. >
  108. range_segment_iterator(range_segment_iterator
  109. <
  110. OtherRange,
  111. OtherValue,
  112. OtherReference
  113. > const& other)
  114. : m_it(other.m_it)
  115. {
  116. typedef typename range_segment_iterator
  117. <
  118. OtherRange, OtherValue, OtherReference
  119. >::iterator_type other_iterator_type;
  120. static const bool are_conv
  121. = boost::is_convertible<other_iterator_type, iterator_type>::value;
  122. BOOST_MPL_ASSERT_MSG((are_conv), NOT_CONVERTIBLE, (types<OtherRange>));
  123. }
  124. private:
  125. friend class boost::iterator_core_access;
  126. template <typename Rng, typename V, typename R>
  127. friend class range_segment_iterator;
  128. inline Reference dereference() const
  129. {
  130. if (m_has_less_than_two_elements)
  131. {
  132. return Reference(*m_it, *m_it);
  133. }
  134. iterator_type next(m_it);
  135. ++next;
  136. return Reference(*m_it, *next);
  137. }
  138. template
  139. <
  140. typename OtherRange,
  141. typename OtherValue,
  142. typename OtherReference
  143. >
  144. inline bool equal(range_segment_iterator
  145. <
  146. OtherRange,
  147. OtherValue,
  148. OtherReference
  149. > const& other) const
  150. {
  151. return m_it == other.m_it;
  152. }
  153. inline void increment()
  154. {
  155. ++m_it;
  156. }
  157. inline void decrement()
  158. {
  159. --m_it;
  160. }
  161. private:
  162. iterator_type m_it;
  163. bool m_has_less_than_two_elements;
  164. };
  165. }} // namespace detail::segment_iterator
  166. #endif // DOXYGEN_NO_DETAIL
  167. }} // namespace boost::geometry
  168. #endif // BOOST_GEOMETRY_ITERATORS_DETAIL_SEGMENT_ITERATOR_RANGE_SEGMENT_ITERATOR_HPP