[libcxx-commits] [libcxx] [libc++][c++23] P2374: `views::cartesian_product` (PR #111215)
via libcxx-commits
libcxx-commits at lists.llvm.org
Sat Dec 7 12:07:40 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/49] 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/49] 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/49] 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/49] 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/49] 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/49] 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/49] 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/49] 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/49] 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/49] 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/49] 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/49] 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/49] 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/49] 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/49] 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/49] 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/49] 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/49] 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/49] 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/49] 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/49] 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/49] 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/49] 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/49] 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/49] 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/49] 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/49] 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/49] 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/49] 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/49] 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/49] 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/49] 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/49] 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/49] 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/49] 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/49] 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/49] 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/49] 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/49] 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_));
>From d614bfb05f633768c21f12076c26bac8cf6d6253 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sun, 17 Nov 2024 21:59:31 +0100
Subject: [PATCH 40/49] test view::begin() WIP
---
.../include/__ranges/cartesian_product_view.h | 19 +-
.../begin.pass.cpp | 120 +++++
.../range.cartesian.product.view/types.h | 438 ++++++++++++++++++
.../ranges/range.adaptors/range.zip/types.h | 2 +-
4 files changed, 571 insertions(+), 8 deletions(-)
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/begin.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/types.h
diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index 2e252503d90c42..9bbdcb0550841c 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -132,24 +132,27 @@ class cartesian_product_view : public view_interface<cartesian_product_view<Firs
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)
+ const auto begin_or_first_end = [is_empty]<class is_first>(is_first, const auto& rng) {
+ if constexpr (is_first::value)
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))...);
+
+ return std::make_tuple(begin_or_first_end(std::bool_constant<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 = 1>
+ template <std::size_t N = 1>
constexpr bool end_is_empty() const {
if constexpr (N == 1 + sizeof...(Vs))
return false;
- if (const auto& v = std::get<N>(bases_); ranges::empty(v))
- return true;
- return end_is_empty<N + 1>();
+ else {
+ if (const auto& v = std::get<N>(bases_); ranges::empty(v))
+ return true;
+ return end_is_empty<N + 1>();
+ }
}
constexpr auto size_impl() const {
@@ -180,6 +183,8 @@ class cartesian_product_view<First, Vs...>::iterator {
return input_iterator_tag{};
}
+ friend cartesian_product_view;
+
public:
using iterator_category = input_iterator_tag;
using iterator_concept = decltype(get_iterator_tag());
diff --git a/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/begin.pass.cpp
new file mode 100644
index 00000000000000..e4c29640ea7931
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/begin.pass.cpp
@@ -0,0 +1,120 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// constexpr iterator<false> begin() requires (!simple-view<First> || ... || !simple-view <Vs>);
+// constexpr iterator<true > begin() const requires (range<const First> && ... && range<const Vs>);
+
+#include <ranges>
+
+// #include <cassert>
+// #include <concepts>
+// #include <tuple>
+// #include <utility>
+
+#include "types.h"
+
+template <class T>
+concept HasConstBegin = requires(const T& ct) { ct.begin(); };
+
+template <class T>
+concept HasNonConstBegin = requires(T& t) { t.begin(); };
+
+template <class T>
+concept HasConstAndNonConstBegin =
+ HasConstBegin<T> && HasNonConstBegin<T> &&
+ requires(T& t, const T& ct) { requires !std::same_as<decltype(t.begin()), decltype(ct.begin())>; };
+
+template <class T>
+concept HasOnlyNonConstBegin = HasNonConstBegin<T> && !HasConstBegin<T>;
+
+template <class T>
+concept HasOnlyConstBegin = HasConstBegin<T> && !HasConstAndNonConstBegin<T>;
+
+struct OnlyNonConstBeginView : std::ranges::view_base {
+ int* begin();
+ int* end();
+};
+
+constexpr bool test() {
+ int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+
+ { // all underlying iterators should be at the begin position
+ { // non-const
+ std::ranges::cartesian_product_view v(
+ SizedRandomAccessView{buffer}, std::views::iota(0), std::ranges::single_view(2.0));
+ std::same_as<std::tuple<int&, int, double&>> decltype(auto) val = *v.begin();
+ assert(val == std::make_tuple(1, 0, 2.0));
+ assert(&(std::get<0>(val)) == &buffer[0]);
+ }
+ { // const
+ const std::ranges::cartesian_product_view v(
+ SizedRandomAccessView{buffer}, std::views::iota(0), std::ranges::single_view(2.0));
+ std::same_as<std::tuple<int&, int, const double&>> decltype(auto) val = *v.begin();
+ assert(val == std::make_tuple(1, 0, 2.0));
+ assert(&(std::get<0>(val)) == &buffer[0]);
+ }
+ }
+
+ { // with empty range
+ { // non-const
+ std::ranges::cartesian_product_view v(SizedRandomAccessView{buffer}, std::ranges::empty_view<int>());
+ assert(v.begin() == v.end());
+ }
+ { // const
+ const std::ranges::cartesian_product_view v(SizedRandomAccessView{buffer}, std::ranges::empty_view<int>());
+ assert(v.begin() == v.end());
+ }
+ }
+
+ {
+ // underlying ranges all model simple-view
+ std::ranges::cartesian_product_view v(SimpleCommon{buffer}, SimpleCommon{buffer});
+ static_assert(std::is_same_v<decltype(v.begin()), decltype(std::as_const(v).begin())>);
+ assert(v.begin() == std::as_const(v).begin());
+ auto [x, y] = *std::as_const(v).begin();
+ assert(&x == &buffer[0]);
+ assert(&y == &buffer[0]);
+
+ using View = decltype(v);
+ static_assert(std::ranges::__simple_view<SimpleCommon>);
+ static_assert(HasOnlyConstBegin<View>);
+ static_assert(!HasOnlyNonConstBegin<View>);
+ static_assert(!HasConstAndNonConstBegin<View>);
+ }
+
+ // {
+ // // not all underlying ranges model simple-view
+ // std::ranges::zip_view v(SimpleCommon{buffer}, NonSimpleNonCommon{buffer});
+ // static_assert(!std::is_same_v<decltype(v.begin()), decltype(std::as_const(v).begin())>);
+ // assert(v.begin() == std::as_const(v).begin());
+ // auto [x, y] = *std::as_const(v).begin();
+ // assert(&x == &buffer[0]);
+ // assert(&y == &buffer[0]);
+
+ // using View = decltype(v);
+ // static_assert(!HasOnlyConstBegin<View>);
+ // static_assert(!HasOnlyNonConstBegin<View>);
+ // static_assert(HasConstAndNonConstBegin<View>);
+ // }
+
+ // {
+ // // underlying const R is not a range
+ // using View = std::ranges::zip_view<SimpleCommon, NoConstBeginView>;
+ // static_assert(!HasOnlyConstBegin<View>);
+ // static_assert(HasOnlyNonConstBegin<View>);
+ // static_assert(!HasConstAndNonConstBegin<View>);
+ // }
+ return true;
+}
+
+int main() {
+ test();
+ static_assert(test());
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/types.h b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/types.h
new file mode 100644
index 00000000000000..1426371770050b
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/types.h
@@ -0,0 +1,438 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_CARTESIAN_PRODUCT_VIEW_TYPES_H
+#define TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_CARTESIAN_PRODUCT_VIEW_TYPES_H
+
+#include <functional>
+#include <ranges>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "test_range.h"
+
+#if TEST_STD_VER <= 20
+# error "range.cartesian.product.view/types.h" can only be included in builds supporting C++23
+#endif // TEST_STD_VER <= 20
+
+template <class T>
+struct BufferView : std::ranges::view_base {
+ T* buffer_;
+ std::size_t size_;
+
+ template <std::size_t N>
+ constexpr BufferView(T (&b)[N]) : buffer_(b), size_(N) {}
+};
+
+using IntBufferView = BufferView<int>;
+
+template <bool Simple>
+struct Common : IntBufferView {
+ using IntBufferView::IntBufferView;
+
+ constexpr int* begin()
+ requires(!Simple)
+ {
+ return buffer_;
+ }
+ constexpr const int* begin() const { return buffer_; }
+ constexpr int* end()
+ requires(!Simple)
+ {
+ return buffer_ + size_;
+ }
+ constexpr const int* end() const { return buffer_ + size_; }
+};
+using SimpleCommon = Common<true>;
+// using NonSimpleCommon = Common<false>;
+
+// using SimpleCommonRandomAccessSized = SimpleCommon;
+// using NonSimpleCommonRandomAccessSized = NonSimpleCommon;
+
+// static_assert(std::ranges::common_range<Common<true>>);
+// static_assert(std::ranges::random_access_range<SimpleCommon>);
+// static_assert(std::ranges::sized_range<SimpleCommon>);
+// static_assert(simple_view<SimpleCommon>);
+// static_assert(!simple_view<NonSimpleCommon>);
+
+// template <bool Simple>
+// struct CommonNonRandom : IntBufferView {
+// using IntBufferView::IntBufferView;
+// using const_iterator = forward_iterator<const int*>;
+// using iterator = forward_iterator<int*>;
+// constexpr iterator begin()
+// requires(!Simple) {
+// return iterator(buffer_);
+// }
+// constexpr const_iterator begin() const { return const_iterator(buffer_); }
+// constexpr iterator end()
+// requires(!Simple) {
+// return iterator(buffer_ + size_);
+// }
+// constexpr const_iterator end() const { return const_iterator(buffer_ + size_); }
+// };
+
+// using SimpleCommonNonRandom = CommonNonRandom<true>;
+// using NonSimpleCommonNonRandom = CommonNonRandom<false>;
+
+// static_assert(std::ranges::common_range<SimpleCommonNonRandom>);
+// static_assert(!std::ranges::random_access_range<SimpleCommonNonRandom>);
+// static_assert(!std::ranges::sized_range<SimpleCommonNonRandom>);
+// static_assert(simple_view<SimpleCommonNonRandom>);
+// static_assert(!simple_view<NonSimpleCommonNonRandom>);
+
+// template <bool Simple>
+// struct NonCommon : IntBufferView {
+// using IntBufferView::IntBufferView;
+// constexpr int* begin()
+// requires(!Simple) {
+// return buffer_;
+// }
+// constexpr const int* begin() const { return buffer_; }
+// constexpr sentinel_wrapper<int*> end()
+// requires(!Simple) {
+// return sentinel_wrapper<int*>(buffer_ + size_);
+// }
+// constexpr sentinel_wrapper<const int*> end() const { return sentinel_wrapper<const int*>(buffer_ + size_); }
+// };
+
+// using SimpleNonCommon = NonCommon<true>;
+// using NonSimpleNonCommon = NonCommon<false>;
+
+// static_assert(!std::ranges::common_range<SimpleNonCommon>);
+// static_assert(std::ranges::random_access_range<SimpleNonCommon>);
+// static_assert(!std::ranges::sized_range<SimpleNonCommon>);
+// static_assert(simple_view<SimpleNonCommon>);
+// static_assert(!simple_view<NonSimpleNonCommon>);
+
+// template <bool Simple>
+// struct NonCommonSized : IntBufferView {
+// using IntBufferView::IntBufferView;
+// constexpr int* begin()
+// requires(!Simple) {
+// return buffer_;
+// }
+// constexpr const int* begin() const { return buffer_; }
+// constexpr sentinel_wrapper<int*> end()
+// requires(!Simple) {
+// return sentinel_wrapper<int*>(buffer_ + size_);
+// }
+// constexpr sentinel_wrapper<const int*> end() const { return sentinel_wrapper<const int*>(buffer_ + size_); }
+// constexpr std::size_t size() const { return size_; }
+// };
+
+// using SimpleNonCommonSized = NonCommonSized<true>;
+// using SimpleNonCommonRandomAccessSized = SimpleNonCommonSized;
+// using NonSimpleNonCommonSized = NonCommonSized<false>;
+// using NonSimpleNonCommonRandomAccessSized = NonSimpleNonCommonSized;
+
+// static_assert(!std::ranges::common_range<SimpleNonCommonSized>);
+// static_assert(std::ranges::random_access_range<SimpleNonCommonSized>);
+// static_assert(std::ranges::sized_range<SimpleNonCommonSized>);
+// static_assert(simple_view<SimpleNonCommonSized>);
+// static_assert(!simple_view<NonSimpleNonCommonSized>);
+
+// template <bool Simple>
+// struct NonCommonNonRandom : IntBufferView {
+// using IntBufferView::IntBufferView;
+
+// using const_iterator = forward_iterator<const int*>;
+// using iterator = forward_iterator<int*>;
+
+// constexpr iterator begin()
+// requires(!Simple) {
+// return iterator(buffer_);
+// }
+// constexpr const_iterator begin() const { return const_iterator(buffer_); }
+// constexpr sentinel_wrapper<iterator> end()
+// requires(!Simple) {
+// return sentinel_wrapper<iterator>(iterator(buffer_ + size_));
+// }
+// constexpr sentinel_wrapper<const_iterator> end() const {
+// return sentinel_wrapper<const_iterator>(const_iterator(buffer_ + size_));
+// }
+// };
+
+// using SimpleNonCommonNonRandom = NonCommonNonRandom<true>;
+// using NonSimpleNonCommonNonRandom = NonCommonNonRandom<false>;
+
+// static_assert(!std::ranges::common_range<SimpleNonCommonNonRandom>);
+// static_assert(!std::ranges::random_access_range<SimpleNonCommonNonRandom>);
+// static_assert(!std::ranges::sized_range<SimpleNonCommonNonRandom>);
+// static_assert(simple_view<SimpleNonCommonNonRandom>);
+// static_assert(!simple_view<NonSimpleNonCommonNonRandom>);
+
+// template <class Iter, class Sent = Iter, class NonConstIter = Iter, class NonConstSent = Sent>
+// struct BasicView : IntBufferView {
+// using IntBufferView::IntBufferView;
+
+// constexpr NonConstIter begin()
+// requires(!std::is_same_v<Iter, NonConstIter>) {
+// return NonConstIter(buffer_);
+// }
+// constexpr Iter begin() const { return Iter(buffer_); }
+
+// constexpr NonConstSent end()
+// requires(!std::is_same_v<Sent, NonConstSent>) {
+// if constexpr (std::is_same_v<NonConstIter, NonConstSent>) {
+// return NonConstIter(buffer_ + size_);
+// } else {
+// return NonConstSent(NonConstIter(buffer_ + size_));
+// }
+// }
+
+// constexpr Sent end() const {
+// if constexpr (std::is_same_v<Iter, Sent>) {
+// return Iter(buffer_ + size_);
+// } else {
+// return Sent(Iter(buffer_ + size_));
+// }
+// }
+// };
+
+// template <class Base = int*>
+// struct forward_sized_iterator {
+// Base it_ = nullptr;
+
+// using iterator_category = std::forward_iterator_tag;
+// using value_type = int;
+// using difference_type = std::intptr_t;
+// using pointer = Base;
+// using reference = decltype(*Base{});
+
+// forward_sized_iterator() = default;
+// constexpr forward_sized_iterator(Base it) : it_(it) {}
+
+// constexpr reference operator*() const { return *it_; }
+
+// constexpr forward_sized_iterator& operator++() {
+// ++it_;
+// return *this;
+// }
+// constexpr forward_sized_iterator operator++(int) { return forward_sized_iterator(it_++); }
+
+// friend constexpr bool operator==(const forward_sized_iterator&, const forward_sized_iterator&) = default;
+
+// friend constexpr difference_type operator-(const forward_sized_iterator& x, const forward_sized_iterator& y) {
+// return x.it_ - y.it_;
+// }
+// };
+// static_assert(std::forward_iterator<forward_sized_iterator<>>);
+// static_assert(std::sized_sentinel_for<forward_sized_iterator<>, forward_sized_iterator<>>);
+
+// using ForwardSizedView = BasicView<forward_sized_iterator<>>;
+// static_assert(std::ranges::forward_range<ForwardSizedView>);
+// static_assert(std::ranges::sized_range<ForwardSizedView>);
+// static_assert(std::ranges::common_range<ForwardSizedView>);
+// static_assert(!std::ranges::random_access_range<ForwardSizedView>);
+// static_assert(simple_view<ForwardSizedView>);
+
+// using NonSimpleForwardSizedView = BasicView<forward_sized_iterator<const int*>, forward_sized_iterator<const int*>,
+// forward_sized_iterator<int*>, forward_sized_iterator<int*>>;
+// static_assert(std::ranges::forward_range<NonSimpleForwardSizedView>);
+// static_assert(std::ranges::sized_range<NonSimpleForwardSizedView>);
+// static_assert(std::ranges::common_range<NonSimpleForwardSizedView>);
+// static_assert(!std::ranges::random_access_range<NonSimpleForwardSizedView>);
+// static_assert(!simple_view<NonSimpleForwardSizedView>);
+
+// using ForwardSizedNonCommon = BasicView<forward_sized_iterator<>, sized_sentinel<forward_sized_iterator<>>>;
+// static_assert(std::ranges::forward_range<ForwardSizedNonCommon>);
+// static_assert(std::ranges::sized_range<ForwardSizedNonCommon>);
+// static_assert(!std::ranges::common_range<ForwardSizedNonCommon>);
+// static_assert(!std::ranges::random_access_range<ForwardSizedNonCommon>);
+// static_assert(simple_view<ForwardSizedNonCommon>);
+
+// using NonSimpleForwardSizedNonCommon =
+// BasicView<forward_sized_iterator<const int*>, sized_sentinel<forward_sized_iterator<const int*>>,
+// forward_sized_iterator<int*>, sized_sentinel<forward_sized_iterator<int*>>>;
+// static_assert(std::ranges::forward_range<NonSimpleForwardSizedNonCommon>);
+// static_assert(std::ranges::sized_range<NonSimpleForwardSizedNonCommon>);
+// static_assert(!std::ranges::common_range<NonSimpleForwardSizedNonCommon>);
+// static_assert(!std::ranges::random_access_range<NonSimpleForwardSizedNonCommon>);
+// static_assert(!simple_view<NonSimpleForwardSizedNonCommon>);
+
+struct SizedRandomAccessView : IntBufferView {
+ using IntBufferView::IntBufferView;
+ using iterator = random_access_iterator<int*>;
+
+ constexpr auto begin() const { return iterator(buffer_); }
+ constexpr auto end() const { return sized_sentinel<iterator>(iterator(buffer_ + size_)); }
+
+ constexpr decltype(auto) operator[](std::size_t n) const { return *(begin() + n); }
+};
+static_assert(std::ranges::view<SizedRandomAccessView>);
+static_assert(std::ranges::random_access_range<SizedRandomAccessView>);
+static_assert(std::ranges::sized_range<SizedRandomAccessView>);
+
+// using NonSizedRandomAccessView =
+// BasicView<random_access_iterator<int*>, sentinel_wrapper<random_access_iterator<int*>>>;
+// static_assert(!std::ranges::contiguous_range<NonSizedRandomAccessView>);
+// static_assert(std::ranges::random_access_range<SizedRandomAccessView>);
+// static_assert(!std::ranges::common_range<NonSizedRandomAccessView>);
+// static_assert(!std::ranges::sized_range<NonSizedRandomAccessView>);
+// static_assert(simple_view<NonSizedRandomAccessView>);
+
+// using NonSimpleNonSizedRandomAccessView =
+// BasicView<random_access_iterator<const int*>, sentinel_wrapper<random_access_iterator<const int*>>,
+// random_access_iterator<int*>, sentinel_wrapper<random_access_iterator<int*>> >;
+// static_assert(!std::ranges::contiguous_range<NonSimpleNonSizedRandomAccessView>);
+// static_assert(std::ranges::random_access_range<NonSimpleNonSizedRandomAccessView>);
+// static_assert(!std::ranges::common_range<NonSimpleNonSizedRandomAccessView>);
+// static_assert(!std::ranges::sized_range<NonSimpleNonSizedRandomAccessView>);
+// static_assert(!simple_view<NonSimpleNonSizedRandomAccessView>);
+
+// using ContiguousCommonView = BasicView<int*>;
+// static_assert(std::ranges::contiguous_range<ContiguousCommonView>);
+// static_assert(std::ranges::common_range<ContiguousCommonView>);
+// static_assert(std::ranges::sized_range<ContiguousCommonView>);
+
+// using ContiguousNonCommonView = BasicView<int*, sentinel_wrapper<int*>>;
+// static_assert(std::ranges::contiguous_range<ContiguousNonCommonView>);
+// static_assert(!std::ranges::common_range<ContiguousNonCommonView>);
+// static_assert(!std::ranges::sized_range<ContiguousNonCommonView>);
+
+// using ContiguousNonCommonSized = BasicView<int*, sized_sentinel<int*>>;
+
+// static_assert(std::ranges::contiguous_range<ContiguousNonCommonSized>);
+// static_assert(!std::ranges::common_range<ContiguousNonCommonSized>);
+// static_assert(std::ranges::sized_range<ContiguousNonCommonSized>);
+
+// using InputCommonView = BasicView<common_input_iterator<int*>>;
+// static_assert(std::ranges::input_range<InputCommonView>);
+// static_assert(!std::ranges::forward_range<InputCommonView>);
+// static_assert(std::ranges::common_range<InputCommonView>);
+// static_assert(simple_view<InputCommonView>);
+
+// using NonSimpleInputCommonView = BasicView<common_input_iterator<const int*>, common_input_iterator<const int*>,
+// common_input_iterator<int*>, common_input_iterator<int*>>;
+// static_assert(std::ranges::input_range<NonSimpleInputCommonView>);
+// static_assert(!std::ranges::forward_range<NonSimpleInputCommonView>);
+// static_assert(std::ranges::common_range<NonSimpleInputCommonView>);
+// static_assert(!simple_view<NonSimpleInputCommonView>);
+
+// using InputNonCommonView = BasicView<common_input_iterator<int*>, sentinel_wrapper<common_input_iterator<int*>>>;
+// static_assert(std::ranges::input_range<InputNonCommonView>);
+// static_assert(!std::ranges::forward_range<InputNonCommonView>);
+// static_assert(!std::ranges::common_range<InputNonCommonView>);
+// static_assert(simple_view<InputNonCommonView>);
+
+// using NonSimpleInputNonCommonView =
+// BasicView<common_input_iterator<const int*>, sentinel_wrapper<common_input_iterator<const int*>>,
+// common_input_iterator<int*>, sentinel_wrapper<common_input_iterator<int*>>>;
+// static_assert(std::ranges::input_range<InputNonCommonView>);
+// static_assert(!std::ranges::forward_range<InputNonCommonView>);
+// static_assert(!std::ranges::common_range<InputNonCommonView>);
+// static_assert(!simple_view<NonSimpleInputNonCommonView>);
+
+// using BidiCommonView = BasicView<bidirectional_iterator<int*>>;
+// static_assert(!std::ranges::sized_range<BidiCommonView>);
+// static_assert(std::ranges::bidirectional_range<BidiCommonView>);
+// static_assert(!std::ranges::random_access_range<BidiCommonView>);
+// static_assert(std::ranges::common_range<BidiCommonView>);
+// static_assert(simple_view<BidiCommonView>);
+
+// using NonSimpleBidiCommonView = BasicView<bidirectional_iterator<const int*>, bidirectional_iterator<const int*>,
+// bidirectional_iterator<int*>, bidirectional_iterator<int*>>;
+// static_assert(!std::ranges::sized_range<NonSimpleBidiCommonView>);
+// static_assert(std::ranges::bidirectional_range<NonSimpleBidiCommonView>);
+// static_assert(!std::ranges::random_access_range<NonSimpleBidiCommonView>);
+// static_assert(std::ranges::common_range<NonSimpleBidiCommonView>);
+// static_assert(!simple_view<NonSimpleBidiCommonView>);
+
+// struct SizedBidiCommon : BidiCommonView {
+// using BidiCommonView::BidiCommonView;
+// std::size_t size() const { return base(end()) - base(begin()); }
+// };
+// static_assert(std::ranges::sized_range<SizedBidiCommon>);
+// static_assert(std::ranges::bidirectional_range<SizedBidiCommon>);
+// static_assert(!std::ranges::random_access_range<SizedBidiCommon>);
+// static_assert(std::ranges::common_range<SizedBidiCommon>);
+// static_assert(simple_view<SizedBidiCommon>);
+
+// struct NonSimpleSizedBidiCommon : NonSimpleBidiCommonView {
+// using NonSimpleBidiCommonView::NonSimpleBidiCommonView;
+// std::size_t size() const { return base(end()) - base(begin()); }
+// };
+// static_assert(std::ranges::sized_range<NonSimpleSizedBidiCommon>);
+// static_assert(std::ranges::bidirectional_range<NonSimpleSizedBidiCommon>);
+// static_assert(!std::ranges::random_access_range<NonSimpleSizedBidiCommon>);
+// static_assert(std::ranges::common_range<NonSimpleSizedBidiCommon>);
+// static_assert(!simple_view<NonSimpleSizedBidiCommon>);
+
+// using BidiNonCommonView = BasicView<bidirectional_iterator<int*>, sentinel_wrapper<bidirectional_iterator<int*>>>;
+// static_assert(!std::ranges::sized_range<BidiNonCommonView>);
+// static_assert(std::ranges::bidirectional_range<BidiNonCommonView>);
+// static_assert(!std::ranges::random_access_range<BidiNonCommonView>);
+// static_assert(!std::ranges::common_range<BidiNonCommonView>);
+// static_assert(simple_view<BidiNonCommonView>);
+
+// using NonSimpleBidiNonCommonView =
+// BasicView<bidirectional_iterator<const int*>, sentinel_wrapper<bidirectional_iterator<const int*>>,
+// bidirectional_iterator<int*>, sentinel_wrapper<bidirectional_iterator<int*>>>;
+// static_assert(!std::ranges::sized_range<NonSimpleBidiNonCommonView>);
+// static_assert(std::ranges::bidirectional_range<NonSimpleBidiNonCommonView>);
+// static_assert(!std::ranges::random_access_range<NonSimpleBidiNonCommonView>);
+// static_assert(!std::ranges::common_range<NonSimpleBidiNonCommonView>);
+// static_assert(!simple_view<NonSimpleBidiNonCommonView>);
+
+// using SizedBidiNonCommonView = BasicView<bidirectional_iterator<int*>, sized_sentinel<bidirectional_iterator<int*>>>;
+// static_assert(std::ranges::sized_range<SizedBidiNonCommonView>);
+// static_assert(std::ranges::bidirectional_range<SizedBidiNonCommonView>);
+// static_assert(!std::ranges::random_access_range<SizedBidiNonCommonView>);
+// static_assert(!std::ranges::common_range<SizedBidiNonCommonView>);
+// static_assert(simple_view<SizedBidiNonCommonView>);
+
+// using NonSimpleSizedBidiNonCommonView =
+// BasicView<bidirectional_iterator<const int*>, sized_sentinel<bidirectional_iterator<const int*>>,
+// bidirectional_iterator<int*>, sized_sentinel<bidirectional_iterator<int*>>>;
+// static_assert(std::ranges::sized_range<NonSimpleSizedBidiNonCommonView>);
+// static_assert(std::ranges::bidirectional_range<NonSimpleSizedBidiNonCommonView>);
+// static_assert(!std::ranges::random_access_range<NonSimpleSizedBidiNonCommonView>);
+// static_assert(!std::ranges::common_range<NonSimpleSizedBidiNonCommonView>);
+// static_assert(!simple_view<NonSimpleSizedBidiNonCommonView>);
+
+// namespace adltest{
+// struct iter_move_swap_iterator {
+
+// std::reference_wrapper<int> iter_move_called_times;
+// std::reference_wrapper<int> iter_swap_called_times;
+// int i = 0;
+
+// using iterator_category = std::input_iterator_tag;
+// using value_type = int;
+// using difference_type = std::intptr_t;
+
+// constexpr int operator*() const { return i; }
+
+// constexpr iter_move_swap_iterator& operator++() {
+// ++i;
+// return *this;
+// }
+// constexpr void operator++(int) { ++i; }
+
+// friend constexpr bool operator==(const iter_move_swap_iterator& x, std::default_sentinel_t) { return x.i == 5; }
+
+// friend constexpr int iter_move(iter_move_swap_iterator const& it) {
+// ++it.iter_move_called_times;
+// return it.i;
+// }
+// friend constexpr void iter_swap(iter_move_swap_iterator const& x, iter_move_swap_iterator const& y) {
+// ++x.iter_swap_called_times;
+// ++y.iter_swap_called_times;
+// }
+// };
+
+// struct IterMoveSwapRange {
+// int iter_move_called_times = 0;
+// int iter_swap_called_times = 0;
+// constexpr auto begin() { return iter_move_swap_iterator{iter_move_called_times, iter_swap_called_times}; }
+// constexpr auto end() const { return std::default_sentinel; }
+// };
+// } // namespace adltest
+
+#endif // TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_CARTESIAN_PRODUCT_VIEW_TYPES_H
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip/types.h b/libcxx/test/std/ranges/range.adaptors/range.zip/types.h
index e084dcfc41b0d9..7cd7fa6e68c6d1 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.zip/types.h
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip/types.h
@@ -17,7 +17,7 @@
#include "test_range.h"
#if TEST_STD_VER <= 20
-# error "range.zip/types.h" can only be included in builds supporting C++20
+# error "range.zip/types.h" can only be included in builds supporting C++23
#endif // TEST_STD_VER <= 20
template <class T>
>From 2c863572c5afb712c6a62415803cd031c11fc112 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 23 Nov 2024 20:23:05 +0100
Subject: [PATCH 41/49] test view::begin()
---
.../begin.pass.cpp | 62 +++++++++----------
.../range.cartesian.product.view/types.h | 30 ++++-----
2 files changed, 44 insertions(+), 48 deletions(-)
diff --git a/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/begin.pass.cpp
index e4c29640ea7931..47e79962a8e13c 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/begin.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/begin.pass.cpp
@@ -12,11 +12,10 @@
// constexpr iterator<true > begin() const requires (range<const First> && ... && range<const Vs>);
#include <ranges>
-
-// #include <cassert>
-// #include <concepts>
-// #include <tuple>
-// #include <utility>
+#include <cassert>
+#include <concepts>
+#include <tuple>
+#include <utility>
#include "types.h"
@@ -27,9 +26,9 @@ template <class T>
concept HasNonConstBegin = requires(T& t) { t.begin(); };
template <class T>
-concept HasConstAndNonConstBegin =
- HasConstBegin<T> && HasNonConstBegin<T> &&
- requires(T& t, const T& ct) { requires !std::same_as<decltype(t.begin()), decltype(ct.begin())>; };
+concept HasConstAndNonConstBegin = HasConstBegin<T> && HasNonConstBegin<T> && requires(T& t, const T& ct) {
+ requires !std::same_as<decltype(t.begin()), decltype(ct.begin())>;
+};
template <class T>
concept HasOnlyNonConstBegin = HasNonConstBegin<T> && !HasConstBegin<T>;
@@ -37,7 +36,7 @@ concept HasOnlyNonConstBegin = HasNonConstBegin<T> && !HasConstBegin<T>;
template <class T>
concept HasOnlyConstBegin = HasConstBegin<T> && !HasConstAndNonConstBegin<T>;
-struct OnlyNonConstBeginView : std::ranges::view_base {
+struct NoConstBeginView : std::ranges::view_base {
int* begin();
int* end();
};
@@ -73,8 +72,7 @@ constexpr bool test() {
}
}
- {
- // underlying ranges all model simple-view
+ { // underlying ranges all model simple-view
std::ranges::cartesian_product_view v(SimpleCommon{buffer}, SimpleCommon{buffer});
static_assert(std::is_same_v<decltype(v.begin()), decltype(std::as_const(v).begin())>);
assert(v.begin() == std::as_const(v).begin());
@@ -89,28 +87,26 @@ constexpr bool test() {
static_assert(!HasConstAndNonConstBegin<View>);
}
- // {
- // // not all underlying ranges model simple-view
- // std::ranges::zip_view v(SimpleCommon{buffer}, NonSimpleNonCommon{buffer});
- // static_assert(!std::is_same_v<decltype(v.begin()), decltype(std::as_const(v).begin())>);
- // assert(v.begin() == std::as_const(v).begin());
- // auto [x, y] = *std::as_const(v).begin();
- // assert(&x == &buffer[0]);
- // assert(&y == &buffer[0]);
-
- // using View = decltype(v);
- // static_assert(!HasOnlyConstBegin<View>);
- // static_assert(!HasOnlyNonConstBegin<View>);
- // static_assert(HasConstAndNonConstBegin<View>);
- // }
-
- // {
- // // underlying const R is not a range
- // using View = std::ranges::zip_view<SimpleCommon, NoConstBeginView>;
- // static_assert(!HasOnlyConstBegin<View>);
- // static_assert(HasOnlyNonConstBegin<View>);
- // static_assert(!HasConstAndNonConstBegin<View>);
- // }
+ { // not all underlying ranges model simple-view
+ std::ranges::cartesian_product_view v(SimpleCommon{buffer}, NonSimpleNonCommon{buffer});
+ static_assert(!std::is_same_v<decltype(v.begin()), decltype(std::as_const(v).begin())>);
+ assert(v.begin() == std::as_const(v).begin());
+ auto [x, y] = *std::as_const(v).begin();
+ assert(&x == &buffer[0]);
+ assert(&y == &buffer[0]);
+
+ using View = decltype(v);
+ static_assert(!HasOnlyConstBegin<View>);
+ static_assert(!HasOnlyNonConstBegin<View>);
+ static_assert(HasConstAndNonConstBegin<View>);
+ }
+
+ { // underlying const R is not a range
+ using View = std::ranges::cartesian_product_view<SimpleCommon, NoConstBeginView>;
+ static_assert(!HasOnlyConstBegin<View>);
+ static_assert(HasOnlyNonConstBegin<View>);
+ static_assert(!HasConstAndNonConstBegin<View>);
+ }
return true;
}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/types.h b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/types.h
index 1426371770050b..83f877334ffa75 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/types.h
+++ b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/types.h
@@ -86,23 +86,23 @@ using SimpleCommon = Common<true>;
// static_assert(simple_view<SimpleCommonNonRandom>);
// static_assert(!simple_view<NonSimpleCommonNonRandom>);
-// template <bool Simple>
-// struct NonCommon : IntBufferView {
-// using IntBufferView::IntBufferView;
-// constexpr int* begin()
-// requires(!Simple) {
-// return buffer_;
-// }
-// constexpr const int* begin() const { return buffer_; }
-// constexpr sentinel_wrapper<int*> end()
-// requires(!Simple) {
-// return sentinel_wrapper<int*>(buffer_ + size_);
-// }
-// constexpr sentinel_wrapper<const int*> end() const { return sentinel_wrapper<const int*>(buffer_ + size_); }
-// };
+template <bool Simple>
+struct NonCommon : IntBufferView {
+ using IntBufferView::IntBufferView;
+ constexpr int* begin()
+ requires(!Simple) {
+ return buffer_;
+ }
+ constexpr const int* begin() const { return buffer_; }
+ constexpr sentinel_wrapper<int*> end()
+ requires(!Simple) {
+ return sentinel_wrapper<int*>(buffer_ + size_);
+ }
+ constexpr sentinel_wrapper<const int*> end() const { return sentinel_wrapper<const int*>(buffer_ + size_); }
+};
// using SimpleNonCommon = NonCommon<true>;
-// using NonSimpleNonCommon = NonCommon<false>;
+using NonSimpleNonCommon = NonCommon<false>;
// static_assert(!std::ranges::common_range<SimpleNonCommon>);
// static_assert(std::ranges::random_access_range<SimpleNonCommon>);
>From 134a9f31ccf9ba0af8f740b2de61b59e09f10763 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 23 Nov 2024 21:13:01 +0100
Subject: [PATCH 42/49] test copied from std
---
.../example_from_std.pass.cpp | 72 +++++++++++++++++++
1 file changed, 72 insertions(+)
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/example_from_std.pass.cpp
diff --git a/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/example_from_std.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/example_from_std.pass.cpp
new file mode 100644
index 00000000000000..fb7f7daef96a31
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/example_from_std.pass.cpp
@@ -0,0 +1,72 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+#include <ranges>
+#include <cassert>
+#include <vector>
+#include <string>
+
+constexpr bool test() {
+ struct ConstexprStringStream {
+ std::string str;
+
+ constexpr ConstexprStringStream& operator<<(int x) {
+ return *this << char(x + 48);
+ }
+ constexpr ConstexprStringStream& operator<<(char c) {
+ str += c;
+ return *this;
+ }
+ };
+
+ const std::vector<int> v{0, 1, 2};
+ ConstexprStringStream out;
+ // fixme: replace by views::cartesian_product
+ for (auto&& [a, b, c] : std::ranges::cartesian_product_view(v, v, v)) {
+ out << a << ' ' << b << ' ' << c << '\n';
+ }
+
+ const std::string_view expected =
+ "0 0 0\n"
+ "0 0 1\n"
+ "0 0 2\n"
+ "0 1 0\n"
+ "0 1 1\n"
+ "0 1 2\n"
+ "0 2 0\n"
+ "0 2 1\n"
+ "0 2 2\n"
+ "1 0 0\n"
+ "1 0 1\n"
+ "1 0 2\n"
+ "1 1 0\n"
+ "1 1 1\n"
+ "1 1 2\n"
+ "1 2 0\n"
+ "1 2 1\n"
+ "1 2 2\n"
+ "2 0 0\n"
+ "2 0 1\n"
+ "2 0 2\n"
+ "2 1 0\n"
+ "2 1 1\n"
+ "2 1 2\n"
+ "2 2 0\n"
+ "2 2 1\n"
+ "2 2 2\n";
+ assert(out.str == expected);
+
+ return true;
+}
+
+int main() {
+ test();
+ static_assert(test());
+}
>From 39e9a29030b8e70fc328df0a5c776a1e7248d352 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 23 Nov 2024 21:31:21 +0100
Subject: [PATCH 43/49] views::cartesian_product + test
---
libcxx/include/__ranges/cartesian_product_view.h | 16 ++++++++++++++++
.../example_from_std.pass.cpp | 3 +--
2 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/libcxx/include/__ranges/cartesian_product_view.h b/libcxx/include/__ranges/cartesian_product_view.h
index 9bbdcb0550841c..4d95de846b3e9d 100644
--- a/libcxx/include/__ranges/cartesian_product_view.h
+++ b/libcxx/include/__ranges/cartesian_product_view.h
@@ -450,6 +450,22 @@ class cartesian_product_view<First, Vs...>::iterator {
}
};
+namespace views {
+namespace __cartesian_product {
+struct __fn {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()() { return views::single(tuple()); }
+
+ template <class... _Ranges>
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Ranges&&... __rs)
+ -> decltype(cartesian_product_view<all_t<_Ranges&&>...>(std::forward<_Ranges>(__rs)...)) {
+ return cartesian_product_view<all_t<_Ranges>...>(std::forward<_Ranges>(__rs)...);
+ }
+};
+} // namespace __cartesian_product
+inline namespace __cpo {
+inline constexpr auto cartesian_product = __cartesian_product::__fn{};
+} // namespace __cpo
+} // namespace views
} // namespace ranges
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/example_from_std.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/example_from_std.pass.cpp
index fb7f7daef96a31..cdab4750f2c2e6 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/example_from_std.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/example_from_std.pass.cpp
@@ -28,8 +28,7 @@ constexpr bool test() {
const std::vector<int> v{0, 1, 2};
ConstexprStringStream out;
- // fixme: replace by views::cartesian_product
- for (auto&& [a, b, c] : std::ranges::cartesian_product_view(v, v, v)) {
+ for (auto&& [a, b, c] : std::ranges::views::cartesian_product(v, v, v)) {
out << a << ' ' << b << ' ' << c << '\n';
}
>From f41452ef3e80871043adf4567008a5675bad189a Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sun, 24 Nov 2024 15:40:51 +0100
Subject: [PATCH 44/49] test view::begin() cleanup
---
.../begin.pass.cpp | 38 +++++++------------
1 file changed, 14 insertions(+), 24 deletions(-)
diff --git a/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/begin.pass.cpp
index 47e79962a8e13c..c1cd8e27fb1c70 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/begin.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/begin.pass.cpp
@@ -44,32 +44,22 @@ struct NoConstBeginView : std::ranges::view_base {
constexpr bool test() {
int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
- { // all underlying iterators should be at the begin position
- { // non-const
- std::ranges::cartesian_product_view v(
- SizedRandomAccessView{buffer}, std::views::iota(0), std::ranges::single_view(2.0));
- std::same_as<std::tuple<int&, int, double&>> decltype(auto) val = *v.begin();
- assert(val == std::make_tuple(1, 0, 2.0));
- assert(&(std::get<0>(val)) == &buffer[0]);
- }
- { // const
- const std::ranges::cartesian_product_view v(
- SizedRandomAccessView{buffer}, std::views::iota(0), std::ranges::single_view(2.0));
- std::same_as<std::tuple<int&, int, const double&>> decltype(auto) val = *v.begin();
- assert(val == std::make_tuple(1, 0, 2.0));
- assert(&(std::get<0>(val)) == &buffer[0]);
- }
+ { // all underlying iterators should be at the begin position
+ std::ranges::cartesian_product_view v(
+ SizedRandomAccessView{buffer}, std::views::iota(0), std::ranges::single_view(2.0));
+ std::same_as<std::tuple<int&, int, double&>> decltype(auto) mutVal = *v.begin();
+ std::same_as<std::tuple<int&, int, const double&>> decltype(auto) constVal =
+ *std::as_const(v).begin();
+ assert(mutVal == std::make_tuple(1, 0, 2.0));
+ assert(constVal == std::make_tuple(1, 0, 2.0));
+ assert(&(std::get<0>(mutVal)) == &buffer[0]);
+ assert(&(std::get<0>(constVal)) == &buffer[0]);
}
- { // with empty range
- { // non-const
- std::ranges::cartesian_product_view v(SizedRandomAccessView{buffer}, std::ranges::empty_view<int>());
- assert(v.begin() == v.end());
- }
- { // const
- const std::ranges::cartesian_product_view v(SizedRandomAccessView{buffer}, std::ranges::empty_view<int>());
- assert(v.begin() == v.end());
- }
+ { // with empty range
+ std::ranges::cartesian_product_view v(SizedRandomAccessView{buffer}, std::ranges::empty_view<int>());
+ assert(v.begin() == v.end());
+ assert(std::as_const(v).begin() == std::as_const(v).end());
}
{ // underlying ranges all model simple-view
>From 7ffc8e9eb6577ea01ec07d0c6beebfcaa9a9f8f3 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sun, 24 Nov 2024 19:44:25 +0100
Subject: [PATCH 45/49] test view default ctor
---
.../ctor.default.pass.cpp | 68 +++++++++++++++++++
1 file changed, 68 insertions(+)
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/ctor.default.pass.cpp
diff --git a/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/ctor.default.pass.cpp
new file mode 100644
index 00000000000000..f623d0f5c01927
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/ctor.default.pass.cpp
@@ -0,0 +1,68 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// cartesian_product_view() = default;
+
+#include <ranges>
+
+#include <cassert>
+#include <type_traits>
+#include <utility>
+
+constexpr int buff[] = {1, 2, 3};
+
+struct DefaultConstructibleView : std::ranges::view_base {
+ constexpr DefaultConstructibleView() : begin_(buff), end_(buff + 3) {}
+ constexpr int const* begin() const { return begin_; }
+ constexpr int const* end() const { return end_; }
+
+private:
+ int const* begin_;
+ int const* end_;
+};
+
+struct NoDefaultCtrView : std::ranges::view_base {
+ NoDefaultCtrView() = delete;
+ int* begin() const;
+ int* end() const;
+};
+
+// The default constructor requires all underlying views to be default constructible.
+// It is implicitly required by the tuple's constructor. If any of the iterators are
+// not default constructible, cartesian product iterator's =default would be implicitly deleted.
+static_assert(std::is_default_constructible_v<std::ranges::cartesian_product_view<DefaultConstructibleView>>);
+static_assert(std::is_default_constructible_v<
+ std::ranges::cartesian_product_view<DefaultConstructibleView, DefaultConstructibleView>>);
+static_assert(
+ !std::is_default_constructible_v<std::ranges::cartesian_product_view<DefaultConstructibleView, NoDefaultCtrView>>);
+static_assert(
+ !std::is_default_constructible_v<std::ranges::cartesian_product_view<NoDefaultCtrView, NoDefaultCtrView>>);
+static_assert(!std::is_default_constructible_v<std::ranges::cartesian_product_view<NoDefaultCtrView>>);
+
+constexpr bool test() {
+ {
+ using View = std::ranges::cartesian_product_view<DefaultConstructibleView, DefaultConstructibleView>;
+ View v = View(); // the default constructor is not explicit
+ assert(v.size() == 9);
+ auto it = v.begin();
+ using Value = std::tuple<const int&, const int&>;
+ assert(*it++ == Value(1, 1));
+ assert(*it++ == Value(1, 2));
+ assert(*it++ == Value(1, 3));
+ assert(*it++ == Value(2, 1));
+ }
+
+ return true;
+}
+
+int main() {
+ test();
+ static_assert(test());
+}
>From 0031ef35b38c9e78c52c16b0eadf6c01e0fbc793 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sun, 24 Nov 2024 20:01:03 +0100
Subject: [PATCH 46/49] test view ctor of views
---
.../ctor.views.pass.cpp | 89 +++++++++++++++++++
1 file changed, 89 insertions(+)
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/ctor.views.pass.cpp
diff --git a/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/ctor.views.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/ctor.views.pass.cpp
new file mode 100644
index 00000000000000..8acad61f878317
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/ctor.views.pass.cpp
@@ -0,0 +1,89 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// constexpr explicit cartesian_product_view(First first_base, Vs... bases);
+
+#include <ranges>
+#include <tuple>
+
+#include "../range.zip/types.h"
+
+template <class T>
+void conversion_test(T);
+
+template <class T, class... Args>
+concept implicitly_constructible_from = requires(Args&&... args) { conversion_test<T>({std::move(args)...}); };
+
+// test constructor is explicit
+static_assert(std::constructible_from<std::ranges::cartesian_product_view<SimpleCommon>, SimpleCommon>);
+static_assert(!implicitly_constructible_from<std::ranges::cartesian_product_view<SimpleCommon>, SimpleCommon>);
+
+static_assert(std::constructible_from<std::ranges::cartesian_product_view<SimpleCommon, SimpleCommon>, SimpleCommon, SimpleCommon>);
+static_assert(
+ !implicitly_constructible_from<std::ranges::cartesian_product_view<SimpleCommon, SimpleCommon>, SimpleCommon, SimpleCommon>);
+
+struct MoveAwareView : std::ranges::view_base {
+ int moves = 0;
+ constexpr MoveAwareView() = default;
+ constexpr MoveAwareView(MoveAwareView&& other) : moves(other.moves + 1) { other.moves = 1; }
+ constexpr MoveAwareView& operator=(MoveAwareView&& other) {
+ moves = other.moves + 1;
+ other.moves = 0;
+ return *this;
+ }
+ constexpr const int* begin() const { return &moves; }
+ constexpr const int* end() const { return &moves + 1; }
+};
+
+template <class View1, class View2>
+constexpr void constructorTest(auto&& buffer1, auto&& buffer2) {
+ std::ranges::cartesian_product_view v{View1{buffer1}, View2{buffer2}};
+ auto [i, j] = *v.begin();
+ assert(i == buffer1[0]);
+ assert(j == buffer2[0]);
+}
+
+constexpr bool test() {
+
+ int buffer[] = {1, 2, 3, 4, 5, 6, 7, 8};
+ int buffer2[] = {9, 8, 7, 6};
+
+ { // constructor from views
+ std::ranges::cartesian_product_view v(SizedRandomAccessView{buffer}, std::views::iota(0), std::ranges::single_view(2.));
+ assert(*v.begin() == std::make_tuple(1, 0, 2.0));
+ }
+
+ { // arguments are moved once
+ MoveAwareView mv;
+ std::ranges::cartesian_product_view v{std::move(mv), MoveAwareView{}};
+ auto [numMoves1, numMoves2] = *v.begin();
+ assert(numMoves1 == 2); // one move from the local variable to parameter, one move from parameter to member
+ assert(numMoves2 == 1);
+ }
+
+ { // input and forward
+ constructorTest<InputCommonView, ForwardSizedView>(buffer, buffer2);
+ }
+
+ { // bidi and random_access
+ constructorTest<BidiCommonView, SizedRandomAccessView>(buffer, buffer2);
+ }
+
+ { // contiguous
+ constructorTest<ContiguousCommonView, ContiguousCommonView>(buffer, buffer2);
+ }
+
+ return true;
+}
+
+int main() {
+ test();
+ static_assert(test());
+}
>From e00a81a4b2a81772f92e861f437f9bf3e4579381 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sun, 24 Nov 2024 20:02:43 +0100
Subject: [PATCH 47/49] test: use range.zip/types.h helper file
---
.../begin.pass.cpp | 2 +-
.../range.cartesian.product.view/types.h | 438 ------------------
2 files changed, 1 insertion(+), 439 deletions(-)
delete mode 100644 libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/types.h
diff --git a/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/begin.pass.cpp
index c1cd8e27fb1c70..7df8dbd57dcaac 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/begin.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/begin.pass.cpp
@@ -17,7 +17,7 @@
#include <tuple>
#include <utility>
-#include "types.h"
+#include "../range.zip/types.h"
template <class T>
concept HasConstBegin = requires(const T& ct) { ct.begin(); };
diff --git a/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/types.h b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/types.h
deleted file mode 100644
index 83f877334ffa75..00000000000000
--- a/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/types.h
+++ /dev/null
@@ -1,438 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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 TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_CARTESIAN_PRODUCT_VIEW_TYPES_H
-#define TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_CARTESIAN_PRODUCT_VIEW_TYPES_H
-
-#include <functional>
-#include <ranges>
-
-#include "test_macros.h"
-#include "test_iterators.h"
-#include "test_range.h"
-
-#if TEST_STD_VER <= 20
-# error "range.cartesian.product.view/types.h" can only be included in builds supporting C++23
-#endif // TEST_STD_VER <= 20
-
-template <class T>
-struct BufferView : std::ranges::view_base {
- T* buffer_;
- std::size_t size_;
-
- template <std::size_t N>
- constexpr BufferView(T (&b)[N]) : buffer_(b), size_(N) {}
-};
-
-using IntBufferView = BufferView<int>;
-
-template <bool Simple>
-struct Common : IntBufferView {
- using IntBufferView::IntBufferView;
-
- constexpr int* begin()
- requires(!Simple)
- {
- return buffer_;
- }
- constexpr const int* begin() const { return buffer_; }
- constexpr int* end()
- requires(!Simple)
- {
- return buffer_ + size_;
- }
- constexpr const int* end() const { return buffer_ + size_; }
-};
-using SimpleCommon = Common<true>;
-// using NonSimpleCommon = Common<false>;
-
-// using SimpleCommonRandomAccessSized = SimpleCommon;
-// using NonSimpleCommonRandomAccessSized = NonSimpleCommon;
-
-// static_assert(std::ranges::common_range<Common<true>>);
-// static_assert(std::ranges::random_access_range<SimpleCommon>);
-// static_assert(std::ranges::sized_range<SimpleCommon>);
-// static_assert(simple_view<SimpleCommon>);
-// static_assert(!simple_view<NonSimpleCommon>);
-
-// template <bool Simple>
-// struct CommonNonRandom : IntBufferView {
-// using IntBufferView::IntBufferView;
-// using const_iterator = forward_iterator<const int*>;
-// using iterator = forward_iterator<int*>;
-// constexpr iterator begin()
-// requires(!Simple) {
-// return iterator(buffer_);
-// }
-// constexpr const_iterator begin() const { return const_iterator(buffer_); }
-// constexpr iterator end()
-// requires(!Simple) {
-// return iterator(buffer_ + size_);
-// }
-// constexpr const_iterator end() const { return const_iterator(buffer_ + size_); }
-// };
-
-// using SimpleCommonNonRandom = CommonNonRandom<true>;
-// using NonSimpleCommonNonRandom = CommonNonRandom<false>;
-
-// static_assert(std::ranges::common_range<SimpleCommonNonRandom>);
-// static_assert(!std::ranges::random_access_range<SimpleCommonNonRandom>);
-// static_assert(!std::ranges::sized_range<SimpleCommonNonRandom>);
-// static_assert(simple_view<SimpleCommonNonRandom>);
-// static_assert(!simple_view<NonSimpleCommonNonRandom>);
-
-template <bool Simple>
-struct NonCommon : IntBufferView {
- using IntBufferView::IntBufferView;
- constexpr int* begin()
- requires(!Simple) {
- return buffer_;
- }
- constexpr const int* begin() const { return buffer_; }
- constexpr sentinel_wrapper<int*> end()
- requires(!Simple) {
- return sentinel_wrapper<int*>(buffer_ + size_);
- }
- constexpr sentinel_wrapper<const int*> end() const { return sentinel_wrapper<const int*>(buffer_ + size_); }
-};
-
-// using SimpleNonCommon = NonCommon<true>;
-using NonSimpleNonCommon = NonCommon<false>;
-
-// static_assert(!std::ranges::common_range<SimpleNonCommon>);
-// static_assert(std::ranges::random_access_range<SimpleNonCommon>);
-// static_assert(!std::ranges::sized_range<SimpleNonCommon>);
-// static_assert(simple_view<SimpleNonCommon>);
-// static_assert(!simple_view<NonSimpleNonCommon>);
-
-// template <bool Simple>
-// struct NonCommonSized : IntBufferView {
-// using IntBufferView::IntBufferView;
-// constexpr int* begin()
-// requires(!Simple) {
-// return buffer_;
-// }
-// constexpr const int* begin() const { return buffer_; }
-// constexpr sentinel_wrapper<int*> end()
-// requires(!Simple) {
-// return sentinel_wrapper<int*>(buffer_ + size_);
-// }
-// constexpr sentinel_wrapper<const int*> end() const { return sentinel_wrapper<const int*>(buffer_ + size_); }
-// constexpr std::size_t size() const { return size_; }
-// };
-
-// using SimpleNonCommonSized = NonCommonSized<true>;
-// using SimpleNonCommonRandomAccessSized = SimpleNonCommonSized;
-// using NonSimpleNonCommonSized = NonCommonSized<false>;
-// using NonSimpleNonCommonRandomAccessSized = NonSimpleNonCommonSized;
-
-// static_assert(!std::ranges::common_range<SimpleNonCommonSized>);
-// static_assert(std::ranges::random_access_range<SimpleNonCommonSized>);
-// static_assert(std::ranges::sized_range<SimpleNonCommonSized>);
-// static_assert(simple_view<SimpleNonCommonSized>);
-// static_assert(!simple_view<NonSimpleNonCommonSized>);
-
-// template <bool Simple>
-// struct NonCommonNonRandom : IntBufferView {
-// using IntBufferView::IntBufferView;
-
-// using const_iterator = forward_iterator<const int*>;
-// using iterator = forward_iterator<int*>;
-
-// constexpr iterator begin()
-// requires(!Simple) {
-// return iterator(buffer_);
-// }
-// constexpr const_iterator begin() const { return const_iterator(buffer_); }
-// constexpr sentinel_wrapper<iterator> end()
-// requires(!Simple) {
-// return sentinel_wrapper<iterator>(iterator(buffer_ + size_));
-// }
-// constexpr sentinel_wrapper<const_iterator> end() const {
-// return sentinel_wrapper<const_iterator>(const_iterator(buffer_ + size_));
-// }
-// };
-
-// using SimpleNonCommonNonRandom = NonCommonNonRandom<true>;
-// using NonSimpleNonCommonNonRandom = NonCommonNonRandom<false>;
-
-// static_assert(!std::ranges::common_range<SimpleNonCommonNonRandom>);
-// static_assert(!std::ranges::random_access_range<SimpleNonCommonNonRandom>);
-// static_assert(!std::ranges::sized_range<SimpleNonCommonNonRandom>);
-// static_assert(simple_view<SimpleNonCommonNonRandom>);
-// static_assert(!simple_view<NonSimpleNonCommonNonRandom>);
-
-// template <class Iter, class Sent = Iter, class NonConstIter = Iter, class NonConstSent = Sent>
-// struct BasicView : IntBufferView {
-// using IntBufferView::IntBufferView;
-
-// constexpr NonConstIter begin()
-// requires(!std::is_same_v<Iter, NonConstIter>) {
-// return NonConstIter(buffer_);
-// }
-// constexpr Iter begin() const { return Iter(buffer_); }
-
-// constexpr NonConstSent end()
-// requires(!std::is_same_v<Sent, NonConstSent>) {
-// if constexpr (std::is_same_v<NonConstIter, NonConstSent>) {
-// return NonConstIter(buffer_ + size_);
-// } else {
-// return NonConstSent(NonConstIter(buffer_ + size_));
-// }
-// }
-
-// constexpr Sent end() const {
-// if constexpr (std::is_same_v<Iter, Sent>) {
-// return Iter(buffer_ + size_);
-// } else {
-// return Sent(Iter(buffer_ + size_));
-// }
-// }
-// };
-
-// template <class Base = int*>
-// struct forward_sized_iterator {
-// Base it_ = nullptr;
-
-// using iterator_category = std::forward_iterator_tag;
-// using value_type = int;
-// using difference_type = std::intptr_t;
-// using pointer = Base;
-// using reference = decltype(*Base{});
-
-// forward_sized_iterator() = default;
-// constexpr forward_sized_iterator(Base it) : it_(it) {}
-
-// constexpr reference operator*() const { return *it_; }
-
-// constexpr forward_sized_iterator& operator++() {
-// ++it_;
-// return *this;
-// }
-// constexpr forward_sized_iterator operator++(int) { return forward_sized_iterator(it_++); }
-
-// friend constexpr bool operator==(const forward_sized_iterator&, const forward_sized_iterator&) = default;
-
-// friend constexpr difference_type operator-(const forward_sized_iterator& x, const forward_sized_iterator& y) {
-// return x.it_ - y.it_;
-// }
-// };
-// static_assert(std::forward_iterator<forward_sized_iterator<>>);
-// static_assert(std::sized_sentinel_for<forward_sized_iterator<>, forward_sized_iterator<>>);
-
-// using ForwardSizedView = BasicView<forward_sized_iterator<>>;
-// static_assert(std::ranges::forward_range<ForwardSizedView>);
-// static_assert(std::ranges::sized_range<ForwardSizedView>);
-// static_assert(std::ranges::common_range<ForwardSizedView>);
-// static_assert(!std::ranges::random_access_range<ForwardSizedView>);
-// static_assert(simple_view<ForwardSizedView>);
-
-// using NonSimpleForwardSizedView = BasicView<forward_sized_iterator<const int*>, forward_sized_iterator<const int*>,
-// forward_sized_iterator<int*>, forward_sized_iterator<int*>>;
-// static_assert(std::ranges::forward_range<NonSimpleForwardSizedView>);
-// static_assert(std::ranges::sized_range<NonSimpleForwardSizedView>);
-// static_assert(std::ranges::common_range<NonSimpleForwardSizedView>);
-// static_assert(!std::ranges::random_access_range<NonSimpleForwardSizedView>);
-// static_assert(!simple_view<NonSimpleForwardSizedView>);
-
-// using ForwardSizedNonCommon = BasicView<forward_sized_iterator<>, sized_sentinel<forward_sized_iterator<>>>;
-// static_assert(std::ranges::forward_range<ForwardSizedNonCommon>);
-// static_assert(std::ranges::sized_range<ForwardSizedNonCommon>);
-// static_assert(!std::ranges::common_range<ForwardSizedNonCommon>);
-// static_assert(!std::ranges::random_access_range<ForwardSizedNonCommon>);
-// static_assert(simple_view<ForwardSizedNonCommon>);
-
-// using NonSimpleForwardSizedNonCommon =
-// BasicView<forward_sized_iterator<const int*>, sized_sentinel<forward_sized_iterator<const int*>>,
-// forward_sized_iterator<int*>, sized_sentinel<forward_sized_iterator<int*>>>;
-// static_assert(std::ranges::forward_range<NonSimpleForwardSizedNonCommon>);
-// static_assert(std::ranges::sized_range<NonSimpleForwardSizedNonCommon>);
-// static_assert(!std::ranges::common_range<NonSimpleForwardSizedNonCommon>);
-// static_assert(!std::ranges::random_access_range<NonSimpleForwardSizedNonCommon>);
-// static_assert(!simple_view<NonSimpleForwardSizedNonCommon>);
-
-struct SizedRandomAccessView : IntBufferView {
- using IntBufferView::IntBufferView;
- using iterator = random_access_iterator<int*>;
-
- constexpr auto begin() const { return iterator(buffer_); }
- constexpr auto end() const { return sized_sentinel<iterator>(iterator(buffer_ + size_)); }
-
- constexpr decltype(auto) operator[](std::size_t n) const { return *(begin() + n); }
-};
-static_assert(std::ranges::view<SizedRandomAccessView>);
-static_assert(std::ranges::random_access_range<SizedRandomAccessView>);
-static_assert(std::ranges::sized_range<SizedRandomAccessView>);
-
-// using NonSizedRandomAccessView =
-// BasicView<random_access_iterator<int*>, sentinel_wrapper<random_access_iterator<int*>>>;
-// static_assert(!std::ranges::contiguous_range<NonSizedRandomAccessView>);
-// static_assert(std::ranges::random_access_range<SizedRandomAccessView>);
-// static_assert(!std::ranges::common_range<NonSizedRandomAccessView>);
-// static_assert(!std::ranges::sized_range<NonSizedRandomAccessView>);
-// static_assert(simple_view<NonSizedRandomAccessView>);
-
-// using NonSimpleNonSizedRandomAccessView =
-// BasicView<random_access_iterator<const int*>, sentinel_wrapper<random_access_iterator<const int*>>,
-// random_access_iterator<int*>, sentinel_wrapper<random_access_iterator<int*>> >;
-// static_assert(!std::ranges::contiguous_range<NonSimpleNonSizedRandomAccessView>);
-// static_assert(std::ranges::random_access_range<NonSimpleNonSizedRandomAccessView>);
-// static_assert(!std::ranges::common_range<NonSimpleNonSizedRandomAccessView>);
-// static_assert(!std::ranges::sized_range<NonSimpleNonSizedRandomAccessView>);
-// static_assert(!simple_view<NonSimpleNonSizedRandomAccessView>);
-
-// using ContiguousCommonView = BasicView<int*>;
-// static_assert(std::ranges::contiguous_range<ContiguousCommonView>);
-// static_assert(std::ranges::common_range<ContiguousCommonView>);
-// static_assert(std::ranges::sized_range<ContiguousCommonView>);
-
-// using ContiguousNonCommonView = BasicView<int*, sentinel_wrapper<int*>>;
-// static_assert(std::ranges::contiguous_range<ContiguousNonCommonView>);
-// static_assert(!std::ranges::common_range<ContiguousNonCommonView>);
-// static_assert(!std::ranges::sized_range<ContiguousNonCommonView>);
-
-// using ContiguousNonCommonSized = BasicView<int*, sized_sentinel<int*>>;
-
-// static_assert(std::ranges::contiguous_range<ContiguousNonCommonSized>);
-// static_assert(!std::ranges::common_range<ContiguousNonCommonSized>);
-// static_assert(std::ranges::sized_range<ContiguousNonCommonSized>);
-
-// using InputCommonView = BasicView<common_input_iterator<int*>>;
-// static_assert(std::ranges::input_range<InputCommonView>);
-// static_assert(!std::ranges::forward_range<InputCommonView>);
-// static_assert(std::ranges::common_range<InputCommonView>);
-// static_assert(simple_view<InputCommonView>);
-
-// using NonSimpleInputCommonView = BasicView<common_input_iterator<const int*>, common_input_iterator<const int*>,
-// common_input_iterator<int*>, common_input_iterator<int*>>;
-// static_assert(std::ranges::input_range<NonSimpleInputCommonView>);
-// static_assert(!std::ranges::forward_range<NonSimpleInputCommonView>);
-// static_assert(std::ranges::common_range<NonSimpleInputCommonView>);
-// static_assert(!simple_view<NonSimpleInputCommonView>);
-
-// using InputNonCommonView = BasicView<common_input_iterator<int*>, sentinel_wrapper<common_input_iterator<int*>>>;
-// static_assert(std::ranges::input_range<InputNonCommonView>);
-// static_assert(!std::ranges::forward_range<InputNonCommonView>);
-// static_assert(!std::ranges::common_range<InputNonCommonView>);
-// static_assert(simple_view<InputNonCommonView>);
-
-// using NonSimpleInputNonCommonView =
-// BasicView<common_input_iterator<const int*>, sentinel_wrapper<common_input_iterator<const int*>>,
-// common_input_iterator<int*>, sentinel_wrapper<common_input_iterator<int*>>>;
-// static_assert(std::ranges::input_range<InputNonCommonView>);
-// static_assert(!std::ranges::forward_range<InputNonCommonView>);
-// static_assert(!std::ranges::common_range<InputNonCommonView>);
-// static_assert(!simple_view<NonSimpleInputNonCommonView>);
-
-// using BidiCommonView = BasicView<bidirectional_iterator<int*>>;
-// static_assert(!std::ranges::sized_range<BidiCommonView>);
-// static_assert(std::ranges::bidirectional_range<BidiCommonView>);
-// static_assert(!std::ranges::random_access_range<BidiCommonView>);
-// static_assert(std::ranges::common_range<BidiCommonView>);
-// static_assert(simple_view<BidiCommonView>);
-
-// using NonSimpleBidiCommonView = BasicView<bidirectional_iterator<const int*>, bidirectional_iterator<const int*>,
-// bidirectional_iterator<int*>, bidirectional_iterator<int*>>;
-// static_assert(!std::ranges::sized_range<NonSimpleBidiCommonView>);
-// static_assert(std::ranges::bidirectional_range<NonSimpleBidiCommonView>);
-// static_assert(!std::ranges::random_access_range<NonSimpleBidiCommonView>);
-// static_assert(std::ranges::common_range<NonSimpleBidiCommonView>);
-// static_assert(!simple_view<NonSimpleBidiCommonView>);
-
-// struct SizedBidiCommon : BidiCommonView {
-// using BidiCommonView::BidiCommonView;
-// std::size_t size() const { return base(end()) - base(begin()); }
-// };
-// static_assert(std::ranges::sized_range<SizedBidiCommon>);
-// static_assert(std::ranges::bidirectional_range<SizedBidiCommon>);
-// static_assert(!std::ranges::random_access_range<SizedBidiCommon>);
-// static_assert(std::ranges::common_range<SizedBidiCommon>);
-// static_assert(simple_view<SizedBidiCommon>);
-
-// struct NonSimpleSizedBidiCommon : NonSimpleBidiCommonView {
-// using NonSimpleBidiCommonView::NonSimpleBidiCommonView;
-// std::size_t size() const { return base(end()) - base(begin()); }
-// };
-// static_assert(std::ranges::sized_range<NonSimpleSizedBidiCommon>);
-// static_assert(std::ranges::bidirectional_range<NonSimpleSizedBidiCommon>);
-// static_assert(!std::ranges::random_access_range<NonSimpleSizedBidiCommon>);
-// static_assert(std::ranges::common_range<NonSimpleSizedBidiCommon>);
-// static_assert(!simple_view<NonSimpleSizedBidiCommon>);
-
-// using BidiNonCommonView = BasicView<bidirectional_iterator<int*>, sentinel_wrapper<bidirectional_iterator<int*>>>;
-// static_assert(!std::ranges::sized_range<BidiNonCommonView>);
-// static_assert(std::ranges::bidirectional_range<BidiNonCommonView>);
-// static_assert(!std::ranges::random_access_range<BidiNonCommonView>);
-// static_assert(!std::ranges::common_range<BidiNonCommonView>);
-// static_assert(simple_view<BidiNonCommonView>);
-
-// using NonSimpleBidiNonCommonView =
-// BasicView<bidirectional_iterator<const int*>, sentinel_wrapper<bidirectional_iterator<const int*>>,
-// bidirectional_iterator<int*>, sentinel_wrapper<bidirectional_iterator<int*>>>;
-// static_assert(!std::ranges::sized_range<NonSimpleBidiNonCommonView>);
-// static_assert(std::ranges::bidirectional_range<NonSimpleBidiNonCommonView>);
-// static_assert(!std::ranges::random_access_range<NonSimpleBidiNonCommonView>);
-// static_assert(!std::ranges::common_range<NonSimpleBidiNonCommonView>);
-// static_assert(!simple_view<NonSimpleBidiNonCommonView>);
-
-// using SizedBidiNonCommonView = BasicView<bidirectional_iterator<int*>, sized_sentinel<bidirectional_iterator<int*>>>;
-// static_assert(std::ranges::sized_range<SizedBidiNonCommonView>);
-// static_assert(std::ranges::bidirectional_range<SizedBidiNonCommonView>);
-// static_assert(!std::ranges::random_access_range<SizedBidiNonCommonView>);
-// static_assert(!std::ranges::common_range<SizedBidiNonCommonView>);
-// static_assert(simple_view<SizedBidiNonCommonView>);
-
-// using NonSimpleSizedBidiNonCommonView =
-// BasicView<bidirectional_iterator<const int*>, sized_sentinel<bidirectional_iterator<const int*>>,
-// bidirectional_iterator<int*>, sized_sentinel<bidirectional_iterator<int*>>>;
-// static_assert(std::ranges::sized_range<NonSimpleSizedBidiNonCommonView>);
-// static_assert(std::ranges::bidirectional_range<NonSimpleSizedBidiNonCommonView>);
-// static_assert(!std::ranges::random_access_range<NonSimpleSizedBidiNonCommonView>);
-// static_assert(!std::ranges::common_range<NonSimpleSizedBidiNonCommonView>);
-// static_assert(!simple_view<NonSimpleSizedBidiNonCommonView>);
-
-// namespace adltest{
-// struct iter_move_swap_iterator {
-
-// std::reference_wrapper<int> iter_move_called_times;
-// std::reference_wrapper<int> iter_swap_called_times;
-// int i = 0;
-
-// using iterator_category = std::input_iterator_tag;
-// using value_type = int;
-// using difference_type = std::intptr_t;
-
-// constexpr int operator*() const { return i; }
-
-// constexpr iter_move_swap_iterator& operator++() {
-// ++i;
-// return *this;
-// }
-// constexpr void operator++(int) { ++i; }
-
-// friend constexpr bool operator==(const iter_move_swap_iterator& x, std::default_sentinel_t) { return x.i == 5; }
-
-// friend constexpr int iter_move(iter_move_swap_iterator const& it) {
-// ++it.iter_move_called_times;
-// return it.i;
-// }
-// friend constexpr void iter_swap(iter_move_swap_iterator const& x, iter_move_swap_iterator const& y) {
-// ++x.iter_swap_called_times;
-// ++y.iter_swap_called_times;
-// }
-// };
-
-// struct IterMoveSwapRange {
-// int iter_move_called_times = 0;
-// int iter_swap_called_times = 0;
-// constexpr auto begin() { return iter_move_swap_iterator{iter_move_called_times, iter_swap_called_times}; }
-// constexpr auto end() const { return std::default_sentinel; }
-// };
-// } // namespace adltest
-
-#endif // TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_CARTESIAN_PRODUCT_VIEW_TYPES_H
>From 7bc9befba048f2ea9232795e6b3fc62c35c6ee76 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 7 Dec 2024 13:32:48 +0100
Subject: [PATCH 48/49] test: view::end()
---
.../range.cartesian.product.view/end.pass.cpp | 138 ++++++++++++++++++
1 file changed, 138 insertions(+)
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/end.pass.cpp
diff --git a/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/end.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/end.pass.cpp
new file mode 100644
index 00000000000000..1d057d05bc8101
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/end.pass.cpp
@@ -0,0 +1,138 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// 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...> ;
+
+#include "assert_macros.h"
+
+#include <array>
+#include <cassert>
+#include <ranges>
+
+constexpr bool test() {
+ { // non-empty range
+ constexpr size_t N = 7;
+ std::array<int, N> a;
+ std::ranges::cartesian_product_view c{a};
+ assert(c.end() == c.begin() + N);
+ }
+
+ { // (non-empty range)^2
+ constexpr size_t N0 = 7;
+ std::array<int, N0> a0;
+ constexpr size_t N1 = 42;
+ std::array<int, N1> a1;
+ std::ranges::cartesian_product_view c{a0, a1};
+ assert(c.end() == c.begin() + N0 * N1);
+ }
+
+ { // (non-empty range)^3
+ constexpr size_t N0 = 5, N1 = 42, N2 = 7;
+ std::array<int, N0> a0;
+ std::array<int, N1> a1;
+ std::array<int, N2> a2;
+ std::ranges::cartesian_product_view c{a0, a1, a2};
+ assert(c.end() == c.begin() + N0*N1*N2);
+ }
+
+ { // empty range
+ std::ranges::empty_view<int> e;
+ std::ranges::cartesian_product_view c{e};
+ assert(c.end() == c.begin());
+ }
+
+ { // (empty range)^2
+ std::ranges::empty_view<int> e;
+ std::ranges::cartesian_product_view c{e, e};
+ assert(c.end() == c.begin());
+ }
+
+ { // empty range X common range
+ std::ranges::empty_view<int> e;
+ constexpr size_t N = 7;
+ std::array<int, N> a;
+ std::ranges::cartesian_product_view c{e, a};
+ assert(c.end() == c.begin());
+ }
+
+ { // common range X empty range
+ std::ranges::empty_view<int> e;
+ constexpr size_t N = 7;
+ std::array<int, N> a;
+ std::ranges::cartesian_product_view c{e, a};
+ assert(c.end() == c.begin());
+ }
+
+ { // (empty range)^3
+ std::ranges::empty_view<int> e;
+ std::ranges::cartesian_product_view c{e, e, e};
+ assert(c.end() == c.begin());
+ }
+
+ { // empty range X empty range X common range
+ std::ranges::empty_view<int> e;
+ constexpr size_t N = 7;
+ std::array<int, N> a;
+ std::ranges::cartesian_product_view c{e, e, a};
+ assert(c.end() == c.begin());
+ }
+
+ { // empty range X common range X empty range
+ std::ranges::empty_view<int> e;
+ constexpr size_t N = 7;
+ std::array<int, N> a;
+ std::ranges::cartesian_product_view c{e, a, e};
+ assert(c.end() == c.begin());
+ }
+
+ { // common range X empty range X empty range
+ std::ranges::empty_view<int> e;
+ constexpr size_t N = 7;
+ std::array<int, N> a;
+ std::ranges::cartesian_product_view c{a, e, e};
+ assert(c.end() == c.begin());
+ }
+
+ { // empty range X common range X common range
+ std::ranges::empty_view<int> e;
+ constexpr size_t N0 = 7, N1 = 42;
+ std::array<int, N0> a0;
+ std::array<int, N1> a1;
+ std::ranges::cartesian_product_view c{e, a0, a1};
+ assert(c.end() == c.begin());
+ }
+
+ { // common range X empty range X common range
+ std::ranges::empty_view<int> e;
+ constexpr size_t N0 = 7, N1 = 42;
+ std::array<int, N0> a0;
+ std::array<int, N1> a1;
+ std::ranges::cartesian_product_view c{a0, e, a1};
+ assert(c.end() == c.begin());
+ }
+
+ { // common range X common range X empty range
+ std::ranges::empty_view<int> e;
+ constexpr size_t N0 = 7, N1 = 42;
+ std::array<int, N0> a0;
+ std::array<int, N1> a1;
+ std::ranges::cartesian_product_view c{a0, a1, e};
+ assert(c.end() == c.begin());
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+ return 0;
+}
>From 3bbaf36437c7f43eed5345db8b3677aa4558e20b Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 7 Dec 2024 13:36:05 +0100
Subject: [PATCH 49/49] test: use libcxx template for main()
---
.../range.cartesian.product.view/begin.pass.cpp | 3 ++-
.../range.cartesian.product.view/ctor.default.pass.cpp | 5 +++--
.../range.cartesian.product.view/ctor.pass.cpp | 3 ++-
.../range.cartesian.product.view/ctor.views.pass.cpp | 5 +++--
.../range.cartesian.product.view/example_from_std.pass.cpp | 5 +++--
.../range.cartesian.product.view/size.pass.cpp | 5 +++--
6 files changed, 16 insertions(+), 10 deletions(-)
diff --git a/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/begin.pass.cpp
index 7df8dbd57dcaac..fac0d39b9f7235 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/begin.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/begin.pass.cpp
@@ -100,7 +100,8 @@ constexpr bool test() {
return true;
}
-int main() {
+int main(int, char**) {
test();
static_assert(test());
+ return 0;
}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/ctor.default.pass.cpp
index f623d0f5c01927..8691ff2122e305 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/ctor.default.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/ctor.default.pass.cpp
@@ -62,7 +62,8 @@ constexpr bool test() {
return true;
}
-int main() {
+int main(int, char**) {
test();
static_assert(test());
-}
+ return 0;
+}
\ No newline at end of file
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
index 72657095c792ef..bf23c913ff9cc3 100644
--- 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
@@ -30,7 +30,8 @@ constexpr bool test() {
return true;
}
-int main() {
+int main(int, char**) {
test();
static_assert(test());
+ return 0;
}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/ctor.views.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/ctor.views.pass.cpp
index 8acad61f878317..0c424acaf3950d 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/ctor.views.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/ctor.views.pass.cpp
@@ -83,7 +83,8 @@ constexpr bool test() {
return true;
}
-int main() {
+int main(int, char**) {
test();
static_assert(test());
-}
+ return 0;
+}
\ No newline at end of file
diff --git a/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/example_from_std.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/example_from_std.pass.cpp
index cdab4750f2c2e6..4d505921b3a772 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/example_from_std.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/example_from_std.pass.cpp
@@ -65,7 +65,8 @@ constexpr bool test() {
return true;
}
-int main() {
+int main(int, char**) {
test();
static_assert(test());
-}
+ return 0;
+}
\ No newline at end of file
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 82ee47997f53b3..44c4de5b3d7a35 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
@@ -36,7 +36,8 @@ constexpr bool test() {
return true;
}
-int main() {
+int main(int, char**) {
test();
static_assert(test());
-}
+ return 0;
+}
\ No newline at end of file
More information about the libcxx-commits
mailing list