[libcxx-commits] [libcxx] [libc++][c++23] P2374: `views::cartesian_product` (PR #111215)

via libcxx-commits libcxx-commits at lists.llvm.org
Sun Nov 17 07:02:10 PST 2024


https://github.com/PaulXiCao updated https://github.com/llvm/llvm-project/pull/111215

>From 2fc600cd52147cdcf556a4ed922b9d5473f4aecc Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 4 Oct 2024 19:04:39 +0200
Subject: [PATCH 01/39] wip

---
 libcxx/include/CMakeLists.txt                 |  1 +
 .../include/__ranges/cartesian_product_view.h | 95 +++++++++++++++++++
 libcxx/include/ranges                         |  1 +
 .../ctor.pass.cpp                             | 36 +++++++
 .../size.pass.cpp                             | 46 +++++++++
 5 files changed, 179 insertions(+)
 create mode 100644 libcxx/include/__ranges/cartesian_product_view.h
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/ctor.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/size.pass.cpp

diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 938d0bb872e0b5..902904ec390545 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -651,6 +651,7 @@ set(files
   __ranges/access.h
   __ranges/all.h
   __ranges/as_rvalue_view.h
+  __ranges/cartesian_product_view.h
   __ranges/chunk_by_view.h
   __ranges/common_view.h
   __ranges/concepts.h
diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
new file mode 100644
index 00000000000000..46941b9e1c97dd
--- /dev/null
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -0,0 +1,95 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___RANGES_CARTESIAN_PRODUCT_VIEW_H
+#define _LIBCPP___RANGES_CARTESIAN_PRODUCT_VIEW_H
+
+#include <__config>
+#include <__ranges/concepts.h> // forward_range, view, range_size_t, sized_range, ...
+#include <tuple> // apply
+#include <type_traits> // common_type_t
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+#if _LIBCPP_STD_VER >= 23
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+namespace ranges {
+
+template <input_range First, forward_range... Vs>
+  requires(view<First> && ... && view<Vs>)
+class cartesian_product_view : public view_interface<cartesian_product_view<First, Vs...>> {
+private:
+  tuple<First, Vs...> bases_; // exposition only
+
+  template <bool Const>
+  struct iterator; // exposition only
+
+public:
+  constexpr cartesian_product_view() = default;
+  constexpr explicit cartesian_product_view(First first_base, Vs... bases)
+      : bases_{std::move(first_base), std::move(bases)...} {}
+
+  // constexpr iterator<false> begin()
+  //     requires (!simple-view<First> || ... || !simple-view<Vs>)
+  // {
+  //     return move_iterator(ranges::begin(bases_));
+  // }
+
+  // constexpr iterator<true> begin() const
+  //     requires (range<const First> && ... && range<const Vs>)
+  // {
+  //     return move_iterator(ranges::begin(__base_));
+  // }
+
+  // constexpr iterator<false> begin()
+  //   requires (!simple-view<First> || ... || !simple-view<Vs>);
+  // constexpr iterator<true> begin() const
+  //   requires (range<const First> && ... && range<const Vs>);
+
+  // constexpr iterator<false> end()
+  //   requires ((!simple-view<First> || ... || !simple-view<Vs>) &&
+  //     cartesian-product-is-common<First, Vs...>);
+  // constexpr iterator<true> end() const
+  //   requires cartesian-product-is-common<const First, const Vs...>;
+  // constexpr default_sentinel_t end() const noexcept;
+
+  // constexpr see below size()
+  //   requires cartesian-product-is-sized<First, Vs...>;
+  // constexpr see below size() const
+  // requires cartesian-product-is-sized<const First, const Vs...>;
+  constexpr auto size() const 
+    requires(sized_range<const First> && ... && sized_range<const Vs>)
+  {
+    return std::apply(
+        [](auto&&... bases) {
+          using size_type = std::common_type_t<std::ranges::range_size_t<decltype(bases)>...>;
+          return (static_cast<size_type>(std::ranges::size(bases)) * ...);
+        },
+        bases_);
+  }
+};
+
+template <class... Rs>
+cartesian_product_view(Rs&&...) -> cartesian_product_view<std::views::all_t<Rs>...>;
+
+} // namespace ranges
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 23
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___RANGES_CARTESIAN_PRODUCT_VIEW_H
diff --git a/libcxx/include/ranges b/libcxx/include/ranges
index b17a399e0ed65b..2c3b3833b67981 100644
--- a/libcxx/include/ranges
+++ b/libcxx/include/ranges
@@ -422,6 +422,7 @@ namespace std {
 
 #if _LIBCPP_STD_VER >= 23
 #  include <__ranges/as_rvalue_view.h>
+#  include <__ranges/cartesian_product_view.h>
 #  include <__ranges/chunk_by_view.h>
 #  include <__ranges/from_range.h>
 #  include <__ranges/repeat_view.h>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/ctor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/ctor.pass.cpp
new file mode 100644
index 00000000000000..72657095c792ef
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/ctor.pass.cpp
@@ -0,0 +1,36 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// std::ranges::cartesian_product_view
+
+#include <cassert>
+#include <ranges>
+
+#include "test_iterators.h"
+
+struct DefaultConstructibleView : std::ranges::view_base {
+  int i_;
+  int* begin();
+  int* end();
+};
+
+constexpr bool test() {
+  { // view | views::as_rvalue
+    // DefaultConstructibleView v{{}, 3};
+    [[maybe_unused]] std::ranges::cartesian_product_view<DefaultConstructibleView> r1;
+    [[maybe_unused]] std::ranges::cartesian_product_view<DefaultConstructibleView, DefaultConstructibleView> r2;
+  }
+  return true;
+}
+
+int main() {
+  test();
+  static_assert(test());
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/size.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/size.pass.cpp
new file mode 100644
index 00000000000000..5486f9416a66bf
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/size.pass.cpp
@@ -0,0 +1,46 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// std::ranges::cartesian_product_view::size
+
+#include <cassert>
+#include <ranges>
+#include <initializer_list>
+
+constexpr bool test() {
+  {
+    using T = std::initializer_list<int>;
+
+    // example taken from: https://en.cppreference.com/w/cpp/ranges/cartesian_product_view/size
+    constexpr static T w = {1};
+    constexpr static T x = {2, 3};
+    constexpr static T y = {4, 5, 6};
+    constexpr static T z = {7, 8, 9, 10, 11, 12, 13};
+
+    constexpr  auto ww = std::ranges::views::all(w);
+    constexpr auto xx = std::ranges::views::all(x);
+    constexpr auto yy = std::ranges::views::all(y);
+    constexpr auto zz = std::ranges::views::all(z);
+
+    constexpr auto v = std::ranges::cartesian_product_view(ww, xx, yy, zz);
+    
+    assert(v.size() == 42);
+    assert(v.size() == w.size() * x.size() * y.size() * z.size());
+    static_assert(v.size() == 42);
+    static_assert(v.size() == w.size() * x.size() * y.size() * z.size());
+  }
+
+  return true;
+}
+
+int main() {
+  test();
+  static_assert(test());
+}

>From 4c7c728f0b945bbd9d65cf8c043e823af0549db0 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 4 Oct 2024 20:31:41 +0200
Subject: [PATCH 02/39] non-const size()

---
 .../include/__ranges/cartesian_product_view.h | 21 ++++++++++++-------
 .../size.pass.cpp                             | 18 +++++++---------
 2 files changed, 21 insertions(+), 18 deletions(-)

diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index 46941b9e1c97dd..59cf31e3503907 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -11,8 +11,8 @@
 
 #include <__config>
 #include <__ranges/concepts.h> // forward_range, view, range_size_t, sized_range, ...
-#include <tuple> // apply
-#include <type_traits> // common_type_t
+#include <tuple>               // apply
+#include <type_traits>         // common_type_t
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -65,13 +65,20 @@ class cartesian_product_view : public view_interface<cartesian_product_view<Firs
   //   requires cartesian-product-is-common<const First, const Vs...>;
   // constexpr default_sentinel_t end() const noexcept;
 
-  // constexpr see below size()
-  //   requires cartesian-product-is-sized<First, Vs...>;
-  // constexpr see below size() const
-  // requires cartesian-product-is-sized<const First, const Vs...>;
-  constexpr auto size() const 
+  constexpr auto size()
+    requires(sized_range<First> && ... && sized_range<Vs>)
+  {
+    return size_impl();
+  }
+
+  constexpr auto size() const
     requires(sized_range<const First> && ... && sized_range<const Vs>)
   {
+    return size_impl();
+  }
+
+private:
+  constexpr auto size_impl() const {
     return std::apply(
         [](auto&&... bases) {
           using size_type = std::common_type_t<std::ranges::range_size_t<decltype(bases)>...>;
diff --git a/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/size.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/size.pass.cpp
index 5486f9416a66bf..82ee47997f53b3 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/size.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/size.pass.cpp
@@ -15,26 +15,22 @@
 #include <initializer_list>
 
 constexpr bool test() {
-  {
-    using T = std::initializer_list<int>;
-
+  { // testing: constexpr auto size() const
     // example taken from: https://en.cppreference.com/w/cpp/ranges/cartesian_product_view/size
-    constexpr static T w = {1};
-    constexpr static T x = {2, 3};
-    constexpr static T y = {4, 5, 6};
-    constexpr static T z = {7, 8, 9, 10, 11, 12, 13};
+    constexpr static auto w = {1};
+    constexpr static auto x = {2, 3};
+    constexpr static auto y = {4, 5, 6};
+    constexpr static auto z = {7, 8, 9, 10, 11, 12, 13};
 
-    constexpr  auto ww = std::ranges::views::all(w);
+    constexpr auto ww = std::ranges::views::all(w);
     constexpr auto xx = std::ranges::views::all(x);
     constexpr auto yy = std::ranges::views::all(y);
     constexpr auto zz = std::ranges::views::all(z);
 
     constexpr auto v = std::ranges::cartesian_product_view(ww, xx, yy, zz);
-    
+
     assert(v.size() == 42);
     assert(v.size() == w.size() * x.size() * y.size() * z.size());
-    static_assert(v.size() == 42);
-    static_assert(v.size() == w.size() * x.size() * y.size() * z.size());
   }
 
   return true;

>From 2395008df2f1d83e29028bca2b0e740f350b3717 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 4 Oct 2024 22:56:20 +0200
Subject: [PATCH 03/39] class cartesian_product_view<First, Vs...>::iterator:
 ctors

---
 .../include/__ranges/cartesian_product_view.h | 97 ++++++++++++++++++-
 1 file changed, 96 insertions(+), 1 deletion(-)

diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index 59cf31e3503907..ac879120295047 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -13,6 +13,7 @@
 #include <__ranges/concepts.h> // forward_range, view, range_size_t, sized_range, ...
 #include <tuple>               // apply
 #include <type_traits>         // common_type_t
+#include <__type_traits/maybe_const.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -31,10 +32,11 @@ template <input_range First, forward_range... Vs>
   requires(view<First> && ... && view<Vs>)
 class cartesian_product_view : public view_interface<cartesian_product_view<First, Vs...>> {
 private:
+public: // fixme: remove me
   tuple<First, Vs...> bases_; // exposition only
 
   template <bool Const>
-  struct iterator; // exposition only
+  class iterator; // exposition only
 
 public:
   constexpr cartesian_product_view() = default;
@@ -88,6 +90,99 @@ class cartesian_product_view : public view_interface<cartesian_product_view<Firs
   }
 };
 
+template<input_range First, forward_range... Vs>
+requires (view<First> && ... && view<Vs>)
+template<bool Const>
+class cartesian_product_view<First, Vs...>::iterator {
+
+  // fixme: implement properly. see section 5.2 in paper.
+  template <class... T>
+  using tuple_or_pair = tuple<T...>;
+
+public:
+//   using iterator_category = input_iterator_tag;
+//   using iterator_concept  = see below;
+//   using value_type = tuple-or-pair<range_value_t<__maybe_const<Const, First>>,
+//     range_value_t<__maybe_const<Const, Vs>>...>;
+//   using reference = tuple-or-pair<reference_t<__maybe_const<Const, First>>,
+//     reference_t<__maybe_const<Const, Vs>>...>;
+//   using difference_type = see below;
+
+  iterator() requires forward_range<__maybe_const<Const, First>> = default;
+
+  constexpr explicit iterator(tuple_or_pair<iterator_t<__maybe_const<Const, First>>,
+    iterator_t<__maybe_const<Const, Vs>>...> current) 
+      : current_(std::move(current)) {}
+
+  constexpr iterator(iterator<!Const> i) requires Const &&
+    (convertible_to<iterator_t<First>, iterator_t<__maybe_const<Const, First>>> &&
+      ... && convertible_to<iterator_t<Vs>, iterator_t<__maybe_const<Const, Vs>>>)
+      : current_(std::move(i.current_)) {}
+
+//   constexpr auto operator*() const;
+//   constexpr iterator& operator++();
+//   constexpr void operator++(int);
+//   constexpr iterator operator++(int) requires forward_range<__maybe_const<Const, First>>;
+
+//   constexpr iterator& operator--()
+//     requires cartesian-product-is-bidirectional<Const, First, Vs...>;
+//   constexpr iterator operator--(int)
+//     requires cartesian-product-is-bidirectional<Const, First, Vs...>;
+
+//   constexpr iterator& operator+=(difference_type x)
+//     requires cartesian-product-is-random-access<Const, First, Vs...>;
+//   constexpr iterator& operator-=(difference_type x)
+//     requires cartesian-product-is-random-access<Const, First, Vs...>;
+
+//   constexpr reference operator[](difference_type n) const
+//     requires cartesian-product-is-random-access<Const, First, Vs...>;
+
+//   friend constexpr bool operator==(const iterator& x, const iterator& y)
+//     requires equality_comparable<iterator_t<__maybe_const<Const, First>>>;
+
+//   friend constexpr bool operator==(const iterator& x, default_sentinel_t);
+
+//   friend constexpr auto operator<=>(const iterator& x, const iterator& y)
+//     requires all-random-access<Const, First, Vs...>;
+
+//   friend constexpr iterator operator+(const iterator& x, difference_type y)
+//     requires cartesian-product-is-random-access<Const, First, Vs...>;
+//   friend constexpr iterator operator+(difference_type x, const iterator& y)
+//     requires cartesian-product-is-random-access<Const, First, Vs...>;
+//   friend constexpr iterator operator-(const iterator& x, difference_type y)
+//     requires cartesian-product-is-random-access<Const, First, Vs...>;
+//   friend constexpr difference_type operator-(const iterator& x, const iterator& y)
+//     requires cartesian-is-sized-sentinel<Const, iterator_t, First, Vs...>;
+
+//   friend constexpr difference_type operator-(iterator i, default_sentinel_t)
+//     requires cartesian-is-sized-sentinel<Const, sentinel_t, First, Vs...>;
+//   friend constexpr difference_type operator-(default_sentinel_t, iterator i)
+//     requires cartesian-is-sized-sentinel<Const, sentinel_t, First, Vs...>;
+
+//   friend constexpr auto iter_move(const iterator& i) noexcept(see below);
+
+//   friend constexpr void iter_swap(const iterator& l, const iterator& r) noexcept(see below)
+//     requires (indirectly_swappable<iterator_t<__maybe_const<Const, First>>> && ... &&
+//       indirectly_swappable<iterator_t<__maybe_const<Const, Vs>>>);
+
+private:
+//   __maybe_const<Const, cartesian_product_view>* parent_ = nullptr; // exposition only
+  tuple_or_pair<iterator_t<__maybe_const<Const, First>>,
+    iterator_t<__maybe_const<Const, Vs>>...> current_; // exposition only
+
+//   template <size_t N = sizeof...(Vs)>
+//   constexpr void next(); // exposition only
+
+//   template <size_t N = sizeof...(Vs)>
+//   constexpr void prev(); // exposition only
+
+//   template <class Tuple>
+//   constexpr difference_type distance-from(Tuple t); // exposition only
+
+//   constexpr explicit iterator(tuple-or-pair<iterator_t<__maybe_const<Const, First>>,
+//     iterator_t<__maybe_const<Const, Vs>>...> current); // exposition only
+};
+
 template <class... Rs>
 cartesian_product_view(Rs&&...) -> cartesian_product_view<std::views::all_t<Rs>...>;
 

>From 1a2e8aaa852f0f7b9e41f3db0778e0ceeb590a4b Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 4 Oct 2024 23:16:15 +0200
Subject: [PATCH 04/39] cleanup

---
 .../include/__ranges/cartesian_product_view.h | 137 +++---------------
 1 file changed, 22 insertions(+), 115 deletions(-)

diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index ac879120295047..811693f3749ce4 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -11,9 +11,9 @@
 
 #include <__config>
 #include <__ranges/concepts.h> // forward_range, view, range_size_t, sized_range, ...
-#include <tuple>               // apply
-#include <type_traits>         // common_type_t
 #include <__type_traits/maybe_const.h>
+#include <tuple>       // apply
+#include <type_traits> // common_type_t
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -32,41 +32,18 @@ template <input_range First, forward_range... Vs>
   requires(view<First> && ... && view<Vs>)
 class cartesian_product_view : public view_interface<cartesian_product_view<First, Vs...>> {
 private:
+
 public: // fixme: remove me
-  tuple<First, Vs...> bases_; // exposition only
+  tuple<First, Vs...> bases_;
 
   template <bool Const>
-  class iterator; // exposition only
+  class iterator;
 
 public:
   constexpr cartesian_product_view() = default;
   constexpr explicit cartesian_product_view(First first_base, Vs... bases)
       : bases_{std::move(first_base), std::move(bases)...} {}
 
-  // constexpr iterator<false> begin()
-  //     requires (!simple-view<First> || ... || !simple-view<Vs>)
-  // {
-  //     return move_iterator(ranges::begin(bases_));
-  // }
-
-  // constexpr iterator<true> begin() const
-  //     requires (range<const First> && ... && range<const Vs>)
-  // {
-  //     return move_iterator(ranges::begin(__base_));
-  // }
-
-  // constexpr iterator<false> begin()
-  //   requires (!simple-view<First> || ... || !simple-view<Vs>);
-  // constexpr iterator<true> begin() const
-  //   requires (range<const First> && ... && range<const Vs>);
-
-  // constexpr iterator<false> end()
-  //   requires ((!simple-view<First> || ... || !simple-view<Vs>) &&
-  //     cartesian-product-is-common<First, Vs...>);
-  // constexpr iterator<true> end() const
-  //   requires cartesian-product-is-common<const First, const Vs...>;
-  // constexpr default_sentinel_t end() const noexcept;
-
   constexpr auto size()
     requires(sized_range<First> && ... && sized_range<Vs>)
   {
@@ -90,102 +67,32 @@ class cartesian_product_view : public view_interface<cartesian_product_view<Firs
   }
 };
 
-template<input_range First, forward_range... Vs>
-requires (view<First> && ... && view<Vs>)
-template<bool Const>
-class cartesian_product_view<First, Vs...>::iterator {
-
-  // fixme: implement properly. see section 5.2 in paper.
-  template <class... T>
-  using tuple_or_pair = tuple<T...>;
+template <class... Vs>
+cartesian_product_view(Vs&&...) -> cartesian_product_view<views::all_t<Vs>...>;
 
+template <input_range First, forward_range... Vs>
+  requires(view<First> && ... && view<Vs>)
+template <bool Const>
+class cartesian_product_view<First, Vs...>::iterator {
 public:
-//   using iterator_category = input_iterator_tag;
-//   using iterator_concept  = see below;
-//   using value_type = tuple-or-pair<range_value_t<__maybe_const<Const, First>>,
-//     range_value_t<__maybe_const<Const, Vs>>...>;
-//   using reference = tuple-or-pair<reference_t<__maybe_const<Const, First>>,
-//     reference_t<__maybe_const<Const, Vs>>...>;
-//   using difference_type = see below;
-
-  iterator() requires forward_range<__maybe_const<Const, First>> = default;
-
-  constexpr explicit iterator(tuple_or_pair<iterator_t<__maybe_const<Const, First>>,
-    iterator_t<__maybe_const<Const, Vs>>...> current) 
+  iterator()
+    requires forward_range<__maybe_const<Const, First>>
+  = default;
+
+  constexpr explicit iterator(
+      tuple<iterator_t<__maybe_const<Const, First>>, iterator_t<__maybe_const<Const, Vs>>...> current)
       : current_(std::move(current)) {}
 
-  constexpr iterator(iterator<!Const> i) requires Const &&
-    (convertible_to<iterator_t<First>, iterator_t<__maybe_const<Const, First>>> &&
-      ... && convertible_to<iterator_t<Vs>, iterator_t<__maybe_const<Const, Vs>>>)
+  constexpr iterator(iterator<!Const> i)
+    requires Const && (convertible_to<iterator_t<First>, iterator_t<__maybe_const<Const, First>>> && ... &&
+                       convertible_to<iterator_t<Vs>, iterator_t<__maybe_const<Const, Vs>>>)
       : current_(std::move(i.current_)) {}
 
-//   constexpr auto operator*() const;
-//   constexpr iterator& operator++();
-//   constexpr void operator++(int);
-//   constexpr iterator operator++(int) requires forward_range<__maybe_const<Const, First>>;
-
-//   constexpr iterator& operator--()
-//     requires cartesian-product-is-bidirectional<Const, First, Vs...>;
-//   constexpr iterator operator--(int)
-//     requires cartesian-product-is-bidirectional<Const, First, Vs...>;
-
-//   constexpr iterator& operator+=(difference_type x)
-//     requires cartesian-product-is-random-access<Const, First, Vs...>;
-//   constexpr iterator& operator-=(difference_type x)
-//     requires cartesian-product-is-random-access<Const, First, Vs...>;
-
-//   constexpr reference operator[](difference_type n) const
-//     requires cartesian-product-is-random-access<Const, First, Vs...>;
-
-//   friend constexpr bool operator==(const iterator& x, const iterator& y)
-//     requires equality_comparable<iterator_t<__maybe_const<Const, First>>>;
-
-//   friend constexpr bool operator==(const iterator& x, default_sentinel_t);
-
-//   friend constexpr auto operator<=>(const iterator& x, const iterator& y)
-//     requires all-random-access<Const, First, Vs...>;
-
-//   friend constexpr iterator operator+(const iterator& x, difference_type y)
-//     requires cartesian-product-is-random-access<Const, First, Vs...>;
-//   friend constexpr iterator operator+(difference_type x, const iterator& y)
-//     requires cartesian-product-is-random-access<Const, First, Vs...>;
-//   friend constexpr iterator operator-(const iterator& x, difference_type y)
-//     requires cartesian-product-is-random-access<Const, First, Vs...>;
-//   friend constexpr difference_type operator-(const iterator& x, const iterator& y)
-//     requires cartesian-is-sized-sentinel<Const, iterator_t, First, Vs...>;
-
-//   friend constexpr difference_type operator-(iterator i, default_sentinel_t)
-//     requires cartesian-is-sized-sentinel<Const, sentinel_t, First, Vs...>;
-//   friend constexpr difference_type operator-(default_sentinel_t, iterator i)
-//     requires cartesian-is-sized-sentinel<Const, sentinel_t, First, Vs...>;
-
-//   friend constexpr auto iter_move(const iterator& i) noexcept(see below);
-
-//   friend constexpr void iter_swap(const iterator& l, const iterator& r) noexcept(see below)
-//     requires (indirectly_swappable<iterator_t<__maybe_const<Const, First>>> && ... &&
-//       indirectly_swappable<iterator_t<__maybe_const<Const, Vs>>>);
-
 private:
-//   __maybe_const<Const, cartesian_product_view>* parent_ = nullptr; // exposition only
-  tuple_or_pair<iterator_t<__maybe_const<Const, First>>,
-    iterator_t<__maybe_const<Const, Vs>>...> current_; // exposition only
-
-//   template <size_t N = sizeof...(Vs)>
-//   constexpr void next(); // exposition only
-
-//   template <size_t N = sizeof...(Vs)>
-//   constexpr void prev(); // exposition only
-
-//   template <class Tuple>
-//   constexpr difference_type distance-from(Tuple t); // exposition only
-
-//   constexpr explicit iterator(tuple-or-pair<iterator_t<__maybe_const<Const, First>>,
-//     iterator_t<__maybe_const<Const, Vs>>...> current); // exposition only
+  //   __maybe_const<Const, cartesian_product_view>* parent_ = nullptr;
+  tuple<iterator_t<__maybe_const<Const, First>>, iterator_t<__maybe_const<Const, Vs>>...> current_;
 };
 
-template <class... Rs>
-cartesian_product_view(Rs&&...) -> cartesian_product_view<std::views::all_t<Rs>...>;
-
 } // namespace ranges
 
 _LIBCPP_END_NAMESPACE_STD

>From 9d3d4b89eb378595d1367148613b5fd51935e978 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 4 Oct 2024 23:24:02 +0200
Subject: [PATCH 05/39] cartesian_product_view::iterator parent member

---
 .../include/__ranges/cartesian_product_view.h  | 18 +++++++-----------
 1 file changed, 7 insertions(+), 11 deletions(-)

diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index 811693f3749ce4..bd0302f7f197d9 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -10,6 +10,7 @@
 #define _LIBCPP___RANGES_CARTESIAN_PRODUCT_VIEW_H
 
 #include <__config>
+#include <__memory/addressof.h>
 #include <__ranges/concepts.h> // forward_range, view, range_size_t, sized_range, ...
 #include <__type_traits/maybe_const.h>
 #include <tuple>       // apply
@@ -75,21 +76,16 @@ template <input_range First, forward_range... Vs>
 template <bool Const>
 class cartesian_product_view<First, Vs...>::iterator {
 public:
-  iterator()
-    requires forward_range<__maybe_const<Const, First>>
-  = default;
-
-  constexpr explicit iterator(
-      tuple<iterator_t<__maybe_const<Const, First>>, iterator_t<__maybe_const<Const, Vs>>...> current)
-      : current_(std::move(current)) {}
+  iterator() = default;
 
   constexpr iterator(iterator<!Const> i)
-    requires Const && (convertible_to<iterator_t<First>, iterator_t<__maybe_const<Const, First>>> && ... &&
-                       convertible_to<iterator_t<Vs>, iterator_t<__maybe_const<Const, Vs>>>)
-      : current_(std::move(i.current_)) {}
+    requires Const && (convertible_to<iterator_t<First>, iterator_t<const First>> && ... &&
+                       convertible_to<iterator_t<Vs>, iterator_t<const Vs>>)
+      : parent_(std::addressof(i.parent_)), current_(std::move(i.current_)) {}
 
 private:
-  //   __maybe_const<Const, cartesian_product_view>* parent_ = nullptr;
+  using Parent    = __maybe_const<Const, cartesian_product_view>;
+  Parent* parent_ = nullptr;
   tuple<iterator_t<__maybe_const<Const, First>>, iterator_t<__maybe_const<Const, Vs>>...> current_;
 };
 

>From 2835bd9c0e4c26e76b7061d90ed52a39e6e609a8 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 4 Oct 2024 23:31:03 +0200
Subject: [PATCH 06/39] iterator: private ctor

---
 libcxx/include/__ranges/cartesian_product_view.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index bd0302f7f197d9..f330f186e72b83 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -87,6 +87,9 @@ class cartesian_product_view<First, Vs...>::iterator {
   using Parent    = __maybe_const<Const, cartesian_product_view>;
   Parent* parent_ = nullptr;
   tuple<iterator_t<__maybe_const<Const, First>>, iterator_t<__maybe_const<Const, Vs>>...> current_;
+
+  constexpr iterator(Parent& parent, decltype(current_) current)
+      : parent_(std::addressof(parent)), current_(std::move(current)) {}
 };
 
 } // namespace ranges

>From f7fb8fe79f071431ff6815998653110e3f92317b Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 4 Oct 2024 23:34:55 +0200
Subject: [PATCH 07/39] iterator: tags

---
 libcxx/include/__ranges/cartesian_product_view.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index f330f186e72b83..65111a7f827426 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -76,6 +76,11 @@ template <input_range First, forward_range... Vs>
 template <bool Const>
 class cartesian_product_view<First, Vs...>::iterator {
 public:
+  using iterator_category = input_iterator_tag;
+  using value_type = tuple<range_value_t<__maybe_const<Const, First>>, range_value_t<__maybe_const<Const, Vs>>...>;
+  using reference =
+      tuple<range_reference_t<__maybe_const<Const, First>>, range_reference_t<__maybe_const<Const, Vs>>...>;
+
   iterator() = default;
 
   constexpr iterator(iterator<!Const> i)

>From a9940c6034a7e9652310800590070112bd157df8 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 4 Oct 2024 23:44:10 +0200
Subject: [PATCH 08/39] iterator: operator*()

---
 libcxx/include/__ranges/cartesian_product_view.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index 65111a7f827426..16fe28a6122c92 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -12,6 +12,7 @@
 #include <__config>
 #include <__memory/addressof.h>
 #include <__ranges/concepts.h> // forward_range, view, range_size_t, sized_range, ...
+#include <__ranges/zip_view.h> // tuple_transform
 #include <__type_traits/maybe_const.h>
 #include <tuple>       // apply
 #include <type_traits> // common_type_t
@@ -88,6 +89,10 @@ class cartesian_product_view<First, Vs...>::iterator {
                        convertible_to<iterator_t<Vs>, iterator_t<const Vs>>)
       : parent_(std::addressof(i.parent_)), current_(std::move(i.current_)) {}
 
+  constexpr auto operator*() const {
+    return __tuple_transform([](auto& i) -> decltype(auto) { return *i; }, current_);
+  }
+
 private:
   using Parent    = __maybe_const<Const, cartesian_product_view>;
   Parent* parent_ = nullptr;

>From d911a973283d68d3e189b27b466fce0e6065c957 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 5 Oct 2024 22:27:46 +0200
Subject: [PATCH 09/39] add to modulemap

---
 libcxx/include/module.modulemap | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index 5465d603b2c4d0..87ee84e6256f1c 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -1698,6 +1698,7 @@ module std [system] {
     module access                         { header "__ranges/access.h" }
     module all                            { header "__ranges/all.h" }
     module as_rvalue_view                 { header "__ranges/as_rvalue_view.h" }
+    module cartesian_product_view         { header "__ranges/cartesian_product_view.h" }
     module chunk_by_view {
       header "__ranges/chunk_by_view.h"
       export std.functional.bind_back

>From 96b4d42b76bdadda1126e55e7f060e464e20dc53 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 5 Oct 2024 22:46:25 +0200
Subject: [PATCH 10/39] iterator: operator++(), next()

---
 .../include/__ranges/cartesian_product_view.h  | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index 16fe28a6122c92..7218da2906a8c1 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -10,6 +10,7 @@
 #define _LIBCPP___RANGES_CARTESIAN_PRODUCT_VIEW_H
 
 #include <__config>
+#include <__iterator/access.h> // begin
 #include <__memory/addressof.h>
 #include <__ranges/concepts.h> // forward_range, view, range_size_t, sized_range, ...
 #include <__ranges/zip_view.h> // tuple_transform
@@ -93,6 +94,11 @@ class cartesian_product_view<First, Vs...>::iterator {
     return __tuple_transform([](auto& i) -> decltype(auto) { return *i; }, current_);
   }
 
+  constexpr iterator& operator++() {
+    next();
+    return *this;
+  }
+
 private:
   using Parent    = __maybe_const<Const, cartesian_product_view>;
   Parent* parent_ = nullptr;
@@ -100,6 +106,18 @@ class cartesian_product_view<First, Vs...>::iterator {
 
   constexpr iterator(Parent& parent, decltype(current_) current)
       : parent_(std::addressof(parent)), current_(std::move(current)) {}
+
+  template <auto N = sizeof...(Vs)>
+  constexpr void next() {
+    const auto& v = std::get<N>(parent_->bases_);
+    auto& it      = std::get<N>(current_);
+    if (++it == std::end(v)) {
+      if constexpr (N != 0) {
+        it = std::ranges::begin(v);
+        next<N - 1>();
+      }
+    }
+  }
 };
 
 } // namespace ranges

>From 1d21f31e37f46116e9149958ed0317c560c9fea3 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 5 Oct 2024 23:05:50 +0200
Subject: [PATCH 11/39] iterator: operator++(int)

---
 libcxx/include/__ranges/cartesian_product_view.h | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index 7218da2906a8c1..fd2d3f4e099804 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -99,6 +99,16 @@ class cartesian_product_view<First, Vs...>::iterator {
     return *this;
   }
 
+  constexpr void operator++(int) { next(); }
+
+  constexpr iterator operator++(int)
+    requires forward_range<__maybe_const<Const, First>>
+  {
+    auto tmp = *this;
+    next();
+    return tmp;
+  }
+
 private:
   using Parent    = __maybe_const<Const, cartesian_product_view>;
   Parent* parent_ = nullptr;

>From 81e4647089a58554f420b17751e16b6613acff75 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 5 Oct 2024 23:38:28 +0200
Subject: [PATCH 12/39] iterator: operator--(), prev(); concepts

---
 .../include/__ranges/cartesian_product_view.h | 40 +++++++++++++++++--
 1 file changed, 37 insertions(+), 3 deletions(-)

diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index fd2d3f4e099804..586dcde42c6f47 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -31,12 +31,27 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 namespace ranges {
 
+template <class R>
+concept cartesian_product_common_arg = common_range<R> || (sized_range<R> && random_access_range<R>);
+
+template <bool Const, class First, class... Vs>
+concept cartesian_product_is_bidirectional =
+    (bidirectional_range<__maybe_const<Const, First>> && ... &&
+     (bidirectional_range<__maybe_const<Const, Vs>> && cartesian_product_common_arg<__maybe_const<Const, Vs>>));
+
+template <cartesian_product_common_arg R>
+constexpr auto cartesian_common_arg_end(R& r) {
+  if constexpr (common_range<R>) {
+    return ranges::end(r);
+  } else {
+    return ranges::begin(r) + ranges::distance(r);
+  }
+}
+
 template <input_range First, forward_range... Vs>
   requires(view<First> && ... && view<Vs>)
 class cartesian_product_view : public view_interface<cartesian_product_view<First, Vs...>> {
-private:
-
-public: // fixme: remove me
+public: // fixme: make private
   tuple<First, Vs...> bases_;
 
   template <bool Const>
@@ -109,6 +124,13 @@ class cartesian_product_view<First, Vs...>::iterator {
     return tmp;
   }
 
+  constexpr iterator& operator--()
+    requires cartesian_product_is_bidirectional<Const, First, Vs...>
+  {
+    prev();
+    return *this;
+  }
+
 private:
   using Parent    = __maybe_const<Const, cartesian_product_view>;
   Parent* parent_ = nullptr;
@@ -128,6 +150,18 @@ class cartesian_product_view<First, Vs...>::iterator {
       }
     }
   }
+
+  template <auto N = sizeof...(Vs)>
+  constexpr void prev() {
+    auto& it = std::get<N>(current_);
+    if constexpr (N > 0) {
+      if (const auto& v = std::get<N>(parent_->bases_); it == ranges::begin(v)) {
+        it = cartesian_common_arg_end(v);
+        prev<N - 1>();
+      }
+    }
+    --it;
+  }
 };
 
 } // namespace ranges

>From 918400c37b0ca7debd061ece97c125b4d37dad76 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 5 Oct 2024 23:41:32 +0200
Subject: [PATCH 13/39] iterator: next() as suggested in std

---
 libcxx/include/__ranges/cartesian_product_view.h | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index 586dcde42c6f47..8fb4a09d4e8d22 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -141,11 +141,11 @@ class cartesian_product_view<First, Vs...>::iterator {
 
   template <auto N = sizeof...(Vs)>
   constexpr void next() {
-    const auto& v = std::get<N>(parent_->bases_);
-    auto& it      = std::get<N>(current_);
-    if (++it == std::end(v)) {
-      if constexpr (N != 0) {
-        it = std::ranges::begin(v);
+    auto& it = std::get<N>(current_);
+    ++it;
+    if constexpr (N > 0) {
+      if (const auto& v = std::get<N>(parent_->bases_); it == ranges::end(v)) {
+        it = ranges::begin(v);
         next<N - 1>();
       }
     }

>From 62a9a6cdf154c4b8c7b142bf19da54cce934c15b Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 5 Oct 2024 23:43:36 +0200
Subject: [PATCH 14/39] iterator: operator--(int)

---
 libcxx/include/__ranges/cartesian_product_view.h | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index 8fb4a09d4e8d22..4f6fded8c74b3d 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -131,6 +131,13 @@ class cartesian_product_view<First, Vs...>::iterator {
     return *this;
   }
 
+  constexpr iterator operator--(int)
+requires cartesian_product_is_bidirectional <Const, First, Vs...> {
+      auto tmp = *this;
+    prev();
+    return tmp;
+}
+
 private:
   using Parent    = __maybe_const<Const, cartesian_product_view>;
   Parent* parent_ = nullptr;

>From 8a01bd50164a4b7823815ad274aad97ef9bea0ba Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sun, 6 Oct 2024 00:11:27 +0200
Subject: [PATCH 15/39] iterator: operator+=(x), -=(x); concept

---
 .../include/__ranges/cartesian_product_view.h | 58 ++++++++++++++++++-
 1 file changed, 55 insertions(+), 3 deletions(-)

diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index 4f6fded8c74b3d..495ec1fd63e51e 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -31,6 +31,11 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 namespace ranges {
 
+template <bool Const, class First, class... Vs>
+concept cartesian_product_is_random_access =
+    (random_access_range<__maybe_const<Const, First>> && ... &&
+     (random_access_range<__maybe_const<Const, Vs>> && sized_range<__maybe_const<Const, Vs>>));
+
 template <class R>
 concept cartesian_product_common_arg = common_range<R> || (sized_range<R> && random_access_range<R>);
 
@@ -97,6 +102,7 @@ class cartesian_product_view<First, Vs...>::iterator {
   using value_type = tuple<range_value_t<__maybe_const<Const, First>>, range_value_t<__maybe_const<Const, Vs>>...>;
   using reference =
       tuple<range_reference_t<__maybe_const<Const, First>>, range_reference_t<__maybe_const<Const, Vs>>...>;
+  using difference_type = std::common_type_t<range_difference_t<First>, range_difference_t<Vs>...>;
 
   iterator() = default;
 
@@ -132,11 +138,26 @@ class cartesian_product_view<First, Vs...>::iterator {
   }
 
   constexpr iterator operator--(int)
-requires cartesian_product_is_bidirectional <Const, First, Vs...> {
-      auto tmp = *this;
+    requires cartesian_product_is_bidirectional<Const, First, Vs...>
+  {
+    auto tmp = *this;
     prev();
     return tmp;
-}
+  }
+
+  constexpr iterator& operator+=(difference_type x)
+    requires cartesian_product_is_random_access<Const, First, Vs...>
+  {
+    advance(x);
+    return *this;
+  }
+
+  constexpr iterator& operator-=(difference_type x)
+    requires cartesian_product_is_random_access<Const, First, Vs...>
+  {
+    advance(x);
+    return *this;
+  }
 
 private:
   using Parent    = __maybe_const<Const, cartesian_product_view>;
@@ -169,6 +190,37 @@ requires cartesian_product_is_bidirectional <Const, First, Vs...> {
     }
     --it;
   }
+
+  template <std::size_t N = sizeof...(Vs)>
+  constexpr void advance(difference_type x) {
+    if (x == 0)
+      return;
+
+    const auto& v    = std::get<N>(parent_->bases_);
+    auto& it         = std::get<N>(current_);
+    const auto sz    = static_cast<difference_type>(std::ranges::size(v));
+    const auto first = begin(v);
+
+    const auto idx = static_cast<difference_type>(it - first);
+    x += idx;
+
+    auto div = sz ? x / sz : 0;
+    auto mod = sz ? x % sz : 0;
+
+    if constexpr (N != 0) {
+      if (mod < 0) {
+        mod += sz;
+        div--;
+      }
+      advance<N - 1>(div);
+    } else {
+      if (div > 0) {
+        mod = sz;
+      }
+    }
+    using D = std::iter_difference_t<decltype(first)>;
+    it      = first + static_cast<D>(mod);
+  }
 };
 
 } // namespace ranges

>From 0bc985d695f8e9184fd2ad1461ab9ab219b263b3 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 11 Oct 2024 22:33:21 +0200
Subject: [PATCH 16/39] cleanup of iterator: operator+=(x), -=(x)

---
 .../include/__ranges/cartesian_product_view.h | 39 +++++++++++--------
 1 file changed, 23 insertions(+), 16 deletions(-)

diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index 495ec1fd63e51e..aca22153e1366e 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -11,6 +11,8 @@
 
 #include <__config>
 #include <__iterator/access.h> // begin
+#include <__iterator/distance.h>
+#include <__iterator/next.h>
 #include <__memory/addressof.h>
 #include <__ranges/concepts.h> // forward_range, view, range_size_t, sized_range, ...
 #include <__ranges/zip_view.h> // tuple_transform
@@ -155,7 +157,7 @@ class cartesian_product_view<First, Vs...>::iterator {
   constexpr iterator& operator-=(difference_type x)
     requires cartesian_product_is_random_access<Const, First, Vs...>
   {
-    advance(x);
+    *this += -x;
     return *this;
   }
 
@@ -201,25 +203,30 @@ class cartesian_product_view<First, Vs...>::iterator {
     const auto sz    = static_cast<difference_type>(std::ranges::size(v));
     const auto first = begin(v);
 
-    const auto idx = static_cast<difference_type>(it - first);
-    x += idx;
-
-    auto div = sz ? x / sz : 0;
-    auto mod = sz ? x % sz : 0;
-
-    if constexpr (N != 0) {
-      if (mod < 0) {
-        mod += sz;
-        div--;
+    if (sz > 0) {
+      const auto idx = static_cast<difference_type>(std::distance(first, it));
+      x += idx;
+
+      difference_type mod;
+      if constexpr (N > 0) {
+        difference_type div = x / sz;
+        mod                 = x % sz;
+        if (mod < 0) {
+          mod += sz;
+          div--;
+        }
+        advance<N - 1>(div);
+      } else {
+        mod = (x >= 0 && x < sz) ? x : sz;
       }
-      advance<N - 1>(div);
+      it = std::next(first, mod);
+
     } else {
-      if (div > 0) {
-        mod = sz;
+      if constexpr (N > 0) {
+        advance<N - 1>(x);
       }
+      it = first;
     }
-    using D = std::iter_difference_t<decltype(first)>;
-    it      = first + static_cast<D>(mod);
   }
 };
 

>From dbb74a07d61dcc739c270838daab6cc3d5c07902 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 11 Oct 2024 22:37:41 +0200
Subject: [PATCH 17/39] iterator: operator[](n)

---
 libcxx/include/__ranges/cartesian_product_view.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index aca22153e1366e..0f9f825dba5e6c 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -161,6 +161,12 @@ class cartesian_product_view<First, Vs...>::iterator {
     return *this;
   }
 
+  constexpr reference operator[](difference_type n) const
+    requires cartesian_product_is_random_access<Const, First, Vs...>
+  {
+    return *((*this) + n);
+  }
+
 private:
   using Parent    = __maybe_const<Const, cartesian_product_view>;
   Parent* parent_ = nullptr;

>From 8218119fb37d2db23aec0c7b4396fc0461c9e242 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 11 Oct 2024 22:40:28 +0200
Subject: [PATCH 18/39] iterator: operator==(iterator, iterator)

---
 libcxx/include/__ranges/cartesian_product_view.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index 0f9f825dba5e6c..bf533ebc59aa96 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -167,6 +167,12 @@ class cartesian_product_view<First, Vs...>::iterator {
     return *((*this) + n);
   }
 
+  friend constexpr bool operator==(const iterator& x, const iterator& y)
+    requires equality_comparable<iterator_t<__maybe_const<Const, First>>>
+  {
+    return x.current_ == y.current_;
+  }
+
 private:
   using Parent    = __maybe_const<Const, cartesian_product_view>;
   Parent* parent_ = nullptr;

>From 53912b14f7431a08bd1ebd4c98f37ec84ba2cc6a Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 11 Oct 2024 22:56:55 +0200
Subject: [PATCH 19/39] iterator: operator==(iterator, sentinel)

---
 libcxx/include/__ranges/cartesian_product_view.h | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index bf533ebc59aa96..191fe44433270b 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -173,6 +173,8 @@ class cartesian_product_view<First, Vs...>::iterator {
     return x.current_ == y.current_;
   }
 
+  friend constexpr bool operator==(const iterator& x, default_sentinel_t) { return x.at_end(); }
+
 private:
   using Parent    = __maybe_const<Const, cartesian_product_view>;
   Parent* parent_ = nullptr;
@@ -240,6 +242,15 @@ class cartesian_product_view<First, Vs...>::iterator {
       it = first;
     }
   }
+
+  template <auto N = sizeof...(Vs)>
+  constexpr bool at_end() const {
+    if (std::get<N>(current_) == end(std::get<N>(parent_->bases_)))
+      return true;
+    if constexpr (N > 0)
+      return at_end<N - 1>();
+    return false;
+  }
 };
 
 } // namespace ranges

>From bb79608b922ebe6fa158f937f5a96c5f1ea3770b Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 11 Oct 2024 23:08:14 +0200
Subject: [PATCH 20/39] iterator: operator<=>(iterator, iterator); concept

---
 libcxx/include/__ranges/cartesian_product_view.h | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index 191fe44433270b..c4428845e2c5c3 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -55,6 +55,10 @@ constexpr auto cartesian_common_arg_end(R& r) {
   }
 }
 
+template <bool Const, class First, class... Vs>
+concept __cartesian_product_all_random_access =
+    (random_access_range<__maybe_const<Const, First>> && ... && random_access_range<__maybe_const<Const, Vs>>);
+
 template <input_range First, forward_range... Vs>
   requires(view<First> && ... && view<Vs>)
 class cartesian_product_view : public view_interface<cartesian_product_view<First, Vs...>> {
@@ -175,6 +179,12 @@ class cartesian_product_view<First, Vs...>::iterator {
 
   friend constexpr bool operator==(const iterator& x, default_sentinel_t) { return x.at_end(); }
 
+  friend constexpr auto operator<=>(const iterator& x, const iterator& y)
+    requires __cartesian_product_all_random_access<Const, First, Vs...>
+  {
+    return x.current_ <=> y.current_;
+  }
+
 private:
   using Parent    = __maybe_const<Const, cartesian_product_view>;
   Parent* parent_ = nullptr;

>From 9eb9ad62a97f22bdab935b1af0d6f012b0c62914 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 11 Oct 2024 23:10:24 +0200
Subject: [PATCH 21/39] iterator: operator+(iterator, diffType)

---
 libcxx/include/__ranges/cartesian_product_view.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index c4428845e2c5c3..329e9787062467 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -185,6 +185,12 @@ class cartesian_product_view<First, Vs...>::iterator {
     return x.current_ <=> y.current_;
   }
 
+  friend constexpr iterator operator+(const iterator& x, difference_type y)
+    requires cartesian_product_is_random_access<Const, First, Vs...>
+  {
+    return iterator(x) += y;
+  }
+
 private:
   using Parent    = __maybe_const<Const, cartesian_product_view>;
   Parent* parent_ = nullptr;

>From 507fcfb43379f20002a2fab808aeb9c9c0efd4b7 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 11 Oct 2024 23:11:41 +0200
Subject: [PATCH 22/39] iterator: operator+(diffType, iterator)

---
 libcxx/include/__ranges/cartesian_product_view.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index 329e9787062467..d2ed56d2a8ae1d 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -191,6 +191,12 @@ class cartesian_product_view<First, Vs...>::iterator {
     return iterator(x) += y;
   }
 
+  friend constexpr iterator operator+(difference_type x, const iterator& y)
+    requires cartesian_product_is_random_access<Const, First, Vs...>
+  {
+    return y + x;
+  }
+
 private:
   using Parent    = __maybe_const<Const, cartesian_product_view>;
   Parent* parent_ = nullptr;

>From 0e92ed3673f1363c7d7e56a17cc1acd37de36838 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 11 Oct 2024 23:13:52 +0200
Subject: [PATCH 23/39] iterator: operator-(iterator, diffType)

---
 libcxx/include/__ranges/cartesian_product_view.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index d2ed56d2a8ae1d..8c09e2b097df9a 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -197,6 +197,12 @@ class cartesian_product_view<First, Vs...>::iterator {
     return y + x;
   }
 
+  friend constexpr iterator operator-(const iterator& x, difference_type y)
+    requires cartesian_product_is_random_access<Const, First, Vs...>
+  {
+    return iterator(x) -= y;
+  }
+
 private:
   using Parent    = __maybe_const<Const, cartesian_product_view>;
   Parent* parent_ = nullptr;

>From 59d7c14b0378b17967fc79b233773c05342fd2d1 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 11 Oct 2024 23:49:29 +0200
Subject: [PATCH 24/39] iterator: operator-(iterator, iterator); concept

---
 .../include/__ranges/cartesian_product_view.h | 36 +++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index 8c09e2b097df9a..399c28585b1414 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -46,6 +46,15 @@ concept cartesian_product_is_bidirectional =
     (bidirectional_range<__maybe_const<Const, First>> && ... &&
      (bidirectional_range<__maybe_const<Const, Vs>> && cartesian_product_common_arg<__maybe_const<Const, Vs>>));
 
+template <class... Vs>
+concept cartesian_product_is_sized = (sized_range<Vs> && ...);
+
+template <bool Const, template <class> class FirstSent, class First, class... Vs>
+concept cartesian_is_sized_sentinel =
+    (sized_sentinel_for<FirstSent<__maybe_const<Const, First>>, iterator_t<__maybe_const<Const, First>>> && ... &&
+     (sized_range<__maybe_const<Const, Vs>> &&
+      sized_sentinel_for<iterator_t<__maybe_const<Const, Vs>>, iterator_t<__maybe_const<Const, Vs>>>));
+
 template <cartesian_product_common_arg R>
 constexpr auto cartesian_common_arg_end(R& r) {
   if constexpr (common_range<R>) {
@@ -203,6 +212,12 @@ class cartesian_product_view<First, Vs...>::iterator {
     return iterator(x) -= y;
   }
 
+  friend constexpr iterator operator-(const iterator& x, const iterator& y)
+    requires cartesian_product_is_random_access<Const, First, Vs...>
+  {
+    return x.distance_from(y.current_);
+  }
+
 private:
   using Parent    = __maybe_const<Const, cartesian_product_view>;
   Parent* parent_ = nullptr;
@@ -279,6 +294,27 @@ class cartesian_product_view<First, Vs...>::iterator {
       return at_end<N - 1>();
     return false;
   }
+
+  template <class Tuple>
+  constexpr difference_type distance_from(const Tuple& t) const {
+    constexpr auto seq        = std::make_integer_sequence<int, sizeof...(Vs) + 1>{};
+    constexpr auto scaled_sum = [&t, this]<int... Ints>(std::integer_sequence<int, Ints...>) -> difference_type {
+      return (scaled_distance<Ints>(t) + ...);
+    };
+    return scaled_sum(seq);
+  }
+
+  template <auto N>
+  constexpr difference_type scaled_size() const {
+    if constexpr (N <= sizeof...(Vs))
+      return static_cast<difference_type>(ranges::size(std::get<N>(parent_->bases_))) * scaled_size<N + 1>();
+    return static_cast<difference_type>(1);
+  }
+
+  template <auto N, class Tuple>
+  constexpr difference_type scaled_distance(const Tuple& t) const {
+    return static_cast<difference_type>(std::get<N>(current_) - std::get<N>(t)) * scaled_size<N + 1>();
+  }
 };
 
 } // namespace ranges

>From 95412b9d6c410f6b2c549a0db608609d33f38a44 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sun, 13 Oct 2024 20:13:12 +0200
Subject: [PATCH 25/39] iterator: operator-(iterator, iterator) <cleanup>

---
 .../include/__ranges/cartesian_product_view.h   | 17 ++++++++++-------
 1 file changed, 10 insertions(+), 7 deletions(-)

diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index 399c28585b1414..6cba859d28c573 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -297,11 +297,7 @@ class cartesian_product_view<First, Vs...>::iterator {
 
   template <class Tuple>
   constexpr difference_type distance_from(const Tuple& t) const {
-    constexpr auto seq        = std::make_integer_sequence<int, sizeof...(Vs) + 1>{};
-    constexpr auto scaled_sum = [&t, this]<int... Ints>(std::integer_sequence<int, Ints...>) -> difference_type {
-      return (scaled_distance<Ints>(t) + ...);
-    };
-    return scaled_sum(seq);
+    return scaled_sum(t);
   }
 
   template <auto N>
@@ -311,10 +307,17 @@ class cartesian_product_view<First, Vs...>::iterator {
     return static_cast<difference_type>(1);
   }
 
-  template <auto N, class Tuple>
-  constexpr difference_type scaled_distance(const Tuple& t) const {
+  template <auto N>
+  constexpr difference_type scaled_distance(const auto& t) const {
     return static_cast<difference_type>(std::get<N>(current_) - std::get<N>(t)) * scaled_size<N + 1>();
   }
+
+  template <auto N = 0>
+  constexpr difference_type scaled_sum(const auto& t) const {
+    if constexpr (N <= sizeof...(Vs))
+      return scaled_distance<N>(t) + scaled_sum<N + 1>(t);
+    return static_cast<difference_type>(0);
+  }
 };
 
 } // namespace ranges

>From 018a50c71377e3ee39815f9ab97f2240bbd146a1 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sun, 13 Oct 2024 20:26:45 +0200
Subject: [PATCH 26/39] iterator: operator-(iterator, sentinel)

---
 libcxx/include/__ranges/cartesian_product_view.h | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index 6cba859d28c573..9d56422e65141d 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -218,10 +218,21 @@ class cartesian_product_view<First, Vs...>::iterator {
     return x.distance_from(y.current_);
   }
 
+  friend constexpr difference_type operator-(const iterator& i, default_sentinel_t)
+    requires cartesian_is_sized_sentinel<Const, sentinel_t, First, Vs...>
+  {
+    MultiIterator end_tuple;
+    std::get<0>(end_tuple) = ranges::end(std::get<0>(i.parent_->bases_));
+    for (int N = 1; N <= sizeof...(Vs); N++)
+      std::get<N>(end_tuple) = ranges::begin(std::get<N>(i.parent_->bases_));
+    return i.distance_from(end_tuple);
+  }
+
 private:
   using Parent    = __maybe_const<Const, cartesian_product_view>;
   Parent* parent_ = nullptr;
-  tuple<iterator_t<__maybe_const<Const, First>>, iterator_t<__maybe_const<Const, Vs>>...> current_;
+  using MultiIterator = tuple<iterator_t<__maybe_const<Const, First>>, iterator_t<__maybe_const<Const, Vs>>...>;
+  MultiIterator current_;
 
   constexpr iterator(Parent& parent, decltype(current_) current)
       : parent_(std::addressof(parent)), current_(std::move(current)) {}

>From ee0cf25395480cbe92e44fd880c8ccd8994cfea9 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sun, 13 Oct 2024 20:28:16 +0200
Subject: [PATCH 27/39] iterator: operator-(sentinel, iterator)

---
 libcxx/include/__ranges/cartesian_product_view.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index 9d56422e65141d..e76af70aaf5907 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -228,6 +228,12 @@ class cartesian_product_view<First, Vs...>::iterator {
     return i.distance_from(end_tuple);
   }
 
+  friend constexpr difference_type operator-(default_sentinel_t s, const iterator& i)
+    requires cartesian_is_sized_sentinel<Const, sentinel_t, First, Vs...>
+  {
+    return -(i - s);
+  }
+
 private:
   using Parent    = __maybe_const<Const, cartesian_product_view>;
   Parent* parent_ = nullptr;

>From 251219d86c8ce427067c067d40c11f4f818cafe1 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sun, 13 Oct 2024 20:38:16 +0200
Subject: [PATCH 28/39] iterator: iter_move(iterator)

---
 libcxx/include/__ranges/cartesian_product_view.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index e76af70aaf5907..a954b2e62aa992 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -12,6 +12,7 @@
 #include <__config>
 #include <__iterator/access.h> // begin
 #include <__iterator/distance.h>
+#include <__iterator/iter_move.h>
 #include <__iterator/next.h>
 #include <__memory/addressof.h>
 #include <__ranges/concepts.h> // forward_range, view, range_size_t, sized_range, ...
@@ -234,6 +235,10 @@ class cartesian_product_view<First, Vs...>::iterator {
     return -(i - s);
   }
 
+  friend constexpr auto iter_move(const iterator& i) /*fixme: noexcept(...) */ {
+    return __tuple_transform(ranges::iter_move, i.current_);
+  }
+
 private:
   using Parent    = __maybe_const<Const, cartesian_product_view>;
   Parent* parent_ = nullptr;

>From 3b7653dd4784628f42f450fca7ba5d3069c12672 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sun, 13 Oct 2024 20:46:50 +0200
Subject: [PATCH 29/39] iterator: iter_swap(iterator, iterator)

---
 libcxx/include/__ranges/cartesian_product_view.h | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index a954b2e62aa992..4903eb4773c00e 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -239,6 +239,13 @@ class cartesian_product_view<First, Vs...>::iterator {
     return __tuple_transform(ranges::iter_move, i.current_);
   }
 
+  friend constexpr void iter_swap(const iterator& l, const iterator& r) /*fixme: noexcept(...) */
+    requires(indirectly_swappable<iterator_t<__maybe_const<Const, First>>> && ... &&
+             indirectly_swappable<iterator_t<__maybe_const<Const, Vs>>>)
+  {
+    iter_swap_helper(l, r);
+  }
+
 private:
   using Parent    = __maybe_const<Const, cartesian_product_view>;
   Parent* parent_ = nullptr;
@@ -340,6 +347,13 @@ class cartesian_product_view<First, Vs...>::iterator {
       return scaled_distance<N>(t) + scaled_sum<N + 1>(t);
     return static_cast<difference_type>(0);
   }
+
+  template <auto N = sizeof...(Vs)>
+  static constexpr void iter_swap_helper(const iterator& l, const iterator& r) {
+    ranges::iter_swap(std::get<N>(l.current_), std::get<N>(r.current_));
+    if constexpr (N > 0)
+      iter_swap_helper<N - 1>(l, r);
+  }
 };
 
 } // namespace ranges

>From 12a45a4a737dc8c9135b65fea3e871258a6484b8 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 18 Oct 2024 22:29:02 +0200
Subject: [PATCH 30/39] concept; style change

---
 libcxx/include/__ranges/cartesian_product_view.h | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index 4903eb4773c00e..035c60a6a94388 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -47,6 +47,9 @@ concept cartesian_product_is_bidirectional =
     (bidirectional_range<__maybe_const<Const, First>> && ... &&
      (bidirectional_range<__maybe_const<Const, Vs>> && cartesian_product_common_arg<__maybe_const<Const, Vs>>));
 
+template <class First, class... Vs>
+concept cartesian_product_is_common = cartesian_product_common_arg<First>;
+
 template <class... Vs>
 concept cartesian_product_is_sized = (sized_range<Vs> && ...);
 
@@ -72,7 +75,7 @@ concept __cartesian_product_all_random_access =
 template <input_range First, forward_range... Vs>
   requires(view<First> && ... && view<Vs>)
 class cartesian_product_view : public view_interface<cartesian_product_view<First, Vs...>> {
-public: // fixme: make private
+private:
   tuple<First, Vs...> bases_;
 
   template <bool Const>

>From f13264ae475e45188da096911e023a9c4afef740 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 18 Oct 2024 22:30:01 +0200
Subject: [PATCH 31/39] view: begin()

---
 libcxx/include/__ranges/cartesian_product_view.h | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index 035c60a6a94388..39e53bffecc628 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -86,6 +86,18 @@ class cartesian_product_view : public view_interface<cartesian_product_view<Firs
   constexpr explicit cartesian_product_view(First first_base, Vs... bases)
       : bases_{std::move(first_base), std::move(bases)...} {}
 
+  constexpr iterator<false> begin()
+    requires(!__simple_view<First> || ... || !__simple_view<Vs>)
+  {
+    return iterator<false>(*this, __tuple_transform(ranges::begin, bases_));
+  }
+
+  constexpr iterator<true> begin() const
+    requires(range<const First> && ... && range<const Vs>)
+  {
+    return iterator<true>(*this, __tuple_transform(ranges::begin, bases_));
+  }
+
   constexpr auto size()
     requires(sized_range<First> && ... && sized_range<Vs>)
   {
@@ -290,7 +302,7 @@ class cartesian_product_view<First, Vs...>::iterator {
     const auto& v    = std::get<N>(parent_->bases_);
     auto& it         = std::get<N>(current_);
     const auto sz    = static_cast<difference_type>(std::ranges::size(v));
-    const auto first = begin(v);
+    const auto first = ranges::begin(v);
 
     if (sz > 0) {
       const auto idx = static_cast<difference_type>(std::distance(first, it));

>From 2026a50231140f0faa0ccf3b5c844209466bb94e Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sun, 20 Oct 2024 22:07:01 +0200
Subject: [PATCH 32/39] view: end()

---
 .../include/__ranges/cartesian_product_view.h | 40 ++++++++++++++++++-
 1 file changed, 39 insertions(+), 1 deletion(-)

diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index 39e53bffecc628..1b9b5211687d46 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -98,6 +98,20 @@ class cartesian_product_view : public view_interface<cartesian_product_view<Firs
     return iterator<true>(*this, __tuple_transform(ranges::begin, bases_));
   }
 
+  constexpr iterator<false> end()
+    requires((!__simple_view<First> || ... || !__simple_view<Vs>) && cartesian_product_is_common<First, Vs...>)
+  {
+    constexpr bool is_const = false;
+    return end_impl<is_const>();
+  }
+
+  constexpr iterator<true> end() const
+    requires(cartesian_product_is_common<const First, const Vs...>)
+  {
+    constexpr bool is_const = true;
+    return end_impl<is_const>();
+  }
+
   constexpr auto size()
     requires(sized_range<First> && ... && sized_range<Vs>)
   {
@@ -111,6 +125,30 @@ class cartesian_product_view : public view_interface<cartesian_product_view<Firs
   }
 
 private:
+  template <bool is_const>
+  constexpr iterator<is_const> end_impl() const {
+    bool is_empty                  = end_is_empty();
+    const auto ranges_to_iterators = [is_empty, &b = bases_]<std::size_t... I>(std::index_sequence<I...>) {
+      const auto begin_or_first_end = [is_empty]<bool is_first>(const auto& rng) {
+        if constexpr (is_first)
+          return is_empty ? ranges::begin(rng) : cartesian_common_arg_end(rng);
+        return ranges::begin(rng);
+      };
+      return std::make_tuple(begin_or_first_end<I == 0>(std::get<I>(b))...);
+    };
+    iterator<is_const> it(*this, ranges_to_iterators(std::make_index_sequence<1 + sizeof...(Vs)>{}));
+    return it;
+  }
+
+  template <auto N = 0>
+  constexpr bool end_is_empty() const {
+    if constexpr (N == sizeof...(Vs))
+      return false;
+    if (const auto& v = std::get<N + 1>(bases_); ranges::empty(v))
+      return true;
+    return end_is_empty<N + 1>();
+  }
+
   constexpr auto size_impl() const {
     return std::apply(
         [](auto&&... bases) {
@@ -332,7 +370,7 @@ class cartesian_product_view<First, Vs...>::iterator {
 
   template <auto N = sizeof...(Vs)>
   constexpr bool at_end() const {
-    if (std::get<N>(current_) == end(std::get<N>(parent_->bases_)))
+    if (std::get<N>(current_) == ranges::end(std::get<N>(parent_->bases_)))
       return true;
     if constexpr (N > 0)
       return at_end<N - 1>();

>From 422d941bd8aaf94a12ca719e2a431ee244f33003 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sun, 3 Nov 2024 12:51:39 +0100
Subject: [PATCH 33/39] view: default_sentinel_t end()

---
 libcxx/include/__ranges/cartesian_product_view.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index 1b9b5211687d46..2b9b6dca4475c7 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -11,6 +11,7 @@
 
 #include <__config>
 #include <__iterator/access.h> // begin
+#include <__iterator/default_sentinel.h>
 #include <__iterator/distance.h>
 #include <__iterator/iter_move.h>
 #include <__iterator/next.h>
@@ -112,6 +113,8 @@ class cartesian_product_view : public view_interface<cartesian_product_view<Firs
     return end_impl<is_const>();
   }
 
+  constexpr default_sentinel_t end() const noexcept { return {}; }
+
   constexpr auto size()
     requires(sized_range<First> && ... && sized_range<Vs>)
   {

>From 68976baa38d4620ebcb24765903428565f8ff8e4 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sun, 3 Nov 2024 13:02:12 +0100
Subject: [PATCH 34/39] view: clarify helper func of end()

---
 libcxx/include/__ranges/cartesian_product_view.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index 2b9b6dca4475c7..09b32864c88f33 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -143,11 +143,11 @@ class cartesian_product_view : public view_interface<cartesian_product_view<Firs
     return it;
   }
 
-  template <auto N = 0>
+  template <auto N = 1>
   constexpr bool end_is_empty() const {
-    if constexpr (N == sizeof...(Vs))
+    if constexpr (N == 1 + sizeof...(Vs))
       return false;
-    if (const auto& v = std::get<N + 1>(bases_); ranges::empty(v))
+    if (const auto& v = std::get<N>(bases_); ranges::empty(v))
       return true;
     return end_is_empty<N + 1>();
   }

>From 471c3601065d764f7a13493ff15b2fd41baeceb3 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sun, 3 Nov 2024 13:08:06 +0100
Subject: [PATCH 35/39] view: end(), size(): cleanup requires

---
 libcxx/include/__ranges/cartesian_product_view.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index 09b32864c88f33..8bd99552c9e109 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -107,7 +107,7 @@ class cartesian_product_view : public view_interface<cartesian_product_view<Firs
   }
 
   constexpr iterator<true> end() const
-    requires(cartesian_product_is_common<const First, const Vs...>)
+    requires cartesian_product_is_common<const First, const Vs...>
   {
     constexpr bool is_const = true;
     return end_impl<is_const>();
@@ -116,13 +116,13 @@ class cartesian_product_view : public view_interface<cartesian_product_view<Firs
   constexpr default_sentinel_t end() const noexcept { return {}; }
 
   constexpr auto size()
-    requires(sized_range<First> && ... && sized_range<Vs>)
+    requires cartesian_product_is_sized<First, Vs...>
   {
     return size_impl();
   }
 
   constexpr auto size() const
-    requires(sized_range<const First> && ... && sized_range<const Vs>)
+    requires cartesian_product_is_sized<const First, const Vs...>
   {
     return size_impl();
   }

>From e94372db5b3c36f956bf727ced0b6c30caea6611 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sun, 3 Nov 2024 13:26:40 +0100
Subject: [PATCH 36/39] iterator: iterator_concept

---
 libcxx/include/__ranges/cartesian_product_view.h | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index 8bd99552c9e109..088cd869a680f6 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -169,8 +169,20 @@ template <input_range First, forward_range... Vs>
   requires(view<First> && ... && view<Vs>)
 template <bool Const>
 class cartesian_product_view<First, Vs...>::iterator {
+  static constexpr auto get_iterator_tag() {
+    if constexpr (cartesian_product_is_random_access<Const, First, Vs...>)
+      return random_access_iterator_tag{};
+    else if constexpr (cartesian_product_is_bidirectional<Const, First, Vs...>)
+      return bidirectional_iterator_tag{};
+    else if constexpr (forward_range<__maybe_const<Const, First>>)
+      return forward_iterator_tag{};
+    else
+      return input_iterator_tag{};
+  }
+
 public:
   using iterator_category = input_iterator_tag;
+  using iterator_concept  = decltype(get_iterator_tag());
   using value_type = tuple<range_value_t<__maybe_const<Const, First>>, range_value_t<__maybe_const<Const, Vs>>...>;
   using reference =
       tuple<range_reference_t<__maybe_const<Const, First>>, range_reference_t<__maybe_const<Const, Vs>>...>;

>From 948ae96409ad1142282eac5041958a84a9a400cf Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sun, 3 Nov 2024 21:46:05 +0100
Subject: [PATCH 37/39] iterator: multiple smaller fixes/cleanups

---
 .../include/__ranges/cartesian_product_view.h | 41 +++++++++----------
 1 file changed, 20 insertions(+), 21 deletions(-)

diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index 088cd869a680f6..79e7cff84d4cdf 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -193,7 +193,7 @@ class cartesian_product_view<First, Vs...>::iterator {
   constexpr iterator(iterator<!Const> i)
     requires Const && (convertible_to<iterator_t<First>, iterator_t<const First>> && ... &&
                        convertible_to<iterator_t<Vs>, iterator_t<const Vs>>)
-      : parent_(std::addressof(i.parent_)), current_(std::move(i.current_)) {}
+      : parent_(i.parent_), current_(std::move(i.current_)) {}
 
   constexpr auto operator*() const {
     return __tuple_transform([](auto& i) -> decltype(auto) { return *i; }, current_);
@@ -204,13 +204,13 @@ class cartesian_product_view<First, Vs...>::iterator {
     return *this;
   }
 
-  constexpr void operator++(int) { next(); }
+  constexpr void operator++(int) { ++*this; }
 
   constexpr iterator operator++(int)
     requires forward_range<__maybe_const<Const, First>>
   {
     auto tmp = *this;
-    next();
+    ++*this;
     return tmp;
   }
 
@@ -225,7 +225,7 @@ class cartesian_product_view<First, Vs...>::iterator {
     requires cartesian_product_is_bidirectional<Const, First, Vs...>
   {
     auto tmp = *this;
-    prev();
+    --*this;
     return tmp;
   }
 
@@ -281,8 +281,8 @@ class cartesian_product_view<First, Vs...>::iterator {
     return iterator(x) -= y;
   }
 
-  friend constexpr iterator operator-(const iterator& x, const iterator& y)
-    requires cartesian_product_is_random_access<Const, First, Vs...>
+  friend constexpr difference_type operator-(const iterator& x, const iterator& y)
+    requires cartesian_is_sized_sentinel<Const, iterator_t, First, Vs...>
   {
     return x.distance_from(y.current_);
   }
@@ -290,10 +290,9 @@ class cartesian_product_view<First, Vs...>::iterator {
   friend constexpr difference_type operator-(const iterator& i, default_sentinel_t)
     requires cartesian_is_sized_sentinel<Const, sentinel_t, First, Vs...>
   {
-    MultiIterator end_tuple;
-    std::get<0>(end_tuple) = ranges::end(std::get<0>(i.parent_->bases_));
-    for (int N = 1; N <= sizeof...(Vs); N++)
-      std::get<N>(end_tuple) = ranges::begin(std::get<N>(i.parent_->bases_));
+    tuple end_tuple = [&b = i.parent_->bases_]<size_t... I>(index_sequence<I...>) {
+      return tuple{ranges::end(std::get<0>(b)), ranges::begin(std::get<1 + I>(b))...};
+    }(std::make_index_sequence<sizeof...(Vs)>{});
     return i.distance_from(end_tuple);
   }
 
@@ -311,19 +310,16 @@ class cartesian_product_view<First, Vs...>::iterator {
     requires(indirectly_swappable<iterator_t<__maybe_const<Const, First>>> && ... &&
              indirectly_swappable<iterator_t<__maybe_const<Const, Vs>>>)
   {
-    iter_swap_helper(l, r);
+    iter_swap_impl(l, r);
   }
 
 private:
-  using Parent    = __maybe_const<Const, cartesian_product_view>;
-  Parent* parent_ = nullptr;
+  using Parent        = __maybe_const<Const, cartesian_product_view>;
+  Parent* parent_     = nullptr;
   using MultiIterator = tuple<iterator_t<__maybe_const<Const, First>>, iterator_t<__maybe_const<Const, Vs>>...>;
   MultiIterator current_;
 
-  constexpr iterator(Parent& parent, decltype(current_) current)
-      : parent_(std::addressof(parent)), current_(std::move(current)) {}
-
-  template <auto N = sizeof...(Vs)>
+  template <size_t N = sizeof...(Vs)>
   constexpr void next() {
     auto& it = std::get<N>(current_);
     ++it;
@@ -335,7 +331,7 @@ class cartesian_product_view<First, Vs...>::iterator {
     }
   }
 
-  template <auto N = sizeof...(Vs)>
+  template <size_t N = sizeof...(Vs)>
   constexpr void prev() {
     auto& it = std::get<N>(current_);
     if constexpr (N > 0) {
@@ -347,7 +343,7 @@ class cartesian_product_view<First, Vs...>::iterator {
     --it;
   }
 
-  template <std::size_t N = sizeof...(Vs)>
+  template <auto N = sizeof...(Vs)>
   constexpr void advance(difference_type x) {
     if (x == 0)
       return;
@@ -416,11 +412,14 @@ class cartesian_product_view<First, Vs...>::iterator {
     return static_cast<difference_type>(0);
   }
 
+  constexpr iterator(Parent& parent, MultiIterator current)
+      : parent_(std::addressof(parent)), current_(std::move(current)) {}
+
   template <auto N = sizeof...(Vs)>
-  static constexpr void iter_swap_helper(const iterator& l, const iterator& r) {
+  static constexpr void iter_swap_impl(const iterator& l, const iterator& r) {
     ranges::iter_swap(std::get<N>(l.current_), std::get<N>(r.current_));
     if constexpr (N > 0)
-      iter_swap_helper<N - 1>(l, r);
+      iter_swap_impl<N - 1>(l, r);
   }
 };
 

>From 6307a12a290db8ea2b11c5bbeaecb1db9a5eaccc Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sun, 17 Nov 2024 15:44:14 +0100
Subject: [PATCH 38/39] iterator: iter_move noexcept requirements

---
 libcxx/include/__ranges/cartesian_product_view.h | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index 79e7cff84d4cdf..3dfdb05fb3d3db 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -302,7 +302,7 @@ class cartesian_product_view<First, Vs...>::iterator {
     return -(i - s);
   }
 
-  friend constexpr auto iter_move(const iterator& i) /*fixme: noexcept(...) */ {
+  friend constexpr auto iter_move(const iterator& i) noexcept(iter_move_noexcept_impl(i)) {
     return __tuple_transform(ranges::iter_move, i.current_);
   }
 
@@ -415,6 +415,19 @@ class cartesian_product_view<First, Vs...>::iterator {
   constexpr iterator(Parent& parent, MultiIterator current)
       : parent_(std::addressof(parent)), current_(std::move(current)) {}
 
+  template <auto N = sizeof...(Vs)>
+  static constexpr bool iter_move_noexcept_impl(const iterator& i) {
+    if (not noexcept(std::ranges::iter_move(std::get<N>(i.current_))))
+      return false;
+    if constexpr (N > 0)
+      return iter_move_noexcept_impl<N - 1>(i);
+
+    return std::is_nothrow_move_constructible_v<
+               std::ranges::range_rvalue_reference_t<__maybe_const<Const, First>>>() and
+           (std::is_nothrow_move_constructible_v<std::ranges::range_rvalue_reference_t<__maybe_const<Const, Vs>>>() and
+            ...);
+  }
+
   template <auto N = sizeof...(Vs)>
   static constexpr void iter_swap_impl(const iterator& l, const iterator& r) {
     ranges::iter_swap(std::get<N>(l.current_), std::get<N>(r.current_));

>From ded8d7d66fa2d47f4d5ede81084ee2892297f52a Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sun, 17 Nov 2024 15:51:32 +0100
Subject: [PATCH 39/39] iterator: iter_swap noexcept requirements

---
 libcxx/include/__ranges/cartesian_product_view.h | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index 3dfdb05fb3d3db..2e252503d90c42 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -306,7 +306,7 @@ class cartesian_product_view<First, Vs...>::iterator {
     return __tuple_transform(ranges::iter_move, i.current_);
   }
 
-  friend constexpr void iter_swap(const iterator& l, const iterator& r) /*fixme: noexcept(...) */
+  friend constexpr void iter_swap(const iterator& l, const iterator& r) noexcept(iter_swap_noexcept_impl(l, r))
     requires(indirectly_swappable<iterator_t<__maybe_const<Const, First>>> && ... &&
              indirectly_swappable<iterator_t<__maybe_const<Const, Vs>>>)
   {
@@ -428,6 +428,15 @@ class cartesian_product_view<First, Vs...>::iterator {
             ...);
   }
 
+  template <auto i = sizeof...(Vs)>
+  static constexpr bool iter_swap_noexcept_impl(const iterator& l, const iterator& r) {
+    if (not noexcept(std::ranges::iter_swap(std::get<i>(l.current_), std::get<i>(r.current_))))
+      return false;
+    if constexpr (i > 0)
+      return iter_move_noexcept_impl<i - 1>(i);
+    return true;
+  }
+
   template <auto N = sizeof...(Vs)>
   static constexpr void iter_swap_impl(const iterator& l, const iterator& r) {
     ranges::iter_swap(std::get<N>(l.current_), std::get<N>(r.current_));



More information about the libcxx-commits mailing list