indexed.hpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. // Copyright 2014 Neil Groves
  2. //
  3. // Copyright (c) 2010 Ilya Murav'jov
  4. //
  5. // Use, modification and distribution is subject to the Boost Software License,
  6. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  7. // http://www.boost.org/LICENSE_1_0.txt)
  8. //
  9. // Credits:
  10. // My (Neil's) first indexed adaptor was hindered by having the underlying
  11. // iterator return the same reference as the wrapped iterator. This meant that
  12. // to obtain the index one had to get to the index_iterator and call the
  13. // index() function on it. Ilya politely pointed out that this was useless in
  14. // a number of scenarios since one naturally hides the use of iterators in
  15. // good range-based code. Ilya provided a new interface (which has remained)
  16. // and a first implementation. Much of this original implementation has
  17. // been simplified and now supports more compilers and platforms.
  18. //
  19. #ifndef BOOST_RANGE_ADAPTOR_INDEXED_HPP_INCLUDED
  20. #define BOOST_RANGE_ADAPTOR_INDEXED_HPP_INCLUDED
  21. #include <boost/range/config.hpp>
  22. #include <boost/range/adaptor/argument_fwd.hpp>
  23. #include <boost/range/iterator_range.hpp>
  24. #include <boost/range/traversal.hpp>
  25. #include <boost/range/size.hpp>
  26. #include <boost/range/begin.hpp>
  27. #include <boost/range/end.hpp>
  28. #include <boost/mpl/if.hpp>
  29. #include <boost/type_traits/is_convertible.hpp>
  30. #include <boost/iterator/iterator_traits.hpp>
  31. #include <boost/iterator/iterator_facade.hpp>
  32. #include <boost/tuple/tuple.hpp>
  33. namespace boost
  34. {
  35. namespace adaptors
  36. {
  37. struct indexed
  38. {
  39. explicit indexed(std::ptrdiff_t x = 0)
  40. : val(x)
  41. {
  42. }
  43. std::ptrdiff_t val;
  44. };
  45. } // namespace adaptors
  46. namespace range
  47. {
  48. // Why yet another "pair" class:
  49. // - std::pair can't store references
  50. // - no need for typing for index type (default to "std::ptrdiff_t"); this is
  51. // useful in BOOST_FOREACH() expressions that have pitfalls with commas
  52. // ( see http://www.boost.org/doc/libs/1_44_0/doc/html/foreach/pitfalls.html )
  53. // - meaningful access functions index(), value()
  54. template<class T, class Indexable = std::ptrdiff_t>
  55. class index_value
  56. : public tuple<Indexable, T>
  57. {
  58. typedef tuple<Indexable, T> base_t;
  59. template<int N>
  60. struct iv_types
  61. {
  62. typedef typename tuples::element<N, base_t>::type n_type;
  63. typedef typename tuples::access_traits<n_type>::non_const_type non_const_type;
  64. typedef typename tuples::access_traits<n_type>::const_type const_type;
  65. };
  66. public:
  67. typedef typename iv_types<0>::non_const_type index_type;
  68. typedef typename iv_types<0>::const_type const_index_type;
  69. typedef typename iv_types<1>::non_const_type value_type;
  70. typedef typename iv_types<1>::const_type const_value_type;
  71. index_value()
  72. {
  73. }
  74. index_value(typename tuples::access_traits<Indexable>::parameter_type t0,
  75. typename tuples::access_traits<T>::parameter_type t1)
  76. : base_t(t0, t1)
  77. {
  78. }
  79. // member functions index(), value() (non-const and const)
  80. index_type index()
  81. {
  82. return boost::tuples::get<0>(*this);
  83. }
  84. const_index_type index() const
  85. {
  86. return boost::tuples::get<0>(*this);
  87. }
  88. value_type value()
  89. {
  90. return boost::tuples::get<1>(*this);
  91. }
  92. const_value_type value() const
  93. {
  94. return boost::tuples::get<1>(*this);
  95. }
  96. };
  97. } // namespace range
  98. namespace range_detail
  99. {
  100. template<typename Iter>
  101. struct indexed_iterator_value_type
  102. {
  103. typedef ::boost::range::index_value<
  104. typename iterator_reference<Iter>::type,
  105. typename iterator_difference<Iter>::type
  106. > type;
  107. };
  108. // Meta-function to get the traversal for the range and therefore iterator
  109. // returned by the indexed adaptor for a specified iterator type.
  110. //
  111. // Random access -> Random access
  112. // Bidirectional -> Forward
  113. // Forward -> Forward
  114. // SinglePass -> SinglePass
  115. //
  116. // The rationale for demoting a Bidirectional input to Forward is that the end
  117. // iterator cannot cheaply have an index computed for it. Therefore I chose to
  118. // demote to forward traversal. I can maintain the ability to traverse randomly
  119. // when the input is Random Access since the index for the end iterator is cheap
  120. // to compute.
  121. template<typename Iter>
  122. struct indexed_traversal
  123. {
  124. private:
  125. typedef typename iterator_traversal<Iter>::type wrapped_traversal;
  126. public:
  127. typedef typename mpl::if_<
  128. is_convertible<wrapped_traversal, random_access_traversal_tag>,
  129. random_access_traversal_tag,
  130. typename mpl::if_<
  131. is_convertible<wrapped_traversal, bidirectional_traversal_tag>,
  132. forward_traversal_tag,
  133. wrapped_traversal
  134. >::type
  135. >::type type;
  136. };
  137. template<typename Iter>
  138. class indexed_iterator
  139. : public iterator_facade<
  140. indexed_iterator<Iter>,
  141. typename indexed_iterator_value_type<Iter>::type,
  142. typename indexed_traversal<Iter>::type,
  143. typename indexed_iterator_value_type<Iter>::type,
  144. typename iterator_difference<Iter>::type
  145. >
  146. {
  147. public:
  148. typedef Iter wrapped;
  149. private:
  150. typedef iterator_facade<
  151. indexed_iterator<wrapped>,
  152. typename indexed_iterator_value_type<wrapped>::type,
  153. typename indexed_traversal<wrapped>::type,
  154. typename indexed_iterator_value_type<wrapped>::type,
  155. typename iterator_difference<wrapped>::type
  156. > base_t;
  157. public:
  158. typedef typename base_t::difference_type difference_type;
  159. typedef typename base_t::reference reference;
  160. typedef typename base_t::difference_type index_type;
  161. indexed_iterator()
  162. : m_it()
  163. , m_index()
  164. {
  165. }
  166. template<typename OtherWrapped>
  167. indexed_iterator(
  168. const indexed_iterator<OtherWrapped>& other,
  169. typename enable_if<is_convertible<OtherWrapped, wrapped> >::type* = 0
  170. )
  171. : m_it(other.get())
  172. , m_index(other.get_index())
  173. {
  174. }
  175. explicit indexed_iterator(wrapped it, index_type index)
  176. : m_it(it)
  177. , m_index(index)
  178. {
  179. }
  180. wrapped get() const
  181. {
  182. return m_it;
  183. }
  184. index_type get_index() const
  185. {
  186. return m_index;
  187. }
  188. private:
  189. friend class boost::iterator_core_access;
  190. reference dereference() const
  191. {
  192. return reference(m_index, *m_it);
  193. }
  194. bool equal(const indexed_iterator& other) const
  195. {
  196. return m_it == other.m_it;
  197. }
  198. void increment()
  199. {
  200. ++m_index;
  201. ++m_it;
  202. }
  203. void decrement()
  204. {
  205. BOOST_ASSERT_MSG(m_index > 0, "indexed Iterator out of bounds");
  206. --m_index;
  207. --m_it;
  208. }
  209. void advance(index_type n)
  210. {
  211. m_index += n;
  212. BOOST_ASSERT_MSG(m_index >= 0, "indexed Iterator out of bounds");
  213. m_it += n;
  214. }
  215. difference_type distance_to(const indexed_iterator& other) const
  216. {
  217. return other.m_it - m_it;
  218. }
  219. wrapped m_it;
  220. index_type m_index;
  221. };
  222. template<typename SinglePassRange>
  223. struct indexed_range
  224. : iterator_range<
  225. indexed_iterator<
  226. typename range_iterator<SinglePassRange>::type
  227. >
  228. >
  229. {
  230. typedef iterator_range<
  231. indexed_iterator<
  232. typename range_iterator<SinglePassRange>::type
  233. >
  234. > base_t;
  235. BOOST_RANGE_CONCEPT_ASSERT((
  236. boost::SinglePassRangeConcept<SinglePassRange>));
  237. public:
  238. typedef indexed_iterator<
  239. typename range_iterator<SinglePassRange>::type
  240. > iterator;
  241. // Constructor for non-random access iterators.
  242. // This sets the end iterator index to i despite this being incorrect it
  243. // is never observable since bidirectional iterators are demoted to
  244. // forward iterators.
  245. indexed_range(
  246. typename base_t::difference_type i,
  247. SinglePassRange& r,
  248. single_pass_traversal_tag
  249. )
  250. : base_t(iterator(boost::begin(r), i),
  251. iterator(boost::end(r), i))
  252. {
  253. }
  254. indexed_range(
  255. typename base_t::difference_type i,
  256. SinglePassRange& r,
  257. random_access_traversal_tag
  258. )
  259. : base_t(iterator(boost::begin(r), i),
  260. iterator(boost::end(r), i + boost::size(r)))
  261. {
  262. }
  263. };
  264. } // namespace range_detail
  265. using range_detail::indexed_range;
  266. namespace adaptors
  267. {
  268. template<class SinglePassRange>
  269. inline indexed_range<SinglePassRange>
  270. operator|(SinglePassRange& r, indexed e)
  271. {
  272. BOOST_RANGE_CONCEPT_ASSERT((
  273. boost::SinglePassRangeConcept<SinglePassRange>
  274. ));
  275. return indexed_range<SinglePassRange>(
  276. e.val, r,
  277. typename range_traversal<SinglePassRange>::type());
  278. }
  279. template<class SinglePassRange>
  280. inline indexed_range<const SinglePassRange>
  281. operator|(const SinglePassRange& r, indexed e)
  282. {
  283. BOOST_RANGE_CONCEPT_ASSERT((
  284. boost::SinglePassRangeConcept<const SinglePassRange>
  285. ));
  286. return indexed_range<const SinglePassRange>(
  287. e.val, r,
  288. typename range_traversal<const SinglePassRange>::type());
  289. }
  290. template<class SinglePassRange>
  291. inline indexed_range<SinglePassRange>
  292. index(
  293. SinglePassRange& rng,
  294. typename range_difference<SinglePassRange>::type index_value = 0)
  295. {
  296. BOOST_RANGE_CONCEPT_ASSERT((
  297. boost::SinglePassRangeConcept<SinglePassRange>
  298. ));
  299. return indexed_range<SinglePassRange>(
  300. index_value, rng,
  301. typename range_traversal<SinglePassRange>::type());
  302. }
  303. template<class SinglePassRange>
  304. inline indexed_range<const SinglePassRange>
  305. index(
  306. const SinglePassRange& rng,
  307. typename range_difference<const SinglePassRange>::type index_value = 0)
  308. {
  309. BOOST_RANGE_CONCEPT_ASSERT((
  310. boost::SinglePassRangeConcept<SinglePassRange>
  311. ));
  312. return indexed_range<const SinglePassRange>(
  313. index_value, rng,
  314. typename range_traversal<const SinglePassRange>::type());
  315. }
  316. } // namespace adaptors
  317. } // namespace boost
  318. #if !defined(BOOST_NO_CXX11_HDR_TUPLE)
  319. namespace std {
  320. #if defined(BOOST_CLANG)
  321. #pragma clang diagnostic push
  322. #pragma clang diagnostic ignored "-Wmismatched-tags"
  323. #endif
  324. template<size_t N, class T, class Indexable>
  325. struct tuple_element<N, boost::range::index_value<T, Indexable>>:
  326. boost::tuples::element<N, boost::range::index_value<T, Indexable>> {};
  327. template<class T, class Indexable>
  328. struct tuple_size<boost::range::index_value<T, Indexable>>:
  329. std::integral_constant<std::size_t, 2> {};
  330. #if defined(BOOST_CLANG)
  331. #pragma clang diagnostic pop
  332. #endif
  333. } // namespace std
  334. #endif // !defined(BOOST_NO_CXX11_HDR_TUPLE)
  335. #endif // include guard