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_DETAIL_SEGMENT_ITERATOR_RANGE_SEGMENT_ITERATOR_HPP 11 #define BOOST_GEOMETRY_ITERATORS_DETAIL_SEGMENT_ITERATOR_RANGE_SEGMENT_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 #include <boost/range.hpp> 18 19 #include <boost/geometry/core/closure.hpp> 20 #include <boost/geometry/iterators/closing_iterator.hpp> 21 22 23 namespace boost { namespace geometry 24 { 25 26 #ifndef DOXYGEN_NO_DETAIL 27 namespace detail { namespace segment_iterator 28 { 29 30 31 template <typename Range, closure_selector Closure = closure<Range>::value> 32 struct range_iterator_type 33 { 34 typedef typename boost::range_iterator<Range>::type type; 35 }; 36 37 template <typename Range> 38 struct range_iterator_type<Range, open> 39 { 40 typedef closing_iterator<Range> type; 41 }; 42 43 44 45 template <typename Range, closure_selector Closure = closure<Range>::value> 46 struct range_iterator_begin 47 { 48 static inline typename range_iterator_type<Range, Closure>::type applyboost::geometry::detail::segment_iterator::range_iterator_begin49 apply(Range& range) 50 { 51 return boost::begin(range); 52 } 53 }; 54 55 template <typename Range> 56 struct range_iterator_begin<Range, open> 57 { 58 static inline typename range_iterator_type<Range, open>::type applyboost::geometry::detail::segment_iterator::range_iterator_begin59 apply(Range& range) 60 { 61 return closing_iterator<Range>(range); 62 } 63 }; 64 65 66 67 template <typename Range, closure_selector Closure = closure<Range>::value> 68 struct range_iterator_end 69 { 70 static inline typename range_iterator_type<Range, Closure>::type applyboost::geometry::detail::segment_iterator::range_iterator_end71 apply(Range& range) 72 { 73 return boost::end(range); 74 } 75 }; 76 77 template <typename Range> 78 struct range_iterator_end<Range, open> 79 { 80 static inline typename range_iterator_type<Range, open>::type applyboost::geometry::detail::segment_iterator::range_iterator_end81 apply(Range& range) 82 { 83 return closing_iterator<Range>(range, true); 84 } 85 }; 86 87 88 89 90 91 92 template <typename Range, typename Value, typename Reference = Value> 93 class range_segment_iterator 94 : public boost::iterator_facade 95 < 96 range_segment_iterator<Range, Value, Reference>, 97 Value, 98 boost::bidirectional_traversal_tag, 99 Reference 100 > 101 { has_less_than_two_elements(Range const & r)102 static inline bool has_less_than_two_elements(Range const& r) 103 { 104 return boost::size(r) < ((closure<Range>::value == open) ? 1u : 2u); 105 } 106 107 public: 108 typedef typename range_iterator_type<Range>::type iterator_type; 109 110 // default constructor range_segment_iterator()111 range_segment_iterator() 112 : m_it(), m_has_less_than_two_elements(false) 113 {} 114 115 // for begin range_segment_iterator(Range & r)116 range_segment_iterator(Range& r) 117 : m_it(range_iterator_begin<Range>::apply(r)) 118 , m_has_less_than_two_elements(has_less_than_two_elements(r)) 119 {} 120 121 // for end range_segment_iterator(Range & r,bool)122 range_segment_iterator(Range& r, bool) 123 : m_it(range_iterator_end<Range>::apply(r)) 124 , m_has_less_than_two_elements(has_less_than_two_elements(r)) 125 { 126 if (! m_has_less_than_two_elements) 127 { 128 // the range consists of at least two items 129 --m_it; 130 } 131 } 132 133 template 134 < 135 typename OtherRange, 136 typename OtherValue, 137 typename OtherReference 138 > range_segment_iterator(range_segment_iterator<OtherRange,OtherValue,OtherReference> const & other)139 range_segment_iterator(range_segment_iterator 140 < 141 OtherRange, 142 OtherValue, 143 OtherReference 144 > const& other) 145 : m_it(other.m_it) 146 { 147 typedef typename range_segment_iterator 148 < 149 OtherRange, OtherValue, OtherReference 150 >::iterator_type other_iterator_type; 151 152 static const bool are_conv 153 = boost::is_convertible<other_iterator_type, iterator_type>::value; 154 155 BOOST_MPL_ASSERT_MSG((are_conv), NOT_CONVERTIBLE, (types<OtherRange>)); 156 } 157 158 private: 159 friend class boost::iterator_core_access; 160 161 template <typename Rng, typename V, typename R> 162 friend class range_segment_iterator; 163 dereference() const164 inline Reference dereference() const 165 { 166 if (m_has_less_than_two_elements) 167 { 168 return Reference(*m_it, *m_it); 169 } 170 171 iterator_type next(m_it); 172 ++next; 173 return Reference(*m_it, *next); 174 } 175 176 template 177 < 178 typename OtherRange, 179 typename OtherValue, 180 typename OtherReference 181 > equal(range_segment_iterator<OtherRange,OtherValue,OtherReference> const & other) const182 inline bool equal(range_segment_iterator 183 < 184 OtherRange, 185 OtherValue, 186 OtherReference 187 > const& other) const 188 { 189 return m_it == other.m_it; 190 } 191 increment()192 inline void increment() 193 { 194 ++m_it; 195 } 196 decrement()197 inline void decrement() 198 { 199 --m_it; 200 } 201 202 private: 203 iterator_type m_it; 204 bool m_has_less_than_two_elements; 205 }; 206 207 208 }} // namespace detail::segment_iterator 209 #endif // DOXYGEN_NO_DETAIL 210 211 }} // namespace boost::geometry 212 213 214 #endif // BOOST_GEOMETRY_ITERATORS_DETAIL_SEGMENT_ITERATOR_RANGE_SEGMENT_ITERATOR_HPP 215