join_iterator.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. // Boost.Range library
  2. //
  3. // Copyright Neil Groves 2009. Use, modification and
  4. // distribution is subject to the Boost Software License, Version
  5. // 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt)
  7. //
  8. // Acknowledgements:
  9. // aschoedl contributed an improvement to the determination
  10. // of the Reference type parameter.
  11. //
  12. // Leonid Gershanovich reported Trac ticket 7376 about the dereference operator
  13. // requiring identical reference types due to using the ternary if.
  14. //
  15. // For more information, see http://www.boost.org/libs/range/
  16. //
  17. #ifndef BOOST_RANGE_DETAIL_JOIN_ITERATOR_HPP_INCLUDED
  18. #define BOOST_RANGE_DETAIL_JOIN_ITERATOR_HPP_INCLUDED
  19. #include <iterator>
  20. #include <boost/assert.hpp>
  21. #include <boost/mpl/if.hpp>
  22. #include <boost/iterator/iterator_traits.hpp>
  23. #include <boost/iterator/iterator_facade.hpp>
  24. #include <boost/range/begin.hpp>
  25. #include <boost/range/end.hpp>
  26. #include <boost/range/empty.hpp>
  27. #include <boost/range/detail/demote_iterator_traversal_tag.hpp>
  28. #include <boost/range/value_type.hpp>
  29. #include <boost/type_traits/add_const.hpp>
  30. #include <boost/type_traits/add_reference.hpp>
  31. #include <boost/type_traits/remove_const.hpp>
  32. #include <boost/type_traits/remove_reference.hpp>
  33. #include <boost/next_prior.hpp>
  34. namespace boost
  35. {
  36. namespace range_detail
  37. {
  38. template<typename Iterator1, typename Iterator2>
  39. struct join_iterator_link
  40. {
  41. public:
  42. join_iterator_link(Iterator1 last1, Iterator2 first2)
  43. : last1(last1)
  44. , first2(first2)
  45. {
  46. }
  47. Iterator1 last1;
  48. Iterator2 first2;
  49. private:
  50. join_iterator_link() /* = delete */ ;
  51. };
  52. class join_iterator_begin_tag {};
  53. class join_iterator_end_tag {};
  54. template<typename Iterator1
  55. , typename Iterator2
  56. , typename Reference
  57. >
  58. class join_iterator_union
  59. {
  60. public:
  61. typedef Iterator1 iterator1_t;
  62. typedef Iterator2 iterator2_t;
  63. join_iterator_union() {}
  64. join_iterator_union(unsigned int /*selected*/, const iterator1_t& it1, const iterator2_t& it2) : m_it1(it1), m_it2(it2) {}
  65. iterator1_t& it1() { return m_it1; }
  66. const iterator1_t& it1() const { return m_it1; }
  67. iterator2_t& it2() { return m_it2; }
  68. const iterator2_t& it2() const { return m_it2; }
  69. Reference dereference(unsigned int selected) const
  70. {
  71. if (selected)
  72. return *m_it2;
  73. return *m_it1;
  74. }
  75. bool equal(const join_iterator_union& other, unsigned int selected) const
  76. {
  77. return selected
  78. ? m_it2 == other.m_it2
  79. : m_it1 == other.m_it1;
  80. }
  81. private:
  82. iterator1_t m_it1;
  83. iterator2_t m_it2;
  84. };
  85. template<class Iterator, class Reference>
  86. class join_iterator_union<Iterator, Iterator, Reference>
  87. {
  88. public:
  89. typedef Iterator iterator1_t;
  90. typedef Iterator iterator2_t;
  91. join_iterator_union() {}
  92. join_iterator_union(unsigned int selected, const iterator1_t& it1, const iterator2_t& it2)
  93. : m_it(selected ? it2 : it1)
  94. {
  95. }
  96. iterator1_t& it1() { return m_it; }
  97. const iterator1_t& it1() const { return m_it; }
  98. iterator2_t& it2() { return m_it; }
  99. const iterator2_t& it2() const { return m_it; }
  100. Reference dereference(unsigned int) const
  101. {
  102. return *m_it;
  103. }
  104. bool equal(const join_iterator_union& other,
  105. unsigned int /*selected*/) const
  106. {
  107. return m_it == other.m_it;
  108. }
  109. private:
  110. iterator1_t m_it;
  111. };
  112. template<typename Iterator1
  113. , typename Iterator2
  114. , typename ValueType = typename iterator_value<Iterator1>::type
  115. // find least demanding, commonly supported reference type, in the order &, const&, and by-value:
  116. , typename Reference = typename mpl::if_c<
  117. !is_reference<typename iterator_reference<Iterator1>::type>::value
  118. || !is_reference<typename iterator_reference<Iterator2>::type>::value,
  119. typename remove_const<
  120. typename remove_reference<
  121. typename iterator_reference<Iterator1>::type
  122. >::type
  123. >::type,
  124. typename mpl::if_c<
  125. is_const<
  126. typename remove_reference<
  127. typename iterator_reference<Iterator1>::type
  128. >::type
  129. >::value
  130. || is_const<
  131. typename remove_reference<
  132. typename iterator_reference<Iterator2>::type
  133. >::type
  134. >::value,
  135. typename add_reference<
  136. typename add_const<
  137. typename remove_reference<
  138. typename iterator_reference<Iterator1>::type
  139. >::type
  140. >::type
  141. >::type,
  142. typename iterator_reference<Iterator1>::type
  143. >::type
  144. >::type
  145. , typename Traversal = typename demote_iterator_traversal_tag<
  146. typename iterator_traversal<Iterator1>::type
  147. , typename iterator_traversal<Iterator2>::type>::type
  148. >
  149. class join_iterator
  150. : public iterator_facade<join_iterator<Iterator1,Iterator2,ValueType,Reference,Traversal>, ValueType, Traversal, Reference>
  151. {
  152. typedef join_iterator_link<Iterator1, Iterator2> link_t;
  153. typedef join_iterator_union<Iterator1, Iterator2, Reference> iterator_union;
  154. public:
  155. typedef Iterator1 iterator1_t;
  156. typedef Iterator2 iterator2_t;
  157. join_iterator()
  158. : m_section(0u)
  159. , m_it(0u, iterator1_t(), iterator2_t())
  160. , m_link(link_t(iterator1_t(), iterator2_t()))
  161. {}
  162. join_iterator(unsigned int section, Iterator1 current1, Iterator1 last1, Iterator2 first2, Iterator2 current2)
  163. : m_section(section)
  164. , m_it(section, current1, current2)
  165. , m_link(link_t(last1, first2))
  166. {
  167. }
  168. template<typename Range1, typename Range2>
  169. join_iterator(Range1& r1, Range2& r2, join_iterator_begin_tag)
  170. : m_section(boost::empty(r1) ? 1u : 0u)
  171. , m_it(boost::empty(r1) ? 1u : 0u, boost::begin(r1), boost::begin(r2))
  172. , m_link(link_t(boost::end(r1), boost::begin(r2)))
  173. {
  174. }
  175. template<typename Range1, typename Range2>
  176. join_iterator(const Range1& r1, const Range2& r2, join_iterator_begin_tag)
  177. : m_section(boost::empty(r1) ? 1u : 0u)
  178. , m_it(boost::empty(r1) ? 1u : 0u, boost::const_begin(r1), boost::const_begin(r2))
  179. , m_link(link_t(boost::const_end(r1), boost::const_begin(r2)))
  180. {
  181. }
  182. template<typename Range1, typename Range2>
  183. join_iterator(Range1& r1, Range2& r2, join_iterator_end_tag)
  184. : m_section(1u)
  185. , m_it(1u, boost::end(r1), boost::end(r2))
  186. , m_link(link_t(boost::end(r1), boost::begin(r2)))
  187. {
  188. }
  189. template<typename Range1, typename Range2>
  190. join_iterator(const Range1& r1, const Range2& r2, join_iterator_end_tag)
  191. : m_section(1u)
  192. , m_it(1u, boost::const_end(r1), boost::const_end(r2))
  193. , m_link(link_t(boost::const_end(r1), boost::const_begin(r2)))
  194. {
  195. }
  196. private:
  197. void increment()
  198. {
  199. if (m_section)
  200. ++m_it.it2();
  201. else
  202. {
  203. ++m_it.it1();
  204. if (m_it.it1() == m_link.last1)
  205. {
  206. m_it.it2() = m_link.first2;
  207. m_section = 1u;
  208. }
  209. }
  210. }
  211. void decrement()
  212. {
  213. if (m_section)
  214. {
  215. if (m_it.it2() == m_link.first2)
  216. {
  217. m_it.it1() = boost::prior(m_link.last1);
  218. m_section = 0u;
  219. }
  220. else
  221. --m_it.it2();
  222. }
  223. else
  224. --m_it.it1();
  225. }
  226. typename join_iterator::reference dereference() const
  227. {
  228. return m_it.dereference(m_section);
  229. }
  230. bool equal(const join_iterator& other) const
  231. {
  232. return m_section == other.m_section
  233. && m_it.equal(other.m_it, m_section);
  234. }
  235. void advance(typename join_iterator::difference_type offset)
  236. {
  237. if (m_section)
  238. advance_from_range2(offset);
  239. else
  240. advance_from_range1(offset);
  241. }
  242. typename join_iterator::difference_type distance_to(const join_iterator& other) const
  243. {
  244. typename join_iterator::difference_type result;
  245. if (m_section)
  246. {
  247. if (other.m_section)
  248. result = other.m_it.it2() - m_it.it2();
  249. else
  250. {
  251. result = (m_link.first2 - m_it.it2())
  252. + (other.m_it.it1() - m_link.last1);
  253. BOOST_ASSERT( result <= 0 );
  254. }
  255. }
  256. else
  257. {
  258. if (other.m_section)
  259. {
  260. result = (m_link.last1 - m_it.it1())
  261. + (other.m_it.it2() - m_link.first2);
  262. }
  263. else
  264. result = other.m_it.it1() - m_it.it1();
  265. }
  266. return result;
  267. }
  268. void advance_from_range2(typename join_iterator::difference_type offset)
  269. {
  270. typedef typename join_iterator::difference_type difference_t;
  271. BOOST_ASSERT( m_section == 1u );
  272. if (offset < 0)
  273. {
  274. difference_t r2_dist = m_link.first2 - m_it.it2();
  275. BOOST_ASSERT( r2_dist <= 0 );
  276. if (offset >= r2_dist)
  277. std::advance(m_it.it2(), offset);
  278. else
  279. {
  280. difference_t r1_dist = offset - r2_dist;
  281. BOOST_ASSERT( r1_dist <= 0 );
  282. m_it.it1() = m_link.last1 + r1_dist;
  283. m_section = 0u;
  284. }
  285. }
  286. else
  287. std::advance(m_it.it2(), offset);
  288. }
  289. void advance_from_range1(typename join_iterator::difference_type offset)
  290. {
  291. typedef typename join_iterator::difference_type difference_t;
  292. BOOST_ASSERT( m_section == 0u );
  293. if (offset > 0)
  294. {
  295. difference_t r1_dist = m_link.last1 - m_it.it1();
  296. BOOST_ASSERT( r1_dist >= 0 );
  297. if (offset < r1_dist)
  298. std::advance(m_it.it1(), offset);
  299. else
  300. {
  301. difference_t r2_dist = offset - r1_dist;
  302. BOOST_ASSERT( r2_dist >= 0 );
  303. m_it.it2() = m_link.first2 + r2_dist;
  304. m_section = 1u;
  305. }
  306. }
  307. else
  308. std::advance(m_it.it1(), offset);
  309. }
  310. unsigned int m_section;
  311. iterator_union m_it;
  312. link_t m_link;
  313. friend class ::boost::iterator_core_access;
  314. };
  315. } // namespace range_detail
  316. } // namespace boost
  317. #endif // include guard