range.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. // Boost.Geometry
  2. // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
  3. // This file was modified by Oracle on 2013-2021.
  4. // Modifications copyright (c) 2013-2021 Oracle and/or its affiliates.
  5. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  6. // Licensed under the Boost Software License version 1.0.
  7. // http://www.boost.org/users/license.html
  8. #ifndef BOOST_GEOMETRY_UTIL_RANGE_HPP
  9. #define BOOST_GEOMETRY_UTIL_RANGE_HPP
  10. #include <algorithm>
  11. #include <iterator>
  12. #include <type_traits>
  13. #include <boost/concept_check.hpp>
  14. #include <boost/config.hpp>
  15. #include <boost/core/addressof.hpp>
  16. #include <boost/mpl/has_xxx.hpp>
  17. #include <boost/range/concepts.hpp>
  18. #include <boost/range/begin.hpp>
  19. #include <boost/range/end.hpp>
  20. #include <boost/range/empty.hpp>
  21. #include <boost/range/difference_type.hpp>
  22. #include <boost/range/has_range_iterator.hpp>
  23. #include <boost/range/iterator.hpp>
  24. #include <boost/range/reference.hpp>
  25. #include <boost/range/size.hpp>
  26. #include <boost/range/value_type.hpp>
  27. #include <boost/geometry/core/assert.hpp>
  28. #include <boost/geometry/core/mutable_range.hpp>
  29. namespace boost { namespace geometry { namespace range
  30. {
  31. namespace detail
  32. {
  33. BOOST_MPL_HAS_XXX_TRAIT_DEF(iterator_category)
  34. template <typename T>
  35. struct is_iterator
  36. : std::integral_constant
  37. <
  38. bool,
  39. has_iterator_category
  40. <
  41. std::iterator_traits<T>
  42. >::value
  43. >
  44. {};
  45. template <typename T, bool HasIterator = boost::has_range_iterator<T>::value>
  46. struct is_range_impl
  47. : is_iterator
  48. <
  49. typename boost::range_iterator<T>::type
  50. >
  51. {};
  52. template <typename T>
  53. struct is_range_impl<T, false>
  54. : std::false_type
  55. {};
  56. template <typename T>
  57. struct is_range
  58. : is_range_impl<T>
  59. {};
  60. template <typename Range, typename T = void>
  61. using enable_if_mutable_t = std::enable_if_t
  62. <
  63. (! std::is_const<std::remove_reference_t<Range>>::value),
  64. T
  65. >;
  66. } // namespace detail
  67. /*!
  68. \brief Short utility to conveniently return an iterator of a RandomAccessRange.
  69. \ingroup utility
  70. */
  71. template <typename RandomAccessRange>
  72. inline typename boost::range_iterator<RandomAccessRange>::type
  73. pos(RandomAccessRange && rng,
  74. typename boost::range_size<RandomAccessRange>::type i)
  75. {
  76. BOOST_RANGE_CONCEPT_ASSERT((boost::RandomAccessRangeConcept<RandomAccessRange>));
  77. BOOST_GEOMETRY_ASSERT(i <= boost::size(rng));
  78. return boost::begin(rng)
  79. + static_cast<typename boost::range_difference<RandomAccessRange>::type>(i);
  80. }
  81. /*!
  82. \brief Short utility to conveniently return an element of a RandomAccessRange.
  83. \ingroup utility
  84. */
  85. template <typename RandomAccessRange>
  86. inline typename boost::range_reference<RandomAccessRange>::type
  87. at(RandomAccessRange && rng,
  88. typename boost::range_size<RandomAccessRange>::type i)
  89. {
  90. return *pos(rng, i);
  91. }
  92. /*!
  93. \brief Short utility to conveniently return the front element of a Range.
  94. \ingroup utility
  95. */
  96. template <typename Range>
  97. inline typename boost::range_reference<Range>::type
  98. front(Range && rng)
  99. {
  100. BOOST_GEOMETRY_ASSERT(!boost::empty(rng));
  101. return *boost::begin(rng);
  102. }
  103. /*!
  104. \brief Short utility to conveniently return the back element of a BidirectionalRange.
  105. \ingroup utility
  106. */
  107. template <typename BidirectionalRange>
  108. inline typename boost::range_reference<BidirectionalRange>::type
  109. back(BidirectionalRange && rng)
  110. {
  111. BOOST_RANGE_CONCEPT_ASSERT((boost::BidirectionalRangeConcept<BidirectionalRange>));
  112. BOOST_GEOMETRY_ASSERT(!boost::empty(rng));
  113. auto it = boost::end(rng);
  114. return *(--it);
  115. }
  116. /*!
  117. \brief Short utility to conveniently clear a mutable range.
  118. It uses traits::clear<>.
  119. \ingroup utility
  120. */
  121. template
  122. <
  123. typename Range,
  124. detail::enable_if_mutable_t<Range, int> = 0
  125. >
  126. inline void clear(Range && rng)
  127. {
  128. geometry::traits::clear
  129. <
  130. std::remove_reference_t<Range>
  131. >::apply(rng);
  132. }
  133. /*!
  134. \brief Short utility to conveniently insert a new element at the end of a mutable range.
  135. It uses boost::geometry::traits::push_back<>.
  136. \ingroup utility
  137. */
  138. template
  139. <
  140. typename Range,
  141. detail::enable_if_mutable_t<Range, int> = 0
  142. >
  143. inline void push_back(Range && rng,
  144. typename boost::range_value<Range>::type const& value)
  145. {
  146. geometry::traits::push_back
  147. <
  148. std::remove_reference_t<Range>
  149. >::apply(rng, value);
  150. }
  151. /*!
  152. \brief Short utility to conveniently insert a new element at the end of a mutable range.
  153. It uses boost::geometry::traits::push_back<>.
  154. \ingroup utility
  155. */
  156. template
  157. <
  158. typename Range,
  159. detail::enable_if_mutable_t<Range, int> = 0
  160. >
  161. inline void push_back(Range && rng,
  162. typename boost::range_value<Range>::type && value)
  163. {
  164. geometry::traits::push_back
  165. <
  166. std::remove_reference_t<Range>
  167. >::apply(rng, std::move(value));
  168. }
  169. /*!
  170. \brief Short utility to conveniently insert a new element at the end of a mutable range.
  171. It uses boost::geometry::traits::emplace_back<>.
  172. \ingroup utility
  173. */
  174. template
  175. <
  176. typename Range,
  177. typename ...Args,
  178. detail::enable_if_mutable_t<Range, int> = 0
  179. >
  180. inline void emplace_back(Range && rng, Args &&... args)
  181. {
  182. geometry::traits::emplace_back
  183. <
  184. std::remove_reference_t<Range>
  185. >::apply(rng, std::forward<Args>(args)...);
  186. }
  187. /*!
  188. \brief Short utility to conveniently resize a mutable range.
  189. It uses boost::geometry::traits::resize<>.
  190. \ingroup utility
  191. */
  192. template
  193. <
  194. typename Range,
  195. detail::enable_if_mutable_t<Range, int> = 0
  196. >
  197. inline void resize(Range && rng,
  198. typename boost::range_size<Range>::type new_size)
  199. {
  200. geometry::traits::resize
  201. <
  202. std::remove_reference_t<Range>
  203. >::apply(rng, new_size);
  204. }
  205. /*!
  206. \brief Short utility to conveniently remove an element from the back of a mutable range.
  207. It uses resize().
  208. \ingroup utility
  209. */
  210. template
  211. <
  212. typename Range,
  213. detail::enable_if_mutable_t<Range, int> = 0
  214. >
  215. inline void pop_back(Range && rng)
  216. {
  217. BOOST_GEOMETRY_ASSERT(!boost::empty(rng));
  218. range::resize(rng, boost::size(rng) - 1);
  219. }
  220. /*!
  221. \brief Short utility to conveniently remove an element from a mutable range.
  222. It uses std::move() and resize(). Version taking mutable iterators.
  223. \ingroup utility
  224. */
  225. template
  226. <
  227. typename Range,
  228. detail::enable_if_mutable_t<Range, int> = 0
  229. >
  230. inline typename boost::range_iterator<Range>::type
  231. erase(Range && rng,
  232. typename boost::range_iterator<Range>::type it)
  233. {
  234. BOOST_GEOMETRY_ASSERT(!boost::empty(rng));
  235. BOOST_GEOMETRY_ASSERT(it != boost::end(rng));
  236. typename boost::range_difference<Range>::type const
  237. d = std::distance(boost::begin(rng), it);
  238. typename boost::range_iterator<Range>::type
  239. next = it;
  240. ++next;
  241. std::move(next, boost::end(rng), it);
  242. range::resize(rng, boost::size(rng) - 1);
  243. // NOTE: In general this should be sufficient:
  244. // return it;
  245. // But in MSVC using the returned iterator causes
  246. // assertion failures when iterator debugging is enabled
  247. // Furthermore the code below should work in the case if resize()
  248. // invalidates iterators when the container is resized down.
  249. return boost::begin(rng) + d;
  250. }
  251. /*!
  252. \brief Short utility to conveniently remove an element from a mutable range.
  253. It uses std::move() and resize(). Version taking non-mutable iterators.
  254. \ingroup utility
  255. */
  256. template
  257. <
  258. typename Range,
  259. detail::enable_if_mutable_t<Range, int> = 0
  260. >
  261. inline typename boost::range_iterator<Range>::type
  262. erase(Range && rng,
  263. typename boost::range_iterator<std::remove_reference_t<Range> const>::type cit)
  264. {
  265. BOOST_RANGE_CONCEPT_ASSERT(( boost::RandomAccessRangeConcept<Range> ));
  266. typename boost::range_iterator<Range>::type
  267. it = boost::begin(rng)
  268. + std::distance(boost::const_begin(rng), cit);
  269. return range::erase(rng, it);
  270. }
  271. /*!
  272. \brief Short utility to conveniently remove a range of elements from a mutable range.
  273. It uses std::move() and resize(). Version taking mutable iterators.
  274. \ingroup utility
  275. */
  276. template
  277. <
  278. typename Range,
  279. detail::enable_if_mutable_t<Range, int> = 0
  280. >
  281. inline typename boost::range_iterator<Range>::type
  282. erase(Range && rng,
  283. typename boost::range_iterator<Range>::type first,
  284. typename boost::range_iterator<Range>::type last)
  285. {
  286. typename boost::range_difference<Range>::type const
  287. diff = std::distance(first, last);
  288. BOOST_GEOMETRY_ASSERT(diff >= 0);
  289. std::size_t const count = static_cast<std::size_t>(diff);
  290. BOOST_GEOMETRY_ASSERT(count <= boost::size(rng));
  291. if ( count > 0 )
  292. {
  293. typename boost::range_difference<Range>::type const
  294. d = std::distance(boost::begin(rng), first);
  295. std::move(last, boost::end(rng), first);
  296. range::resize(rng, boost::size(rng) - count);
  297. // NOTE: In general this should be sufficient:
  298. // return first;
  299. // But in MSVC using the returned iterator causes
  300. // assertion failures when iterator debugging is enabled
  301. // Furthermore the code below should work in the case if resize()
  302. // invalidates iterators when the container is resized down.
  303. return boost::begin(rng) + d;
  304. }
  305. return first;
  306. }
  307. /*!
  308. \brief Short utility to conveniently remove a range of elements from a mutable range.
  309. It uses std::move() and resize(). Version taking non-mutable iterators.
  310. \ingroup utility
  311. */
  312. template
  313. <
  314. typename Range,
  315. detail::enable_if_mutable_t<Range, int> = 0
  316. >
  317. inline typename boost::range_iterator<Range>::type
  318. erase(Range && rng,
  319. typename boost::range_iterator<std::remove_reference_t<Range> const>::type cfirst,
  320. typename boost::range_iterator<std::remove_reference_t<Range> const>::type clast)
  321. {
  322. BOOST_RANGE_CONCEPT_ASSERT(( boost::RandomAccessRangeConcept<Range> ));
  323. typename boost::range_iterator<Range>::type
  324. first = boost::begin(rng)
  325. + std::distance(boost::const_begin(rng), cfirst);
  326. typename boost::range_iterator<Range>::type
  327. last = boost::begin(rng)
  328. + std::distance(boost::const_begin(rng), clast);
  329. return range::erase(rng, first, last);
  330. }
  331. // back_inserter
  332. template <class Container>
  333. class back_insert_iterator
  334. {
  335. public:
  336. typedef std::output_iterator_tag iterator_category;
  337. typedef void value_type;
  338. typedef void difference_type;
  339. typedef void pointer;
  340. typedef void reference;
  341. typedef Container container_type;
  342. explicit back_insert_iterator(Container & c)
  343. : container(boost::addressof(c))
  344. {}
  345. back_insert_iterator & operator=(typename Container::value_type const& value)
  346. {
  347. range::push_back(*container, value);
  348. return *this;
  349. }
  350. back_insert_iterator & operator=(typename Container::value_type && value)
  351. {
  352. range::push_back(*container, std::move(value));
  353. return *this;
  354. }
  355. back_insert_iterator & operator* ()
  356. {
  357. return *this;
  358. }
  359. back_insert_iterator & operator++ ()
  360. {
  361. return *this;
  362. }
  363. back_insert_iterator operator++(int)
  364. {
  365. return *this;
  366. }
  367. private:
  368. Container * container;
  369. };
  370. template <typename Range>
  371. inline back_insert_iterator<Range> back_inserter(Range & rng)
  372. {
  373. return back_insert_iterator<Range>(rng);
  374. }
  375. }}} // namespace boost::geometry::range
  376. #endif // BOOST_GEOMETRY_UTIL_RANGE_HPP