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.

join.hpp 23KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  1. /// \file
  2. // Range v3 library
  3. //
  4. // Copyright Eric Niebler 2014-present
  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_JOIN_HPP
  14. #define RANGES_V3_VIEW_JOIN_HPP
  15. #include <type_traits>
  16. #include <utility>
  17. #include <meta/meta.hpp>
  18. #include <range/v3/range_fwd.hpp>
  19. #include <range/v3/functional/bind_back.hpp>
  20. #include <range/v3/iterator/default_sentinel.hpp>
  21. #include <range/v3/range/access.hpp>
  22. #include <range/v3/range/primitives.hpp>
  23. #include <range/v3/range/traits.hpp>
  24. #include <range/v3/range_for.hpp>
  25. #include <range/v3/utility/static_const.hpp>
  26. #include <range/v3/utility/variant.hpp>
  27. #include <range/v3/view/all.hpp>
  28. #include <range/v3/view/facade.hpp>
  29. #include <range/v3/view/single.hpp>
  30. #include <range/v3/view/view.hpp>
  31. namespace ranges
  32. {
  33. /// \cond
  34. namespace detail
  35. {
  36. // Compute the cardinality of a joined range
  37. constexpr cardinality join_cardinality_(
  38. cardinality Outer, cardinality Inner,
  39. cardinality Joiner = static_cast<cardinality>(0)) noexcept
  40. {
  41. return Outer == infinite || Inner == infinite ||
  42. (Joiner == infinite && Outer != 0 && Outer != 1)
  43. ? infinite
  44. : Outer == unknown || Inner == unknown ||
  45. (Joiner == unknown && Outer != 0 && Outer != 1)
  46. ? unknown
  47. : Outer == finite || Inner == finite ||
  48. (Joiner == finite && Outer != 0 && Outer != 1)
  49. ? finite
  50. : static_cast<cardinality>(
  51. Outer * Inner +
  52. (Outer == 0 ? 0 : (Outer - 1) * Joiner));
  53. }
  54. template<typename Range>
  55. constexpr cardinality join_cardinality() noexcept
  56. {
  57. return detail::join_cardinality_(
  58. range_cardinality<Range>::value,
  59. range_cardinality<range_reference_t<Range>>::value);
  60. }
  61. template<typename Range, typename JoinRange>
  62. constexpr cardinality join_cardinality() noexcept
  63. {
  64. return detail::join_cardinality_(
  65. range_cardinality<Range>::value,
  66. range_cardinality<range_reference_t<Range>>::value,
  67. range_cardinality<JoinRange>::value);
  68. }
  69. template<typename Inner>
  70. struct store_inner_
  71. {
  72. views::all_t<Inner> inner_ = views::all_t<Inner>();
  73. constexpr views::all_t<Inner> & update_inner_(Inner && inner)
  74. {
  75. return (inner_ = views::all(static_cast<Inner &&>(inner)));
  76. }
  77. constexpr views::all_t<Inner> & get_inner_(ignore_t) noexcept
  78. {
  79. return inner_;
  80. }
  81. };
  82. struct pass_thru_inner_
  83. {
  84. // Intentionally promote xvalues to lvalues here:
  85. template<typename Inner>
  86. static constexpr Inner & update_inner_(Inner && inner) noexcept
  87. {
  88. return inner;
  89. }
  90. template<typename OuterIt>
  91. static constexpr decltype(auto) get_inner_(OuterIt && outer_it)
  92. {
  93. return *outer_it;
  94. }
  95. };
  96. template<typename Rng>
  97. using join_view_inner =
  98. if_then_t<!std::is_reference<range_reference_t<Rng>>::value,
  99. store_inner_<range_reference_t<Rng>>, pass_thru_inner_>;
  100. // clang-format off
  101. CPP_def
  102. (
  103. template(typename I)
  104. concept has_member_arrow_,
  105. requires (I i)
  106. (
  107. i.operator->()
  108. )
  109. );
  110. CPP_def
  111. (
  112. template(typename I)
  113. concept has_arrow_,
  114. input_iterator<I> && (std::is_pointer<I>::value || has_member_arrow_<I>)
  115. );
  116. // clang-format on
  117. } // namespace detail
  118. /// \endcond
  119. /// \addtogroup group-views
  120. /// @{
  121. // Join a range of ranges
  122. template<typename Rng>
  123. struct RANGES_EMPTY_BASES join_view
  124. : view_facade<join_view<Rng>, detail::join_cardinality<Rng>()>
  125. , private detail::join_view_inner<Rng>
  126. {
  127. CPP_assert(input_range<Rng> && view_<Rng>);
  128. CPP_assert(input_range<range_reference_t<Rng>>);
  129. CPP_assert(viewable_range<range_reference_t<Rng>>);
  130. join_view() = default;
  131. explicit join_view(Rng rng)
  132. : outer_(views::all(std::move(rng)))
  133. {}
  134. // Not to spec
  135. CPP_member
  136. static constexpr auto size() -> CPP_ret(std::size_t)( //
  137. requires(detail::join_cardinality<Rng>() >= 0))
  138. {
  139. return static_cast<std::size_t>(detail::join_cardinality<Rng>());
  140. }
  141. // Not to spec
  142. CPP_member
  143. constexpr auto CPP_fun(size)()(requires(detail::join_cardinality<Rng>() < 0) &&
  144. (range_cardinality<Rng>::value >= 0) &&
  145. forward_range<Rng> &&
  146. sized_range<range_reference_t<Rng>>)
  147. {
  148. range_size_t<range_reference_t<Rng>> n = 0;
  149. RANGES_FOR(auto && inner, outer_)
  150. n += ranges::size(inner);
  151. return n;
  152. }
  153. // // ericniebler/stl2#605
  154. constexpr Rng base() const
  155. {
  156. return outer_;
  157. }
  158. private:
  159. friend range_access;
  160. Rng outer_{};
  161. template<bool Const>
  162. struct cursor
  163. {
  164. private:
  165. using Parent = detail::if_then_t<Const, join_view const, join_view>;
  166. using COuter = detail::if_then_t<Const, Rng const, Rng>;
  167. using CInner = range_reference_t<COuter>;
  168. using ref_is_glvalue = std::is_reference<CInner>;
  169. Parent * rng_ = nullptr;
  170. iterator_t<COuter> outer_it_{};
  171. iterator_t<CInner> inner_it_{};
  172. void satisfy()
  173. {
  174. for(; outer_it_ != ranges::end(rng_->outer_); ++outer_it_)
  175. {
  176. auto & inner = rng_->update_inner_(*outer_it_);
  177. inner_it_ = ranges::begin(inner);
  178. if(inner_it_ != ranges::end(inner))
  179. return;
  180. }
  181. if(RANGES_CONSTEXPR_IF(ref_is_glvalue::value))
  182. inner_it_ = iterator_t<CInner>();
  183. }
  184. public:
  185. using single_pass = meta::bool_<single_pass_iterator_<iterator_t<COuter>> ||
  186. single_pass_iterator_<iterator_t<CInner>> ||
  187. !ref_is_glvalue::value>;
  188. cursor() = default;
  189. template<typename BeginOrEnd>
  190. constexpr cursor(Parent * rng, BeginOrEnd begin_or_end)
  191. : rng_{rng}
  192. , outer_it_(begin_or_end(rng->outer_))
  193. {
  194. satisfy();
  195. }
  196. CPP_template(bool Other)( //
  197. requires Const && (!Other) &&
  198. convertible_to<iterator_t<Rng>, iterator_t<COuter>> &&
  199. convertible_to<iterator_t<range_reference_t<Rng>>,
  200. iterator_t<CInner>>) //
  201. constexpr cursor(cursor<Other> that)
  202. : rng_(that.rng_)
  203. , outer_it_(std::move(that.outer_it_))
  204. , inner_it_(std::move(that.inner_it_))
  205. {}
  206. CPP_member
  207. constexpr auto arrow() -> CPP_ret(iterator_t<CInner>)( //
  208. requires detail::has_arrow_<iterator_t<CInner>>)
  209. {
  210. return inner_it_;
  211. }
  212. constexpr bool equal(default_sentinel_t) const
  213. {
  214. return outer_it_ == ranges::end(rng_->outer_);
  215. }
  216. CPP_member
  217. constexpr auto equal(cursor const & that) const -> CPP_ret(bool)( //
  218. requires ref_is_glvalue::value && equality_comparable<
  219. iterator_t<COuter>> && equality_comparable<iterator_t<CInner>>)
  220. {
  221. return outer_it_ == that.outer_it_ && inner_it_ == that.inner_it_;
  222. }
  223. constexpr void next()
  224. {
  225. auto && inner_rng = rng_->get_inner_(outer_it_);
  226. if(++inner_it_ == ranges::end(inner_rng))
  227. {
  228. ++outer_it_;
  229. satisfy();
  230. }
  231. }
  232. CPP_member
  233. constexpr auto prev() -> CPP_ret(void)( //
  234. requires ref_is_glvalue::value && bidirectional_range<COuter> &&
  235. bidirectional_range<CInner> &&
  236. common_range<CInner>) // ericniebler/stl2#606
  237. {
  238. if(outer_it_ == ranges::end(rng_->outer_))
  239. inner_it_ = ranges::end(*--outer_it_);
  240. while(inner_it_ == ranges::begin(*outer_it_))
  241. inner_it_ = ranges::end(*--outer_it_);
  242. --inner_it_;
  243. }
  244. // clang-format off
  245. constexpr auto CPP_auto_fun(read)()(const)
  246. (
  247. return *inner_it_
  248. )
  249. constexpr auto CPP_auto_fun(move)()(const)
  250. (
  251. return iter_move(inner_it_)
  252. )
  253. // clang-format on
  254. };
  255. static constexpr bool use_const_always() noexcept
  256. {
  257. return simple_view<Rng>() && std::is_reference<range_reference_t<Rng>>::value;
  258. }
  259. struct end_cursor_fn
  260. {
  261. constexpr auto operator()(join_view * this_, std::true_type) const
  262. {
  263. return cursor<use_const_always()>{this_, ranges::end};
  264. }
  265. constexpr auto operator()(join_view *, std::false_type) const
  266. {
  267. return default_sentinel_t{};
  268. }
  269. };
  270. struct cend_cursor_fn
  271. {
  272. constexpr auto operator()(join_view const * this_, std::true_type) const
  273. {
  274. return cursor<true>{this_, ranges::end};
  275. }
  276. constexpr auto operator()(join_view const *, std::false_type) const
  277. {
  278. return default_sentinel_t{};
  279. }
  280. };
  281. constexpr cursor<use_const_always()> begin_cursor()
  282. {
  283. return {this, ranges::begin};
  284. }
  285. template<bool Const = true>
  286. constexpr auto begin_cursor() const -> CPP_ret(cursor<Const>)( //
  287. requires Const && input_range<meta::const_if_c<Const, Rng>> &&
  288. std::is_reference<range_reference_t<meta::const_if_c<Const, Rng>>>::value)
  289. {
  290. return {this, ranges::begin};
  291. }
  292. constexpr auto end_cursor()
  293. {
  294. using cond =
  295. meta::bool_<std::is_reference<range_reference_t<Rng>>::value &&
  296. forward_range<Rng> && forward_range<range_reference_t<Rng>> &&
  297. common_range<Rng> && common_range<range_reference_t<Rng>>>;
  298. return end_cursor_fn{}(this, cond{});
  299. }
  300. template<bool Const = true>
  301. constexpr auto CPP_fun(end_cursor)()(
  302. const requires Const && input_range<meta::const_if_c<Const, Rng>> &&
  303. std::is_reference<range_reference_t<meta::const_if_c<Const, Rng>>>::value)
  304. {
  305. using CRng = meta::const_if_c<Const, Rng>;
  306. using cond =
  307. meta::bool_<std::is_reference<range_reference_t<CRng>>::value &&
  308. forward_range<CRng> &&
  309. forward_range<range_reference_t<CRng>> &&
  310. common_range<CRng> && common_range<range_reference_t<CRng>>>;
  311. return cend_cursor_fn{}(this, cond{});
  312. }
  313. };
  314. // Join a range of ranges, inserting a range of values between them.
  315. // TODO: Support const iteration when range_reference_t<Rng> is a true reference.
  316. template<typename Rng, typename ValRng>
  317. struct join_with_view
  318. : view_facade<join_with_view<Rng, ValRng>, detail::join_cardinality<Rng, ValRng>()>
  319. {
  320. CPP_assert(input_range<Rng>);
  321. CPP_assert(input_range<range_reference_t<Rng>>);
  322. CPP_assert(forward_range<ValRng>);
  323. CPP_assert(
  324. common_with<range_value_t<range_reference_t<Rng>>, range_value_t<ValRng>>);
  325. CPP_assert(semiregular<common_type_t<range_value_t<range_reference_t<Rng>>,
  326. range_value_t<ValRng>>>);
  327. join_with_view() = default;
  328. join_with_view(Rng rng, ValRng val)
  329. : outer_(views::all(std::move(rng)))
  330. , val_(views::all(std::move(val)))
  331. {}
  332. CPP_member
  333. static constexpr auto size() -> CPP_ret(std::size_t)( //
  334. requires(detail::join_cardinality<Rng, ValRng>() >= 0))
  335. {
  336. return static_cast<std::size_t>(detail::join_cardinality<Rng, ValRng>());
  337. }
  338. CPP_member
  339. auto CPP_fun(size)()(const requires(detail::join_cardinality<Rng, ValRng>() <
  340. 0) &&
  341. (range_cardinality<Rng>::value >= 0) && forward_range<Rng> &&
  342. sized_range<range_reference_t<Rng>> && sized_range<ValRng>)
  343. {
  344. range_size_t<range_reference_t<Rng>> n = 0;
  345. RANGES_FOR(auto && inner, outer_)
  346. n += ranges::size(inner);
  347. return n + (range_cardinality<Rng>::value == 0
  348. ? 0
  349. : ranges::size(val_) * (range_cardinality<Rng>::value - 1));
  350. }
  351. private:
  352. friend range_access;
  353. using Outer = views::all_t<Rng>;
  354. using Inner = views::all_t<range_reference_t<Outer>>;
  355. Outer outer_{};
  356. Inner inner_{};
  357. views::all_t<ValRng> val_{};
  358. class cursor
  359. {
  360. join_with_view * rng_ = nullptr;
  361. iterator_t<Outer> outer_it_{};
  362. variant<iterator_t<ValRng>, iterator_t<Inner>> cur_{};
  363. void satisfy()
  364. {
  365. while(true)
  366. {
  367. if(cur_.index() == 0)
  368. {
  369. if(ranges::get<0>(cur_) != ranges::end(rng_->val_))
  370. break;
  371. rng_->inner_ = views::all(*outer_it_);
  372. ranges::emplace<1>(cur_, ranges::begin(rng_->inner_));
  373. }
  374. else
  375. {
  376. if(ranges::get<1>(cur_) != ranges::end(rng_->inner_))
  377. break;
  378. if(++outer_it_ == ranges::end(rng_->outer_))
  379. break;
  380. ranges::emplace<0>(cur_, ranges::begin(rng_->val_));
  381. }
  382. }
  383. }
  384. public:
  385. using value_type = common_type_t<range_value_t<Inner>, range_value_t<ValRng>>;
  386. using reference =
  387. common_reference_t<range_reference_t<Inner>, range_reference_t<ValRng>>;
  388. using rvalue_reference = common_reference_t<range_rvalue_reference_t<Inner>,
  389. range_rvalue_reference_t<ValRng>>;
  390. using single_pass = std::true_type;
  391. cursor() = default;
  392. cursor(join_with_view * rng)
  393. : rng_{rng}
  394. , outer_it_(ranges::begin(rng->outer_))
  395. {
  396. if(outer_it_ != ranges::end(rng->outer_))
  397. {
  398. rng->inner_ = views::all(*outer_it_);
  399. ranges::emplace<1>(cur_, ranges::begin(rng->inner_));
  400. satisfy();
  401. }
  402. }
  403. bool equal(default_sentinel_t) const
  404. {
  405. return outer_it_ == ranges::end(rng_->outer_);
  406. }
  407. void next()
  408. {
  409. // visit(cur_, [](auto& it){ ++it; });
  410. if(cur_.index() == 0)
  411. {
  412. auto & it = ranges::get<0>(cur_);
  413. RANGES_ASSERT(it != ranges::end(rng_->val_));
  414. ++it;
  415. }
  416. else
  417. {
  418. auto & it = ranges::get<1>(cur_);
  419. RANGES_ASSERT(it != ranges::end(rng_->inner_));
  420. ++it;
  421. }
  422. satisfy();
  423. }
  424. reference read() const
  425. {
  426. // return visit(cur_, [](auto& it) -> reference { return *it; });
  427. if(cur_.index() == 0)
  428. return *ranges::get<0>(cur_);
  429. else
  430. return *ranges::get<1>(cur_);
  431. }
  432. rvalue_reference move() const
  433. {
  434. // return visit(cur_, [](auto& it) -> rvalue_reference { return
  435. // iter_move(it); });
  436. if(cur_.index() == 0)
  437. return iter_move(ranges::get<0>(cur_));
  438. else
  439. return iter_move(ranges::get<1>(cur_));
  440. }
  441. };
  442. cursor begin_cursor()
  443. {
  444. return {this};
  445. }
  446. };
  447. namespace views
  448. {
  449. /// \cond
  450. // Don't forget to update views::for_each whenever this set
  451. // of concepts changes
  452. // clang-format off
  453. CPP_def
  454. (
  455. template(typename Rng)
  456. concept joinable_range,
  457. viewable_range<Rng> && input_range<Rng> &&
  458. input_range<range_reference_t<Rng>> &&
  459. viewable_range<range_reference_t<Rng>>
  460. );
  461. CPP_def
  462. (
  463. template(typename Rng, typename ValRng)
  464. concept joinable_with_range,
  465. joinable_range<Rng> &&
  466. viewable_range<ValRng> && forward_range<ValRng> &&
  467. common_with<range_value_t<ValRng>, range_value_t<range_reference_t<Rng>>> &&
  468. semiregular<
  469. common_type_t<
  470. range_value_t<ValRng>,
  471. range_value_t<range_reference_t<Rng>>>> &&
  472. common_reference_with<
  473. range_reference_t<ValRng>,
  474. range_reference_t<range_reference_t<Rng>>> &&
  475. common_reference_with<
  476. range_rvalue_reference_t<ValRng>,
  477. range_rvalue_reference_t<range_reference_t<Rng>>>
  478. );
  479. // clang-format on
  480. /// \endcond
  481. struct cpp20_join_fn
  482. {
  483. template<typename Rng>
  484. auto operator()(Rng && rng) const -> CPP_ret(join_view<all_t<Rng>>)( //
  485. requires joinable_range<Rng>)
  486. {
  487. return join_view<all_t<Rng>>{all(static_cast<Rng &&>(rng))};
  488. }
  489. };
  490. struct join_fn : cpp20_join_fn
  491. {
  492. private:
  493. friend view_access;
  494. template<typename T>
  495. static auto CPP_fun(bind)(join_fn join, T && t)( //
  496. requires(!joinable_range<T>))
  497. {
  498. return make_pipeable(bind_back(join, static_cast<T &&>(t)));
  499. }
  500. #ifdef RANGES_WORKAROUND_MSVC_OLD_LAMBDA
  501. template<typename T, std::size_t N>
  502. struct lamduh
  503. {
  504. T (&val_)[N];
  505. template<typename Rng>
  506. auto operator()(Rng && rng) const
  507. -> invoke_result_t<join_fn, Rng, T (&)[N]>
  508. {
  509. return join_fn{}(static_cast<Rng &&>(rng), val_);
  510. }
  511. };
  512. template<typename T, std::size_t N>
  513. static lamduh<T, N> bind(join_fn, T (&val)[N])
  514. {
  515. return {val};
  516. }
  517. #else // ^^^ workaround / no workaround vvv
  518. template<typename T, std::size_t N>
  519. static auto bind(join_fn, T (&val)[N])
  520. {
  521. return [&val](auto && rng)
  522. -> invoke_result_t<join_fn, decltype(rng), T(&)[N]>
  523. {
  524. return join_fn{}(static_cast<decltype(rng)>(rng), val);
  525. };
  526. }
  527. #endif // RANGES_WORKAROUND_MSVC_OLD_LAMBDA
  528. template<typename Rng>
  529. using inner_value_t = range_value_t<range_reference_t<Rng>>;
  530. public:
  531. using cpp20_join_fn::operator();
  532. template<typename Rng>
  533. auto operator()(Rng && rng, inner_value_t<Rng> v) const
  534. -> CPP_ret(join_with_view<all_t<Rng>,
  535. single_view<inner_value_t<Rng>>>)( //
  536. requires joinable_with_range<Rng, single_view<inner_value_t<Rng>>>)
  537. {
  538. return {all(static_cast<Rng &&>(rng)), single(std::move(v))};
  539. }
  540. template<typename Rng, typename ValRng>
  541. auto operator()(Rng && rng, ValRng && val) const
  542. -> CPP_ret(join_with_view<all_t<Rng>, all_t<ValRng>>)( //
  543. requires joinable_with_range<Rng, ValRng>)
  544. {
  545. return {all(static_cast<Rng &&>(rng)), all(static_cast<ValRng &&>(val))};
  546. }
  547. };
  548. /// \relates join_fn
  549. /// \ingroup group-views
  550. RANGES_INLINE_VARIABLE(view<join_fn>, join)
  551. } // namespace views
  552. /// @}
  553. #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
  554. CPP_template(typename Rng)( //
  555. requires views::joinable_range<Rng>) //
  556. explicit join_view(Rng &&)
  557. ->join_view<views::all_t<Rng>>;
  558. CPP_template(typename Rng, typename ValRng)( //
  559. requires views::joinable_with_range<Rng, ValRng>) //
  560. explicit join_with_view(Rng &&, ValRng &&)
  561. ->join_with_view<views::all_t<Rng>, views::all_t<ValRng>>;
  562. #endif
  563. namespace cpp20
  564. {
  565. namespace views
  566. {
  567. RANGES_INLINE_VARIABLE(ranges::views::view<ranges::views::cpp20_join_fn>,
  568. join)
  569. }
  570. CPP_template(typename Rng)( //
  571. requires input_range<Rng> && view_<Rng> &&
  572. input_range<iter_reference_t<iterator_t<Rng>>> &&
  573. (std::is_reference<iter_reference_t<iterator_t<Rng>>>::value ||
  574. view_<iter_value_t<iterator_t<Rng>>>)) //
  575. using join_view = ranges::join_view<Rng>;
  576. } // namespace cpp20
  577. } // namespace ranges
  578. #include <range/v3/detail/satisfy_boost_range.hpp>
  579. RANGES_SATISFY_BOOST_RANGE(::ranges::join_view)
  580. RANGES_SATISFY_BOOST_RANGE(::ranges::join_with_view)
  581. #endif