@@ -98,6 +98,20 @@ class cartesian_product_view : public view_interface<cartesian_product_view<Firs
9898 return iterator<true >(*this , __tuple_transform (ranges::begin, bases_));
9999 }
100100
101+ constexpr iterator<false > end ()
102+ requires((!__simple_view<First> || ... || !__simple_view<Vs>) && cartesian_product_is_common<First, Vs...>)
103+ {
104+ constexpr bool is_const = false ;
105+ return end_impl<is_const>();
106+ }
107+
108+ constexpr iterator<true > end () const
109+ requires(cartesian_product_is_common<const First, const Vs...>)
110+ {
111+ constexpr bool is_const = true ;
112+ return end_impl<is_const>();
113+ }
114+
101115 constexpr auto size ()
102116 requires(sized_range<First> && ... && sized_range<Vs>)
103117 {
@@ -111,6 +125,30 @@ class cartesian_product_view : public view_interface<cartesian_product_view<Firs
111125 }
112126
113127private:
128+ template <bool is_const>
129+ constexpr iterator<is_const> end_impl () const {
130+ bool is_empty = end_is_empty ();
131+ const auto ranges_to_iterators = [is_empty, &b = bases_]<std::size_t ... I>(std::index_sequence<I...>) {
132+ const auto begin_or_first_end = [is_empty]<bool is_first>(const auto & rng) {
133+ if constexpr (is_first)
134+ return is_empty ? ranges::begin (rng) : cartesian_common_arg_end (rng);
135+ return ranges::begin (rng);
136+ };
137+ return std::make_tuple (begin_or_first_end<I == 0 >(std::get<I>(b))...);
138+ };
139+ iterator<is_const> it (*this , ranges_to_iterators (std::make_index_sequence<1 + sizeof ...(Vs)>{}));
140+ return it;
141+ }
142+
143+ template <auto N = 0 >
144+ constexpr bool end_is_empty () const {
145+ if constexpr (N == sizeof ...(Vs))
146+ return false ;
147+ if (const auto & v = std::get<N + 1 >(bases_); ranges::empty (v))
148+ return true ;
149+ return end_is_empty<N + 1 >();
150+ }
151+
114152 constexpr auto size_impl () const {
115153 return std::apply (
116154 [](auto &&... bases) {
@@ -332,7 +370,7 @@ class cartesian_product_view<First, Vs...>::iterator {
332370
333371 template <auto N = sizeof ...(Vs)>
334372 constexpr bool at_end () const {
335- if (std::get<N>(current_) == end (std::get<N>(parent_->bases_ )))
373+ if (std::get<N>(current_) == ranges:: end (std::get<N>(parent_->bases_ )))
336374 return true ;
337375 if constexpr (N > 0 )
338376 return at_end<N - 1 >();
0 commit comments