6namespace probfd::views {
8#ifndef __cpp_lib_ranges_concat
17template <
bool Const,
typename Tp>
18using maybe_const_t = std::conditional_t<Const, const Tp, Tp>;
20template <
typename... Rs>
21using concat_reference_t =
22 std::common_reference_t<std::ranges::range_reference_t<Rs>...>;
24template <
typename... Rs>
25using concat_value_t = std::common_type_t<std::ranges::range_value_t<Rs>...>;
27template <
typename... Rs>
28using concat_rvalue_reference_t =
29 std::common_reference_t<std::ranges::range_rvalue_reference_t<Rs>...>;
31template <
typename Ref,
typename RRef,
typename It>
32concept concat_indirectly_readable_impl =
requires(
const It it) {
33 { *it } -> std::convertible_to<Ref>;
34 { std::ranges::iter_move(it) } -> std::convertible_to<RRef>;
37template <
typename... Rs>
38concept concat_indirectly_readable = std::common_reference_with<
39 concat_reference_t<Rs...>&&,
40 concat_value_t<Rs...>&> &&
41 std::common_reference_with<
42 concat_reference_t<Rs...>&&,
43 concat_rvalue_reference_t<Rs...>&&> &&
44 std::common_reference_with<
45 concat_rvalue_reference_t<Rs...>&&,
46 concat_value_t<Rs...>
const&> &&
47 (concat_indirectly_readable_impl<
48 concat_reference_t<Rs...>,
49 concat_rvalue_reference_t<Rs...>,
50 std::ranges::iterator_t<Rs>> &&
53template <
typename... Rs>
54concept concatable =
requires {
55 typename concat_reference_t<Rs...>;
56 typename concat_value_t<Rs...>;
57 typename concat_rvalue_reference_t<Rs...>;
58} && concat_indirectly_readable<Rs...>;
60template <
bool Const,
typename Range,
typename... Rs>
61struct all_but_last_common {
62 static inline constexpr bool value =
requires {
64 std::ranges::common_range<maybe_const_t<Const, Range>> &&
65 all_but_last_common<Const, Rs...>::value);
69template <
bool Const,
typename Range>
70struct all_but_last_common<Const, Range> {
71 static inline constexpr bool value =
true;
74template <
bool Const,
typename... Vs>
75concept all_random_access =
76 (std::ranges::random_access_range<maybe_const_t<Const, Vs>> && ...);
78template <
bool Const,
typename... Vs>
79concept all_bidirectional =
80 (std::ranges::bidirectional_range<maybe_const_t<Const, Vs>> && ...);
82template <
bool Const,
typename... Vs>
84 (std::ranges::forward_range<maybe_const_t<Const, Vs>> && ...);
86template <
bool Const,
typename... Rs>
87concept concat_is_random_access =
88 all_random_access<Const, Rs...> && all_but_last_common<Const, Rs...>::value;
90template <
bool Const,
typename... Rs>
91concept concat_is_bidirectional =
92 all_bidirectional<Const, Rs...> && all_but_last_common<Const, Rs...>::value;
94template <
typename Range,
typename... Rs>
95struct last_is_common {
96 static inline constexpr bool value = last_is_common<Rs...>::value;
99template <
typename Range>
100struct last_is_common<Range> {
101 static inline constexpr bool value = std::ranges::common_range<Range>;
104template <
typename Fp,
typename Tuple>
105constexpr auto tuple_transform(Fp&& f, Tuple&& t)
108 [&]<
typename... Ts>(Ts&&... elts) {
109 return tuple<std::invoke_result_t<Fp&, Ts>...>(
110 std::invoke(f, std::forward<Ts>(elts))...);
112 std::forward<Tuple>(t));
115template <
typename Range>
117 std::ranges::view<Range> && std::ranges::range<const Range> &&
119 std::ranges::iterator_t<Range>,
120 std::ranges::iterator_t<const Range>> &&
122 std::ranges::sentinel_t<Range>,
123 std::ranges::sentinel_t<const Range>>;
125template <std::
integral Tp>
126constexpr auto to_unsigned_like(Tp t)
noexcept
128 return static_cast<std::make_unsigned_t<Tp>
>(t);
131template <
typename Tp>
132using make_unsigned_like_t =
133 decltype(detail::to_unsigned_like(std::declval<Tp>()));
137using detail::maybe_const_t;
139template <std::ranges::input_range... Vs>
140 requires(std::ranges::view<Vs> && ...) &&
141 (
sizeof...(Vs) > 0) && detail::concatable<Vs...>
142class concat_view : public
std::ranges::view_interface<concat_view<Vs...>> {
143 std::tuple<Vs...> M_views;
145 template <
bool Const>
149 constexpr concat_view() =
default;
151 constexpr explicit concat_view(Vs... views)
152 : M_views(
std::move(views)...)
156 constexpr iterator<false> begin()
157 requires(!(detail::simple_view<Vs> && ...))
161 std::in_place_index<0>,
162 std::ranges::begin(std::get<0>(M_views)));
163 it.template M_satisfy<0>();
167 constexpr iterator<true> begin() const
168 requires(
std::ranges::range<const Vs> && ...) &&
169 detail::concatable<const Vs...>
173 std::in_place_index<0>,
174 std::ranges::begin(std::get<0>(M_views)));
175 it.template M_satisfy<0>();
180 requires(!(detail::simple_view<Vs> && ...))
182 if constexpr (detail::last_is_common<Vs...>::value) {
183 constexpr auto n =
sizeof...(Vs);
184 return iterator<false>(
186 std::in_place_index<n - 1>,
187 std::ranges::end(std::get<n - 1>(M_views)));
189 return std::default_sentinel;
192 constexpr auto end() const
193 requires(
std::ranges::range<const Vs> && ...) &&
194 detail::concatable<const Vs...>
196 if constexpr (detail::last_is_common<
const Vs...>::value) {
197 constexpr auto n =
sizeof...(Vs);
198 return iterator<true>(
200 std::in_place_index<n - 1>,
201 std::ranges::end(std::get<n - 1>(M_views)));
203 return std::default_sentinel;
206 constexpr auto size()
207 requires(std::ranges::sized_range<Vs> && ...)
211 using CT = detail::make_unsigned_like_t<
212 std::common_type_t<
decltype(sizes)...>>;
213 return (CT(sizes) + ...);
215 detail::tuple_transform(std::ranges::size, M_views));
218 constexpr auto size() const
219 requires(
std::ranges::sized_range<const Vs> && ...)
223 using CT = detail::make_unsigned_like_t<
224 std::common_type_t<
decltype(sizes)...>>;
225 return (CT(sizes) + ...);
227 detail::tuple_transform(std::ranges::size, M_views));
231template <
typename... Rs>
232concat_view(Rs&&...) -> concat_view<std::views::all_t<Rs>...>;
235template <
bool Const,
typename... Vs>
236struct concat_view_iter_cat {};
238template <
bool Const,
typename... Vs>
239 requires detail::all_forward<Const, Vs...>
240struct concat_view_iter_cat<Const, Vs...> {
241 static auto S_iter_cat()
243 if constexpr (!std::is_reference_v<
244 concat_reference_t<maybe_const_t<Const, Vs>...>>)
245 return std::input_iterator_tag{};
247 return []<
typename... Cats>(Cats...) {
249 (std::derived_from<Cats, std::random_access_iterator_tag> &&
251 concat_is_random_access<Const, Vs...>)
252 return std::random_access_iterator_tag{};
254 (std::derived_from<Cats, std::bidirectional_iterator_tag> &&
256 concat_is_bidirectional<Const, Vs...>)
257 return std::bidirectional_iterator_tag{};
258 else if constexpr ((std::derived_from<
260 std::forward_iterator_tag> &&
262 return std::forward_iterator_tag{};
264 return std::input_iterator_tag{};
265 }(
typename std::iterator_traits<std::ranges::iterator_t<
266 maybe_const_t<Const, Vs>>>::iterator_category{}...);
271template <std::ranges::input_range... Vs>
272 requires(std::ranges::view<Vs> && ...) &&
273 (
sizeof...(Vs) > 0) && detail::concatable<Vs...>
275class concat_view<Vs...>::iterator
276 : public detail::concat_view_iter_cat<Const, Vs...> {
277 static auto S_iter_concept()
279 if constexpr (detail::concat_is_random_access<Const, Vs...>)
280 return std::random_access_iterator_tag{};
281 else if constexpr (detail::concat_is_bidirectional<Const, Vs...>)
282 return std::bidirectional_iterator_tag{};
283 else if constexpr (detail::all_forward<Const, Vs...>)
284 return std::forward_iterator_tag{};
286 return std::input_iterator_tag{};
290 friend iterator<!Const>;
294 using iterator_concept =
decltype(S_iter_concept());
295 using value_type = detail::concat_value_t<maybe_const_t<Const, Vs>...>;
296 using difference_type = std::common_type_t<
297 std::ranges::range_difference_t<maybe_const_t<Const, Vs>>...>;
301 std::variant<std::ranges::iterator_t<maybe_const_t<Const, Vs>>...>;
303 maybe_const_t<Const, concat_view>* M_parent =
nullptr;
307 constexpr void M_satisfy()
309 if constexpr (Nm < (
sizeof...(Vs) - 1)) {
310 if (std::get<Nm>(M_it) ==
311 std::ranges::end(std::get<Nm>(M_parent->M_views))) {
312 M_it.template emplace<Nm + 1>(
313 std::ranges::begin(std::get<Nm + 1>(M_parent->M_views)));
320 constexpr void M_prev()
322 if constexpr (Nm == 0)
325 if (std::get<Nm>(M_it) ==
326 std::ranges::begin(std::get<Nm>(M_parent->M_views))) {
327 M_it.template emplace<Nm - 1>(
328 std::ranges::end(std::get<Nm - 1>(M_parent->M_views)));
331 --std::get<Nm>(M_it);
336 constexpr void M_advance_fwd(difference_type offset, difference_type steps)
339 std::iter_difference_t<std::variant_alternative_t<Nm, base_iter>>;
340 if constexpr (Nm ==
sizeof...(Vs) - 1)
341 std::get<Nm>(M_it) +=
static_cast<Dt
>(steps);
344 std::ranges::distance(std::get<Nm>(M_parent->M_views));
345 if (offset + steps < n_size)
346 std::get<Nm>(M_it) +=
static_cast<Dt
>(steps);
348 M_it.template emplace<Nm + 1>(
349 std::ranges::begin(std::get<Nm + 1>(M_parent->M_views)));
350 M_advance_fwd<Nm + 1>(0, offset + steps - n_size);
356 constexpr void M_advance_bwd(difference_type offset, difference_type steps)
359 std::iter_difference_t<std::variant_alternative_t<Nm, base_iter>>;
360 if constexpr (Nm == 0)
361 std::get<Nm>(M_it) -=
static_cast<Dt
>(steps);
364 std::get<Nm>(M_it) -=
static_cast<Dt
>(steps);
367 std::ranges::distance(std::get<Nm - 1>(M_parent->M_views));
368 M_it.template emplace<Nm - 1>(
369 std::ranges::end(std::get<Nm - 1>(M_parent->M_views)));
370 M_advance_bwd<Nm - 1>(prev_size, steps - offset);
378 template <
typename Fp>
379 static constexpr auto S_invoke_with_runtime_index(Fp&& f,
size_t index)
381 return [&f, index]<
size_t Idx>(
this auto&& self) {
382 if (Idx == index)
return f.template operator()<Idx>();
383 if constexpr (Idx + 1 <
sizeof...(Vs))
384 return self.template
operator()<Idx + 1>();
385 }.template operator()<0>();
388 template <
typename Fp>
389 constexpr auto M_invoke_with_runtime_index(Fp&& f)
391 return S_invoke_with_runtime_index(std::forward<Fp>(f), M_it.index());
394 template <
typename... Args>
395 explicit constexpr iterator(
396 maybe_const_t<Const, concat_view>* parent,
398 requires std::constructible_from<base_iter, Args&&...>
400 , M_it(std::forward<Args>(args)...)
405 iterator() =
default;
407 constexpr iterator(iterator<!Const> it)
408 requires Const && (std::convertible_to<
409 std::ranges::iterator_t<Vs>,
410 std::ranges::iterator_t<const Vs>> &&
412 : M_parent(it.M_parent)
414 M_invoke_with_runtime_index([
this, &it]<
size_t Idx>() {
415 M_it.template emplace<Idx>(std::get<Idx>(std::move(it.M_it)));
419 constexpr decltype(
auto)
operator*()
const
421 glibcxx_assert(!M_it.valueless_by_exception());
423 detail::concat_reference_t<maybe_const_t<Const, Vs>...>;
424 return std::visit([](
auto&& it) -> reference {
return *it; }, M_it);
427 constexpr iterator& operator++()
429 M_invoke_with_runtime_index([
this]<
size_t Idx>() {
430 ++std::get<Idx>(M_it);
436 constexpr void operator++(
int) { ++*
this; }
438 constexpr iterator operator++(
int)
439 requires detail::all_forward<Const, Vs...>
446 constexpr iterator& operator--()
447 requires detail::concat_is_bidirectional<Const, Vs...>
449 glibcxx_assert(!M_it.valueless_by_exception());
450 M_invoke_with_runtime_index([
this]<
size_t Idx>() { M_prev<Idx>(); });
454 constexpr iterator operator--(
int)
455 requires detail::concat_is_bidirectional<Const, Vs...>
462 constexpr iterator& operator+=(difference_type n)
463 requires detail::concat_is_random_access<Const, Vs...>
465 glibcxx_assert(!M_it.valueless_by_exception());
466 M_invoke_with_runtime_index([
this, n]<
size_t Idx>() {
467 auto begin = std::ranges::begin(std::get<Idx>(M_parent->M_views));
469 M_advance_fwd<Idx>(std::get<Idx>(M_it) - begin, n);
471 M_advance_bwd<Idx>(std::get<Idx>(M_it) - begin, -n);
476 constexpr iterator& operator-=(difference_type n)
477 requires detail::concat_is_random_access<Const, Vs...>
483 constexpr decltype(
auto)
operator[](difference_type n)
const
484 requires detail::concat_is_random_access<Const, Vs...>
486 return *((*this) + n);
489 friend constexpr bool operator==(
const iterator& x,
const iterator& y)
491 std::equality_comparable<
492 std::ranges::iterator_t<maybe_const_t<Const, Vs>>> &&
495 glibcxx_assert(!x.M_it.valueless_by_exception());
496 glibcxx_assert(!y.M_it.valueless_by_exception());
497 return x.M_it == y.M_it;
500 friend constexpr bool
501 operator==(
const iterator& it, std::default_sentinel_t)
503 glibcxx_assert(!it.M_it.valueless_by_exception());
504 constexpr auto last_idx =
sizeof...(Vs) - 1;
506 it.M_it.index() == last_idx &&
507 (std::get<last_idx>(it.M_it) ==
508 std::ranges::end(std::get<last_idx>(it.M_parent->M_views))));
511 friend constexpr bool operator<(
const iterator& x,
const iterator& y)
512 requires detail::all_random_access<Const, Vs...>
514 return x.M_it < y.M_it;
517 friend constexpr bool operator>(
const iterator& x,
const iterator& y)
518 requires detail::all_random_access<Const, Vs...>
520 return x.M_it > y.M_it;
523 friend constexpr bool operator<=(
const iterator& x,
const iterator& y)
524 requires detail::all_random_access<Const, Vs...>
526 return x.M_it <= y.M_it;
529 friend constexpr bool operator>=(
const iterator& x,
const iterator& y)
530 requires detail::all_random_access<Const, Vs...>
532 return x.M_it >= y.M_it;
535 friend constexpr auto operator<=>(
const iterator& x,
const iterator& y)
536 requires detail::all_random_access<Const, Vs...> &&
537 (std::three_way_comparable<
538 std::ranges::iterator_t<maybe_const_t<Const, Vs>>> &&
541 return x.M_it <=> y.M_it;
544 friend constexpr iterator
operator+(
const iterator& it, difference_type n)
545 requires detail::concat_is_random_access<Const, Vs...>
551 friend constexpr iterator
operator+(difference_type n,
const iterator& it)
552 requires detail::concat_is_random_access<Const, Vs...>
557 friend constexpr iterator operator-(
const iterator& it, difference_type n)
558 requires detail::concat_is_random_access<Const, Vs...>
564 friend constexpr difference_type
565 operator-(
const iterator& x,
const iterator& y)
566 requires detail::concat_is_random_access<Const, Vs...>
568 return S_invoke_with_runtime_index(
569 [&]<
size_t Ix>() -> difference_type {
570 return S_invoke_with_runtime_index(
571 [&]<
size_t Iy>() -> difference_type {
572 if constexpr (Ix > Iy) {
573 auto dy = std::ranges::distance(
574 std::get<Iy>(y.M_it),
576 std::get<Iy>(y.M_parent->M_views)));
577 auto dx = std::ranges::distance(
579 std::get<Ix>(x.M_parent->M_views)),
580 std::get<Ix>(x.M_it));
581 difference_type s = 0;
582 [&]<
size_t Idx = Iy + 1>(
this auto&& self) {
583 if constexpr (Idx < Ix) {
584 s += std::ranges::size(
585 std::get<Idx>(x.M_parent->M_views));
586 self.template operator()<Idx + 1>();
590 }
else if constexpr (Ix < Iy)
593 return std::get<Ix>(x.M_it) - std::get<Iy>(y.M_it);
600 friend constexpr difference_type
601 operator-(
const iterator& x, std::default_sentinel_t)
602 requires detail::concat_is_random_access<Const, Vs...> &&
603 detail::last_is_common<maybe_const_t<Const, Vs>...>::value
605 return S_invoke_with_runtime_index(
606 [&]<
size_t Ix>() -> difference_type {
607 auto dx = std::ranges::distance(
608 std::get<Ix>(x.M_it),
609 std::ranges::end(std::get<Ix>(x.M_parent->M_views)));
610 difference_type s = 0;
611 [&]<
size_t Idx = Ix + 1>(
this auto&& self) {
612 if constexpr (Idx <
sizeof...(Vs)) {
613 s += std::ranges::size(
614 std::get<Idx>(x.M_parent->M_views));
615 self.template operator()<Idx + 1>();
623 friend constexpr difference_type
624 operator-(std::default_sentinel_t,
const iterator& x)
625 requires detail::concat_is_random_access<Const, Vs...> &&
626 detail::last_is_common<maybe_const_t<Const, Vs>...>::value
628 return -(x - std::default_sentinel);
631 friend constexpr decltype(
auto) iter_move(
const iterator& it)
634 detail::concat_rvalue_reference_t<maybe_const_t<Const, Vs>...>;
636 [](
const auto& i) -> Res {
return std::ranges::iter_move(i); },
640 friend constexpr void iter_swap(
const iterator& x,
const iterator& y)
641 requires std::swappable_with<
642 std::iter_reference_t<iterator>,
643 std::iter_reference_t<iterator>> &&
644 (... && std::indirectly_swappable<
645 std::ranges::iterator_t<maybe_const_t<Const, Vs>>>)
648 [&]<
typename Tp,
typename Up>(
const Tp& it1,
const Up& it2) {
649 if constexpr (std::is_same_v<Tp, Up>)
650 std::ranges::iter_swap(it1, it2);
652 std::ranges::swap(*it1, *it2);
660template <
typename... Ts>
661concept can_concat_view =
requires { concat_view(std::declval<Ts>()...); };
665 template <
typename... Ts>
666 requires detail::can_concat_view<Ts...>
667 constexpr auto operator() [[nodiscard]] (Ts&&... ts)
const
669 if constexpr (
sizeof...(Ts) == 1)
670 return std::views::all(std::forward<Ts>(ts)...);
672 return concat_view(std::forward<Ts>(ts)...);
676inline constexpr Concat concat;
680inline constexpr auto concat = std::views::concat;
Interval operator+(Interval lhs, Interval rhs)
Computes the component-wise addition of two intervals.