You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

concat.hpp 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. /// \file
  2. // Range v3 library
  3. //
  4. // Copyright Eric Niebler 2013-2014.
  5. //
  6. // Use, modification and distribution is subject to the
  7. // Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at
  9. // http://www.boost.org/LICENSE_1_0.txt)
  10. //
  11. // Project home: https://github.com/ericniebler/range-v3
  12. //
  13. #ifndef RANGES_V3_VIEW_CONCAT_HPP
  14. #define RANGES_V3_VIEW_CONCAT_HPP
  15. #include <tuple>
  16. #include <type_traits>
  17. #include <utility>
  18. #include <meta/meta.hpp>
  19. #include <range/v3/range_fwd.hpp>
  20. #include <range/v3/functional/arithmetic.hpp>
  21. #include <range/v3/functional/compose.hpp>
  22. #include <range/v3/iterator/operations.hpp>
  23. #include <range/v3/range/access.hpp>
  24. #include <range/v3/range/concepts.hpp>
  25. #include <range/v3/range/primitives.hpp>
  26. #include <range/v3/range/traits.hpp>
  27. #include <range/v3/utility/static_const.hpp>
  28. #include <range/v3/utility/tuple_algorithm.hpp>
  29. #include <range/v3/utility/variant.hpp>
  30. #include <range/v3/view/all.hpp>
  31. #include <range/v3/view/facade.hpp>
  32. #include <range/v3/view/view.hpp>
  33. namespace ranges
  34. {
  35. /// \cond
  36. namespace detail
  37. {
  38. template<typename State, typename Value>
  39. using concat_cardinality_ = std::integral_constant<
  40. cardinality,
  41. State::value == infinite || Value::value == infinite
  42. ? infinite
  43. : State::value == unknown || Value::value == unknown
  44. ? unknown
  45. : State::value == finite || Value::value == finite
  46. ? finite
  47. : static_cast<cardinality>(State::value + Value::value)>;
  48. template<typename... Rngs>
  49. using concat_cardinality =
  50. meta::fold<meta::list<range_cardinality<Rngs>...>,
  51. std::integral_constant<cardinality, static_cast<cardinality>(0)>,
  52. meta::quote<concat_cardinality_>>;
  53. } // namespace detail
  54. /// \endcond
  55. /// \addtogroup group-views
  56. /// @{
  57. template<typename... Rngs>
  58. struct concat_view
  59. : view_facade<concat_view<Rngs...>, detail::concat_cardinality<Rngs...>::value>
  60. {
  61. private:
  62. friend range_access;
  63. using difference_type_ = common_type_t<range_difference_t<Rngs>...>;
  64. static constexpr std::size_t cranges{sizeof...(Rngs)};
  65. std::tuple<Rngs...> rngs_;
  66. template<bool IsConst>
  67. struct cursor;
  68. template<bool IsConst>
  69. struct sentinel
  70. {
  71. private:
  72. friend struct sentinel<!IsConst>;
  73. friend struct cursor<IsConst>;
  74. template<typename T>
  75. using constify_if = meta::const_if_c<IsConst, T>;
  76. using concat_view_t = constify_if<concat_view>;
  77. sentinel_t<constify_if<meta::back<meta::list<Rngs...>>>> end_;
  78. public:
  79. sentinel() = default;
  80. sentinel(concat_view_t * rng, end_tag)
  81. : end_(end(std::get<cranges - 1>(rng->rngs_)))
  82. {}
  83. CPP_template(bool Other)( //
  84. requires IsConst && (!Other)) sentinel(sentinel<Other> that)
  85. : end_(std::move(that.end_))
  86. {}
  87. };
  88. template<bool IsConst>
  89. struct cursor
  90. {
  91. using difference_type = common_type_t<range_difference_t<Rngs>...>;
  92. private:
  93. friend struct cursor<!IsConst>;
  94. template<typename T>
  95. using constify_if = meta::const_if_c<IsConst, T>;
  96. using concat_view_t = constify_if<concat_view>;
  97. concat_view_t * rng_;
  98. variant<iterator_t<constify_if<Rngs>>...> its_;
  99. template<std::size_t N>
  100. void satisfy(meta::size_t<N>)
  101. {
  102. RANGES_EXPECT(its_.index() == N);
  103. if(ranges::get<N>(its_) == end(std::get<N>(rng_->rngs_)))
  104. {
  105. ranges::emplace<N + 1>(its_, begin(std::get<N + 1>(rng_->rngs_)));
  106. this->satisfy(meta::size_t<N + 1>{});
  107. }
  108. }
  109. void satisfy(meta::size_t<cranges - 1>)
  110. {
  111. RANGES_EXPECT(its_.index() == cranges - 1);
  112. }
  113. struct next_fun
  114. {
  115. cursor * pos;
  116. template<typename I, std::size_t N>
  117. auto operator()(indexed_element<I, N> it) const -> CPP_ret(void)( //
  118. requires input_iterator<I>)
  119. {
  120. RANGES_ASSERT(it.get() != end(std::get<N>(pos->rng_->rngs_)));
  121. ++it.get();
  122. pos->satisfy(meta::size_t<N>{});
  123. }
  124. };
  125. struct prev_fun
  126. {
  127. cursor * pos;
  128. template<typename I>
  129. auto operator()(indexed_element<I, 0> it) const -> CPP_ret(void)( //
  130. requires bidirectional_iterator<I>)
  131. {
  132. RANGES_ASSERT(it.get() != begin(std::get<0>(pos->rng_->rngs_)));
  133. --it.get();
  134. }
  135. template<typename I, std::size_t N>
  136. auto operator()(indexed_element<I, N> it) const -> CPP_ret(void)( //
  137. requires(N != 0) && bidirectional_iterator<I>)
  138. {
  139. if(it.get() == begin(std::get<N>(pos->rng_->rngs_)))
  140. {
  141. auto && rng = std::get<N - 1>(pos->rng_->rngs_);
  142. ranges::emplace<N - 1>(
  143. pos->its_,
  144. ranges::next(ranges::begin(rng), ranges::end(rng)));
  145. pos->its_.visit_i(*this);
  146. }
  147. else
  148. --it.get();
  149. }
  150. };
  151. struct advance_fwd_fun
  152. {
  153. cursor * pos;
  154. difference_type n;
  155. template<typename I>
  156. auto operator()(indexed_element<I, cranges - 1> it) const
  157. -> CPP_ret(void)( //
  158. requires random_access_iterator<I>)
  159. {
  160. ranges::advance(it.get(), n);
  161. }
  162. template<typename I, std::size_t N>
  163. auto operator()(indexed_element<I, N> it) const -> CPP_ret(void)( //
  164. requires random_access_iterator<I>)
  165. {
  166. auto last = ranges::end(std::get<N>(pos->rng_->rngs_));
  167. // BUGBUG If distance(it, last) > n, then using bounded advance
  168. // is O(n) when it need not be since the last iterator position
  169. // is actually not interesting. Only the "rest" is needed, which
  170. // can sometimes be O(1).
  171. auto rest = ranges::advance(it.get(), n, std::move(last));
  172. pos->satisfy(meta::size_t<N>{});
  173. if(rest != 0)
  174. pos->its_.visit_i(advance_fwd_fun{pos, rest});
  175. }
  176. };
  177. struct advance_rev_fun
  178. {
  179. cursor * pos;
  180. difference_type n;
  181. template<typename I>
  182. auto operator()(indexed_element<I, 0> it) const -> CPP_ret(void)( //
  183. requires random_access_iterator<I>)
  184. {
  185. ranges::advance(it.get(), n);
  186. }
  187. template<typename I, std::size_t N>
  188. auto operator()(indexed_element<I, N> it) const -> CPP_ret(void)( //
  189. requires random_access_iterator<I>)
  190. {
  191. auto first = ranges::begin(std::get<N>(pos->rng_->rngs_));
  192. if(it.get() == first)
  193. {
  194. auto && rng = std::get<N - 1>(pos->rng_->rngs_);
  195. ranges::emplace<N - 1>(
  196. pos->its_,
  197. ranges::next(ranges::begin(rng), ranges::end(rng)));
  198. pos->its_.visit_i(*this);
  199. }
  200. else
  201. {
  202. auto rest = ranges::advance(it.get(), n, std::move(first));
  203. if(rest != 0)
  204. pos->its_.visit_i(advance_rev_fun{pos, rest});
  205. }
  206. }
  207. };
  208. [[noreturn]] static difference_type distance_to_(meta::size_t<cranges>,
  209. cursor const &,
  210. cursor const &)
  211. {
  212. RANGES_EXPECT(false);
  213. }
  214. template<std::size_t N>
  215. static difference_type distance_to_(meta::size_t<N>, cursor const & from,
  216. cursor const & to)
  217. {
  218. if(from.its_.index() > N)
  219. return cursor::distance_to_(meta::size_t<N + 1>{}, from, to);
  220. if(from.its_.index() == N)
  221. {
  222. if(to.its_.index() == N)
  223. return distance(ranges::get<N>(from.its_),
  224. ranges::get<N>(to.its_));
  225. return distance(ranges::get<N>(from.its_),
  226. end(std::get<N>(from.rng_->rngs_))) +
  227. cursor::distance_to_(meta::size_t<N + 1>{}, from, to);
  228. }
  229. if(from.its_.index() < N && to.its_.index() > N)
  230. return distance(std::get<N>(from.rng_->rngs_)) +
  231. cursor::distance_to_(meta::size_t<N + 1>{}, from, to);
  232. RANGES_EXPECT(to.its_.index() == N);
  233. return distance(begin(std::get<N>(from.rng_->rngs_)),
  234. ranges::get<N>(to.its_));
  235. }
  236. public:
  237. // BUGBUG what about rvalue_reference and common_reference?
  238. using reference = common_reference_t<range_reference_t<constify_if<Rngs>>...>;
  239. using single_pass = meta::or_c<single_pass_iterator_<iterator_t<Rngs>>...>;
  240. cursor() = default;
  241. cursor(concat_view_t * rng, begin_tag)
  242. : rng_(rng)
  243. , its_{emplaced_index<0>, begin(std::get<0>(rng->rngs_))}
  244. {
  245. this->satisfy(meta::size_t<0>{});
  246. }
  247. cursor(concat_view_t * rng, end_tag)
  248. : rng_(rng)
  249. , its_{emplaced_index<cranges - 1>, end(std::get<cranges - 1>(rng->rngs_))}
  250. {}
  251. CPP_template(bool Other)( //
  252. requires IsConst && (!Other)) //
  253. cursor(cursor<Other> that)
  254. : rng_(that.rng_)
  255. , its_(std::move(that.its_))
  256. {}
  257. reference read() const
  258. {
  259. // Kind of a dumb implementation. Surely there's a better way.
  260. return ranges::get<0>(unique_variant(its_.visit(
  261. compose(convert_to<reference>{}, detail::dereference_fn{}))));
  262. }
  263. void next()
  264. {
  265. its_.visit_i(next_fun{this});
  266. }
  267. CPP_member
  268. auto equal(cursor const & pos) const -> CPP_ret(bool)( //
  269. requires equality_comparable<variant<iterator_t<constify_if<Rngs>>...>>)
  270. {
  271. return its_ == pos.its_;
  272. }
  273. bool equal(sentinel<IsConst> const & pos) const
  274. {
  275. return its_.index() == cranges - 1 &&
  276. ranges::get<cranges - 1>(its_) == pos.end_;
  277. }
  278. CPP_member
  279. auto prev() -> CPP_ret(void)( //
  280. requires and_v<bidirectional_range<Rngs>...>)
  281. {
  282. its_.visit_i(prev_fun{this});
  283. }
  284. CPP_member
  285. auto advance(difference_type n) -> CPP_ret(void)( //
  286. requires and_v<random_access_range<Rngs>...>)
  287. {
  288. if(n > 0)
  289. its_.visit_i(advance_fwd_fun{this, n});
  290. else if(n < 0)
  291. its_.visit_i(advance_rev_fun{this, n});
  292. }
  293. CPP_member
  294. auto distance_to(cursor const & that) const -> CPP_ret(difference_type)( //
  295. requires and_v<sized_sentinel_for<iterator_t<Rngs>, iterator_t<Rngs>>...>)
  296. {
  297. if(its_.index() <= that.its_.index())
  298. return cursor::distance_to_(meta::size_t<0>{}, *this, that);
  299. return -cursor::distance_to_(meta::size_t<0>{}, that, *this);
  300. }
  301. };
  302. cursor<meta::and_c<simple_view<Rngs>()...>::value> begin_cursor()
  303. {
  304. return {this, begin_tag{}};
  305. }
  306. meta::if_<meta::and_c<(bool)common_range<Rngs>...>,
  307. cursor<meta::and_c<simple_view<Rngs>()...>::value>,
  308. sentinel<meta::and_c<simple_view<Rngs>()...>::value>>
  309. end_cursor()
  310. {
  311. return {this, end_tag{}};
  312. }
  313. CPP_member
  314. auto begin_cursor() const -> CPP_ret(cursor<true>)( //
  315. requires and_v<range<Rngs const>...>)
  316. {
  317. return {this, begin_tag{}};
  318. }
  319. CPP_member
  320. auto end_cursor() const -> CPP_ret(
  321. meta::if_<meta::and_c<(bool)common_range<Rngs const>...>, cursor<true>,
  322. sentinel<true>>)( //
  323. requires and_v<range<Rngs const>...>)
  324. {
  325. return {this, end_tag{}};
  326. }
  327. public:
  328. concat_view() = default;
  329. explicit concat_view(Rngs... rngs)
  330. : rngs_{std::move(rngs)...}
  331. {}
  332. CPP_member
  333. constexpr auto size() const -> CPP_ret(std::size_t)( //
  334. requires(detail::concat_cardinality<Rngs...>::value >= 0))
  335. {
  336. return static_cast<std::size_t>(detail::concat_cardinality<Rngs...>::value);
  337. }
  338. CPP_member
  339. constexpr auto CPP_fun(size)()(
  340. const requires(detail::concat_cardinality<Rngs...>::value < 0) &&
  341. and_v<sized_range<Rngs const>...>)
  342. {
  343. using size_type = common_type_t<range_size_t<Rngs const>...>;
  344. return tuple_foldl(
  345. tuple_transform(rngs_,
  346. [](auto && r) -> size_type { return ranges::size(r); }),
  347. size_type{0},
  348. plus{});
  349. }
  350. CPP_member
  351. constexpr auto CPP_fun(size)()(
  352. requires(detail::concat_cardinality<Rngs...>::value < 0) &&
  353. and_v<sized_range<Rngs>...>)
  354. {
  355. using size_type = common_type_t<range_size_t<Rngs>...>;
  356. return tuple_foldl(
  357. tuple_transform(rngs_,
  358. [](auto && r) -> size_type { return ranges::size(r); }),
  359. size_type{0},
  360. plus{});
  361. }
  362. };
  363. #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
  364. template<typename... Rng>
  365. concat_view(Rng &&...)->concat_view<views::all_t<Rng>...>;
  366. #endif
  367. namespace views
  368. {
  369. struct concat_fn
  370. {
  371. template<typename... Rngs>
  372. auto operator()(Rngs &&... rngs) const
  373. -> CPP_ret(concat_view<all_t<Rngs>...>)( //
  374. requires and_v<(viewable_range<Rngs> && input_range<Rngs>)...>)
  375. {
  376. return concat_view<all_t<Rngs>...>{all(static_cast<Rngs &&>(rngs))...};
  377. }
  378. };
  379. /// \relates concat_fn
  380. /// \ingroup group-views
  381. RANGES_INLINE_VARIABLE(concat_fn, concat)
  382. } // namespace views
  383. /// @}
  384. } // namespace ranges
  385. #include <range/v3/detail/satisfy_boost_range.hpp>
  386. RANGES_SATISFY_BOOST_RANGE(::ranges::concat_view)
  387. #endif