From 260b6af3f1d9ada0aa748e12acc5b03885ed0333 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 4 Oct 2024 19:04:39 +0200 Subject: [PATCH 01/51] 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 d7c36d6b438fb..6098b3f43fdf9 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -676,6 +676,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 0000000000000..46941b9e1c97d --- /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 // apply +#include // 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 + requires(view && ... && view) +class cartesian_product_view : public view_interface> { +private: + tuple bases_; // exposition only + + template + 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 begin() + // requires (!simple-view || ... || !simple-view) + // { + // return move_iterator(ranges::begin(bases_)); + // } + + // constexpr iterator begin() const + // requires (range && ... && range) + // { + // return move_iterator(ranges::begin(__base_)); + // } + + // constexpr iterator begin() + // requires (!simple-view || ... || !simple-view); + // constexpr iterator begin() const + // requires (range && ... && range); + + // constexpr iterator end() + // requires ((!simple-view || ... || !simple-view) && + // cartesian-product-is-common); + // constexpr iterator end() const + // requires cartesian-product-is-common; + // constexpr default_sentinel_t end() const noexcept; + + // constexpr see below size() + // requires cartesian-product-is-sized; + // constexpr see below size() const + // requires cartesian-product-is-sized; + constexpr auto size() const + requires(sized_range && ... && sized_range) + { + return std::apply( + [](auto&&... bases) { + using size_type = std::common_type_t...>; + return (static_cast(std::ranges::size(bases)) * ...); + }, + bases_); + } +}; + +template +cartesian_product_view(Rs&&...) -> cartesian_product_view...>; + +} // 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 9ef614d21f525..668287ffe02c8 100644 --- a/libcxx/include/ranges +++ b/libcxx/include/ranges @@ -425,6 +425,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 0000000000000..72657095c792e --- /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 +#include + +#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 r1; + [[maybe_unused]] std::ranges::cartesian_product_view 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 0000000000000..5486f9416a66b --- /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 +#include +#include + +constexpr bool test() { + { + using T = std::initializer_list; + + // 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 a6cb4d60f56cedc04ab75c8f7a85b25a038349e9 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 4 Oct 2024 20:31:41 +0200 Subject: [PATCH 02/51] 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 46941b9e1c97d..59cf31e350390 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 // apply -#include // common_type_t +#include // apply +#include // 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; // constexpr default_sentinel_t end() const noexcept; - // constexpr see below size() - // requires cartesian-product-is-sized; - // constexpr see below size() const - // requires cartesian-product-is-sized; - constexpr auto size() const + constexpr auto size() + requires(sized_range && ... && sized_range) + { + return size_impl(); + } + + constexpr auto size() const requires(sized_range && ... && sized_range) { + return size_impl(); + } + +private: + constexpr auto size_impl() const { return std::apply( [](auto&&... bases) { using size_type = std::common_type_t...>; 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 5486f9416a66b..82ee47997f53b 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 constexpr bool test() { - { - using T = std::initializer_list; - + { // 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 2d7a8179aacee1b1843c791911146706783562b4 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 4 Oct 2024 22:56:20 +0200 Subject: [PATCH 03/51] class cartesian_product_view::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 59cf31e350390..ac87912029504 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 // apply #include // 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 requires(view && ... && view) class cartesian_product_view : public view_interface> { private: +public: // fixme: remove me tuple bases_; // exposition only template - 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 +requires (view && ... && view) +template +class cartesian_product_view::iterator { + + // fixme: implement properly. see section 5.2 in paper. + template + using tuple_or_pair = tuple; + +public: +// using iterator_category = input_iterator_tag; +// using iterator_concept = see below; +// using value_type = tuple-or-pair>, +// range_value_t<__maybe_const>...>; +// using reference = tuple-or-pair>, +// reference_t<__maybe_const>...>; +// using difference_type = see below; + + iterator() requires forward_range<__maybe_const> = default; + + constexpr explicit iterator(tuple_or_pair>, + iterator_t<__maybe_const>...> current) + : current_(std::move(current)) {} + + constexpr iterator(iterator i) requires Const && + (convertible_to, iterator_t<__maybe_const>> && + ... && convertible_to, iterator_t<__maybe_const>>) + : 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>; + +// constexpr iterator& operator--() +// requires cartesian-product-is-bidirectional; +// constexpr iterator operator--(int) +// requires cartesian-product-is-bidirectional; + +// constexpr iterator& operator+=(difference_type x) +// requires cartesian-product-is-random-access; +// constexpr iterator& operator-=(difference_type x) +// requires cartesian-product-is-random-access; + +// constexpr reference operator[](difference_type n) const +// requires cartesian-product-is-random-access; + +// friend constexpr bool operator==(const iterator& x, const iterator& y) +// requires equality_comparable>>; + +// friend constexpr bool operator==(const iterator& x, default_sentinel_t); + +// friend constexpr auto operator<=>(const iterator& x, const iterator& y) +// requires all-random-access; + +// friend constexpr iterator operator+(const iterator& x, difference_type y) +// requires cartesian-product-is-random-access; +// friend constexpr iterator operator+(difference_type x, const iterator& y) +// requires cartesian-product-is-random-access; +// friend constexpr iterator operator-(const iterator& x, difference_type y) +// requires cartesian-product-is-random-access; +// friend constexpr difference_type operator-(const iterator& x, const iterator& y) +// requires cartesian-is-sized-sentinel; + +// friend constexpr difference_type operator-(iterator i, default_sentinel_t) +// requires cartesian-is-sized-sentinel; +// friend constexpr difference_type operator-(default_sentinel_t, iterator i) +// requires cartesian-is-sized-sentinel; + +// 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>> && ... && +// indirectly_swappable>>); + +private: +// __maybe_const* parent_ = nullptr; // exposition only + tuple_or_pair>, + iterator_t<__maybe_const>...> current_; // exposition only + +// template +// constexpr void next(); // exposition only + +// template +// constexpr void prev(); // exposition only + +// template +// constexpr difference_type distance-from(Tuple t); // exposition only + +// constexpr explicit iterator(tuple-or-pair>, +// iterator_t<__maybe_const>...> current); // exposition only +}; + template cartesian_product_view(Rs&&...) -> cartesian_product_view...>; From 5e72fcd6803885068086da25b950a34fc499ae3a Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 4 Oct 2024 23:16:15 +0200 Subject: [PATCH 04/51] 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 ac87912029504..811693f3749ce 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 // apply -#include // common_type_t #include <__type_traits/maybe_const.h> +#include // apply +#include // common_type_t #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -32,41 +32,18 @@ template requires(view && ... && view) class cartesian_product_view : public view_interface> { private: + public: // fixme: remove me - tuple bases_; // exposition only + tuple bases_; template - 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 begin() - // requires (!simple-view || ... || !simple-view) - // { - // return move_iterator(ranges::begin(bases_)); - // } - - // constexpr iterator begin() const - // requires (range && ... && range) - // { - // return move_iterator(ranges::begin(__base_)); - // } - - // constexpr iterator begin() - // requires (!simple-view || ... || !simple-view); - // constexpr iterator begin() const - // requires (range && ... && range); - - // constexpr iterator end() - // requires ((!simple-view || ... || !simple-view) && - // cartesian-product-is-common); - // constexpr iterator end() const - // requires cartesian-product-is-common; - // constexpr default_sentinel_t end() const noexcept; - constexpr auto size() requires(sized_range && ... && sized_range) { @@ -90,102 +67,32 @@ class cartesian_product_view : public view_interface -requires (view && ... && view) -template -class cartesian_product_view::iterator { - - // fixme: implement properly. see section 5.2 in paper. - template - using tuple_or_pair = tuple; +template +cartesian_product_view(Vs&&...) -> cartesian_product_view...>; +template + requires(view && ... && view) +template +class cartesian_product_view::iterator { public: -// using iterator_category = input_iterator_tag; -// using iterator_concept = see below; -// using value_type = tuple-or-pair>, -// range_value_t<__maybe_const>...>; -// using reference = tuple-or-pair>, -// reference_t<__maybe_const>...>; -// using difference_type = see below; - - iterator() requires forward_range<__maybe_const> = default; - - constexpr explicit iterator(tuple_or_pair>, - iterator_t<__maybe_const>...> current) + iterator() + requires forward_range<__maybe_const> + = default; + + constexpr explicit iterator( + tuple>, iterator_t<__maybe_const>...> current) : current_(std::move(current)) {} - constexpr iterator(iterator i) requires Const && - (convertible_to, iterator_t<__maybe_const>> && - ... && convertible_to, iterator_t<__maybe_const>>) + constexpr iterator(iterator i) + requires Const && (convertible_to, iterator_t<__maybe_const>> && ... && + convertible_to, iterator_t<__maybe_const>>) : 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>; - -// constexpr iterator& operator--() -// requires cartesian-product-is-bidirectional; -// constexpr iterator operator--(int) -// requires cartesian-product-is-bidirectional; - -// constexpr iterator& operator+=(difference_type x) -// requires cartesian-product-is-random-access; -// constexpr iterator& operator-=(difference_type x) -// requires cartesian-product-is-random-access; - -// constexpr reference operator[](difference_type n) const -// requires cartesian-product-is-random-access; - -// friend constexpr bool operator==(const iterator& x, const iterator& y) -// requires equality_comparable>>; - -// friend constexpr bool operator==(const iterator& x, default_sentinel_t); - -// friend constexpr auto operator<=>(const iterator& x, const iterator& y) -// requires all-random-access; - -// friend constexpr iterator operator+(const iterator& x, difference_type y) -// requires cartesian-product-is-random-access; -// friend constexpr iterator operator+(difference_type x, const iterator& y) -// requires cartesian-product-is-random-access; -// friend constexpr iterator operator-(const iterator& x, difference_type y) -// requires cartesian-product-is-random-access; -// friend constexpr difference_type operator-(const iterator& x, const iterator& y) -// requires cartesian-is-sized-sentinel; - -// friend constexpr difference_type operator-(iterator i, default_sentinel_t) -// requires cartesian-is-sized-sentinel; -// friend constexpr difference_type operator-(default_sentinel_t, iterator i) -// requires cartesian-is-sized-sentinel; - -// 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>> && ... && -// indirectly_swappable>>); - private: -// __maybe_const* parent_ = nullptr; // exposition only - tuple_or_pair>, - iterator_t<__maybe_const>...> current_; // exposition only - -// template -// constexpr void next(); // exposition only - -// template -// constexpr void prev(); // exposition only - -// template -// constexpr difference_type distance-from(Tuple t); // exposition only - -// constexpr explicit iterator(tuple-or-pair>, -// iterator_t<__maybe_const>...> current); // exposition only + // __maybe_const* parent_ = nullptr; + tuple>, iterator_t<__maybe_const>...> current_; }; -template -cartesian_product_view(Rs&&...) -> cartesian_product_view...>; - } // namespace ranges _LIBCPP_END_NAMESPACE_STD From 4066908b50c77a3d04c0ce0a1276b4b47675e4be Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 4 Oct 2024 23:24:02 +0200 Subject: [PATCH 05/51] 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 811693f3749ce..bd0302f7f197d 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 // apply @@ -75,21 +76,16 @@ template template class cartesian_product_view::iterator { public: - iterator() - requires forward_range<__maybe_const> - = default; - - constexpr explicit iterator( - tuple>, iterator_t<__maybe_const>...> current) - : current_(std::move(current)) {} + iterator() = default; constexpr iterator(iterator i) - requires Const && (convertible_to, iterator_t<__maybe_const>> && ... && - convertible_to, iterator_t<__maybe_const>>) - : current_(std::move(i.current_)) {} + requires Const && (convertible_to, iterator_t> && ... && + convertible_to, iterator_t>) + : parent_(std::addressof(i.parent_)), current_(std::move(i.current_)) {} private: - // __maybe_const* parent_ = nullptr; + using Parent = __maybe_const; + Parent* parent_ = nullptr; tuple>, iterator_t<__maybe_const>...> current_; }; From bb441d15c0f02db4b22e987f876d186e5af46ba9 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 4 Oct 2024 23:31:03 +0200 Subject: [PATCH 06/51] 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 bd0302f7f197d..f330f186e72b8 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::iterator { using Parent = __maybe_const; Parent* parent_ = nullptr; tuple>, iterator_t<__maybe_const>...> current_; + + constexpr iterator(Parent& parent, decltype(current_) current) + : parent_(std::addressof(parent)), current_(std::move(current)) {} }; } // namespace ranges From ea68eb39ffadabc91a776aa17f497d025a0238c9 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 4 Oct 2024 23:34:55 +0200 Subject: [PATCH 07/51] 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 f330f186e72b8..65111a7f82742 100644 --- a/libcxx/include/__ranges/cartesian_product_view.h +++ b/libcxx/include/__ranges/cartesian_product_view.h @@ -76,6 +76,11 @@ template template class cartesian_product_view::iterator { public: + using iterator_category = input_iterator_tag; + using value_type = tuple>, range_value_t<__maybe_const>...>; + using reference = + tuple>, range_reference_t<__maybe_const>...>; + iterator() = default; constexpr iterator(iterator i) From ac3e52d7de9401a6c31f1f63d9a924825bf1aeb0 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 4 Oct 2024 23:44:10 +0200 Subject: [PATCH 08/51] 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 65111a7f82742..16fe28a6122c9 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 // apply #include // common_type_t @@ -88,6 +89,10 @@ class cartesian_product_view::iterator { convertible_to, iterator_t>) : 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; Parent* parent_ = nullptr; From 1d0bebc6099baa4cec7668ce9bee1b2cade06607 Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 5 Oct 2024 22:27:46 +0200 Subject: [PATCH 09/51] 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 43072aa0fb0f1..8c20a03faf901 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -1786,6 +1786,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 e713a9d9e0ac7d2f24a7c9ee3dedba4155706d89 Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 5 Oct 2024 22:46:25 +0200 Subject: [PATCH 10/51] 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 16fe28a6122c9..7218da2906a8c 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::iterator { return __tuple_transform([](auto& i) -> decltype(auto) { return *i; }, current_); } + constexpr iterator& operator++() { + next(); + return *this; + } + private: using Parent = __maybe_const; Parent* parent_ = nullptr; @@ -100,6 +106,18 @@ class cartesian_product_view::iterator { constexpr iterator(Parent& parent, decltype(current_) current) : parent_(std::addressof(parent)), current_(std::move(current)) {} + + template + constexpr void next() { + const auto& v = std::get(parent_->bases_); + auto& it = std::get(current_); + if (++it == std::end(v)) { + if constexpr (N != 0) { + it = std::ranges::begin(v); + next(); + } + } + } }; } // namespace ranges From b9edd63622522171f6ccf91384a762a3c34e45e2 Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 5 Oct 2024 23:05:50 +0200 Subject: [PATCH 11/51] 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 7218da2906a8c..fd2d3f4e09980 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::iterator { return *this; } + constexpr void operator++(int) { next(); } + + constexpr iterator operator++(int) + requires forward_range<__maybe_const> + { + auto tmp = *this; + next(); + return tmp; + } + private: using Parent = __maybe_const; Parent* parent_ = nullptr; From 02714b063dd609a89c405b5b94da83967ac8942e Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 5 Oct 2024 23:38:28 +0200 Subject: [PATCH 12/51] 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 fd2d3f4e09980..586dcde42c6f4 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 +concept cartesian_product_common_arg = common_range || (sized_range && random_access_range); + +template +concept cartesian_product_is_bidirectional = + (bidirectional_range<__maybe_const> && ... && + (bidirectional_range<__maybe_const> && cartesian_product_common_arg<__maybe_const>)); + +template +constexpr auto cartesian_common_arg_end(R& r) { + if constexpr (common_range) { + return ranges::end(r); + } else { + return ranges::begin(r) + ranges::distance(r); + } +} + template requires(view && ... && view) class cartesian_product_view : public view_interface> { -private: - -public: // fixme: remove me +public: // fixme: make private tuple bases_; template @@ -109,6 +124,13 @@ class cartesian_product_view::iterator { return tmp; } + constexpr iterator& operator--() + requires cartesian_product_is_bidirectional + { + prev(); + return *this; + } + private: using Parent = __maybe_const; Parent* parent_ = nullptr; @@ -128,6 +150,18 @@ class cartesian_product_view::iterator { } } } + + template + constexpr void prev() { + auto& it = std::get(current_); + if constexpr (N > 0) { + if (const auto& v = std::get(parent_->bases_); it == ranges::begin(v)) { + it = cartesian_common_arg_end(v); + prev(); + } + } + --it; + } }; } // namespace ranges From 2768abfc1368bde411572ab974de7c839121811f Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 5 Oct 2024 23:41:32 +0200 Subject: [PATCH 13/51] 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 586dcde42c6f4..8fb4a09d4e8d2 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::iterator { template constexpr void next() { - const auto& v = std::get(parent_->bases_); - auto& it = std::get(current_); - if (++it == std::end(v)) { - if constexpr (N != 0) { - it = std::ranges::begin(v); + auto& it = std::get(current_); + ++it; + if constexpr (N > 0) { + if (const auto& v = std::get(parent_->bases_); it == ranges::end(v)) { + it = ranges::begin(v); next(); } } From f6d07dc02d7d44a5eccea8154384810ffa10389d Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 5 Oct 2024 23:43:36 +0200 Subject: [PATCH 14/51] 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 8fb4a09d4e8d2..4f6fded8c74b3 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::iterator { return *this; } + constexpr iterator operator--(int) +requires cartesian_product_is_bidirectional { + auto tmp = *this; + prev(); + return tmp; +} + private: using Parent = __maybe_const; Parent* parent_ = nullptr; From df6f072af39fd1e72329513e087ea0d92bec392a Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 6 Oct 2024 00:11:27 +0200 Subject: [PATCH 15/51] 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 4f6fded8c74b3..495ec1fd63e51 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 +concept cartesian_product_is_random_access = + (random_access_range<__maybe_const> && ... && + (random_access_range<__maybe_const> && sized_range<__maybe_const>)); + template concept cartesian_product_common_arg = common_range || (sized_range && random_access_range); @@ -97,6 +102,7 @@ class cartesian_product_view::iterator { using value_type = tuple>, range_value_t<__maybe_const>...>; using reference = tuple>, range_reference_t<__maybe_const>...>; + using difference_type = std::common_type_t, range_difference_t...>; iterator() = default; @@ -132,11 +138,26 @@ class cartesian_product_view::iterator { } constexpr iterator operator--(int) -requires cartesian_product_is_bidirectional { - auto tmp = *this; + requires cartesian_product_is_bidirectional + { + auto tmp = *this; prev(); return tmp; -} + } + + constexpr iterator& operator+=(difference_type x) + requires cartesian_product_is_random_access + { + advance(x); + return *this; + } + + constexpr iterator& operator-=(difference_type x) + requires cartesian_product_is_random_access + { + advance(x); + return *this; + } private: using Parent = __maybe_const; @@ -169,6 +190,37 @@ requires cartesian_product_is_bidirectional { } --it; } + + template + constexpr void advance(difference_type x) { + if (x == 0) + return; + + const auto& v = std::get(parent_->bases_); + auto& it = std::get(current_); + const auto sz = static_cast(std::ranges::size(v)); + const auto first = begin(v); + + const auto idx = static_cast(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(div); + } else { + if (div > 0) { + mod = sz; + } + } + using D = std::iter_difference_t; + it = first + static_cast(mod); + } }; } // namespace ranges From 0fd083d1fa0c5692b484b5d112d08ee364cf1e1b Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 11 Oct 2024 22:33:21 +0200 Subject: [PATCH 16/51] 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 495ec1fd63e51..aca22153e1366 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::iterator { constexpr iterator& operator-=(difference_type x) requires cartesian_product_is_random_access { - advance(x); + *this += -x; return *this; } @@ -201,25 +203,30 @@ class cartesian_product_view::iterator { const auto sz = static_cast(std::ranges::size(v)); const auto first = begin(v); - const auto idx = static_cast(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(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(div); + } else { + mod = (x >= 0 && x < sz) ? x : sz; } - advance(div); + it = std::next(first, mod); + } else { - if (div > 0) { - mod = sz; + if constexpr (N > 0) { + advance(x); } + it = first; } - using D = std::iter_difference_t; - it = first + static_cast(mod); } }; From 95d4992ddb0da895a479204a9426f555705cf2f8 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 11 Oct 2024 22:37:41 +0200 Subject: [PATCH 17/51] 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 aca22153e1366..0f9f825dba5e6 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::iterator { return *this; } + constexpr reference operator[](difference_type n) const + requires cartesian_product_is_random_access + { + return *((*this) + n); + } + private: using Parent = __maybe_const; Parent* parent_ = nullptr; From 7d06a2bfbec98b9f023eca19934b502d7f617362 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 11 Oct 2024 22:40:28 +0200 Subject: [PATCH 18/51] 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 0f9f825dba5e6..bf533ebc59aa9 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::iterator { return *((*this) + n); } + friend constexpr bool operator==(const iterator& x, const iterator& y) + requires equality_comparable>> + { + return x.current_ == y.current_; + } + private: using Parent = __maybe_const; Parent* parent_ = nullptr; From 6015f6d7e13e8d702ec802c2caf5de84b1b486de Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 11 Oct 2024 22:56:55 +0200 Subject: [PATCH 19/51] 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 bf533ebc59aa9..191fe44433270 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::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; Parent* parent_ = nullptr; @@ -240,6 +242,15 @@ class cartesian_product_view::iterator { it = first; } } + + template + constexpr bool at_end() const { + if (std::get(current_) == end(std::get(parent_->bases_))) + return true; + if constexpr (N > 0) + return at_end(); + return false; + } }; } // namespace ranges From 398c3fa57f7322f634a0595c0d4166b4993a8fee Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 11 Oct 2024 23:08:14 +0200 Subject: [PATCH 20/51] 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 191fe44433270..c4428845e2c5c 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 +concept __cartesian_product_all_random_access = + (random_access_range<__maybe_const> && ... && random_access_range<__maybe_const>); + template requires(view && ... && view) class cartesian_product_view : public view_interface> { @@ -175,6 +179,12 @@ class cartesian_product_view::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 + { + return x.current_ <=> y.current_; + } + private: using Parent = __maybe_const; Parent* parent_ = nullptr; From e6581c2ca9e6ff7d650aa1d7d0b476c3a040a835 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 11 Oct 2024 23:10:24 +0200 Subject: [PATCH 21/51] 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 c4428845e2c5c..329e978706246 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::iterator { return x.current_ <=> y.current_; } + friend constexpr iterator operator+(const iterator& x, difference_type y) + requires cartesian_product_is_random_access + { + return iterator(x) += y; + } + private: using Parent = __maybe_const; Parent* parent_ = nullptr; From db6a31b0962a9063295dde708b798375915db42d Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 11 Oct 2024 23:11:41 +0200 Subject: [PATCH 22/51] 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 329e978706246..d2ed56d2a8ae1 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::iterator { return iterator(x) += y; } + friend constexpr iterator operator+(difference_type x, const iterator& y) + requires cartesian_product_is_random_access + { + return y + x; + } + private: using Parent = __maybe_const; Parent* parent_ = nullptr; From 28be9325e1d349dc389a0625ea40825464543b58 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 11 Oct 2024 23:13:52 +0200 Subject: [PATCH 23/51] 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 d2ed56d2a8ae1..8c09e2b097df9 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::iterator { return y + x; } + friend constexpr iterator operator-(const iterator& x, difference_type y) + requires cartesian_product_is_random_access + { + return iterator(x) -= y; + } + private: using Parent = __maybe_const; Parent* parent_ = nullptr; From ccd8690d8518dae247aae497e0e100ab4dc2eea3 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 11 Oct 2024 23:49:29 +0200 Subject: [PATCH 24/51] 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 8c09e2b097df9..399c28585b141 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> && ... && (bidirectional_range<__maybe_const> && cartesian_product_common_arg<__maybe_const>)); +template +concept cartesian_product_is_sized = (sized_range && ...); + +template class FirstSent, class First, class... Vs> +concept cartesian_is_sized_sentinel = + (sized_sentinel_for>, iterator_t<__maybe_const>> && ... && + (sized_range<__maybe_const> && + sized_sentinel_for>, iterator_t<__maybe_const>>)); + template constexpr auto cartesian_common_arg_end(R& r) { if constexpr (common_range) { @@ -203,6 +212,12 @@ class cartesian_product_view::iterator { return iterator(x) -= y; } + friend constexpr iterator operator-(const iterator& x, const iterator& y) + requires cartesian_product_is_random_access + { + return x.distance_from(y.current_); + } + private: using Parent = __maybe_const; Parent* parent_ = nullptr; @@ -279,6 +294,27 @@ class cartesian_product_view::iterator { return at_end(); return false; } + + template + constexpr difference_type distance_from(const Tuple& t) const { + constexpr auto seq = std::make_integer_sequence{}; + constexpr auto scaled_sum = [&t, this](std::integer_sequence) -> difference_type { + return (scaled_distance(t) + ...); + }; + return scaled_sum(seq); + } + + template + constexpr difference_type scaled_size() const { + if constexpr (N <= sizeof...(Vs)) + return static_cast(ranges::size(std::get(parent_->bases_))) * scaled_size(); + return static_cast(1); + } + + template + constexpr difference_type scaled_distance(const Tuple& t) const { + return static_cast(std::get(current_) - std::get(t)) * scaled_size(); + } }; } // namespace ranges From d2f8e369aa4463092436bcd202f919ff62ef9f72 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 13 Oct 2024 20:13:12 +0200 Subject: [PATCH 25/51] iterator: operator-(iterator, iterator) --- .../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 399c28585b141..6cba859d28c57 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::iterator { template constexpr difference_type distance_from(const Tuple& t) const { - constexpr auto seq = std::make_integer_sequence{}; - constexpr auto scaled_sum = [&t, this](std::integer_sequence) -> difference_type { - return (scaled_distance(t) + ...); - }; - return scaled_sum(seq); + return scaled_sum(t); } template @@ -311,10 +307,17 @@ class cartesian_product_view::iterator { return static_cast(1); } - template - constexpr difference_type scaled_distance(const Tuple& t) const { + template + constexpr difference_type scaled_distance(const auto& t) const { return static_cast(std::get(current_) - std::get(t)) * scaled_size(); } + + template + constexpr difference_type scaled_sum(const auto& t) const { + if constexpr (N <= sizeof...(Vs)) + return scaled_distance(t) + scaled_sum(t); + return static_cast(0); + } }; } // namespace ranges From 3a8ab2b3ca29d6c2af287ea281ea46dec2b9a3c2 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 13 Oct 2024 20:26:45 +0200 Subject: [PATCH 26/51] 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 6cba859d28c57..9d56422e65141 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::iterator { return x.distance_from(y.current_); } + friend constexpr difference_type operator-(const iterator& i, default_sentinel_t) + requires cartesian_is_sized_sentinel + { + 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(end_tuple) = ranges::begin(std::get(i.parent_->bases_)); + return i.distance_from(end_tuple); + } + private: using Parent = __maybe_const; Parent* parent_ = nullptr; - tuple>, iterator_t<__maybe_const>...> current_; + using MultiIterator = tuple>, iterator_t<__maybe_const>...>; + MultiIterator current_; constexpr iterator(Parent& parent, decltype(current_) current) : parent_(std::addressof(parent)), current_(std::move(current)) {} From df507c50adea17c082160e7836db0a07924a6478 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 13 Oct 2024 20:28:16 +0200 Subject: [PATCH 27/51] 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 9d56422e65141..e76af70aaf590 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::iterator { return i.distance_from(end_tuple); } + friend constexpr difference_type operator-(default_sentinel_t s, const iterator& i) + requires cartesian_is_sized_sentinel + { + return -(i - s); + } + private: using Parent = __maybe_const; Parent* parent_ = nullptr; From edb00e186fdbcad1952316bf1f997c9b560d442e Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 13 Oct 2024 20:38:16 +0200 Subject: [PATCH 28/51] 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 e76af70aaf590..a954b2e62aa99 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::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; Parent* parent_ = nullptr; From 6011c0af76b965299d9df9ca5ca1827aa10c1108 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 13 Oct 2024 20:46:50 +0200 Subject: [PATCH 29/51] 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 a954b2e62aa99..4903eb4773c00 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::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>> && ... && + indirectly_swappable>>) + { + iter_swap_helper(l, r); + } + private: using Parent = __maybe_const; Parent* parent_ = nullptr; @@ -340,6 +347,13 @@ class cartesian_product_view::iterator { return scaled_distance(t) + scaled_sum(t); return static_cast(0); } + + template + static constexpr void iter_swap_helper(const iterator& l, const iterator& r) { + ranges::iter_swap(std::get(l.current_), std::get(r.current_)); + if constexpr (N > 0) + iter_swap_helper(l, r); + } }; } // namespace ranges From d042c11e903647a847b4af5db0811401f80393db Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 18 Oct 2024 22:29:02 +0200 Subject: [PATCH 30/51] 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 4903eb4773c00..035c60a6a9438 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> && ... && (bidirectional_range<__maybe_const> && cartesian_product_common_arg<__maybe_const>)); +template +concept cartesian_product_is_common = cartesian_product_common_arg; + template concept cartesian_product_is_sized = (sized_range && ...); @@ -72,7 +75,7 @@ concept __cartesian_product_all_random_access = template requires(view && ... && view) class cartesian_product_view : public view_interface> { -public: // fixme: make private +private: tuple bases_; template From d58048e1f4280005dfa8a2c37024ade6df845599 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 18 Oct 2024 22:30:01 +0200 Subject: [PATCH 31/51] 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 035c60a6a9438..39e53bffecc62 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 begin() + requires(!__simple_view || ... || !__simple_view) + { + return iterator(*this, __tuple_transform(ranges::begin, bases_)); + } + + constexpr iterator begin() const + requires(range && ... && range) + { + return iterator(*this, __tuple_transform(ranges::begin, bases_)); + } + constexpr auto size() requires(sized_range && ... && sized_range) { @@ -290,7 +302,7 @@ class cartesian_product_view::iterator { const auto& v = std::get(parent_->bases_); auto& it = std::get(current_); const auto sz = static_cast(std::ranges::size(v)); - const auto first = begin(v); + const auto first = ranges::begin(v); if (sz > 0) { const auto idx = static_cast(std::distance(first, it)); From d1ff775b9064bd1e52f5468457f215fa96a6d149 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 20 Oct 2024 22:07:01 +0200 Subject: [PATCH 32/51] 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 39e53bffecc62..1b9b5211687d4 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(*this, __tuple_transform(ranges::begin, bases_)); } + constexpr iterator end() + requires((!__simple_view || ... || !__simple_view) && cartesian_product_is_common) + { + constexpr bool is_const = false; + return end_impl(); + } + + constexpr iterator end() const + requires(cartesian_product_is_common) + { + constexpr bool is_const = true; + return end_impl(); + } + constexpr auto size() requires(sized_range && ... && sized_range) { @@ -111,6 +125,30 @@ class cartesian_product_view : public view_interface + constexpr iterator end_impl() const { + bool is_empty = end_is_empty(); + const auto ranges_to_iterators = [is_empty, &b = bases_](std::index_sequence) { + const auto begin_or_first_end = [is_empty](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(std::get(b))...); + }; + iterator it(*this, ranges_to_iterators(std::make_index_sequence<1 + sizeof...(Vs)>{})); + return it; + } + + template + constexpr bool end_is_empty() const { + if constexpr (N == sizeof...(Vs)) + return false; + if (const auto& v = std::get(bases_); ranges::empty(v)) + return true; + return end_is_empty(); + } + constexpr auto size_impl() const { return std::apply( [](auto&&... bases) { @@ -332,7 +370,7 @@ class cartesian_product_view::iterator { template constexpr bool at_end() const { - if (std::get(current_) == end(std::get(parent_->bases_))) + if (std::get(current_) == ranges::end(std::get(parent_->bases_))) return true; if constexpr (N > 0) return at_end(); From 4703bad43d2a12f4e586813e995e665570c902fd Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 3 Nov 2024 12:51:39 +0100 Subject: [PATCH 33/51] 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 1b9b5211687d4..2b9b6dca4475c 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(); } + constexpr default_sentinel_t end() const noexcept { return {}; } + constexpr auto size() requires(sized_range && ... && sized_range) { From e40214b8bfbfea1f1665989f2999a7ff9e2940c7 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 3 Nov 2024 13:02:12 +0100 Subject: [PATCH 34/51] 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 2b9b6dca4475c..09b32864c88f3 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 + template 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(bases_); ranges::empty(v)) + if (const auto& v = std::get(bases_); ranges::empty(v)) return true; return end_is_empty(); } From 35343360624f291b76bf1919b0e5e49c99668c9a Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 3 Nov 2024 13:08:06 +0100 Subject: [PATCH 35/51] 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 09b32864c88f3..8bd99552c9e10 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 end() const - requires(cartesian_product_is_common) + requires cartesian_product_is_common { constexpr bool is_const = true; return end_impl(); @@ -116,13 +116,13 @@ class cartesian_product_view : public view_interface && ... && sized_range) + requires cartesian_product_is_sized { return size_impl(); } constexpr auto size() const - requires(sized_range && ... && sized_range) + requires cartesian_product_is_sized { return size_impl(); } From b512fe54e472f5d52276f2c6b6e1461cff1eba5f Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 3 Nov 2024 13:26:40 +0100 Subject: [PATCH 36/51] 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 8bd99552c9e10..088cd869a680f 100644 --- a/libcxx/include/__ranges/cartesian_product_view.h +++ b/libcxx/include/__ranges/cartesian_product_view.h @@ -169,8 +169,20 @@ template requires(view && ... && view) template class cartesian_product_view::iterator { + static constexpr auto get_iterator_tag() { + if constexpr (cartesian_product_is_random_access) + return random_access_iterator_tag{}; + else if constexpr (cartesian_product_is_bidirectional) + return bidirectional_iterator_tag{}; + else if constexpr (forward_range<__maybe_const>) + 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>...>; using reference = tuple>, range_reference_t<__maybe_const>...>; From 7b75d8286cfe55221159ec6c40129e91844da7fa Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 3 Nov 2024 21:46:05 +0100 Subject: [PATCH 37/51] 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 088cd869a680f..79e7cff84d4cd 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::iterator { constexpr iterator(iterator i) requires Const && (convertible_to, iterator_t> && ... && convertible_to, iterator_t>) - : 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::iterator { return *this; } - constexpr void operator++(int) { next(); } + constexpr void operator++(int) { ++*this; } constexpr iterator operator++(int) requires forward_range<__maybe_const> { auto tmp = *this; - next(); + ++*this; return tmp; } @@ -225,7 +225,7 @@ class cartesian_product_view::iterator { requires cartesian_product_is_bidirectional { auto tmp = *this; - prev(); + --*this; return tmp; } @@ -281,8 +281,8 @@ class cartesian_product_view::iterator { return iterator(x) -= y; } - friend constexpr iterator operator-(const iterator& x, const iterator& y) - requires cartesian_product_is_random_access + friend constexpr difference_type operator-(const iterator& x, const iterator& y) + requires cartesian_is_sized_sentinel { return x.distance_from(y.current_); } @@ -290,10 +290,9 @@ class cartesian_product_view::iterator { friend constexpr difference_type operator-(const iterator& i, default_sentinel_t) requires cartesian_is_sized_sentinel { - 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(end_tuple) = ranges::begin(std::get(i.parent_->bases_)); + tuple end_tuple = [&b = i.parent_->bases_](index_sequence) { + return tuple{ranges::end(std::get<0>(b)), ranges::begin(std::get<1 + I>(b))...}; + }(std::make_index_sequence{}); return i.distance_from(end_tuple); } @@ -311,19 +310,16 @@ class cartesian_product_view::iterator { requires(indirectly_swappable>> && ... && indirectly_swappable>>) { - iter_swap_helper(l, r); + iter_swap_impl(l, r); } private: - using Parent = __maybe_const; - Parent* parent_ = nullptr; + using Parent = __maybe_const; + Parent* parent_ = nullptr; using MultiIterator = tuple>, iterator_t<__maybe_const>...>; MultiIterator current_; - constexpr iterator(Parent& parent, decltype(current_) current) - : parent_(std::addressof(parent)), current_(std::move(current)) {} - - template + template constexpr void next() { auto& it = std::get(current_); ++it; @@ -335,7 +331,7 @@ class cartesian_product_view::iterator { } } - template + template constexpr void prev() { auto& it = std::get(current_); if constexpr (N > 0) { @@ -347,7 +343,7 @@ class cartesian_product_view::iterator { --it; } - template + template constexpr void advance(difference_type x) { if (x == 0) return; @@ -416,11 +412,14 @@ class cartesian_product_view::iterator { return static_cast(0); } + constexpr iterator(Parent& parent, MultiIterator current) + : parent_(std::addressof(parent)), current_(std::move(current)) {} + template - 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(l.current_), std::get(r.current_)); if constexpr (N > 0) - iter_swap_helper(l, r); + iter_swap_impl(l, r); } }; From 7445b2fdfcef02fe65071eeedf570f0c7addc589 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 17 Nov 2024 15:44:14 +0100 Subject: [PATCH 38/51] 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 79e7cff84d4cd..3dfdb05fb3d3d 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::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::iterator { constexpr iterator(Parent& parent, MultiIterator current) : parent_(std::addressof(parent)), current_(std::move(current)) {} + template + static constexpr bool iter_move_noexcept_impl(const iterator& i) { + if (not noexcept(std::ranges::iter_move(std::get(i.current_)))) + return false; + if constexpr (N > 0) + return iter_move_noexcept_impl(i); + + return std::is_nothrow_move_constructible_v< + std::ranges::range_rvalue_reference_t<__maybe_const>>() and + (std::is_nothrow_move_constructible_v>>() and + ...); + } + template static constexpr void iter_swap_impl(const iterator& l, const iterator& r) { ranges::iter_swap(std::get(l.current_), std::get(r.current_)); From e07cd584a4f4bfa6c72f4b0bbe0b08977472e422 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 17 Nov 2024 15:51:32 +0100 Subject: [PATCH 39/51] 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 3dfdb05fb3d3d..2e252503d90c4 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::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>> && ... && indirectly_swappable>>) { @@ -428,6 +428,15 @@ class cartesian_product_view::iterator { ...); } + template + static constexpr bool iter_swap_noexcept_impl(const iterator& l, const iterator& r) { + if (not noexcept(std::ranges::iter_swap(std::get(l.current_), std::get(r.current_)))) + return false; + if constexpr (i > 0) + return iter_move_noexcept_impl(i); + return true; + } + template static constexpr void iter_swap_impl(const iterator& l, const iterator& r) { ranges::iter_swap(std::get(l.current_), std::get(r.current_)); From ea66101d2e7092dd0b5c62df2c8f15b2487020df Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 17 Nov 2024 21:59:31 +0100 Subject: [PATCH 40/51] 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 2e252503d90c4..9bbdcb0550841 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 end_impl() const { bool is_empty = end_is_empty(); const auto ranges_to_iterators = [is_empty, &b = bases_](std::index_sequence) { - const auto begin_or_first_end = [is_empty](const auto& rng) { - if constexpr (is_first) + const auto begin_or_first_end = [is_empty](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(std::get(b))...); + + return std::make_tuple(begin_or_first_end(std::bool_constant{}, std::get(b))...); }; iterator it(*this, ranges_to_iterators(std::make_index_sequence<1 + sizeof...(Vs)>{})); return it; } - template + template constexpr bool end_is_empty() const { if constexpr (N == 1 + sizeof...(Vs)) return false; - if (const auto& v = std::get(bases_); ranges::empty(v)) - return true; - return end_is_empty(); + else { + if (const auto& v = std::get(bases_); ranges::empty(v)) + return true; + return end_is_empty(); + } } constexpr auto size_impl() const { @@ -180,6 +183,8 @@ class cartesian_product_view::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 0000000000000..e4c29640ea793 --- /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 begin() requires (!simple-view || ... || !simple-view ); +// constexpr iterator begin() const requires (range && ... && range); + +#include + +// #include +// #include +// #include +// #include + +#include "types.h" + +template +concept HasConstBegin = requires(const T& ct) { ct.begin(); }; + +template +concept HasNonConstBegin = requires(T& t) { t.begin(); }; + +template +concept HasConstAndNonConstBegin = + HasConstBegin && HasNonConstBegin && + requires(T& t, const T& ct) { requires !std::same_as; }; + +template +concept HasOnlyNonConstBegin = HasNonConstBegin && !HasConstBegin; + +template +concept HasOnlyConstBegin = HasConstBegin && !HasConstAndNonConstBegin; + +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> 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> 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()); + assert(v.begin() == v.end()); + } + { // const + const std::ranges::cartesian_product_view v(SizedRandomAccessView{buffer}, std::ranges::empty_view()); + 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); + 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); + static_assert(HasOnlyConstBegin); + static_assert(!HasOnlyNonConstBegin); + static_assert(!HasConstAndNonConstBegin); + } + + // { + // // not all underlying ranges model simple-view + // std::ranges::zip_view v(SimpleCommon{buffer}, NonSimpleNonCommon{buffer}); + // static_assert(!std::is_same_v); + // 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); + // static_assert(!HasOnlyNonConstBegin); + // static_assert(HasConstAndNonConstBegin); + // } + + // { + // // underlying const R is not a range + // using View = std::ranges::zip_view; + // static_assert(!HasOnlyConstBegin); + // static_assert(HasOnlyNonConstBegin); + // static_assert(!HasConstAndNonConstBegin); + // } + 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 0000000000000..1426371770050 --- /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 +#include + +#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 +struct BufferView : std::ranges::view_base { + T* buffer_; + std::size_t size_; + + template + constexpr BufferView(T (&b)[N]) : buffer_(b), size_(N) {} +}; + +using IntBufferView = BufferView; + +template +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; +// using NonSimpleCommon = Common; + +// using SimpleCommonRandomAccessSized = SimpleCommon; +// using NonSimpleCommonRandomAccessSized = NonSimpleCommon; + +// static_assert(std::ranges::common_range>); +// static_assert(std::ranges::random_access_range); +// static_assert(std::ranges::sized_range); +// static_assert(simple_view); +// static_assert(!simple_view); + +// template +// struct CommonNonRandom : IntBufferView { +// using IntBufferView::IntBufferView; +// using const_iterator = forward_iterator; +// using iterator = forward_iterator; +// 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; +// using NonSimpleCommonNonRandom = CommonNonRandom; + +// static_assert(std::ranges::common_range); +// static_assert(!std::ranges::random_access_range); +// static_assert(!std::ranges::sized_range); +// static_assert(simple_view); +// static_assert(!simple_view); + +// template +// struct NonCommon : IntBufferView { +// using IntBufferView::IntBufferView; +// constexpr int* begin() +// requires(!Simple) { +// return buffer_; +// } +// constexpr const int* begin() const { return buffer_; } +// constexpr sentinel_wrapper end() +// requires(!Simple) { +// return sentinel_wrapper(buffer_ + size_); +// } +// constexpr sentinel_wrapper end() const { return sentinel_wrapper(buffer_ + size_); } +// }; + +// using SimpleNonCommon = NonCommon; +// using NonSimpleNonCommon = NonCommon; + +// static_assert(!std::ranges::common_range); +// static_assert(std::ranges::random_access_range); +// static_assert(!std::ranges::sized_range); +// static_assert(simple_view); +// static_assert(!simple_view); + +// template +// struct NonCommonSized : IntBufferView { +// using IntBufferView::IntBufferView; +// constexpr int* begin() +// requires(!Simple) { +// return buffer_; +// } +// constexpr const int* begin() const { return buffer_; } +// constexpr sentinel_wrapper end() +// requires(!Simple) { +// return sentinel_wrapper(buffer_ + size_); +// } +// constexpr sentinel_wrapper end() const { return sentinel_wrapper(buffer_ + size_); } +// constexpr std::size_t size() const { return size_; } +// }; + +// using SimpleNonCommonSized = NonCommonSized; +// using SimpleNonCommonRandomAccessSized = SimpleNonCommonSized; +// using NonSimpleNonCommonSized = NonCommonSized; +// using NonSimpleNonCommonRandomAccessSized = NonSimpleNonCommonSized; + +// static_assert(!std::ranges::common_range); +// static_assert(std::ranges::random_access_range); +// static_assert(std::ranges::sized_range); +// static_assert(simple_view); +// static_assert(!simple_view); + +// template +// struct NonCommonNonRandom : IntBufferView { +// using IntBufferView::IntBufferView; + +// using const_iterator = forward_iterator; +// using iterator = forward_iterator; + +// constexpr iterator begin() +// requires(!Simple) { +// return iterator(buffer_); +// } +// constexpr const_iterator begin() const { return const_iterator(buffer_); } +// constexpr sentinel_wrapper end() +// requires(!Simple) { +// return sentinel_wrapper(iterator(buffer_ + size_)); +// } +// constexpr sentinel_wrapper end() const { +// return sentinel_wrapper(const_iterator(buffer_ + size_)); +// } +// }; + +// using SimpleNonCommonNonRandom = NonCommonNonRandom; +// using NonSimpleNonCommonNonRandom = NonCommonNonRandom; + +// static_assert(!std::ranges::common_range); +// static_assert(!std::ranges::random_access_range); +// static_assert(!std::ranges::sized_range); +// static_assert(simple_view); +// static_assert(!simple_view); + +// template +// struct BasicView : IntBufferView { +// using IntBufferView::IntBufferView; + +// constexpr NonConstIter begin() +// requires(!std::is_same_v) { +// return NonConstIter(buffer_); +// } +// constexpr Iter begin() const { return Iter(buffer_); } + +// constexpr NonConstSent end() +// requires(!std::is_same_v) { +// if constexpr (std::is_same_v) { +// return NonConstIter(buffer_ + size_); +// } else { +// return NonConstSent(NonConstIter(buffer_ + size_)); +// } +// } + +// constexpr Sent end() const { +// if constexpr (std::is_same_v) { +// return Iter(buffer_ + size_); +// } else { +// return Sent(Iter(buffer_ + size_)); +// } +// } +// }; + +// template +// 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>); +// static_assert(std::sized_sentinel_for, forward_sized_iterator<>>); + +// using ForwardSizedView = BasicView>; +// static_assert(std::ranges::forward_range); +// static_assert(std::ranges::sized_range); +// static_assert(std::ranges::common_range); +// static_assert(!std::ranges::random_access_range); +// static_assert(simple_view); + +// using NonSimpleForwardSizedView = BasicView, forward_sized_iterator, +// forward_sized_iterator, forward_sized_iterator>; +// static_assert(std::ranges::forward_range); +// static_assert(std::ranges::sized_range); +// static_assert(std::ranges::common_range); +// static_assert(!std::ranges::random_access_range); +// static_assert(!simple_view); + +// using ForwardSizedNonCommon = BasicView, sized_sentinel>>; +// static_assert(std::ranges::forward_range); +// static_assert(std::ranges::sized_range); +// static_assert(!std::ranges::common_range); +// static_assert(!std::ranges::random_access_range); +// static_assert(simple_view); + +// using NonSimpleForwardSizedNonCommon = +// BasicView, sized_sentinel>, +// forward_sized_iterator, sized_sentinel>>; +// static_assert(std::ranges::forward_range); +// static_assert(std::ranges::sized_range); +// static_assert(!std::ranges::common_range); +// static_assert(!std::ranges::random_access_range); +// static_assert(!simple_view); + +struct SizedRandomAccessView : IntBufferView { + using IntBufferView::IntBufferView; + using iterator = random_access_iterator; + + constexpr auto begin() const { return iterator(buffer_); } + constexpr auto end() const { return sized_sentinel(iterator(buffer_ + size_)); } + + constexpr decltype(auto) operator[](std::size_t n) const { return *(begin() + n); } +}; +static_assert(std::ranges::view); +static_assert(std::ranges::random_access_range); +static_assert(std::ranges::sized_range); + +// using NonSizedRandomAccessView = +// BasicView, sentinel_wrapper>>; +// static_assert(!std::ranges::contiguous_range); +// static_assert(std::ranges::random_access_range); +// static_assert(!std::ranges::common_range); +// static_assert(!std::ranges::sized_range); +// static_assert(simple_view); + +// using NonSimpleNonSizedRandomAccessView = +// BasicView, sentinel_wrapper>, +// random_access_iterator, sentinel_wrapper> >; +// static_assert(!std::ranges::contiguous_range); +// static_assert(std::ranges::random_access_range); +// static_assert(!std::ranges::common_range); +// static_assert(!std::ranges::sized_range); +// static_assert(!simple_view); + +// using ContiguousCommonView = BasicView; +// static_assert(std::ranges::contiguous_range); +// static_assert(std::ranges::common_range); +// static_assert(std::ranges::sized_range); + +// using ContiguousNonCommonView = BasicView>; +// static_assert(std::ranges::contiguous_range); +// static_assert(!std::ranges::common_range); +// static_assert(!std::ranges::sized_range); + +// using ContiguousNonCommonSized = BasicView>; + +// static_assert(std::ranges::contiguous_range); +// static_assert(!std::ranges::common_range); +// static_assert(std::ranges::sized_range); + +// using InputCommonView = BasicView>; +// static_assert(std::ranges::input_range); +// static_assert(!std::ranges::forward_range); +// static_assert(std::ranges::common_range); +// static_assert(simple_view); + +// using NonSimpleInputCommonView = BasicView, common_input_iterator, +// common_input_iterator, common_input_iterator>; +// static_assert(std::ranges::input_range); +// static_assert(!std::ranges::forward_range); +// static_assert(std::ranges::common_range); +// static_assert(!simple_view); + +// using InputNonCommonView = BasicView, sentinel_wrapper>>; +// static_assert(std::ranges::input_range); +// static_assert(!std::ranges::forward_range); +// static_assert(!std::ranges::common_range); +// static_assert(simple_view); + +// using NonSimpleInputNonCommonView = +// BasicView, sentinel_wrapper>, +// common_input_iterator, sentinel_wrapper>>; +// static_assert(std::ranges::input_range); +// static_assert(!std::ranges::forward_range); +// static_assert(!std::ranges::common_range); +// static_assert(!simple_view); + +// using BidiCommonView = BasicView>; +// static_assert(!std::ranges::sized_range); +// static_assert(std::ranges::bidirectional_range); +// static_assert(!std::ranges::random_access_range); +// static_assert(std::ranges::common_range); +// static_assert(simple_view); + +// using NonSimpleBidiCommonView = BasicView, bidirectional_iterator, +// bidirectional_iterator, bidirectional_iterator>; +// static_assert(!std::ranges::sized_range); +// static_assert(std::ranges::bidirectional_range); +// static_assert(!std::ranges::random_access_range); +// static_assert(std::ranges::common_range); +// static_assert(!simple_view); + +// struct SizedBidiCommon : BidiCommonView { +// using BidiCommonView::BidiCommonView; +// std::size_t size() const { return base(end()) - base(begin()); } +// }; +// static_assert(std::ranges::sized_range); +// static_assert(std::ranges::bidirectional_range); +// static_assert(!std::ranges::random_access_range); +// static_assert(std::ranges::common_range); +// static_assert(simple_view); + +// struct NonSimpleSizedBidiCommon : NonSimpleBidiCommonView { +// using NonSimpleBidiCommonView::NonSimpleBidiCommonView; +// std::size_t size() const { return base(end()) - base(begin()); } +// }; +// static_assert(std::ranges::sized_range); +// static_assert(std::ranges::bidirectional_range); +// static_assert(!std::ranges::random_access_range); +// static_assert(std::ranges::common_range); +// static_assert(!simple_view); + +// using BidiNonCommonView = BasicView, sentinel_wrapper>>; +// static_assert(!std::ranges::sized_range); +// static_assert(std::ranges::bidirectional_range); +// static_assert(!std::ranges::random_access_range); +// static_assert(!std::ranges::common_range); +// static_assert(simple_view); + +// using NonSimpleBidiNonCommonView = +// BasicView, sentinel_wrapper>, +// bidirectional_iterator, sentinel_wrapper>>; +// static_assert(!std::ranges::sized_range); +// static_assert(std::ranges::bidirectional_range); +// static_assert(!std::ranges::random_access_range); +// static_assert(!std::ranges::common_range); +// static_assert(!simple_view); + +// using SizedBidiNonCommonView = BasicView, sized_sentinel>>; +// static_assert(std::ranges::sized_range); +// static_assert(std::ranges::bidirectional_range); +// static_assert(!std::ranges::random_access_range); +// static_assert(!std::ranges::common_range); +// static_assert(simple_view); + +// using NonSimpleSizedBidiNonCommonView = +// BasicView, sized_sentinel>, +// bidirectional_iterator, sized_sentinel>>; +// static_assert(std::ranges::sized_range); +// static_assert(std::ranges::bidirectional_range); +// static_assert(!std::ranges::random_access_range); +// static_assert(!std::ranges::common_range); +// static_assert(!simple_view); + +// namespace adltest{ +// struct iter_move_swap_iterator { + +// std::reference_wrapper iter_move_called_times; +// std::reference_wrapper 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 e084dcfc41b0d..7cd7fa6e68c6d 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 From 8a6109565d42747159842f6c45976156a794bf17 Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 23 Nov 2024 20:23:05 +0100 Subject: [PATCH 41/51] 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 e4c29640ea793..47e79962a8e13 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 begin() const requires (range && ... && range); #include - -// #include -// #include -// #include -// #include +#include +#include +#include +#include #include "types.h" @@ -27,9 +26,9 @@ template concept HasNonConstBegin = requires(T& t) { t.begin(); }; template -concept HasConstAndNonConstBegin = - HasConstBegin && HasNonConstBegin && - requires(T& t, const T& ct) { requires !std::same_as; }; +concept HasConstAndNonConstBegin = HasConstBegin && HasNonConstBegin && requires(T& t, const T& ct) { + requires !std::same_as; +}; template concept HasOnlyNonConstBegin = HasNonConstBegin && !HasConstBegin; @@ -37,7 +36,7 @@ concept HasOnlyNonConstBegin = HasNonConstBegin && !HasConstBegin; template concept HasOnlyConstBegin = HasConstBegin && !HasConstAndNonConstBegin; -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); assert(v.begin() == std::as_const(v).begin()); @@ -89,28 +87,26 @@ constexpr bool test() { static_assert(!HasConstAndNonConstBegin); } - // { - // // not all underlying ranges model simple-view - // std::ranges::zip_view v(SimpleCommon{buffer}, NonSimpleNonCommon{buffer}); - // static_assert(!std::is_same_v); - // 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); - // static_assert(!HasOnlyNonConstBegin); - // static_assert(HasConstAndNonConstBegin); - // } - - // { - // // underlying const R is not a range - // using View = std::ranges::zip_view; - // static_assert(!HasOnlyConstBegin); - // static_assert(HasOnlyNonConstBegin); - // static_assert(!HasConstAndNonConstBegin); - // } + { // not all underlying ranges model simple-view + std::ranges::cartesian_product_view v(SimpleCommon{buffer}, NonSimpleNonCommon{buffer}); + static_assert(!std::is_same_v); + 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); + static_assert(!HasOnlyNonConstBegin); + static_assert(HasConstAndNonConstBegin); + } + + { // underlying const R is not a range + using View = std::ranges::cartesian_product_view; + static_assert(!HasOnlyConstBegin); + static_assert(HasOnlyNonConstBegin); + static_assert(!HasConstAndNonConstBegin); + } 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 1426371770050..83f877334ffa7 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; // static_assert(simple_view); // static_assert(!simple_view); -// template -// struct NonCommon : IntBufferView { -// using IntBufferView::IntBufferView; -// constexpr int* begin() -// requires(!Simple) { -// return buffer_; -// } -// constexpr const int* begin() const { return buffer_; } -// constexpr sentinel_wrapper end() -// requires(!Simple) { -// return sentinel_wrapper(buffer_ + size_); -// } -// constexpr sentinel_wrapper end() const { return sentinel_wrapper(buffer_ + size_); } -// }; +template +struct NonCommon : IntBufferView { + using IntBufferView::IntBufferView; + constexpr int* begin() + requires(!Simple) { + return buffer_; + } + constexpr const int* begin() const { return buffer_; } + constexpr sentinel_wrapper end() + requires(!Simple) { + return sentinel_wrapper(buffer_ + size_); + } + constexpr sentinel_wrapper end() const { return sentinel_wrapper(buffer_ + size_); } +}; // using SimpleNonCommon = NonCommon; -// using NonSimpleNonCommon = NonCommon; +using NonSimpleNonCommon = NonCommon; // static_assert(!std::ranges::common_range); // static_assert(std::ranges::random_access_range); From f79867a33df23ea2323733f089df8429a2a74526 Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 23 Nov 2024 21:13:01 +0100 Subject: [PATCH 42/51] 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 0000000000000..fb7f7daef96a3 --- /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 +#include +#include +#include + +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 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 e5ebd792f22970b62a50a7532d712a0d1c890c92 Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 23 Nov 2024 21:31:21 +0100 Subject: [PATCH 43/51] 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 9bbdcb0550841..4d95de846b3e9 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::iterator { } }; +namespace views { +namespace __cartesian_product { +struct __fn { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()() { return views::single(tuple()); } + + template + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Ranges&&... __rs) + -> decltype(cartesian_product_view...>(std::forward<_Ranges>(__rs)...)) { + return cartesian_product_view...>(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 fb7f7daef96a3..cdab4750f2c2e 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 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 370613d304837c0c79a6e8967f0f065ad7de0e57 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 24 Nov 2024 15:40:51 +0100 Subject: [PATCH 44/51] 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 47e79962a8e13..c1cd8e27fb1c7 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> 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> 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> decltype(auto) mutVal = *v.begin(); + std::same_as> 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()); - assert(v.begin() == v.end()); - } - { // const - const std::ranges::cartesian_product_view v(SizedRandomAccessView{buffer}, std::ranges::empty_view()); - assert(v.begin() == v.end()); - } + { // with empty range + std::ranges::cartesian_product_view v(SizedRandomAccessView{buffer}, std::ranges::empty_view()); + assert(v.begin() == v.end()); + assert(std::as_const(v).begin() == std::as_const(v).end()); } { // underlying ranges all model simple-view From e4fd6463f07bc2ea864f31daa588a0164dff6eb9 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 24 Nov 2024 19:44:25 +0100 Subject: [PATCH 45/51] 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 0000000000000..f623d0f5c0192 --- /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 + +#include +#include +#include + +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>); +static_assert(std::is_default_constructible_v< + std::ranges::cartesian_product_view>); +static_assert( + !std::is_default_constructible_v>); +static_assert( + !std::is_default_constructible_v>); +static_assert(!std::is_default_constructible_v>); + +constexpr bool test() { + { + using View = std::ranges::cartesian_product_view; + View v = View(); // the default constructor is not explicit + assert(v.size() == 9); + auto it = v.begin(); + using Value = std::tuple; + 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 244ab9b1a984b119edcee1cb52e9bcb1f91a351b Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 24 Nov 2024 20:01:03 +0100 Subject: [PATCH 46/51] 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 0000000000000..8acad61f87831 --- /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 +#include + +#include "../range.zip/types.h" + +template +void conversion_test(T); + +template +concept implicitly_constructible_from = requires(Args&&... args) { conversion_test({std::move(args)...}); }; + +// test constructor is explicit +static_assert(std::constructible_from, SimpleCommon>); +static_assert(!implicitly_constructible_from, SimpleCommon>); + +static_assert(std::constructible_from, SimpleCommon, SimpleCommon>); +static_assert( + !implicitly_constructible_from, 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 +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(buffer, buffer2); + } + + { // bidi and random_access + constructorTest(buffer, buffer2); + } + + { // contiguous + constructorTest(buffer, buffer2); + } + + return true; +} + +int main() { + test(); + static_assert(test()); +} From c87e1ee5a8f6397e9e9509c0dfda9364eb886d24 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 24 Nov 2024 20:02:43 +0100 Subject: [PATCH 47/51] 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 c1cd8e27fb1c7..7df8dbd57dcaa 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 #include -#include "types.h" +#include "../range.zip/types.h" template 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 83f877334ffa7..0000000000000 --- 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 -#include - -#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 -struct BufferView : std::ranges::view_base { - T* buffer_; - std::size_t size_; - - template - constexpr BufferView(T (&b)[N]) : buffer_(b), size_(N) {} -}; - -using IntBufferView = BufferView; - -template -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; -// using NonSimpleCommon = Common; - -// using SimpleCommonRandomAccessSized = SimpleCommon; -// using NonSimpleCommonRandomAccessSized = NonSimpleCommon; - -// static_assert(std::ranges::common_range>); -// static_assert(std::ranges::random_access_range); -// static_assert(std::ranges::sized_range); -// static_assert(simple_view); -// static_assert(!simple_view); - -// template -// struct CommonNonRandom : IntBufferView { -// using IntBufferView::IntBufferView; -// using const_iterator = forward_iterator; -// using iterator = forward_iterator; -// 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; -// using NonSimpleCommonNonRandom = CommonNonRandom; - -// static_assert(std::ranges::common_range); -// static_assert(!std::ranges::random_access_range); -// static_assert(!std::ranges::sized_range); -// static_assert(simple_view); -// static_assert(!simple_view); - -template -struct NonCommon : IntBufferView { - using IntBufferView::IntBufferView; - constexpr int* begin() - requires(!Simple) { - return buffer_; - } - constexpr const int* begin() const { return buffer_; } - constexpr sentinel_wrapper end() - requires(!Simple) { - return sentinel_wrapper(buffer_ + size_); - } - constexpr sentinel_wrapper end() const { return sentinel_wrapper(buffer_ + size_); } -}; - -// using SimpleNonCommon = NonCommon; -using NonSimpleNonCommon = NonCommon; - -// static_assert(!std::ranges::common_range); -// static_assert(std::ranges::random_access_range); -// static_assert(!std::ranges::sized_range); -// static_assert(simple_view); -// static_assert(!simple_view); - -// template -// struct NonCommonSized : IntBufferView { -// using IntBufferView::IntBufferView; -// constexpr int* begin() -// requires(!Simple) { -// return buffer_; -// } -// constexpr const int* begin() const { return buffer_; } -// constexpr sentinel_wrapper end() -// requires(!Simple) { -// return sentinel_wrapper(buffer_ + size_); -// } -// constexpr sentinel_wrapper end() const { return sentinel_wrapper(buffer_ + size_); } -// constexpr std::size_t size() const { return size_; } -// }; - -// using SimpleNonCommonSized = NonCommonSized; -// using SimpleNonCommonRandomAccessSized = SimpleNonCommonSized; -// using NonSimpleNonCommonSized = NonCommonSized; -// using NonSimpleNonCommonRandomAccessSized = NonSimpleNonCommonSized; - -// static_assert(!std::ranges::common_range); -// static_assert(std::ranges::random_access_range); -// static_assert(std::ranges::sized_range); -// static_assert(simple_view); -// static_assert(!simple_view); - -// template -// struct NonCommonNonRandom : IntBufferView { -// using IntBufferView::IntBufferView; - -// using const_iterator = forward_iterator; -// using iterator = forward_iterator; - -// constexpr iterator begin() -// requires(!Simple) { -// return iterator(buffer_); -// } -// constexpr const_iterator begin() const { return const_iterator(buffer_); } -// constexpr sentinel_wrapper end() -// requires(!Simple) { -// return sentinel_wrapper(iterator(buffer_ + size_)); -// } -// constexpr sentinel_wrapper end() const { -// return sentinel_wrapper(const_iterator(buffer_ + size_)); -// } -// }; - -// using SimpleNonCommonNonRandom = NonCommonNonRandom; -// using NonSimpleNonCommonNonRandom = NonCommonNonRandom; - -// static_assert(!std::ranges::common_range); -// static_assert(!std::ranges::random_access_range); -// static_assert(!std::ranges::sized_range); -// static_assert(simple_view); -// static_assert(!simple_view); - -// template -// struct BasicView : IntBufferView { -// using IntBufferView::IntBufferView; - -// constexpr NonConstIter begin() -// requires(!std::is_same_v) { -// return NonConstIter(buffer_); -// } -// constexpr Iter begin() const { return Iter(buffer_); } - -// constexpr NonConstSent end() -// requires(!std::is_same_v) { -// if constexpr (std::is_same_v) { -// return NonConstIter(buffer_ + size_); -// } else { -// return NonConstSent(NonConstIter(buffer_ + size_)); -// } -// } - -// constexpr Sent end() const { -// if constexpr (std::is_same_v) { -// return Iter(buffer_ + size_); -// } else { -// return Sent(Iter(buffer_ + size_)); -// } -// } -// }; - -// template -// 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>); -// static_assert(std::sized_sentinel_for, forward_sized_iterator<>>); - -// using ForwardSizedView = BasicView>; -// static_assert(std::ranges::forward_range); -// static_assert(std::ranges::sized_range); -// static_assert(std::ranges::common_range); -// static_assert(!std::ranges::random_access_range); -// static_assert(simple_view); - -// using NonSimpleForwardSizedView = BasicView, forward_sized_iterator, -// forward_sized_iterator, forward_sized_iterator>; -// static_assert(std::ranges::forward_range); -// static_assert(std::ranges::sized_range); -// static_assert(std::ranges::common_range); -// static_assert(!std::ranges::random_access_range); -// static_assert(!simple_view); - -// using ForwardSizedNonCommon = BasicView, sized_sentinel>>; -// static_assert(std::ranges::forward_range); -// static_assert(std::ranges::sized_range); -// static_assert(!std::ranges::common_range); -// static_assert(!std::ranges::random_access_range); -// static_assert(simple_view); - -// using NonSimpleForwardSizedNonCommon = -// BasicView, sized_sentinel>, -// forward_sized_iterator, sized_sentinel>>; -// static_assert(std::ranges::forward_range); -// static_assert(std::ranges::sized_range); -// static_assert(!std::ranges::common_range); -// static_assert(!std::ranges::random_access_range); -// static_assert(!simple_view); - -struct SizedRandomAccessView : IntBufferView { - using IntBufferView::IntBufferView; - using iterator = random_access_iterator; - - constexpr auto begin() const { return iterator(buffer_); } - constexpr auto end() const { return sized_sentinel(iterator(buffer_ + size_)); } - - constexpr decltype(auto) operator[](std::size_t n) const { return *(begin() + n); } -}; -static_assert(std::ranges::view); -static_assert(std::ranges::random_access_range); -static_assert(std::ranges::sized_range); - -// using NonSizedRandomAccessView = -// BasicView, sentinel_wrapper>>; -// static_assert(!std::ranges::contiguous_range); -// static_assert(std::ranges::random_access_range); -// static_assert(!std::ranges::common_range); -// static_assert(!std::ranges::sized_range); -// static_assert(simple_view); - -// using NonSimpleNonSizedRandomAccessView = -// BasicView, sentinel_wrapper>, -// random_access_iterator, sentinel_wrapper> >; -// static_assert(!std::ranges::contiguous_range); -// static_assert(std::ranges::random_access_range); -// static_assert(!std::ranges::common_range); -// static_assert(!std::ranges::sized_range); -// static_assert(!simple_view); - -// using ContiguousCommonView = BasicView; -// static_assert(std::ranges::contiguous_range); -// static_assert(std::ranges::common_range); -// static_assert(std::ranges::sized_range); - -// using ContiguousNonCommonView = BasicView>; -// static_assert(std::ranges::contiguous_range); -// static_assert(!std::ranges::common_range); -// static_assert(!std::ranges::sized_range); - -// using ContiguousNonCommonSized = BasicView>; - -// static_assert(std::ranges::contiguous_range); -// static_assert(!std::ranges::common_range); -// static_assert(std::ranges::sized_range); - -// using InputCommonView = BasicView>; -// static_assert(std::ranges::input_range); -// static_assert(!std::ranges::forward_range); -// static_assert(std::ranges::common_range); -// static_assert(simple_view); - -// using NonSimpleInputCommonView = BasicView, common_input_iterator, -// common_input_iterator, common_input_iterator>; -// static_assert(std::ranges::input_range); -// static_assert(!std::ranges::forward_range); -// static_assert(std::ranges::common_range); -// static_assert(!simple_view); - -// using InputNonCommonView = BasicView, sentinel_wrapper>>; -// static_assert(std::ranges::input_range); -// static_assert(!std::ranges::forward_range); -// static_assert(!std::ranges::common_range); -// static_assert(simple_view); - -// using NonSimpleInputNonCommonView = -// BasicView, sentinel_wrapper>, -// common_input_iterator, sentinel_wrapper>>; -// static_assert(std::ranges::input_range); -// static_assert(!std::ranges::forward_range); -// static_assert(!std::ranges::common_range); -// static_assert(!simple_view); - -// using BidiCommonView = BasicView>; -// static_assert(!std::ranges::sized_range); -// static_assert(std::ranges::bidirectional_range); -// static_assert(!std::ranges::random_access_range); -// static_assert(std::ranges::common_range); -// static_assert(simple_view); - -// using NonSimpleBidiCommonView = BasicView, bidirectional_iterator, -// bidirectional_iterator, bidirectional_iterator>; -// static_assert(!std::ranges::sized_range); -// static_assert(std::ranges::bidirectional_range); -// static_assert(!std::ranges::random_access_range); -// static_assert(std::ranges::common_range); -// static_assert(!simple_view); - -// struct SizedBidiCommon : BidiCommonView { -// using BidiCommonView::BidiCommonView; -// std::size_t size() const { return base(end()) - base(begin()); } -// }; -// static_assert(std::ranges::sized_range); -// static_assert(std::ranges::bidirectional_range); -// static_assert(!std::ranges::random_access_range); -// static_assert(std::ranges::common_range); -// static_assert(simple_view); - -// struct NonSimpleSizedBidiCommon : NonSimpleBidiCommonView { -// using NonSimpleBidiCommonView::NonSimpleBidiCommonView; -// std::size_t size() const { return base(end()) - base(begin()); } -// }; -// static_assert(std::ranges::sized_range); -// static_assert(std::ranges::bidirectional_range); -// static_assert(!std::ranges::random_access_range); -// static_assert(std::ranges::common_range); -// static_assert(!simple_view); - -// using BidiNonCommonView = BasicView, sentinel_wrapper>>; -// static_assert(!std::ranges::sized_range); -// static_assert(std::ranges::bidirectional_range); -// static_assert(!std::ranges::random_access_range); -// static_assert(!std::ranges::common_range); -// static_assert(simple_view); - -// using NonSimpleBidiNonCommonView = -// BasicView, sentinel_wrapper>, -// bidirectional_iterator, sentinel_wrapper>>; -// static_assert(!std::ranges::sized_range); -// static_assert(std::ranges::bidirectional_range); -// static_assert(!std::ranges::random_access_range); -// static_assert(!std::ranges::common_range); -// static_assert(!simple_view); - -// using SizedBidiNonCommonView = BasicView, sized_sentinel>>; -// static_assert(std::ranges::sized_range); -// static_assert(std::ranges::bidirectional_range); -// static_assert(!std::ranges::random_access_range); -// static_assert(!std::ranges::common_range); -// static_assert(simple_view); - -// using NonSimpleSizedBidiNonCommonView = -// BasicView, sized_sentinel>, -// bidirectional_iterator, sized_sentinel>>; -// static_assert(std::ranges::sized_range); -// static_assert(std::ranges::bidirectional_range); -// static_assert(!std::ranges::random_access_range); -// static_assert(!std::ranges::common_range); -// static_assert(!simple_view); - -// namespace adltest{ -// struct iter_move_swap_iterator { - -// std::reference_wrapper iter_move_called_times; -// std::reference_wrapper 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 088d166fcd2f33f7fe63dc5428fa60a34afb488c Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 7 Dec 2024 13:32:48 +0100 Subject: [PATCH 48/51] 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 0000000000000..1d057d05bc810 --- /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 end() requires ((!simple-view || ... || !simple-view ) && cartesian-product-is-common< First, Vs...>); +// constexpr iterator end() const requires cartesian-product-is-common ; + +#include "assert_macros.h" + +#include +#include +#include + +constexpr bool test() { + { // non-empty range + constexpr size_t N = 7; + std::array 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 a0; + constexpr size_t N1 = 42; + std::array 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 a0; + std::array a1; + std::array a2; + std::ranges::cartesian_product_view c{a0, a1, a2}; + assert(c.end() == c.begin() + N0*N1*N2); + } + + { // empty range + std::ranges::empty_view e; + std::ranges::cartesian_product_view c{e}; + assert(c.end() == c.begin()); + } + + { // (empty range)^2 + std::ranges::empty_view e; + std::ranges::cartesian_product_view c{e, e}; + assert(c.end() == c.begin()); + } + + { // empty range X common range + std::ranges::empty_view e; + constexpr size_t N = 7; + std::array a; + std::ranges::cartesian_product_view c{e, a}; + assert(c.end() == c.begin()); + } + + { // common range X empty range + std::ranges::empty_view e; + constexpr size_t N = 7; + std::array a; + std::ranges::cartesian_product_view c{e, a}; + assert(c.end() == c.begin()); + } + + { // (empty range)^3 + std::ranges::empty_view 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 e; + constexpr size_t N = 7; + std::array 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 e; + constexpr size_t N = 7; + std::array 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 e; + constexpr size_t N = 7; + std::array 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 e; + constexpr size_t N0 = 7, N1 = 42; + std::array a0; + std::array 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 e; + constexpr size_t N0 = 7, N1 = 42; + std::array a0; + std::array 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 e; + constexpr size_t N0 = 7, N1 = 42; + std::array a0; + std::array 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 f8cb050cffa63a6c5c49c2641cb9c2ce06ebae7f Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 7 Dec 2024 13:36:05 +0100 Subject: [PATCH 49/51] 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 7df8dbd57dcaa..fac0d39b9f723 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 f623d0f5c0192..8691ff2122e30 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 72657095c792e..bf23c913ff9cc 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 8acad61f87831..0c424acaf3950 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 cdab4750f2c2e..4d505921b3a77 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 82ee47997f53b..44c4de5b3d7a3 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 From 62c2d226f8ce2880ee5a65c4fd5203c5ae812a9e Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 7 Dec 2024 21:12:51 +0100 Subject: [PATCH 50/51] test: view::size() more tests --- .../size.pass.cpp | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) 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 44c4de5b3d7a3..c29990a205e6a 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 @@ -10,13 +10,13 @@ // std::ranges::cartesian_product_view::size +#include #include -#include #include +#include constexpr bool test() { - { // testing: constexpr auto size() const - // example taken from: https://en.cppreference.com/w/cpp/ranges/cartesian_product_view/size + { // example taken from: https://en.cppreference.com/w/cpp/ranges/cartesian_product_view/size constexpr static auto w = {1}; constexpr static auto x = {2, 3}; constexpr static auto y = {4, 5, 6}; @@ -33,6 +33,22 @@ constexpr bool test() { assert(v.size() == w.size() * x.size() * y.size() * z.size()); } + { // empty range + std::ranges::empty_view e; + auto v = std::ranges::cartesian_product_view(e); + assert(v.size() == 0); + } + + { // 1..3 range(s) + constexpr size_t N0 = 3, N1 = 7, N2 = 42; + std::array a0; + std::array a1; + std::array a2; + assert(std::ranges::cartesian_product_view(a0).size() == N0); + assert(std::ranges::cartesian_product_view(a0, a1).size() == N0 * N1); + assert(std::ranges::cartesian_product_view(a0, a1, a2).size() == N0 * N1 * N2); + } + return true; } From 150eed31fbe65730b989bf02cb1e62fbb99f340d Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 7 Dec 2024 21:23:01 +0100 Subject: [PATCH 51/51] test: view CTAD --- .../ctad.compile.pass.cpp | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/ctad.compile.pass.cpp diff --git a/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/ctad.compile.pass.cpp new file mode 100644 index 0000000000000..d67e018828c27 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.cartesian.product.view/ctad.compile.pass.cpp @@ -0,0 +1,41 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// template +// cartesian_product_view(Vs&&...) -> cartesian_product_view...>; + +#include +#include +#include + +struct Container { + int* begin() const; + int* end() const; +}; + +struct View : std::ranges::view_base { + int* begin() const; + int* end() const; +}; + +void testCTAD() { + static_assert(std::is_same_v>>); + + static_assert(std::is_same_v, View>>); + + Container c{}; + static_assert( + std::is_same_v< + decltype(std::ranges::cartesian_product_view(Container{}, View{}, c)), + std::ranges:: + cartesian_product_view, View, std::ranges::ref_view>>); +}