3 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
5 // This file was modified by Oracle on 2013-2021.
6 // Modifications copyright (c) 2013-2021 Oracle and/or its affiliates.
7 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
9 // Licensed under the Boost Software License version 1.0.
10 // http://www.boost.org/users/license.html
12 #ifndef BOOST_GEOMETRY_UTIL_RANGE_HPP
13 #define BOOST_GEOMETRY_UTIL_RANGE_HPP
17 #include <type_traits>
19 #include <boost/concept_check.hpp>
20 #include <boost/config.hpp>
21 #include <boost/core/addressof.hpp>
22 #include <boost/mpl/has_xxx.hpp>
23 #include <boost/range/concepts.hpp>
24 #include <boost/range/begin.hpp>
25 #include <boost/range/end.hpp>
26 #include <boost/range/empty.hpp>
27 #include <boost/range/difference_type.hpp>
28 #include <boost/range/has_range_iterator.hpp>
29 #include <boost/range/iterator.hpp>
30 #include <boost/range/reference.hpp>
31 #include <boost/range/size.hpp>
32 #include <boost/range/value_type.hpp>
34 #include <boost/geometry/core/assert.hpp>
35 #include <boost/geometry/core/mutable_range.hpp>
37 namespace boost { namespace geometry { namespace range
43 BOOST_MPL_HAS_XXX_TRAIT_DEF(iterator_category)
47 : std::integral_constant
52 std::iterator_traits<T>
58 template <typename T, bool HasIterator = boost::has_range_iterator<T>::value>
62 typename boost::range_iterator<T>::type
66 struct is_range_impl<T, false>
75 template <typename Range, typename T = void>
76 using enable_if_mutable_t = std::enable_if_t
78 (! std::is_const<std::remove_reference_t<Range>>::value),
87 \brief Short utility to conveniently return an iterator of a RandomAccessRange.
90 template <typename RandomAccessRange>
91 inline typename boost::range_iterator<RandomAccessRange>::type
92 pos(RandomAccessRange && rng,
93 typename boost::range_size<RandomAccessRange>::type i)
95 BOOST_RANGE_CONCEPT_ASSERT((boost::RandomAccessRangeConcept<RandomAccessRange>));
96 BOOST_GEOMETRY_ASSERT(i <= boost::size(rng));
97 return boost::begin(rng)
98 + static_cast<typename boost::range_difference<RandomAccessRange>::type>(i);
102 \brief Short utility to conveniently return an element of a RandomAccessRange.
105 template <typename RandomAccessRange>
106 inline typename boost::range_reference<RandomAccessRange>::type
107 at(RandomAccessRange && rng,
108 typename boost::range_size<RandomAccessRange>::type i)
114 \brief Short utility to conveniently return the front element of a Range.
117 template <typename Range>
118 inline typename boost::range_reference<Range>::type
121 BOOST_GEOMETRY_ASSERT(!boost::empty(rng));
122 return *boost::begin(rng);
126 \brief Short utility to conveniently return the back element of a BidirectionalRange.
129 template <typename BidirectionalRange>
130 inline typename boost::range_reference<BidirectionalRange>::type
131 back(BidirectionalRange && rng)
133 BOOST_RANGE_CONCEPT_ASSERT((boost::BidirectionalRangeConcept<BidirectionalRange>));
134 BOOST_GEOMETRY_ASSERT(!boost::empty(rng));
135 auto it = boost::end(rng);
141 \brief Short utility to conveniently clear a mutable range.
142 It uses traits::clear<>.
148 detail::enable_if_mutable_t<Range, int> = 0
150 inline void clear(Range && rng)
152 geometry::traits::clear
154 std::remove_reference_t<Range>
159 \brief Short utility to conveniently insert a new element at the end of a mutable range.
160 It uses boost::geometry::traits::push_back<>.
166 detail::enable_if_mutable_t<Range, int> = 0
168 inline void push_back(Range && rng,
169 typename boost::range_value<Range>::type const& value)
171 geometry::traits::push_back
173 std::remove_reference_t<Range>
174 >::apply(rng, value);
178 \brief Short utility to conveniently insert a new element at the end of a mutable range.
179 It uses boost::geometry::traits::push_back<>.
185 detail::enable_if_mutable_t<Range, int> = 0
187 inline void push_back(Range && rng,
188 typename boost::range_value<Range>::type && value)
190 geometry::traits::push_back
192 std::remove_reference_t<Range>
193 >::apply(rng, std::move(value));
197 \brief Short utility to conveniently insert a new element at the end of a mutable range.
198 It uses boost::geometry::traits::emplace_back<>.
205 detail::enable_if_mutable_t<Range, int> = 0
207 inline void emplace_back(Range && rng, Args &&... args)
209 geometry::traits::emplace_back
211 std::remove_reference_t<Range>
212 >::apply(rng, std::forward<Args>(args)...);
216 \brief Short utility to conveniently resize a mutable range.
217 It uses boost::geometry::traits::resize<>.
223 detail::enable_if_mutable_t<Range, int> = 0
225 inline void resize(Range && rng,
226 typename boost::range_size<Range>::type new_size)
228 geometry::traits::resize
230 std::remove_reference_t<Range>
231 >::apply(rng, new_size);
235 \brief Short utility to conveniently remove an element from the back of a mutable range.
242 detail::enable_if_mutable_t<Range, int> = 0
244 inline void pop_back(Range && rng)
246 BOOST_GEOMETRY_ASSERT(!boost::empty(rng));
247 range::resize(rng, boost::size(rng) - 1);
251 \brief Short utility to conveniently remove an element from a mutable range.
252 It uses std::move() and resize(). Version taking mutable iterators.
258 detail::enable_if_mutable_t<Range, int> = 0
260 inline typename boost::range_iterator<Range>::type
262 typename boost::range_iterator<Range>::type it)
264 BOOST_GEOMETRY_ASSERT(!boost::empty(rng));
265 BOOST_GEOMETRY_ASSERT(it != boost::end(rng));
267 typename boost::range_difference<Range>::type const
268 d = std::distance(boost::begin(rng), it);
270 typename boost::range_iterator<Range>::type
274 std::move(next, boost::end(rng), it);
275 range::resize(rng, boost::size(rng) - 1);
277 // NOTE: In general this should be sufficient:
279 // But in MSVC using the returned iterator causes
280 // assertion failures when iterator debugging is enabled
281 // Furthermore the code below should work in the case if resize()
282 // invalidates iterators when the container is resized down.
283 return boost::begin(rng) + d;
287 \brief Short utility to conveniently remove an element from a mutable range.
288 It uses std::move() and resize(). Version taking non-mutable iterators.
294 detail::enable_if_mutable_t<Range, int> = 0
296 inline typename boost::range_iterator<Range>::type
298 typename boost::range_iterator<std::remove_reference_t<Range> const>::type cit)
300 BOOST_RANGE_CONCEPT_ASSERT(( boost::RandomAccessRangeConcept<Range> ));
302 typename boost::range_iterator<Range>::type
303 it = boost::begin(rng)
304 + std::distance(boost::const_begin(rng), cit);
306 return range::erase(rng, it);
310 \brief Short utility to conveniently remove a range of elements from a mutable range.
311 It uses std::move() and resize(). Version taking mutable iterators.
317 detail::enable_if_mutable_t<Range, int> = 0
319 inline typename boost::range_iterator<Range>::type
321 typename boost::range_iterator<Range>::type first,
322 typename boost::range_iterator<Range>::type last)
324 typename boost::range_difference<Range>::type const
325 diff = std::distance(first, last);
326 BOOST_GEOMETRY_ASSERT(diff >= 0);
328 std::size_t const count = static_cast<std::size_t>(diff);
329 BOOST_GEOMETRY_ASSERT(count <= boost::size(rng));
333 typename boost::range_difference<Range>::type const
334 d = std::distance(boost::begin(rng), first);
336 std::move(last, boost::end(rng), first);
337 range::resize(rng, boost::size(rng) - count);
339 // NOTE: In general this should be sufficient:
341 // But in MSVC using the returned iterator causes
342 // assertion failures when iterator debugging is enabled
343 // Furthermore the code below should work in the case if resize()
344 // invalidates iterators when the container is resized down.
345 return boost::begin(rng) + d;
352 \brief Short utility to conveniently remove a range of elements from a mutable range.
353 It uses std::move() and resize(). Version taking non-mutable iterators.
359 detail::enable_if_mutable_t<Range, int> = 0
361 inline typename boost::range_iterator<Range>::type
363 typename boost::range_iterator<std::remove_reference_t<Range> const>::type cfirst,
364 typename boost::range_iterator<std::remove_reference_t<Range> const>::type clast)
366 BOOST_RANGE_CONCEPT_ASSERT(( boost::RandomAccessRangeConcept<Range> ));
368 typename boost::range_iterator<Range>::type
369 first = boost::begin(rng)
370 + std::distance(boost::const_begin(rng), cfirst);
371 typename boost::range_iterator<Range>::type
372 last = boost::begin(rng)
373 + std::distance(boost::const_begin(rng), clast);
375 return range::erase(rng, first, last);
380 template <class Container>
381 class back_insert_iterator
384 typedef std::output_iterator_tag iterator_category;
385 typedef void value_type;
386 typedef void difference_type;
387 typedef void pointer;
388 typedef void reference;
390 typedef Container container_type;
392 explicit back_insert_iterator(Container & c)
393 : container(boost::addressof(c))
396 back_insert_iterator & operator=(typename Container::value_type const& value)
398 range::push_back(*container, value);
402 back_insert_iterator & operator=(typename Container::value_type && value)
404 range::push_back(*container, std::move(value));
408 back_insert_iterator & operator* ()
413 back_insert_iterator & operator++ ()
418 back_insert_iterator operator++(int)
424 Container * container;
427 template <typename Range>
428 inline back_insert_iterator<Range> back_inserter(Range & rng)
430 return back_insert_iterator<Range>(rng);
433 }}} // namespace boost::geometry::range
435 #endif // BOOST_GEOMETRY_UTIL_RANGE_HPP