172#include <type_traits>
178 concept single_pass_iterator = std::input_or_output_iterator<I> && !std::forward_iterator<I>;
180 template <
typename... V>
181 constexpr auto common_iterator_category() {
182 if constexpr ((std::ranges::random_access_range<V> && ...))
183 return std::random_access_iterator_tag{};
184 else if constexpr ((std::ranges::bidirectional_range<V> && ...))
185 return std::bidirectional_iterator_tag{};
186 else if constexpr ((std::ranges::forward_range<V> && ...))
187 return std::forward_iterator_tag{};
188 else if constexpr ((std::ranges::input_range<V> && ...))
189 return std::input_iterator_tag{};
191 return std::output_iterator_tag{};
195 template <
class... V>
196 using common_iterator_category =
decltype(detail::common_iterator_category<V...>());
199 concept simple_view = std::ranges::view<R> && std::ranges::range<const R> &&
200 std::same_as<std::ranges::iterator_t<R>, std::ranges::iterator_t<const R>> &&
201 std::same_as<std::ranges::sentinel_t<R>,
202 std::ranges::sentinel_t<const R>>;
204 struct as_sentinel_t {};
205 constexpr inline as_sentinel_t as_sentinel;
207 template <
bool Const,
class T>
208 using maybe_const = std::conditional_t<Const, const T, T>;
210 template <std::destructible T>
211 class basic_mixin :
protected T {
213 constexpr basic_mixin()
214 noexcept(std::is_nothrow_default_constructible<T>::value)
215 requires std::default_initializable<T> :
217 constexpr basic_mixin(
const T& t)
218 noexcept(std::is_nothrow_copy_constructible<T>::value)
219 requires std::copy_constructible<T> :
221 constexpr basic_mixin(T&& t)
222 noexcept(std::is_nothrow_move_constructible<T>::value)
223 requires std::move_constructible<T> :
227 constexpr T& get() &
noexcept {
return *
static_cast<T*
>(
this); }
228 constexpr const T& get() const& noexcept {
return *
static_cast<T const*
>(
this); }
229 constexpr T&& get() &&
noexcept {
return std::move(*
static_cast<T*
>(
this)); }
230 constexpr const T&& get() const&& noexcept {
return std::move(*
static_cast<T const*
>(
this)); }
237 static constexpr auto single_pass()
requires requires { { C::single_pass } -> std::convertible_to<bool>; } {
238 return C::single_pass;
240 static constexpr auto single_pass() {
return false; }
242 static constexpr auto contiguous()
requires requires { { C::contiguous } -> std::convertible_to<bool>; } {
243 return C::contiguous;
245 static constexpr auto contiguous() {
return false; }
249 constexpr bool single_pass = detail::tags<C>::single_pass();
252 constexpr bool tagged_contiguous = detail::tags<C>::contiguous();
256 struct deduced_mixin_t {
257 template <
class T>
static auto deduce(
int)->
typename T::mixin;
258 template <
class T>
static auto deduce(...)->tl::basic_mixin<
T>;
259 using type =
decltype(deduce<C>(0));
264 using mixin_t =
typename detail::deduced_mixin_t<C>::type;
268 requires(
const C&
c) {
c.read(); }
269 using reference_t =
decltype(std::declval<const C&>().read());
273 struct deduced_value_t {
274 template<
class T>
static auto deduce(
int)->
typename T::value_type;
275 template<
class T>
static auto deduce(...)->std::decay_t<reference_t<T>>;
277 using type =
decltype(deduce<C>(0));
282 requires std::same_as<typename detail::deduced_value_t<C>::type, std::decay_t<typename detail::deduced_value_t<C>::type>>
283 using value_type_t =
typename detail::deduced_value_t<C>::type;
287 struct deduced_difference_t {
288 template <
class T>
static auto deduce(
int)->
typename T::difference_type;
290 static auto deduce(
long)->decltype(std::declval<const T&>().distance_to(std::declval<const T&>()));
292 static auto deduce(...)->std::ptrdiff_t;
294 using type =
decltype(deduce<C>(0));
299 using difference_type_t =
typename detail::deduced_difference_t<C>::type;
302 concept cursor = std::semiregular<std::remove_cv_t<C>>
303 && std::semiregular<mixin_t<std::remove_cv_t<C>>>
304 &&
requires {
typename difference_type_t<C>; };
307 concept readable = cursor<C> &&
requires(
const C &
c) {
309 typename reference_t<C>;
310 typename value_type_t<C>;
314 concept arrow = readable<C>
315 &&
requires(
const C &
c) {
c.arrow(); };
317 template <
class C,
class T>
318 concept writable = cursor<C>
319 &&
requires(C &
c,
T &&
t) {
c.write(std::forward<T>(t)); };
321 template <
class S,
class C>
322 concept sentinel_for = cursor<C> && std::semiregular<S>
323 &&
requires(
const C &
c,
const S &
s) { {
c.equal(s)} -> std::same_as<bool>; };
325 template <
class S,
class C>
326 concept sized_sentinel_for = sentinel_for<S, C> &&
327 requires(
const C &
c,
const S &
s) {
328 {
c.distance_to(s)} -> std::same_as<difference_type_t<C>>;
332 concept next = cursor<C> &&
requires(C &
c) {
c.next(); };
335 concept prev = cursor<C> &&
requires(C &
c) {
c.prev(); };
338 concept advance = cursor<C>
339 &&
requires(C &
c, difference_type_t<C>
n) {
c.advance(n); };
342 concept indirect_move = readable<C>
343 &&
requires(
const C &
c) {
c.indirect_move(); };
345 template <
class C,
class O>
346 concept indirect_swap = readable<C> && readable<O>
347 &&
requires(
const C &
c,
const O & o) {
353 concept input = readable<C> && next<C>;
355 concept forward = input<C> && sentinel_for<C, C> && !single_pass<C>;
357 concept bidirectional = forward<C> && prev<C>;
359 concept random_access = bidirectional<C> && advance<C> && sized_sentinel_for<C, C>;
361 concept contiguous = random_access<C> && tagged_contiguous<C> && std::is_reference_v<reference_t<C>>;
364 constexpr auto cpp20_iterator_category() {
365 if constexpr (contiguous<C>)
366 return std::contiguous_iterator_tag{};
367 else if constexpr (random_access<C>)
368 return std::random_access_iterator_tag{};
369 else if constexpr (bidirectional<C>)
370 return std::bidirectional_iterator_tag{};
371 else if constexpr (forward<C>)
372 return std::forward_iterator_tag{};
374 return std::input_iterator_tag{};
377 using cpp20_iterator_category_t =
decltype(cpp20_iterator_category<C>());
384 struct not_a_cpp17_iterator {};
387 concept reference_is_value_type_ref =
388 (std::same_as<reference_t<C>, value_type_t<C>&> || std::same_as<reference_t<C>, value_type_t<C>
const&>);
391 concept can_create_postincrement_proxy =
392 (std::move_constructible<value_type_t<C>> && std::constructible_from<value_type_t<C>, reference_t<C>>);
395 constexpr auto cpp17_iterator_category() {
396 if constexpr (random_access<C>
397#if !defined(__NVCOMPILER)
400 && reference_is_value_type_ref<C>
403 return std::random_access_iterator_tag{};
404 else if constexpr (bidirectional<C> && reference_is_value_type_ref<C>)
405 return std::bidirectional_iterator_tag{};
406 else if constexpr (forward<C> && reference_is_value_type_ref<C>)
407 return std::forward_iterator_tag{};
408 else if constexpr (can_create_postincrement_proxy<C>)
409 return std::input_iterator_tag{};
411 return not_a_cpp17_iterator{};
414 using cpp17_iterator_category_t =
decltype(cpp17_iterator_category<C>());
423 template <cursor C,
class category = cpp17_iterator_category_t<C>>
424 struct associated_types_category_base {
425 using iterator_category = category;
428 struct associated_types_category_base<C, not_a_cpp17_iterator> {};
431 struct associated_types : associated_types_category_base<C> {
432 using iterator_concept = cpp20_iterator_category_t<C>;
433 using value_type = cursor::value_type_t<C>;
434 using difference_type = cursor::difference_type_t<C>;
435 using reference = cursor::reference_t<C>;
442 struct is_writable_cursor {
443 template <readable T>
444 requires requires (C
c) {
447 static auto deduce()->std::true_type;
449 template <readable T>
450 static auto deduce()->std::false_type;
453 static auto deduce()->std::true_type;
455 static constexpr bool value =
decltype(deduce<C>())::value;
462 struct post_increment_proxy {
468 constexpr post_increment_proxy(U&& t)
469 : cache_(std::forward<U>(
t))
479 template <cursor::input C>
480 class basic_iterator :
481 public cursor::mixin_t<C>
484 using mixin = cursor::mixin_t<C>;
486 constexpr auto& cursor() noexcept {
return this->mixin::get(); }
487 constexpr auto const& cursor() const noexcept {
return this->mixin::get(); }
489 template <cursor::input>
490 friend class basic_iterator;
493 using reference_t =
decltype(std::declval<C>().read());
494 using const_reference_t = reference_t;
499 using value_type = cursor::value_type_t<C>;
500 using difference_type = cursor::difference_type_t<C>;
501 using reference = cursor::reference_t<C>;
503 basic_iterator() =
default;
507 constexpr explicit basic_iterator(C&& c)
508 noexcept(std::is_nothrow_constructible_v<mixin, C&&>) :
509 mixin(std::move(
c)) {}
512 constexpr explicit basic_iterator(C
const& c)
513 noexcept(std::is_nothrow_constructible_v<mixin, C const&>) :
516 template <std::convertible_to<C> O>
517 constexpr basic_iterator(basic_iterator<O>&& that)
518 noexcept(std::is_nothrow_constructible<mixin, O&&>::value) :
519 mixin(that.cursor()) {}
521 template <std::convertible_to<C> O>
522 constexpr basic_iterator(
const basic_iterator<O>& that)
523 noexcept(std::is_nothrow_constructible<mixin, const O&>::value) :
524 mixin(std::move(that.cursor())) {}
526 template <std::convertible_to<C> O>
527 constexpr basic_iterator& operator=(basic_iterator<O>&& that) &
528 noexcept(std::is_nothrow_assignable<C&, O&&>::value) {
529 cursor() = std::move(that.cursor());
533 template <std::convertible_to<C> O>
534 constexpr basic_iterator& operator=(
const basic_iterator<O>& that) &
535 noexcept(std::is_nothrow_assignable<C&, const O&>::value) {
536 cursor() = that.cursor();
542 (!std::same_as<std::decay_t<T>, basic_iterator> &&
544 cursor::writable<C, T>)
545 constexpr basic_iterator&
operator=(T&& t) &
546 noexcept(
noexcept(std::declval<C&>().write(
static_cast<T&&
>(t)))) {
547 cursor() = std::forward<T>(t);
551 friend constexpr decltype(
auto) iter_move(
const basic_iterator& i)
552#if !defined(__NVCOMPILER)
553 noexcept(
noexcept(
i.cursor().indirect_move()))
555 requires cursor::indirect_move<C> {
556 return i.cursor().indirect_move();
560 requires cursor::indirect_swap<C, O>
561 friend constexpr void iter_swap(
562 const basic_iterator& x,
const basic_iterator<O>& y)
563#if !defined(__NVCOMPILER)
564 noexcept(
noexcept((void)
x.indirect_swap(y)))
571 constexpr decltype(
auto)
operator*()
const
572 noexcept(
noexcept(std::declval<const C&>().read()))
573 requires (cursor::readable<C> && !cursor::detail::is_writable_cursor<C>::value) {
574 return cursor().read();
578 constexpr decltype(
auto)
operator*()
579 noexcept(
noexcept(reference_t{ cursor() }))
580 requires (cursor::next<C>&& cursor::detail::is_writable_cursor<C>::value) {
581 return reference_t{ cursor() };
585 constexpr decltype(
auto)
operator*()
const
587 const_reference_t{ cursor() }))
588 requires (cursor::next<C>&& cursor::detail::is_writable_cursor<C>::value) {
589 return const_reference_t{ cursor() };
592 constexpr basic_iterator&
operator*() noexcept
593 requires (!cursor::next<C>) {
598 constexpr decltype(
auto) operator->() const
599 noexcept(noexcept(cursor().arrow()))
600 requires cursor::arrow<C> {
601 return cursor().arrow();
604 constexpr decltype(
auto) operator->() const
605 noexcept(noexcept(*std::declval<const basic_iterator&>()))
606 requires (cursor::readable<C> && !cursor::arrow<C>)
607 && std::is_lvalue_reference<const_reference_t>::value{
608 return std::addressof(**
this);
612 constexpr basic_iterator& operator++() &
noexcept {
615 constexpr basic_iterator& operator++() &
616 noexcept(
noexcept(std::declval<basic_iterator>().cursor().next()))
617 requires cursor::next<C> {
624 constexpr auto operator++(
int) &
625 noexcept(
noexcept(++std::declval<basic_iterator&>()) &&
626 std::is_nothrow_move_constructible_v<value_type>&&
627 std::is_nothrow_constructible_v<value_type, reference>)
628 requires (cursor::single_pass<C>&&
629 std::move_constructible<value_type>&&
630 std::constructible_from<value_type, reference>) {
631 detail::post_increment_proxy<value_type>
p(**
this);
637 constexpr void operator++(
int) &
638 noexcept(
noexcept(++std::declval<basic_iterator&>()))
639 requires (cursor::single_pass<C> && !(std::move_constructible<value_type>&&
640 std::constructible_from<value_type, reference>)) {
645 constexpr basic_iterator operator++(
int) &
646 noexcept(std::is_nothrow_copy_constructible_v<C>&&
647 std::is_nothrow_move_constructible_v<C> &&
648 noexcept(++std::declval<basic_iterator&>()))
649 requires (!cursor::single_pass<C>) {
655 constexpr basic_iterator& operator--() &
656 noexcept(
noexcept(cursor().prev()))
657 requires cursor::bidirectional<C> {
665 constexpr basic_iterator operator--(
int) &
666 noexcept(std::is_nothrow_copy_constructible<basic_iterator>::value&&
667 std::is_nothrow_move_constructible<basic_iterator>::value &&
668 noexcept(--std::declval<basic_iterator&>()))
669 requires cursor::bidirectional<C> {
675 constexpr basic_iterator&
operator+=(difference_type n) &
676 noexcept(
noexcept(cursor().advance(n)))
677 requires cursor::random_access<C> {
682 constexpr basic_iterator&
operator-=(difference_type n) &
683 noexcept(
noexcept(cursor().advance(-n)))
684 requires cursor::random_access<C> {
685 cursor().advance(-n);
689 constexpr decltype(
auto)
operator[](difference_type n)
const
690 noexcept(
noexcept(*(std::declval<basic_iterator&>() +
n)))
691 requires cursor::random_access<C> {
696 friend constexpr difference_type
operator-(
697 const basic_iterator& x,
const basic_iterator& y)
698 noexcept(
noexcept(
y.cursor().distance_to(
x.cursor())))
699 requires cursor::sized_sentinel_for<C, C> {
700 return y.cursor().distance_to(
x.cursor());
703 const basic_iterator& x,
const basic_iterator& y)
704#if !defined(__NVCOMPILER)
705 noexcept(
noexcept(
x.cursor().equal(
y.cursor())))
706 requires cursor::sentinel_for<C, C>
709 return x.cursor().equal(
y.cursor());
712 const basic_iterator& x,
const basic_iterator& y)
713#if !defined(__NVCOMPILER)
714 noexcept(
noexcept(!(
x ==
y)))
715 requires cursor::sentinel_for<C, C>
721 const basic_iterator& x,
const basic_iterator& y)
722#if !defined(__NVCOMPILER)
723 noexcept(
noexcept(
y -
x))
725 requires cursor::sized_sentinel_for<C, C> {
728 friend constexpr bool operator>(
729 const basic_iterator& x,
const basic_iterator& y)
730#if !defined(__NVCOMPILER)
731 noexcept(
noexcept(
y -
x))
733 requires cursor::sized_sentinel_for<C, C> {
736 friend constexpr bool operator<=(
737 const basic_iterator& x,
const basic_iterator& y)
738#if !defined(__NVCOMPILER)
739 noexcept(
noexcept(
y -
x))
741 requires cursor::sized_sentinel_for<C, C> {
744 friend constexpr bool operator>=(
745 const basic_iterator& x,
const basic_iterator& y)
746#if !defined(__NVCOMPILER)
747 noexcept(
noexcept(
y -
x))
749 requires cursor::sized_sentinel_for<C, C> {
756 struct is_basic_iterator {
758 static auto deduce(basic_iterator<T>
const&)->std::true_type;
760 static auto deduce(...)->std::false_type;
761 static constexpr inline bool value =
decltype(deduce(std::declval<C>()))::value;
768 const basic_iterator<C>& i, cursor::difference_type_t<C> n)
769 noexcept(std::is_nothrow_copy_constructible<basic_iterator<C>>::value&&
770 std::is_nothrow_move_constructible<basic_iterator<C>>::value &&
771 noexcept(std::declval<basic_iterator<C>&>() += n))
772 requires cursor::random_access<C> {
779 cursor::difference_type_t<C> n,
const basic_iterator<C>& i)
780 noexcept(
noexcept(
i +
n))
781 requires cursor::random_access<C> {
787 const basic_iterator<C>& i, cursor::difference_type_t<C> n)
788 noexcept(
noexcept(
i + (-
n)))
789 requires cursor::random_access<C> {
792 template <
class C1,
class C2>
793 requires cursor::sized_sentinel_for<C1, C2>
794 constexpr cursor::difference_type_t<C2>
operator-(
795 const basic_iterator<C1>& lhs,
const basic_iterator<C2>& rhs)
797 rhs.get().distance_to(lhs.get()))) {
798 return rhs.get().distance_to(lhs.get());
800 template <
class C,
class S>
801 requires cursor::sized_sentinel_for<S, C>
802 constexpr cursor::difference_type_t<C>
operator-(
803 const S& lhs,
const basic_iterator<C>& rhs)
804 noexcept(
noexcept(
rhs.get().distance_to(lhs))) {
805 return rhs.get().distance_to(lhs);
807 template <
class C,
class S>
808 requires cursor::sized_sentinel_for<S, C>
809 constexpr cursor::difference_type_t<C>
operator-(
810 const basic_iterator<C>& lhs,
const S& rhs)
811 noexcept(
noexcept(-(
rhs - lhs))) {
815 template <
class C1,
class C2>
816 requires cursor::sentinel_for<C2, C1>
818 const basic_iterator<C1>& lhs,
const basic_iterator<C2>& rhs)
819 noexcept(
noexcept(lhs.get().equal(
rhs.get()))) {
820 return lhs.get().equal(
rhs.get());
822 template <
class C,
class S>
823 requires cursor::sentinel_for<S, C>
825 const basic_iterator<C>& lhs,
const S& rhs)
826 noexcept(
noexcept(lhs.get().equal(rhs))) {
827 return lhs.get().equal(rhs);
829 template <
class C,
class S>
830 requires cursor::sentinel_for<S, C>
832 const S& lhs,
const basic_iterator<C>& rhs)
833 noexcept(
noexcept(
rhs == lhs)) {
837 template <
class C1,
class C2>
838 requires cursor::sentinel_for<C2, C1>
840 const basic_iterator<C1>& lhs,
const basic_iterator<C2>& rhs)
841 noexcept(
noexcept(!(lhs ==
rhs))) {
842 return !(lhs ==
rhs);
844 template <
class C,
class S>
845 requires cursor::sentinel_for<S, C>
847 const basic_iterator<C>& lhs,
const S& rhs)
848 noexcept(
noexcept(!lhs.get().equal(rhs))) {
849 return !lhs.get().equal(rhs);
851 template <
class C,
class S>
852 requires cursor::sentinel_for<S, C>
854 const S& lhs,
const basic_iterator<C>& rhs)
855 noexcept(
noexcept(!
rhs.get().equal(lhs))) {
856 return !
rhs.get().equal(lhs);
859 template <
class C1,
class C2>
860 requires cursor::sized_sentinel_for<C1, C2>
862 const basic_iterator<C1>& lhs,
const basic_iterator<C2>& rhs)
863 noexcept(
noexcept(lhs -
rhs < 0)) {
864 return (lhs - rhs) < 0;
867 template <
class C1,
class C2>
868 requires cursor::sized_sentinel_for<C1, C2>
869 constexpr bool operator>(
870 const basic_iterator<C1>& lhs,
const basic_iterator<C2>& rhs)
871 noexcept(
noexcept((lhs -
rhs) > 0)) {
872 return (lhs - rhs) > 0;
875 template <
class C1,
class C2>
876 requires cursor::sized_sentinel_for<C1, C2>
877 constexpr bool operator<=(
878 const basic_iterator<C1>& lhs,
const basic_iterator<C2>& rhs)
879 noexcept(
noexcept((lhs -
rhs) <= 0)) {
880 return (lhs - rhs) <= 0;
883 template <
class C1,
class C2>
884 requires cursor::sized_sentinel_for<C1, C2>
885 constexpr bool operator>=(
886 const basic_iterator<C1>& lhs,
const basic_iterator<C2>& rhs)
887 noexcept(
noexcept((lhs -
rhs) >= 0)) {
888 return (lhs - rhs) >= 0;
891 template <
class V,
bool Const>
892 class basic_sentinel {
893 using Base = std::conditional_t<Const, const V, V>;
896 std::ranges::sentinel_t<Base> end_{};
897 basic_sentinel() =
default;
898 constexpr explicit basic_sentinel(std::ranges::sentinel_t<Base> end)
899 : end_{ std::move(end) } {}
901 constexpr basic_sentinel(basic_sentinel<V, !Const> other)
requires Const&& std::
902 convertible_to<std::ranges::sentinel_t<V>,
903 std::ranges::sentinel_t<Base>>
904 : end_{ std::move(other.end_) } {}
906 constexpr auto end()
const {
910 friend class basic_sentinel<V, !Const>;
914 template <
class F,
class G>
916 [[no_unique_address]] F
f;
917 [[no_unique_address]]
G g;
919 template <
class A,
class B>
920 compose_fn(A&& a, B&& b) :
f(std::forward<A>(
a)), g(std::forward<B>(
b)) {}
922 template <
class A,
class B,
class ... Args>
923 static constexpr auto call(A&& a, B&& b, Args&&... args) {
924 if constexpr (std::is_void_v<std::invoke_result_t<
G, Args...>>) {
925 std::invoke(std::forward<B>(b), std::forward<Args>(args)...);
926 return std::invoke(std::forward<A>(a));
929 return std::invoke(std::forward<A>(a), std::invoke(std::forward<B>(b), std::forward<Args>(args)...));
933 template <
class... Args>
934 constexpr auto operator()(Args&&... args) & {
935 return call(f, g, std::forward<Args>(args)...);
938 template <
class... Args>
939 constexpr auto operator()(Args&&... args)
const& {
940 return call(f, g, std::forward<Args>(args)...);
943 template <
class... Args>
944 constexpr auto operator()(Args&&... args)&& {
945 return call(std::move(f), std::move(g), std::forward<Args>(args)...);
948 template <
class... Args>
949 constexpr auto operator()(Args&&... args)
const&& {
950 return call(std::move(f), std::move(g), std::forward<Args>(args)...);
954 template <
class F,
class G>
955 constexpr auto compose(F&& f, G&& g) {
956 return compose_fn<std::remove_cvref_t<F>, std::remove_cvref_t<G>>(std::forward<F>(f), std::forward<G>(g));
962 struct pipeable_base {};
964 concept is_pipeable = std::is_base_of_v<pipeable_base, std::remove_cvref_t<T>>;
967 struct pipeable_fn : pipeable_base {
968 [[no_unique_address]] F f_;
970 constexpr pipeable_fn(F f) : f_(std::move(
f)) {}
972 template <
class... Args>
973 constexpr auto operator()(Args&&... args)
const requires std::invocable<F, Args...> {
974 return std::invoke(f_, std::forward<Args>(args)...);
979 constexpr auto pipeable(F f) {
980 return pipeable_fn{ std::move(f) };
983 template <
class V,
class Pipe>
984 constexpr auto operator|(V&& v, Pipe&& fn)
985 requires (!is_pipeable<V> && is_pipeable<Pipe> && std::invocable<Pipe, V>) {
986 return std::invoke(std::forward<Pipe>(fn).f_, std::forward<V>(v));
989 template <
class Pipe1,
class Pipe2>
990 constexpr auto operator|(Pipe1&& p1, Pipe2&& p2)
991 requires (is_pipeable<Pipe1>&& is_pipeable<Pipe2>) {
992 return pipeable(
compose(std::forward<Pipe2>(p2).f_, std::forward<Pipe1>(p1).f_));
996 template <
class F,
class... Args>
997 constexpr auto bind_back(F&& f, Args&&... args) {
998 return[f_ = std::forward<F>(f), ...args_ = std::forward<Args>(args)]
999 (
auto&&... other_args)
1000 requires std::invocable<F&,
decltype(other_args)..., Args&...> {
1001 return std::invoke(f_, std::forward<
decltype(other_args)>(other_args)..., args_...);
1008 struct iterator_traits<tl::basic_iterator<C>> : tl::cursor::associated_types<C> {};
1013 template <
class Tuple>
1014 constexpr inline std::size_t tuple_size = std::tuple_size_v<std::remove_cvref_t<Tuple>>;
1016 template <std::
size_t N>
1017 using index_constant = std::integral_constant<std::size_t, N>;
1021 template <
template <
class...>
class T,
class... Args>
1023 template <
class... MoreArgs>
1025 using type =
T<Args..., MoreArgs...>;
1030 template <
class T,
template<
class...>
class Into, std::size_t... Idx>
1031 constexpr auto repeat_into_impl(std::index_sequence<Idx...>)
1032 ->Into <
typename decltype((Idx, std::type_identity<T>{}))::type... > ;
1036 template <
class T, std::size_t
N,
template <
class...>
class Into>
1037 using repeat_into =
decltype(tl::meta::detail::repeat_into_impl<T,Into>(std::make_index_sequence<N>{}));
1042 template<
class... Ts>
1043 struct tuple_or_pair_impl : std::type_identity<std::tuple<Ts...>> {};
1044 template<
class Fst,
class Snd>
1045 struct tuple_or_pair_impl<Fst, Snd> : std::type_identity<std::pair<Fst, Snd>> {};
1047 template<
class... Ts>
1048 using tuple_or_pair =
typename detail::tuple_or_pair_impl<Ts...>::type;
1050 template <
class Tuple>
1051 constexpr auto min_tuple(Tuple&& tuple) {
1052 return std::apply([](
auto... sizes) {
1053 return std::ranges::min({
1054 std::common_type_t<
decltype(sizes)...>(sizes)...
1056 }, std::forward<Tuple>(tuple));
1059 template <
class Tuple>
1060 constexpr auto max_tuple(Tuple&& tuple) {
1061 return std::apply([](
auto... sizes) {
1062 return std::ranges::max({
1063 std::common_type_t<
decltype(sizes)...>(sizes)...
1065 }, std::forward<Tuple>(tuple));
1069 template<
class F,
class... Tuples>
1070 constexpr auto tuple_transform(F&& f, Tuples&&... tuples)
1072 if constexpr (
sizeof...(Tuples) > 1) {
1073 auto call_at_index = []<std::size_t Idx,
class Fu, class... Ts>
1074 (tl::index_constant<Idx>, Fu
f, Ts&&... tuples) {
1075 return f(std::get<Idx>(std::forward<Ts>(tuples))...);
1078 constexpr auto min_size = tl::min_tuple(std::tuple(tl::tuple_size<Tuples>...));
1080 return[&] <std::size_t... Idx>(std::index_sequence<Idx...>) {
1081 return tuple_or_pair < std::decay_t<
decltype(call_at_index(tl::index_constant<Idx>{}, std::move(f), std::forward<Tuples>(tuples)...)) > ... >
1082 (call_at_index(tl::index_constant<Idx>{}, std::move(f), std::forward<Tuples>(tuples)...)...);
1083 }(std::make_index_sequence<min_size>{});
1085 else if constexpr (
sizeof...(Tuples) == 1) {
1086 return std::apply([&]<
class... Ts>(Ts&&... elements) {
1087 return tuple_or_pair<std::invoke_result_t<F&, Ts>...>(
1088 std::invoke(f, std::forward<Ts>(elements))...
1090 }, std::forward<Tuples>(tuples)...);
1093 return std::tuple{};
1098 template<
class F,
class Tuple>
1099 constexpr auto tuple_for_each(F&& f, Tuple&& tuple)
1101 return std::apply([&]<
class... Ts>(Ts&&... elements) {
1102 (std::invoke(f, std::forward<Ts>(elements)), ...);
1103 }, std::forward<Tuple>(tuple));
1106 template <
class Tuple>
1107 constexpr auto tuple_pop_front(Tuple&& tuple) {
1108 return std::apply([](
auto&& head,
auto&&... tail) {
1109 return std::pair(std::forward<
decltype(head)>(head), std::tuple(std::forward<
decltype(tail)>(tail)...));
1110 }, std::forward<Tuple>(tuple));
1114 template <
class F,
class V>
1115 constexpr auto tuple_fold_impl(F, V v) {
1118 template <
class F,
class V,
class Arg,
class... Args>
1119 constexpr auto tuple_fold_impl(F f, V v, Arg arg, Args&&... args) {
1120 return tl::detail::tuple_fold_impl(f,
1121 std::invoke(f, std::move(v), std::move(arg)),
1122 std::forward<Args>(args)...);
1126 template <
class F,
class T,
class Tuple>
1127 constexpr auto tuple_fold(Tuple tuple, T t, F f) {
1128 return std::apply([&](
auto&&... args) {
1129 return tl::detail::tuple_fold_impl(std::move(f), std::move(t), std::forward<
decltype(args)>(args)...);
1130 }, std::forward<Tuple>(tuple));
1133 template<
class... Tuples>
1134 constexpr auto tuple_zip(Tuples&&... tuples) {
1135 auto zip_at_index = []<std::size_t Idx,
class... Ts>
1136 (tl::index_constant<Idx>, Ts&&... tuples) {
1137 return tuple_or_pair<std::decay_t<decltype(std::get<Idx>(std::forward<Ts>(tuples)))>...>(std::get<Idx>(std::forward<Ts>(tuples))...);
1140 constexpr auto min_size = tl::min_tuple(std::tuple(tl::tuple_size<Tuples>...));
1142 return[&] <std::size_t... Idx>(std::index_sequence<Idx...>) {
1143 return tuple_or_pair<std::decay_t<
decltype(zip_at_index(tl::index_constant<Idx>{}, std::forward<Tuples>(tuples)...))>... >
1144 (zip_at_index(tl::index_constant<Idx>{}, std::forward<Tuples>(tuples)...)...);
1145 }(std::make_index_sequence<min_size>{});
1148 template <std::ranges::forward_range... Vs>
1149 requires (std::ranges::view<Vs> && ...)
class cartesian_product_view
1150 :
public std::ranges::view_interface<cartesian_product_view<Vs...>> {
1153 template <
class... Ts>
1154 static constexpr bool am_common = (std::ranges::common_range<Ts> && ...)
1155 || ((std::ranges::random_access_range<Ts> && ...) && (std::ranges::sized_range<Ts> && ...));
1157 template <
class... Ts>
1158 static constexpr bool am_sized = (std::ranges::sized_range<Ts> && ...);
1161 template <
class... Ts>
1162 static constexpr bool am_bidirectional =
1163 ((std::ranges::bidirectional_range<Ts> && ...) && (std::ranges::common_range<Ts> && ...));
1166 template <
class... Ts>
1167 static constexpr bool am_random_access =
1168 ((std::ranges::random_access_range<Ts> && ...) &&
1169 (std::ranges::sized_range<Ts> && ...));
1171 template <
class... Ts>
1172 static constexpr bool am_distanceable =
1173 ((std::sized_sentinel_for<std::ranges::iterator_t<Ts>, std::ranges::iterator_t<Ts>>) && ...)
1176 std::tuple<Vs...> bases_;
1178 template <
bool Const>
1184 template <
bool Const>
1186 using parent = std::conditional_t<Const, const cartesian_product_view, cartesian_product_view>;
1187 using first_base =
decltype(std::get<0>(std::declval<parent>().bases_));
1188 std::ranges::sentinel_t<first_base> end_;
1191 sentinel() =
default;
1192 sentinel(std::ranges::sentinel_t<first_base> end) : end_(std::move(end)) {}
1195 constexpr sentinel(sentinel<!Const> other)
requires Const &&
1196 (std::convertible_to<std::ranges::sentinel_t<first_base>, std::ranges::sentinel_t<const first_base>>)
1197 : end_(std::move(other.end_)) {
1201 friend class cursor;
1204 template <
bool Const>
1207 using constify = std::conditional_t<Const, const T, T>;
1210 using intify = std::conditional_t<true, std::int64_t, T>;
1213 std::tuple<std::ranges::iterator_t<constify<Vs>>...> currents_{};
1214 std::tuple<std::ranges::iterator_t<constify<Vs>>...> begins_{};
1215 std::tuple<std::ranges::sentinel_t<constify<Vs>>...> ends_{};
1216 std::tuple<intify<Vs>...> counts_{};
1221 std::tuple<std::ranges::range_reference_t<constify<Vs>>...>;
1223 std::tuple<std::ranges::range_value_t<constify<Vs>>...>;
1225 using difference_type = std::ptrdiff_t;
1228 constexpr explicit cursor(constify<std::tuple<Vs...>>* bases)
1229 : currents_( tl::tuple_transform(std::ranges::begin, *bases) )
1230 , begins_( currents_ )
1231 , ends_( tl::tuple_transform(std::ranges::end, *bases) )
1232 , counts_( tl::tuple_transform(std::ranges::
size, *bases) )
1237 constexpr explicit cursor(as_sentinel_t, constify<std::tuple<Vs...>>* bases)
1238 requires(std::ranges::common_range<Vs> && ...)
1241 std::get<0>(currents_) = std::get<0>(ends_);
1245 constexpr explicit cursor(as_sentinel_t, constify<std::tuple<Vs...>>* bases)
1246 requires(!(std::ranges::common_range<Vs> && ...) && (std::ranges::random_access_range<Vs> && ...) && (std::ranges::sized_range<Vs> && ...))
1249 std::get<0>(currents_) += std::ranges::size(std::ranges::subrange(std::get<0>(begins_), std::get<0>(ends_)));
1253 constexpr cursor(cursor<!Const> i)
requires Const && (std::convertible_to<
1254 std::ranges::iterator_t<Vs>,
1255 std::ranges::iterator_t<constify<Vs>>> && ...)
1256 : currents_{ std::move(
i.currents_) } {}
1259 constexpr decltype(
auto) read()
const {
1260 return tuple_transform([](
auto& i) ->
decltype(
auto) {
return *
i; }, currents_);
1263 template <std::size_t
N = (
sizeof...(Vs) - 1)>
1264 void update(
int idx) {
1265 if constexpr(
N == 0)
1266 std::get<N>(currents_) = idx + std::get<N>(begins_);
1268 std::get<N>(currents_) = idx % std::get<N>(counts_) + std::get<N>(begins_);
1269 if constexpr (
N > 0) {
1270 idx /= std::get<N>(counts_);
1283 void prev()
requires (am_bidirectional<constify<Vs>...>) {
1287 void advance(difference_type n)
requires (am_random_access<constify<Vs>...>) {
1292 constexpr bool equal(
const cursor& rhs)
const
1293#if !defined(__NVCOMPILER)
1294 requires (std::equality_comparable<std::ranges::iterator_t<constify<Vs>>> && ...)
1297 return currents_ ==
rhs.currents_;
1300 constexpr bool equal(
const sentinel<Const>& s)
const {
1301 return std::get<0>(currents_) ==
s.end_;
1304 template <std::size_t
N = (
sizeof...(Vs) - 1)>
1305 constexpr auto distance_to(cursor
const& other)
const
1306 requires (am_distanceable<constify<Vs>...>) {
1307 if constexpr (
N == 0) {
1308 return std::ranges::distance(std::get<0>(currents_), std::get<0>(other.currents_));
1311 auto distance = distance_to<
N - 1>(other);
1312 auto scale = std::ranges::distance(std::get<N>(begins_), std::get<N>(ends_));
1313 auto diff = std::ranges::distance(std::get<N>(currents_), std::get<N>(other.currents_));
1314#if !defined(__NVCOMPILER)
1315 return difference_type{ distance *
scale +
diff };
1317 return static_cast<difference_type
>(distance *
scale +
diff);
1322 friend class cursor<!Const>;
1326 cartesian_product_view() =
default;
1327 explicit cartesian_product_view(Vs... bases) : bases_(std::move(bases)...) {}
1329 constexpr auto begin()
requires (!(simple_view<Vs> && ...)) {
1330 return basic_iterator{ cursor<false>(std::addressof(bases_)) };
1332 constexpr auto begin() const requires (std::ranges::range<const Vs> && ...) {
1333 return basic_iterator{ cursor<true>(std::addressof(bases_)) };
1336 constexpr auto end()
requires (!(simple_view<Vs> && ...) && am_common<Vs...>) {
1337 return basic_iterator{ cursor<false>(as_sentinel, std::addressof(bases_)) };
1340 constexpr auto end() const requires (am_common<const Vs...>) {
1341 return basic_iterator{ cursor<true>(as_sentinel, std::addressof(bases_)) };
1344 constexpr auto end()
requires(!(simple_view<Vs> && ...) && !am_common<Vs...>) {
1345 return sentinel<false>(std::ranges::end(std::get<0>(bases_)));
1348 constexpr auto end() const requires ((std::ranges::range<const Vs> && ...) && !am_common<const Vs...>) {
1349 return sentinel<true>(std::ranges::end(std::get<0>(bases_)));
1352 constexpr auto size()
requires (am_sized<Vs...>) {
1354 return std::apply([](
auto&&... bases) {
1355 using size_type = std::common_type_t<std::ranges::range_size_t<
decltype(bases)>...>;
1356 return (
static_cast<size_type
>(std::ranges::size(bases)) * ...);
1360 constexpr auto size() const requires (am_sized<const Vs...>) {
1361 return std::apply([](
auto&&... bases) {
1362 using size_type = std::common_type_t<std::ranges::range_size_t<
decltype(bases)>...>;
1363 return (
static_cast<size_type
>(std::ranges::size(bases)) * ...);
1368#ifndef DISABLE_CART_PROD_IOTA_SPEC
1369 template <
typename W,
typename B>
1370 requires std::is_integral_v<W> && std::is_integral_v<B>
1371 class cartesian_product_view<
1372 std::ranges::iota_view<W, B>,
1373 std::ranges::iota_view<W, B>,
1374 std::ranges::iota_view<W, B>
1376 :
public std::ranges::view_interface<
1377 cartesian_product_view<
1378 std::ranges::iota_view<W, B>,
1379 std::ranges::iota_view<W, B>,
1380 std::ranges::iota_view<W, B>
1384 using self = cartesian_product_view<
1385 std::ranges::iota_view<W, B>,
1386 std::ranges::iota_view<W, B>,
1387 std::ranges::iota_view<W, B>
1394 template <
bool Const>
1397 template <
bool Const>
1399 W x_i, y_i, z_i, x_0, y_0, z_0;
1403 using reference = std::tuple<W const&, W const&, W const&>;
1404 using value_type = std::tuple<W, W, W>;
1406 using difference_type = std::ptrdiff_t;
1409 constexpr explicit cursor(
1428 constexpr decltype(
auto) read()
const {
1429 return std::make_tuple<W const&, W const&, W const&>(x_i, y_i, z_i);
1431 constexpr auto linear()
const {
1432 return (z_i - z_0) + nz * (y_i - y_0) + nz * ny * (x_i - x_0);
1435 void advance(difference_type n) {
1436 auto idx = linear() +
n;
1437 x_i = idx / (nz * ny) + x_0;
1438 y_i = (idx / nz) % ny + y_0;
1439 z_i = idx % nz + z_0;
1444 if (z_i == (z_0 + nz)) {
1447 if (y_i == (y_0 + ny)) {
1457 constexpr bool equal(
const cursor& rhs)
const {
1458 return x_i ==
rhs.x_i && y_i ==
rhs.y_i && z_i ==
rhs.z_i;
1461 constexpr auto distance_to(cursor
const& other)
const {
1462 auto idx = linear();
1463 auto oidx = other.linear();
1464 return static_cast<difference_type
>(oidx) -
static_cast<difference_type
>(idx);
1467 friend class cursor<!Const>;
1471 cartesian_product_view() =
default;
1472 constexpr explicit cartesian_product_view(
1473 std::ranges::iota_view<W, B> xs,
1474 std::ranges::iota_view<W, B> ys,
1475 std::ranges::iota_view<W, B> zs
1476 ) : x_b(*std::ranges::begin(xs))
1477 , y_b(*std::ranges::begin(ys))
1478 , z_b(*std::ranges::begin(
zs))
1479 , nx(std::ranges::
size(xs))
1480 , ny(std::ranges::
size(ys))
1481 , nz(std::ranges::
size(
zs))
1484 constexpr auto begin() {
1485 return basic_iterator{ cursor<false>(x_b, y_b, z_b, nx, ny, nz) };
1487 constexpr auto begin()
const {
1488 return basic_iterator{ cursor<true>(x_b, y_b, z_b, nx, ny, nz) };
1491 constexpr auto size() {
1492 return nx * ny * nz;
1495 constexpr auto size()
const {
1496 return nx * ny * nz;
1499 constexpr auto end() {
1500 return begin() +
size();
1503 constexpr auto end()
const {
1504 return begin() +
size();
1508 template <
typename W,
typename B>
1509 requires std::is_integral_v<W> && std::is_integral_v<B>
1510 class cartesian_product_view<
1511 std::ranges::iota_view<W, B>,
1512 std::ranges::iota_view<W, B>
1514 :
public std::ranges::view_interface<
1515 cartesian_product_view<
1516 std::ranges::iota_view<W, B>,
1517 std::ranges::iota_view<W, B>
1521 using self = cartesian_product_view<
1522 std::ranges::iota_view<W, B>,
1523 std::ranges::iota_view<W, B>
1530 template <
bool Const>
1533 template <
bool Const>
1535 W x_i, y_i, x_0, y_0;
1539 using reference = std::tuple<W const&, W const&>;
1540 using value_type = std::tuple<W, W>;
1542 using difference_type = std::ptrdiff_t;
1545 constexpr explicit cursor(
1559 constexpr decltype(
auto) read()
const {
1560 return std::make_tuple<W const&, W const&>(x_i, y_i);
1562 constexpr auto linear()
const {
1563 return (y_i - y_0) + ny * (x_i - x_0);
1566 void advance(difference_type n) {
1567 auto idx = linear() +
n;
1568 x_i = idx / ny + x_0;
1569 y_i = idx % ny + y_0;
1574 if (y_i == (y_0 + ny)) {
1583 constexpr bool equal(
const cursor& rhs)
const {
1584 return x_i ==
rhs.x_i && y_i ==
rhs.y_i;
1587 constexpr auto distance_to(cursor
const& other)
const {
1588 auto idx = linear();
1589 auto oidx = other.linear();
1590 return static_cast<difference_type
>(oidx) -
static_cast<difference_type
>(idx);
1593 friend class cursor<!Const>;
1597 cartesian_product_view() =
default;
1598 constexpr explicit cartesian_product_view(
1599 std::ranges::iota_view<W, B> xs,
1600 std::ranges::iota_view<W, B> ys
1601 ) : x_b(*std::ranges::begin(xs))
1602 , y_b(*std::ranges::begin(ys))
1603 , nx(std::ranges::
size(xs))
1604 , ny(std::ranges::
size(ys))
1607 constexpr auto begin() {
1608 return basic_iterator{ cursor<false>(x_b, y_b, nx, ny) };
1610 constexpr auto begin()
const {
1611 return basic_iterator{ cursor<true>(x_b, y_b, nx, ny) };
1614 constexpr auto size() {
1618 constexpr auto size()
const {
1622 constexpr auto end() {
1623 return begin() +
size();
1626 constexpr auto end()
const {
1627 return begin() +
size();
1632 template <
typename W,
typename B>
1633 requires std::is_integral_v<W> && std::is_integral_v<B>
1634 class cartesian_product_view<
1635 std::ranges::iota_view<W, B>
1637 :
public std::ranges::view_interface<
1638 cartesian_product_view<
1639 std::ranges::iota_view<W, B>
1645 template <
bool Const>
1648 template <
bool Const>
1653 using reference = std::tuple<int const&>;
1654 using value_type = std::tuple<int>;
1656 using difference_type = std::ptrdiff_t;
1659 constexpr explicit cursor(
1666 constexpr decltype(
auto) read()
const {
1667 return std::make_tuple<int const&>(x_i);
1669 void advance(difference_type n) {
1679 constexpr bool equal(
const cursor& rhs)
const {
1680 return x_i ==
rhs.x_i;
1683 constexpr auto distance_to(cursor
const& other)
const {
1684 return static_cast<difference_type
>(other.x_i - x_i);
1687 friend class cursor<!Const>;
1691 cartesian_product_view() =
default;
1692 constexpr explicit cartesian_product_view(
1693 std::ranges::iota_view<W, B> xs
1694 ) : x_i(*std::ranges::begin(xs))
1695 , x_e(*std::ranges::begin(xs) + std::ranges::
size(xs))
1698 constexpr auto begin() {
1699 return basic_iterator{ cursor<false>(x_i, x_e) };
1701 constexpr auto begin()
const {
1702 return basic_iterator{ cursor<true>(x_i, x_e) };
1705 constexpr auto size() {
1709 constexpr auto size()
const {
1713 constexpr auto end() {
1714 return begin() +
size();
1717 constexpr auto end()
const {
1718 return begin() +
size();
1723 template <
class... Rs>
1724 cartesian_product_view(Rs&&...)->cartesian_product_view<std::views::all_t<Rs>...>;
1728 class cartesian_product_fn {
1730 constexpr std::ranges::empty_view<std::tuple<>> operator()() const noexcept {
1733#ifndef DISABLE_CART_PROD_IOTA_SPEC
1734 template <
typename W,
typename B>
1735 constexpr auto operator()(
1736 std::ranges::iota_view<W, B> xs
1738 return tl::cartesian_product_view<
1739 std::ranges::iota_view<W, B>
1743 template <
typename W,
typename B>
1744 constexpr auto operator()(
1745 std::ranges::iota_view<W, B> xs,
1746 std::ranges::iota_view<W, B> ys
1748 return tl::cartesian_product_view<
1749 std::ranges::iota_view<W, B>,
1750 std::ranges::iota_view<W, B>
1751 >{ std::move(xs), std::move(ys) };
1753 template <
typename W,
typename B>
1754 constexpr auto operator()(
1755 std::ranges::iota_view<W, B> xs,
1756 std::ranges::iota_view<W, B> ys,
1757 std::ranges::iota_view<W, B> zs
1759 return tl::cartesian_product_view<
1760 std::ranges::iota_view<W, B>,
1761 std::ranges::iota_view<W, B>,
1762 std::ranges::iota_view<W, B>
1763 >{ std::move(xs), std::move(ys), std::move(zs) };
1767 template <std::ranges::viewable_range... V>
1768 requires ((std::ranges::forward_range<V> && ...) && (
sizeof...(V) != 0))
1769 constexpr auto operator()(V&&... vs)
const {
1770 return tl::cartesian_product_view{ std::views::all(std::forward<V>(vs))... };
1775 inline constexpr detail::cartesian_product_fn cartesian_product;
1785template <std::ranges::forward_range V>
1786 requires std::ranges::view<V>
class stride_view
1787 :
public std::ranges::view_interface<stride_view<V>> {
1791 static constexpr bool am_common = std::ranges::common_range<T> &&
1792 (!std::ranges::bidirectional_range<T> || std::ranges::sized_range<T>);
1794 template <
class T>
static constexpr bool am_sized = std::ranges::sized_range<T>;
1797 std::ranges::range_difference_t<V> stride_size_;
1806 template <
bool Const,
class Base = std::conditional_t<Const, const V, V>,
bool = std::ranges::b
idirectional_range<Base>,
bool = std::ranges::sized_range<Base>>
1807 struct cursor_base {
1808 cursor_base() =
default;
1809 constexpr explicit cursor_base(std::ranges::range_difference_t<Base> offs) {}
1812 void set_offset(std::ranges::range_difference_t<Base> off) {}
1813 std::ranges::range_difference_t<Base> get_offset() {
1819 template <
bool Const,
class Base>
1820 struct cursor_base<Const, Base, true, false> {
1821 using difference_type = std::ranges::range_difference_t<Base>;
1822 difference_type offset_{};
1824 cursor_base() =
default;
1825 constexpr explicit cursor_base(difference_type offset)
1828 void set_offset(difference_type off) {
1832 difference_type get_offset() {
1838 template <
bool Const,
class Base>
1839 struct cursor_base<Const, Base, true, true> {
1840 using difference_type = std::ranges::range_difference_t<Base>;
1841 difference_type offset_{};
1843 cursor_base() =
default;
1844 constexpr explicit cursor_base(difference_type offset)
1848 void set_offset(std::ranges::range_difference_t<Base>) {}
1850 std::ranges::range_difference_t<Base> get_offset() {
1855 template <
bool Const>
1856 struct cursor : cursor_base<Const> {
1858 using constify = std::conditional_t<Const, const T, T>;
1859 using Base = constify<V>;
1861 using difference_type = std::ranges::range_difference_t<Base>;
1863 std::ranges::iterator_t<Base> current_{};
1864 std::ranges::sentinel_t<Base> end_{};
1865 std::ranges::range_difference_t<Base> stride_size_{};
1870 constexpr cursor(std::ranges::iterator_t<Base> begin, Base* base, std::ranges::range_difference_t<Base> stride_size)
1871 requires(std::ranges::sized_range<Base>)
1872 : cursor_base<Const>(stride_size - (std::ranges::
size(*
base) % stride_size)),
1873 current_(std::move(begin)), end_(std::ranges::end(*
base)), stride_size_(stride_size) {}
1875 constexpr cursor(std::ranges::iterator_t<Base> begin, Base* base, std::ranges::range_difference_t<Base> stride_size)
1876 requires(!std::ranges::sized_range<Base>)
1877 : cursor_base<Const>(), current_(std::move(begin)), end_(std::ranges::end(*
base)), stride_size_(stride_size) {}
1880 constexpr cursor(cursor<!Const> i)
requires Const&& std::convertible_to<
1881 std::ranges::iterator_t<V>,
1882 std::ranges::iterator_t<const V>>
1883 : cursor_base<Const>(
i.get_offset()) {}
1885 constexpr decltype(
auto) read()
const {
1889 constexpr void next() {
1890 auto delta = std::ranges::advance(current_, stride_size_, end_);
1893 this->set_offset(delta);
1896 constexpr void prev()
requires std::ranges::bidirectional_range<Base> {
1897 auto delta = -stride_size_;
1899 if (current_ == end_) {
1900 delta += this->get_offset();
1902 std::advance(current_, delta);
1905 constexpr void advance(difference_type x)
1906 requires std::ranges::random_access_range<Base> {
1912 auto delta = std::ranges::advance(current_, x, end_);
1913 this->set_offset(delta);
1916 if (current_ == end_) {
1917 x += this->get_offset();
1919 std::advance(this->current_, x);
1924 constexpr auto distance_to(cursor
const& other)
const
1926 requires (std::sized_sentinel_for<std::ranges::iterator_t<V>, std::ranges::iterator_t<V>>)
1927 && std::ranges::sized_range<V>
1929 auto delta = std::ranges::distance(this->current_, other.current_);
1931 delta -= stride_size_ - 1;
1933 delta += stride_size_ -1;
1934 return delta / stride_size_;
1937 constexpr bool equal(cursor
const& rhs)
const {
1938 return current_ ==
rhs.current_;
1940 constexpr bool equal(basic_sentinel<V, Const>
const& rhs)
const {
1941 return current_ ==
rhs.end_;
1944 friend struct cursor<!Const>;
1948 stride_view() =
default;
1949 stride_view(V v, std::ranges::range_difference_t<V> n) : base_(std::move(
v)), stride_size_(
n) {}
1951 constexpr auto begin()
requires (!simple_view<V>) {
1952 return basic_iterator{ cursor<false>{ std::ranges::begin(base_), std::addressof(base_), stride_size_ } };
1955 constexpr auto begin() const requires (std::ranges::range<const V>) {
1956 return basic_iterator{ cursor<true>{ std::ranges::begin(base_), std::addressof(base_), stride_size_ } };
1959 constexpr auto end()
requires (!simple_view<V>&& am_common<V>) {
1960 return basic_iterator{ cursor<false>(std::ranges::end(base_), std::addressof(base_), stride_size_) };
1963 constexpr auto end() const requires (std::ranges::range<const V>&& am_common<const V>) {
1964 return basic_iterator{ cursor<true>(std::ranges::end(base_), std::addressof(base_), stride_size_) };
1967 constexpr auto end()
requires (!simple_view<V> && !am_common<V>) {
1968 return basic_sentinel<V, false>(std::ranges::end(base_));
1971 constexpr auto end() const requires (std::ranges::range<const V> && !am_common<const V>) {
1972 return basic_sentinel<V, true>(std::ranges::end(base_));
1975 constexpr auto size()
requires (am_sized<V>) {
1976 return (std::ranges::size(base_) + stride_size_ - 1) / stride_size_;
1979 constexpr auto size() const requires (am_sized<const V>) {
1980 return (std::ranges::size(base_) + stride_size_ - 1) / stride_size_;
1987 auto const&
base()
const {
1992 template <
class R,
class N>
1993 stride_view(R&&, N n)->stride_view<std::views::all_t<R>>;
1997 struct stride_fn_base {
1998 template <std::ranges::viewable_range R>
1999 constexpr auto operator()(R&& r, std::ranges::range_difference_t<R> n)
const
2000 requires std::ranges::forward_range<R> {
2001 return stride_view(std::forward<R>(r), n);
2005 struct stride_fn : stride_fn_base {
2006 using stride_fn_base::operator();
2008 template <std::
integral N>
2009 constexpr auto operator()(N n)
const {
2010 return pipeable(bind_back(stride_fn_base{},
n));
2015 constexpr inline detail::stride_fn stride;
2019namespace std::ranges {
2021 inline constexpr bool enable_borrowed_range<tl::stride_view<R>> = enable_borrowed_range<R>;
2029 using tl::cartesian_product_view;
2031 inline constexpr tl::views::detail::cartesian_product_fn cartesian_product;
2032 inline constexpr tl::views::detail::stride_fn stride;
tarch::la::DynamicMatrix operator*(const tarch::la::DynamicMatrix &A, const tarch::la::DynamicMatrix &B)
bool operator==(const exaparty::TaskNumber &lhs, const exaparty::TaskNumber &rhs)
bool operator!=(const exaparty::TaskNumber &lhs, const exaparty::TaskNumber &rhs)
bool operator<(const tarch::multicore::Task &lhs, const tarch::multicore::Task &rhs)
peano4::grid::GridStatistics operator+(peano4::grid::GridStatistics lhs, peano4::grid::GridStatistics rhs)
Matrix< Rows, Cols, Scalar > operator-(const Matrix< Rows, Cols, Scalar > &lhs, const Matrix< Rows, Cols, Scalar > &rhs)
Vector< Size, Scalar > & operator+=(Vector< Size, Scalar > &vector, const Scalar &scalar)
Adds every component of the vector to the scalar and assigns the result to the vector.
Vector< Size, Scalar > & operator-=(Vector< Size, Scalar > &vector, const Scalar &scalar)
Subtracts the scalar from every component of the vector and assigns the result to the vector.