From 6eca11547efbf2d6ac625f03bbcb9a802f4107af Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Tue, 17 Sep 2024 15:31:33 +0200 Subject: [PATCH 01/47] [oneDPL][ranges][zip_view] + initial implementation of standard compliance zip_view --- include/oneapi/dpl/pstl/zip_view_impl.h | 336 ++++++++++++++++++++++++ 1 file changed, 336 insertions(+) create mode 100644 include/oneapi/dpl/pstl/zip_view_impl.h diff --git a/include/oneapi/dpl/pstl/zip_view_impl.h b/include/oneapi/dpl/pstl/zip_view_impl.h new file mode 100644 index 00000000000..ce8a5e97f7d --- /dev/null +++ b/include/oneapi/dpl/pstl/zip_view_impl.h @@ -0,0 +1,336 @@ +#include +#include +#include +#include +#include +#include + + +namespace my { + +template +concept all_forward = ( std::ranges::forward_range> && ... ); + +template +concept all_bidirectional = ( std::ranges::bidirectional_range> && ... ); + +template +concept all_random_access = ( std::ranges::random_access_range> && ... ); + +template +concept zip_is_common = + (sizeof...(Rs) == 1 && ( std::ranges::common_range && ... )) + || + (!(std::ranges::bidirectional_range && ...) && (std::ranges::common_range && ...)) + || + ((std::ranges::random_access_range && ...) && (std::ranges::sized_range && ...)); + +template +struct declare_iterator_category {}; + +template + requires all_forward +struct declare_iterator_category { + using iterator_category = std::input_iterator_tag; +}; + +template + requires ((std::ranges::view && ... ) && (sizeof...(Views) > 0)) +class zip_view : public std::ranges::view_interface> { +public: + zip_view() = default; + constexpr zip_view(Views... views) : views_(views...) {} + + template + class iterator : declare_iterator_category { + public: + using iterator_concept = std::conditional_t, + std::random_access_iterator_tag, + std::conditional_t, + std::bidirectional_iterator_tag, + std::conditional_t, + std::forward_iterator_tag, + std::input_iterator_tag>>>; + + using value_type = std::conditional_t...>, + std::tuple...>>; + + using difference_type = std::conditional_t...>, + std::common_type_t...>>; + + iterator() = default; + + constexpr iterator(iterator i) + requires Const && (std::convertible_to, std::ranges::iterator_t> && ...) + : current_(std::move(i.current_)) {} + + private: + template + constexpr iterator(const Iterators&... iterators) + : current_(iterators...) {} + public: + + constexpr auto operator*() const { + using return_tuple_type = std::conditional_t>::reference...>, + std::tuple>::reference...>>; + + + return std::apply([](auto&... iterators) { + return std::make_tuple((*iterators)...); + }, + current_); + } + + constexpr auto operator[]( difference_type n ) const + requires all_random_access + { + return *(*this + n); + } + + constexpr iterator& operator++() { + std::apply([](auto&... iterators) { + ( (++iterators) , ... ); + }, + current_); + return *this; + } + + constexpr void operator++(int) { + ++*this; + } + + constexpr iterator operator++(int) requires all_forward { + auto tmp = *this; + ++*this; + return tmp; + } + + constexpr iterator& operator--() requires all_bidirectional { + step_backward(std::make_index_sequence()); + + std::apply([](auto&... iterators) { + ((--iterators) , ... ); + }, + current_); + return *this; + } + + constexpr iterator operator--(int) requires all_bidirectional { + auto tmp = *this; + --*this; + return tmp; + } + + constexpr iterator& operator+=(difference_type n) + requires all_random_access + { + std::apply([n](auto&... iterators) { + ((iterators += n) , ...); + }, + current_); + return *this; + } + + constexpr iterator& operator-=(difference_type n) + requires all_random_access + { + std::apply([n](auto&... iterators) { + ((iterators -= n) , ...); + }, + current_); + return *this; + } + + friend constexpr bool operator==(const iterator& x, const iterator& y) + requires ( std::equality_comparable, + std::ranges::iterator_t>> && ... ) + { + if constexpr (all_bidirectional) { + return x.current_ == y.current_; + } else { + return x.compare_equal(y, std::make_index_sequence()); + } + } + + friend constexpr auto operator<=>(const iterator& x, const iterator& y) + requires all_random_access + { + return x.current_ <=> y.current_; + } + + private: + template + constexpr bool compare_equal(iterator y, std::index_sequence) { + return ((std::get(current_) == std::get(y.current_)) && ...); + } + + template + constexpr bool compare_with_sentinels(const SentinelsTuple& sentinels, std::index_sequence) { + return ( (std::get(current_) == std::get(sentinels)) || ... ); + } + + template + constexpr std::common_type_t, + std::ranges::range_difference_t>...> + distance_to_sentinels(const SentinelsTuple& sentinels, std::index_sequence<0, In...>) { + auto min = std::get<0>(current_) - std::get<0>(sentinels); + + ( (min = std::min(min, (std::get(current_) - std::get(sentinels)))) , ... ); + return min; + } + + friend class zip_view; + + using current_type = std::conditional_t...>, + std::tuple...>>; + + current_type current_; + }; // class iterator + + template + class sentinel { + public: + sentinel() = default; + constexpr sentinel(sentinel i) + requires Const && + ( std::convertible_to, std::ranges::sentinel_t> && ... ) + : end_(std::move(i.end_)) {} + + private: + template + constexpr sentinel(const Sentinels&... sentinels) + : end_(sentinels...) {} + public: + template + requires (std::sentinel_for, + std::ranges::sentinel_t>, + std::conditional_t, + std::ranges::iterator_t>> && ...) + friend constexpr bool operator==(const iterator& x, const sentinel& y) + { + return x.compare_with_sentinels(y.end_, std::make_index_sequence()); + } + + template + requires (std::sized_sentinel_for, + std::ranges::sentinel_t>, + std::conditional_t, + std::ranges::iterator_t>> && ...) + friend constexpr std::common_type_t, + std::ranges::range_difference_t>...> + operator-(const iterator& x, const sentinel& y) { + return x.distance_to_sentinels(y.end_, std::make_index_sequence()); + } + + template + requires (std::sized_sentinel_for, + std::ranges::sentinel_t>, + std::conditional_t, + std::ranges::iterator_t>> && ...) + friend constexpr std::common_type_t, + std::ranges::range_difference_t>...> + operator-(const sentinel& y, const iterator& x) { + return -(x - y); + } + + private: + friend class zip_view; + + using end_type = std::conditional_t...>, + std::tuple...>>; + + end_type end_; + }; // class sentinel + + constexpr auto begin() requires (std:: ranges::range && ...) // !simple_view? + { + return std::apply([](auto... views) { + return iterator(std::ranges::begin(views)...); + }, + views_); + } + + constexpr auto begin() const requires ( std::ranges::range && ... ) + { + return std::apply([](auto... views) { + return iterator(std::ranges::begin(views)...); + }, + views_); + } + + constexpr auto end() requires (std::ranges::range && ...) // requires !simple_view { + { + if constexpr (!zip_is_common) { + return std::apply([](auto... views) { + return sentinel(std::ranges::end(views)...); + }, + views_); + } else if constexpr ((std::ranges::random_access_range && ...)) { + auto it = begin(); + it += size(); + return it; + } else { + return std::apply([](auto... views) { + return iterator(std::ranges::end(views)...); + }, + views_); + } + } + + constexpr auto end() const requires (std::ranges::range && ...) + { + if constexpr (!zip_is_common) { + return std::apply([](auto... views) { + return sentinel(std::ranges::end(views)...); + }, + views_); + } else if constexpr ((std::ranges::random_access_range && ...)) { + auto it = begin(); + it += size(); + return it; + } else { + return std::apply([](auto... views) { + return iterator(std::ranges::end(views)...); + }, + views_); + } + } + + constexpr auto size() requires (std::ranges::sized_range && ...) + { + return std::apply([](auto... sizes) { + using CT = std::make_unsigned_t>; + return std::ranges::min({CT(sizes)...}); + }, + std::apply([](auto... views) { + return std::make_tuple(std::ranges::size(views)...); + }, + views_)); + } + + constexpr auto size() const requires (std::ranges::sized_range && ...) + { + return const_cast(this)->size(); + } +private: + std::tuple views_; +}; // class zip_view + +template +zip_view(Rs&&...) -> zip_view...>; + +struct zip_fn { + template + constexpr auto operator()( Rs&&... rs ) const { + return zip_view...>(std::forward(rs)...); + } +}; + +inline constexpr zip_fn zip{}; + +} // namespace my + +int main() +{ + +} \ No newline at end of file From 0213fd9e5a900f501a2bc0defae7543871b8b1f1 Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Wed, 18 Sep 2024 18:38:34 +0200 Subject: [PATCH 02/47] [oneDPL][ranges][zip_view] + missing arithmetic operations for zip_view::iterator type --- include/oneapi/dpl/pstl/zip_view_impl.h | 28 +++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/include/oneapi/dpl/pstl/zip_view_impl.h b/include/oneapi/dpl/pstl/zip_view_impl.h index ce8a5e97f7d..b7164223c90 100644 --- a/include/oneapi/dpl/pstl/zip_view_impl.h +++ b/include/oneapi/dpl/pstl/zip_view_impl.h @@ -158,6 +158,27 @@ class zip_view : public std::ranges::view_interface> { return x.current_ <=> y.current_; } + friend constexpr auto operator-(const iterator& x, const iterator& y) + requires all_random_access + { + return std::get<0>(x.current_) - std::get<0>(y.current_); + } + + friend constexpr iterator operator+(iterator it, difference_type n) + { + return it+=n; + } + + friend constexpr iterator operator+(difference_type n, iterator it) + { + return it+=n; + } + + friend constexpr iterator operator-(iterator it, difference_type n) + { + return it-=n; + } + private: template constexpr bool compare_equal(iterator y, std::index_sequence) { @@ -328,9 +349,4 @@ struct zip_fn { inline constexpr zip_fn zip{}; -} // namespace my - -int main() -{ - -} \ No newline at end of file +} // namespace my \ No newline at end of file From 2defcddfa325afbd25057d372ee4122c65880ce2 Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Fri, 20 Sep 2024 14:17:50 +0200 Subject: [PATCH 03/47] [oneDPL][ranges][zip_view] + return type fix for operator*() --- include/oneapi/dpl/pstl/zip_view_impl.h | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/include/oneapi/dpl/pstl/zip_view_impl.h b/include/oneapi/dpl/pstl/zip_view_impl.h index b7164223c90..54b128bf84e 100644 --- a/include/oneapi/dpl/pstl/zip_view_impl.h +++ b/include/oneapi/dpl/pstl/zip_view_impl.h @@ -5,7 +5,6 @@ #include #include - namespace my { template @@ -57,6 +56,8 @@ class zip_view : public std::ranges::view_interface> { using difference_type = std::conditional_t...>, std::common_type_t...>>; + using return_tuple_type = std::conditional_t>::reference...>, + std::tuple>::reference...>>; iterator() = default; @@ -70,18 +71,16 @@ class zip_view : public std::ranges::view_interface> { : current_(iterators...) {} public: - constexpr auto operator*() const { - using return_tuple_type = std::conditional_t>::reference...>, - std::tuple>::reference...>>; + constexpr return_tuple_type operator*() const { - return std::apply([](auto&... iterators) { - return std::make_tuple((*iterators)...); + return std::apply([](auto... iterators) { + return return_tuple_type((*iterators)...); }, current_); } - constexpr auto operator[]( difference_type n ) const + constexpr return_tuple_type operator[]( difference_type n ) const requires all_random_access { return *(*this + n); From d2eb9edaab14c55432a094fc4d51a4a96ca918bd Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Tue, 24 Sep 2024 18:05:43 +0200 Subject: [PATCH 04/47] [oneDPL][ranges][tuple] + const assignment operator overload --- include/oneapi/dpl/pstl/tuple_impl.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/oneapi/dpl/pstl/tuple_impl.h b/include/oneapi/dpl/pstl/tuple_impl.h index 239734d4861..01b5237bdf7 100644 --- a/include/oneapi/dpl/pstl/tuple_impl.h +++ b/include/oneapi/dpl/pstl/tuple_impl.h @@ -500,6 +500,15 @@ struct tuple next = other.next; return *this; } + + template + tuple& + operator=(const tuple& other) const + { + holder.value = other.holder.value; + next = other.next; + return *this; + } // if T1 is deduced with reference, compiler generates deleted operator= and, // since "template operator=" is not considered as operator= overload From dc22d432707cf3604b8e77ee8f2b4c111b441fd7 Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Tue, 24 Sep 2024 18:05:58 +0200 Subject: [PATCH 05/47] [oneDPL][ranges][zip_view] + test --- test/parallel_api/ranges/std_ranges_test.h | 14 +++++ .../ranges/std_ranges_zip_view.pass.cpp | 56 +++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 test/parallel_api/ranges/std_ranges_zip_view.pass.cpp diff --git a/test/parallel_api/ranges/std_ranges_test.h b/test/parallel_api/ranges/std_ranges_test.h index 51e0665a27f..0f6310ac6c3 100644 --- a/test/parallel_api/ranges/std_ranges_test.h +++ b/test/parallel_api/ranges/std_ranges_test.h @@ -15,6 +15,7 @@ #include #include +#include #include "support/test_config.h" #include "support/test_macros.h" @@ -144,6 +145,14 @@ template static constexpr bool is_range().begin())>> = true; +void call_with_host_policies(auto algo, auto... args) +{ + algo(oneapi::dpl::execution::seq, args...); + algo(oneapi::dpl::execution::unseq, args...); + algo(oneapi::dpl::execution::par, args...); + algo(oneapi::dpl::execution::par_unseq, args...); +} + template struct test { @@ -540,6 +549,11 @@ struct test_range_algo test, mode>{max_n}(host_policies(), algo, checker, std::views::all, std::identity{}, args...); #endif +#if 0//zip_view + auto zip_view = [](auto&& v) { return my::zip(v); }; + test, mode>{}(host_policies(), algo, checker, zip_view, std::identity{}, args...); +#endif + #if TEST_DPCPP_BACKEND_PRESENT //Skip the cases with pointer-to-function and hetero policy because pointer-to-function is not supported within kernel code. if constexpr(!std::disjunction_v...>) diff --git a/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp b/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp new file mode 100644 index 00000000000..a777db2bad1 --- /dev/null +++ b/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp @@ -0,0 +1,56 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Copyright (C) Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// This file incorporates work covered by the following copyright and permission +// notice: +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// +//===----------------------------------------------------------------------===// + +#include "std_ranges_test.h" + +template +struct print_type; + +std::int32_t +main() +{ +#if _ENABLE_STD_RANGES_TESTING + + namespace dpl_ranges = oneapi::dpl::ranges; + const char* err_msg = "Wrong effect algo transform with zip_view."; + + constexpr int max_n = 10; + int data[max_n] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + + auto zip_view = my::zip(data, std::views::iota(0, max_n)) | std::views::take(5); + std::ranges::for_each(zip_view, test_std_ranges::f_mutuable, [](const auto& val) { return std::get<1>(val); }); + + test_std_ranges::call_with_host_policies(dpl_ranges::for_each, zip_view, test_std_ranges::f_mutuable, [](const auto& val) { return std::get<1>(val); }); + //EXPECT_EQ_N(expected.begin(), res.begin(), n, err_msg); + + dpl_ranges::for_each(test_std_ranges::dpcpp_policy(), zip_view, test_std_ranges::f_mutuable, [](const auto& val) { return std::get<1>(val); }); + + auto zip_view_sort = my::zip(data, data); + + auto it = zip_view_sort.begin(); + std::sort(zip_view_sort.begin(), zip_view_sort.begin() + 5, [](const auto& val1, const auto& val2) { return std::get<0>(val1) < std::get<0>(val2); }); + std::ranges::sort(zip_view_sort, std::greater{}, [](auto&& val) { return std::get<0>(val); }); + + static_assert(std::ranges::random_access_range); + static_assert(std::random_access_iterator); + //dpl_ranges::sort(oneapi::dpl::execution::seq, zip_view_sort, std::greater{}, [](auto&& val) { return std::get<0>(val); }); + + //test_std_ranges::call_with_host_policies(dpl_ranges::sort, zip_view_sort, test_std_ranges::binary_pred, [](const auto& val) { return std::get<0>(val); }); + + +#endif //_ENABLE_STD_RANGES_TESTING + + return TestUtils::done(_ENABLE_STD_RANGES_TESTING); +} From 138ecd432efd6a04654c6ebc57453575bb2f44f6 Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Tue, 24 Sep 2024 18:07:19 +0200 Subject: [PATCH 06/47] [oneDPL][ranges][zip_view] + apply_to_tuple instead of std::apply; std::apply doesnt work with oneDPL tuple --- include/oneapi/dpl/pstl/zip_view_impl.h | 111 +++++++++++++----------- 1 file changed, 59 insertions(+), 52 deletions(-) diff --git a/include/oneapi/dpl/pstl/zip_view_impl.h b/include/oneapi/dpl/pstl/zip_view_impl.h index 54b128bf84e..6b3df2bc15b 100644 --- a/include/oneapi/dpl/pstl/zip_view_impl.h +++ b/include/oneapi/dpl/pstl/zip_view_impl.h @@ -33,9 +33,38 @@ struct declare_iterator_category { using iterator_category = std::input_iterator_tag; }; +template +using tuple_type = oneapi::dpl::__internal::tuple; + template requires ((std::ranges::view && ... ) && (sizeof...(Views) > 0)) class zip_view : public std::ranges::view_interface> { +public: + template + using tuple_type = oneapi::dpl::__internal::tuple; + +private: + template + static decltype(auto) + apply_to_tuple_impl(_ReturnAdapter __tr, _F __f, _Tuple& __t, std::index_sequence<_Ip...>) + { + return __tr(__f(oneapi::dpl::__internal::get_impl<_Ip>()(__t))...); + } + + template + static decltype(auto) + apply_to_tuple(_ReturnAdapter __tr, _F __f, _Tuple& __t) + { + return apply_to_tuple_impl(__tr, __f, __t, std::make_index_sequence{}); + } + + template + static auto + apply_to_tuple(_F __f, _Tuple& __t) + { + apply_to_tuple_impl([](auto...){}, __f, __t, std::make_index_sequence{}); + } + public: zip_view() = default; constexpr zip_view(Views... views) : views_(views...) {} @@ -51,13 +80,13 @@ class zip_view : public std::ranges::view_interface> { std::forward_iterator_tag, std::input_iterator_tag>>>; - using value_type = std::conditional_t...>, - std::tuple...>>; + using value_type = std::conditional_t...>, + tuple_type...>>; using difference_type = std::conditional_t...>, std::common_type_t...>>; - using return_tuple_type = std::conditional_t>::reference...>, - std::tuple>::reference...>>; + using return_tuple_type = std::conditional_t>::reference...>, + tuple_type>::reference...>>; iterator() = default; @@ -71,26 +100,20 @@ class zip_view : public std::ranges::view_interface> { : current_(iterators...) {} public: - constexpr return_tuple_type operator*() const { + return_tuple_type operator*() const { - - return std::apply([](auto... iterators) { - return return_tuple_type((*iterators)...); - }, - current_); + auto __tr = [](auto&&... __args) -> decltype(auto) { return return_tuple_type(__args...);}; + return apply_to_tuple(__tr, [](auto it) -> decltype(auto) { return *it;}, current_); } constexpr return_tuple_type operator[]( difference_type n ) const requires all_random_access { return *(*this + n); - } + } constexpr iterator& operator++() { - std::apply([](auto&... iterators) { - ( (++iterators) , ... ); - }, - current_); + zip_view::apply_to_tuple([](auto& it) { return ++it; }, current_); return *this; } @@ -105,12 +128,8 @@ class zip_view : public std::ranges::view_interface> { } constexpr iterator& operator--() requires all_bidirectional { - step_backward(std::make_index_sequence()); - std::apply([](auto&... iterators) { - ((--iterators) , ... ); - }, - current_); + zip_view::apply_to_tuple([](auto& it) { return --it; }, current_); return *this; } @@ -123,20 +142,14 @@ class zip_view : public std::ranges::view_interface> { constexpr iterator& operator+=(difference_type n) requires all_random_access { - std::apply([n](auto&... iterators) { - ((iterators += n) , ...); - }, - current_); + zip_view::apply_to_tuple([n](auto& it) { return it += n; }, current_); return *this; } constexpr iterator& operator-=(difference_type n) requires all_random_access { - std::apply([n](auto&... iterators) { - ((iterators -= n) , ...); - }, - current_); + zip_view::apply_to_tuple([n](auto& it) { return it -= n; }, current_); return *this; } @@ -154,7 +167,7 @@ class zip_view : public std::ranges::view_interface> { friend constexpr auto operator<=>(const iterator& x, const iterator& y) requires all_random_access { - return x.current_ <=> y.current_; + return x.current_ == y.current_; } friend constexpr auto operator-(const iterator& x, const iterator& y) @@ -201,8 +214,8 @@ class zip_view : public std::ranges::view_interface> { friend class zip_view; - using current_type = std::conditional_t...>, - std::tuple...>>; + using current_type = std::conditional_t...>, + tuple_type...>>; current_type current_; }; // class iterator @@ -256,26 +269,22 @@ class zip_view : public std::ranges::view_interface> { private: friend class zip_view; - using end_type = std::conditional_t...>, - std::tuple...>>; + using end_type = std::conditional_t...>, + tuple_type...>>; end_type end_; - }; // class sentinel + }; // class sentinel - constexpr auto begin() requires (std:: ranges::range && ...) // !simple_view? + constexpr auto begin() requires (std::ranges::range && ...) // !simple_view? { - return std::apply([](auto... views) { - return iterator(std::ranges::begin(views)...); - }, - views_); + auto __tr = [](auto... __args) { return iterator(__args...);}; + return apply_to_tuple(__tr, std::ranges::begin, views_); } constexpr auto begin() const requires ( std::ranges::range && ... ) { - return std::apply([](auto... views) { - return iterator(std::ranges::begin(views)...); - }, - views_); + auto __tr = [](auto... __args) { return iterator(__args...);}; + return apply_to_tuple(__tr, std::ranges::begin, views_); } constexpr auto end() requires (std::ranges::range && ...) // requires !simple_view { @@ -318,14 +327,12 @@ class zip_view : public std::ranges::view_interface> { constexpr auto size() requires (std::ranges::sized_range && ...) { - return std::apply([](auto... sizes) { - using CT = std::make_unsigned_t>; - return std::ranges::min({CT(sizes)...}); - }, - std::apply([](auto... views) { - return std::make_tuple(std::ranges::size(views)...); - }, - views_)); + auto __tr = [](auto... __args) { + using CT = std::make_unsigned_t>; + return std::ranges::min({CT(__args)...}); + }; + + return apply_to_tuple(__tr, std::ranges::size, views_); } constexpr auto size() const requires (std::ranges::sized_range && ...) @@ -333,7 +340,7 @@ class zip_view : public std::ranges::view_interface> { return const_cast(this)->size(); } private: - std::tuple views_; + tuple_type views_; }; // class zip_view template From 41a93dfc3221a25db63eb6a549a033bb4896acc0 Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Wed, 25 Sep 2024 15:47:23 +0200 Subject: [PATCH 07/47] [oneDPL][ranges][zip_view] + changes in the test --- .../ranges/std_ranges_zip_view.pass.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp b/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp index a777db2bad1..99f2157e506 100644 --- a/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp +++ b/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp @@ -24,7 +24,6 @@ main() #if _ENABLE_STD_RANGES_TESTING namespace dpl_ranges = oneapi::dpl::ranges; - const char* err_msg = "Wrong effect algo transform with zip_view."; constexpr int max_n = 10; int data[max_n] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; @@ -33,22 +32,25 @@ main() std::ranges::for_each(zip_view, test_std_ranges::f_mutuable, [](const auto& val) { return std::get<1>(val); }); test_std_ranges::call_with_host_policies(dpl_ranges::for_each, zip_view, test_std_ranges::f_mutuable, [](const auto& val) { return std::get<1>(val); }); - //EXPECT_EQ_N(expected.begin(), res.begin(), n, err_msg); dpl_ranges::for_each(test_std_ranges::dpcpp_policy(), zip_view, test_std_ranges::f_mutuable, [](const auto& val) { return std::get<1>(val); }); auto zip_view_sort = my::zip(data, data); - auto it = zip_view_sort.begin(); - std::sort(zip_view_sort.begin(), zip_view_sort.begin() + 5, [](const auto& val1, const auto& val2) { return std::get<0>(val1) < std::get<0>(val2); }); - std::ranges::sort(zip_view_sort, std::greater{}, [](auto&& val) { return std::get<0>(val); }); + std::sort(zip_view_sort.begin(), zip_view_sort.begin() + max_n, [](const auto& val1, const auto& val2) { return std::get<0>(val1) > std::get<0>(val2); }); + for(int i = 0; i < max_n; ++i) + assert(std::get<0>(zip_view_sort[i]) == max_n - 1 - i); + + std::ranges::sort(zip_view_sort, std::less{}, [](auto&& val) { return std::get<0>(val); }); + for(int i = 0; i < max_n; ++i) + assert(std::get<0>(zip_view_sort[i]) == i); static_assert(std::ranges::random_access_range); static_assert(std::random_access_iterator); - //dpl_ranges::sort(oneapi::dpl::execution::seq, zip_view_sort, std::greater{}, [](auto&& val) { return std::get<0>(val); }); - - //test_std_ranges::call_with_host_policies(dpl_ranges::sort, zip_view_sort, test_std_ranges::binary_pred, [](const auto& val) { return std::get<0>(val); }); + test_std_ranges::call_with_host_policies(dpl_ranges::sort, zip_view_sort, std::greater{}, [](const auto& val) { return std::get<0>(val); }); + for(int i = 0; i < max_n; ++i) + assert(std::get<0>(zip_view_sort[i]) == max_n - 1 - i); #endif //_ENABLE_STD_RANGES_TESTING From 21191408c06105d47df0b8d2a00434d8f535e7cd Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Wed, 25 Sep 2024 16:09:00 +0200 Subject: [PATCH 08/47] [oneDPL][ranges][zip_view] -> oneapi::dpl::ranges --- include/oneapi/dpl/pstl/zip_view_impl.h | 40 ++++++++++++++----------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/include/oneapi/dpl/pstl/zip_view_impl.h b/include/oneapi/dpl/pstl/zip_view_impl.h index 6b3df2bc15b..ae1345b434c 100644 --- a/include/oneapi/dpl/pstl/zip_view_impl.h +++ b/include/oneapi/dpl/pstl/zip_view_impl.h @@ -5,7 +5,13 @@ #include #include -namespace my { +namespace oneapi +{ +namespace dpl +{ + +namespace ranges +{ template concept all_forward = ( std::ranges::forward_range> && ... ); @@ -33,9 +39,6 @@ struct declare_iterator_category { using iterator_category = std::input_iterator_tag; }; -template -using tuple_type = oneapi::dpl::__internal::tuple; - template requires ((std::ranges::view && ... ) && (sizeof...(Views) > 0)) class zip_view : public std::ranges::view_interface> { @@ -283,7 +286,7 @@ class zip_view : public std::ranges::view_interface> { constexpr auto begin() const requires ( std::ranges::range && ... ) { - auto __tr = [](auto... __args) { return iterator(__args...);}; + auto __tr = [](auto... __args) { return iterator(__args...);}; return apply_to_tuple(__tr, std::ranges::begin, views_); } @@ -308,20 +311,21 @@ class zip_view : public std::ranges::view_interface> { constexpr auto end() const requires (std::ranges::range && ...) { - if constexpr (!zip_is_common) { - return std::apply([](auto... views) { - return sentinel(std::ranges::end(views)...); - }, - views_); - } else if constexpr ((std::ranges::random_access_range && ...)) { + if constexpr (!zip_is_common) + { + auto __tr = [](auto... __args) { return sentinel(__args...);}; + return apply_to_tuple(__tr, std::ranges::end, views_); + } + else if constexpr ((std::ranges::random_access_range && ...)) + { auto it = begin(); it += size(); return it; - } else { - return std::apply([](auto... views) { - return iterator(std::ranges::end(views)...); - }, - views_); + } + else + { + auto __tr = [](auto... __args) { return iterator(__args...);}; + return apply_to_tuple(__tr, std::ranges::end, views_); } } @@ -355,4 +359,6 @@ struct zip_fn { inline constexpr zip_fn zip{}; -} // namespace my \ No newline at end of file +} // namespace ranges +} // namespace dpl +} // namespace oneapi \ No newline at end of file From 85b099ce8d3eec76261090b856f74e3d21db3128 Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Wed, 25 Sep 2024 16:09:27 +0200 Subject: [PATCH 09/47] [oneDPL][ranges][zip_view][test] -> oneapi::dpl::ranges --- test/parallel_api/ranges/std_ranges_zip_view.pass.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp b/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp index 99f2157e506..b4b972e0c7d 100644 --- a/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp +++ b/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp @@ -28,14 +28,14 @@ main() constexpr int max_n = 10; int data[max_n] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - auto zip_view = my::zip(data, std::views::iota(0, max_n)) | std::views::take(5); + auto zip_view = dpl_ranges::zip(data, std::views::iota(0, max_n)) | std::views::take(5); std::ranges::for_each(zip_view, test_std_ranges::f_mutuable, [](const auto& val) { return std::get<1>(val); }); test_std_ranges::call_with_host_policies(dpl_ranges::for_each, zip_view, test_std_ranges::f_mutuable, [](const auto& val) { return std::get<1>(val); }); dpl_ranges::for_each(test_std_ranges::dpcpp_policy(), zip_view, test_std_ranges::f_mutuable, [](const auto& val) { return std::get<1>(val); }); - auto zip_view_sort = my::zip(data, data); + auto zip_view_sort = dpl_ranges::zip(data, data); std::sort(zip_view_sort.begin(), zip_view_sort.begin() + max_n, [](const auto& val1, const auto& val2) { return std::get<0>(val1) > std::get<0>(val2); }); for(int i = 0; i < max_n; ++i) From 727197bcac0b55c30f4c4c30e177091f901fa12e Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Wed, 25 Sep 2024 16:14:31 +0200 Subject: [PATCH 10/47] [oneDPL][ranges][zip_view] + file header and guards --- include/oneapi/dpl/pstl/zip_view_impl.h | 29 +++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/include/oneapi/dpl/pstl/zip_view_impl.h b/include/oneapi/dpl/pstl/zip_view_impl.h index ae1345b434c..f975e9a2554 100644 --- a/include/oneapi/dpl/pstl/zip_view_impl.h +++ b/include/oneapi/dpl/pstl/zip_view_impl.h @@ -1,8 +1,25 @@ -#include +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Copyright (C) Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// This file incorporates work covered by the following copyright and permission +// notice: +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// +//===----------------------------------------------------------------------===// + +#ifndef _ONEDPL_ZIP_VIEW_IMPL_H +#define _ONEDPL_ZIP_VIEW_IMPL_H + +#if _ONEDPL_CPP20_RANGES_PRESENT + #include -#include #include -#include #include namespace oneapi @@ -361,4 +378,8 @@ inline constexpr zip_fn zip{}; } // namespace ranges } // namespace dpl -} // namespace oneapi \ No newline at end of file +} // namespace oneapi + +#endif //_ONEDPL_CPP20_RANGES_PRESENT + +#endif //_ONEDPL_ZIP_VIEW_IMPL_H \ No newline at end of file From cdcea024939460c9318681b262458228010b027e Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Wed, 25 Sep 2024 17:08:46 +0200 Subject: [PATCH 11/47] [oneDPL][ranges][zip_view] + apply_to_tuple instead of std::apply; std::apply doesnt work with oneDPL tuple --- include/oneapi/dpl/pstl/zip_view_impl.h | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/include/oneapi/dpl/pstl/zip_view_impl.h b/include/oneapi/dpl/pstl/zip_view_impl.h index f975e9a2554..6b3afad9e01 100644 --- a/include/oneapi/dpl/pstl/zip_view_impl.h +++ b/include/oneapi/dpl/pstl/zip_view_impl.h @@ -309,20 +309,21 @@ class zip_view : public std::ranges::view_interface> { constexpr auto end() requires (std::ranges::range && ...) // requires !simple_view { { - if constexpr (!zip_is_common) { - return std::apply([](auto... views) { - return sentinel(std::ranges::end(views)...); - }, - views_); - } else if constexpr ((std::ranges::random_access_range && ...)) { + if constexpr (!zip_is_common) + { + auto __tr = [](auto... __args) { return sentinel(__args...);}; + return apply_to_tuple(__tr, std::ranges::end, views_); + } + else if constexpr ((std::ranges::random_access_range && ...)) + { auto it = begin(); it += size(); return it; - } else { - return std::apply([](auto... views) { - return iterator(std::ranges::end(views)...); - }, - views_); + } + else + { + auto __tr = [](auto... __args) { return iterator(__args...);}; + return apply_to_tuple(__tr, std::ranges::end, views_); } } From 18377e48cdba86305e177731fa56bc02b2197121 Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Thu, 26 Sep 2024 11:31:10 +0200 Subject: [PATCH 12/47] [oneDPL][ranges][zip_view] + begin_imp, end_impl to reduce code duplication --- include/oneapi/dpl/pstl/zip_view_impl.h | 54 ++++++++++++------------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/include/oneapi/dpl/pstl/zip_view_impl.h b/include/oneapi/dpl/pstl/zip_view_impl.h index 6b3afad9e01..913724ee0c8 100644 --- a/include/oneapi/dpl/pstl/zip_view_impl.h +++ b/include/oneapi/dpl/pstl/zip_view_impl.h @@ -293,25 +293,22 @@ class zip_view : public std::ranges::view_interface> { tuple_type...>>; end_type end_; - }; // class sentinel + }; // class sentinel - constexpr auto begin() requires (std::ranges::range && ...) // !simple_view? - { - auto __tr = [](auto... __args) { return iterator(__args...);}; - return apply_to_tuple(__tr, std::ranges::begin, views_); - } - - constexpr auto begin() const requires ( std::ranges::range && ... ) +private: + template + constexpr auto begin_impl() { - auto __tr = [](auto... __args) { return iterator(__args...);}; + auto __tr = [](auto... __args) { return iterator(__args...);}; return apply_to_tuple(__tr, std::ranges::begin, views_); } - constexpr auto end() requires (std::ranges::range && ...) // requires !simple_view { + template + constexpr auto end_impl() { if constexpr (!zip_is_common) { - auto __tr = [](auto... __args) { return sentinel(__args...);}; + auto __tr = [](auto... __args) { return sentinel(__args...);}; return apply_to_tuple(__tr, std::ranges::end, views_); } else if constexpr ((std::ranges::random_access_range && ...)) @@ -322,29 +319,30 @@ class zip_view : public std::ranges::view_interface> { } else { - auto __tr = [](auto... __args) { return iterator(__args...);}; + auto __tr = [](auto... __args) { return iterator(__args...);}; return apply_to_tuple(__tr, std::ranges::end, views_); } } +public: + constexpr auto begin() requires (std::ranges::range && ...) // !simple_view? + { + return begin_impl(); + } + + constexpr auto begin() const requires ( std::ranges::range && ... ) + { + return const_cast(this)->begin_impl(); + } + + constexpr auto end() requires (std::ranges::range && ...) // requires !simple_view { + { + return end_impl(); + } + constexpr auto end() const requires (std::ranges::range && ...) { - if constexpr (!zip_is_common) - { - auto __tr = [](auto... __args) { return sentinel(__args...);}; - return apply_to_tuple(__tr, std::ranges::end, views_); - } - else if constexpr ((std::ranges::random_access_range && ...)) - { - auto it = begin(); - it += size(); - return it; - } - else - { - auto __tr = [](auto... __args) { return iterator(__args...);}; - return apply_to_tuple(__tr, std::ranges::end, views_); - } + return const_cast(this)->end_impl(); } constexpr auto size() requires (std::ranges::sized_range && ...) From fbb2e85f692cf98aeb93dcde2b3f6891caa7f650 Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Thu, 26 Sep 2024 14:18:20 +0200 Subject: [PATCH 13/47] Revert "[oneDPL][ranges][zip_view] + begin_imp, end_impl to reduce code duplication" This reverts commit fc04cafc39bc694473a2b8a34ea578dc6fcf4562. --- include/oneapi/dpl/pstl/zip_view_impl.h | 54 +++++++++++++------------ 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/include/oneapi/dpl/pstl/zip_view_impl.h b/include/oneapi/dpl/pstl/zip_view_impl.h index 913724ee0c8..6b3afad9e01 100644 --- a/include/oneapi/dpl/pstl/zip_view_impl.h +++ b/include/oneapi/dpl/pstl/zip_view_impl.h @@ -293,22 +293,25 @@ class zip_view : public std::ranges::view_interface> { tuple_type...>>; end_type end_; - }; // class sentinel + }; // class sentinel -private: - template - constexpr auto begin_impl() + constexpr auto begin() requires (std::ranges::range && ...) // !simple_view? { - auto __tr = [](auto... __args) { return iterator(__args...);}; + auto __tr = [](auto... __args) { return iterator(__args...);}; return apply_to_tuple(__tr, std::ranges::begin, views_); } - template - constexpr auto end_impl() + constexpr auto begin() const requires ( std::ranges::range && ... ) + { + auto __tr = [](auto... __args) { return iterator(__args...);}; + return apply_to_tuple(__tr, std::ranges::begin, views_); + } + + constexpr auto end() requires (std::ranges::range && ...) // requires !simple_view { { if constexpr (!zip_is_common) { - auto __tr = [](auto... __args) { return sentinel(__args...);}; + auto __tr = [](auto... __args) { return sentinel(__args...);}; return apply_to_tuple(__tr, std::ranges::end, views_); } else if constexpr ((std::ranges::random_access_range && ...)) @@ -319,30 +322,29 @@ class zip_view : public std::ranges::view_interface> { } else { - auto __tr = [](auto... __args) { return iterator(__args...);}; + auto __tr = [](auto... __args) { return iterator(__args...);}; return apply_to_tuple(__tr, std::ranges::end, views_); } } -public: - constexpr auto begin() requires (std::ranges::range && ...) // !simple_view? - { - return begin_impl(); - } - - constexpr auto begin() const requires ( std::ranges::range && ... ) - { - return const_cast(this)->begin_impl(); - } - - constexpr auto end() requires (std::ranges::range && ...) // requires !simple_view { - { - return end_impl(); - } - constexpr auto end() const requires (std::ranges::range && ...) { - return const_cast(this)->end_impl(); + if constexpr (!zip_is_common) + { + auto __tr = [](auto... __args) { return sentinel(__args...);}; + return apply_to_tuple(__tr, std::ranges::end, views_); + } + else if constexpr ((std::ranges::random_access_range && ...)) + { + auto it = begin(); + it += size(); + return it; + } + else + { + auto __tr = [](auto... __args) { return iterator(__args...);}; + return apply_to_tuple(__tr, std::ranges::end, views_); + } } constexpr auto size() requires (std::ranges::sized_range && ...) From c865420da10dea8c406c99647b6536342051aa8d Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Fri, 27 Sep 2024 18:41:35 +0200 Subject: [PATCH 14/47] [oneDPL][ranges][zip_view][test] + minor changes --- test/parallel_api/ranges/std_ranges_test.h | 6 ------ test/parallel_api/ranges/std_ranges_zip_view.pass.cpp | 3 +++ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/test/parallel_api/ranges/std_ranges_test.h b/test/parallel_api/ranges/std_ranges_test.h index 0f6310ac6c3..cfd6477915d 100644 --- a/test/parallel_api/ranges/std_ranges_test.h +++ b/test/parallel_api/ranges/std_ranges_test.h @@ -15,7 +15,6 @@ #include #include -#include #include "support/test_config.h" #include "support/test_macros.h" @@ -549,11 +548,6 @@ struct test_range_algo test, mode>{max_n}(host_policies(), algo, checker, std::views::all, std::identity{}, args...); #endif -#if 0//zip_view - auto zip_view = [](auto&& v) { return my::zip(v); }; - test, mode>{}(host_policies(), algo, checker, zip_view, std::identity{}, args...); -#endif - #if TEST_DPCPP_BACKEND_PRESENT //Skip the cases with pointer-to-function and hetero policy because pointer-to-function is not supported within kernel code. if constexpr(!std::disjunction_v...>) diff --git a/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp b/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp index b4b972e0c7d..d560b94b45f 100644 --- a/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp +++ b/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp @@ -14,6 +14,7 @@ //===----------------------------------------------------------------------===// #include "std_ranges_test.h" +#include template struct print_type; @@ -33,7 +34,9 @@ main() test_std_ranges::call_with_host_policies(dpl_ranges::for_each, zip_view, test_std_ranges::f_mutuable, [](const auto& val) { return std::get<1>(val); }); +#if TEST_DPCPP_BACKEND_PRESENT dpl_ranges::for_each(test_std_ranges::dpcpp_policy(), zip_view, test_std_ranges::f_mutuable, [](const auto& val) { return std::get<1>(val); }); +#endif auto zip_view_sort = dpl_ranges::zip(data, data); From e5f9650aa166f7cfc8d7af8638be852d06a2475a Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Mon, 7 Oct 2024 18:33:23 +0200 Subject: [PATCH 15/47] [oneDPL][ranges][zip_view] + minor changes --- include/oneapi/dpl/pstl/ranges_defs.h | 3 +++ include/oneapi/dpl/pstl/zip_view_impl.h | 2 +- test/parallel_api/ranges/std_ranges_zip_view.pass.cpp | 5 +---- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/oneapi/dpl/pstl/ranges_defs.h b/include/oneapi/dpl/pstl/ranges_defs.h index 39f67ed8589..aab2aad2db4 100644 --- a/include/oneapi/dpl/pstl/ranges_defs.h +++ b/include/oneapi/dpl/pstl/ranges_defs.h @@ -23,6 +23,9 @@ #include #endif +//oneapi::dpl::ranges::zip_view support for C++20 +#include "zip_view_impl.h" + #include "utils_ranges.h" #if _ONEDPL_BACKEND_SYCL # include "hetero/dpcpp/utils_ranges_sycl.h" diff --git a/include/oneapi/dpl/pstl/zip_view_impl.h b/include/oneapi/dpl/pstl/zip_view_impl.h index 6b3afad9e01..e40626cbd56 100644 --- a/include/oneapi/dpl/pstl/zip_view_impl.h +++ b/include/oneapi/dpl/pstl/zip_view_impl.h @@ -383,4 +383,4 @@ inline constexpr zip_fn zip{}; #endif //_ONEDPL_CPP20_RANGES_PRESENT -#endif //_ONEDPL_ZIP_VIEW_IMPL_H \ No newline at end of file +#endif //_ONEDPL_ZIP_VIEW_IMPL_H diff --git a/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp b/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp index d560b94b45f..cacbedfcd38 100644 --- a/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp +++ b/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp @@ -14,10 +14,7 @@ //===----------------------------------------------------------------------===// #include "std_ranges_test.h" -#include - -template -struct print_type; +#include std::int32_t main() From ad3d4ba2622142ebf33047c44f6bd9810929985d Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Wed, 9 Oct 2024 14:56:52 +0200 Subject: [PATCH 16/47] [oneDPL][ranges][zip_view] + #include "tuple_impl.h" --- include/oneapi/dpl/pstl/zip_view_impl.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/oneapi/dpl/pstl/zip_view_impl.h b/include/oneapi/dpl/pstl/zip_view_impl.h index e40626cbd56..08ee581198d 100644 --- a/include/oneapi/dpl/pstl/zip_view_impl.h +++ b/include/oneapi/dpl/pstl/zip_view_impl.h @@ -22,6 +22,8 @@ #include #include +#include "tuple_impl.h" + namespace oneapi { namespace dpl From 013ff9d7778004c059916b46d7363cc34fadd281 Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Tue, 22 Oct 2024 14:38:45 +0200 Subject: [PATCH 17/47] [oneDPL][ranges][zip_view][test] + test_zip_view_base_op() --- .../ranges/std_ranges_zip_view.pass.cpp | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp b/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp index cacbedfcd38..eb65ab140cd 100644 --- a/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp +++ b/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp @@ -16,11 +16,43 @@ #include "std_ranges_test.h" #include +#if _ENABLE_STD_RANGES_TESTING +#include + +void test_zip_view_base_op() +{ + namespace dpl_ranges = oneapi::dpl::ranges; + + constexpr int max_n = 100; + std::vector vec1(max_n); + std::vector vec2(max_n/2); + + auto zip_view = dpl_ranges::zip(vec1, vec2); + + static_assert(std::random_access_iterator); + static_assert(std::sentinel_for); + + static_assert(std::random_access_iterator); + static_assert(std::sentinel_for); + + EXPECT_TRUE(zip_view.end() - zip_view.begin() == max_n/2, + "Difference operation between an iterator and a sentinel (zip_view) returns a wrong result."); + + EXPECT_TRUE(zip_view[2] == *(zip_view.begin() + 2), + "Subscription or dereferencing operation for zip_view returns a wrong result."); + + EXPECT_TRUE(std::ranges::size(zip_view) == max_n/2, "zip_view::size method returns a wrong result."); + EXPECT_TRUE((bool)zip_view, "zip_view::operator bool() method returns a wrong result."); +} +#endif //_ENABLE_STD_RANGES_TESTING + std::int32_t main() { #if _ENABLE_STD_RANGES_TESTING + test_zip_view_base_op(); + namespace dpl_ranges = oneapi::dpl::ranges; constexpr int max_n = 10; From a4e7322646cac21baa2a2f77671f3f8c4080e4b2 Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Fri, 18 Oct 2024 18:11:38 +0200 Subject: [PATCH 18/47] [oneDPL][ranges][zip_view] + implementation fix for 'operator-' between zip_view::iterators --- include/oneapi/dpl/pstl/zip_view_impl.h | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/include/oneapi/dpl/pstl/zip_view_impl.h b/include/oneapi/dpl/pstl/zip_view_impl.h index 08ee581198d..793fc3d6618 100644 --- a/include/oneapi/dpl/pstl/zip_view_impl.h +++ b/include/oneapi/dpl/pstl/zip_view_impl.h @@ -189,13 +189,13 @@ class zip_view : public std::ranges::view_interface> { friend constexpr auto operator<=>(const iterator& x, const iterator& y) requires all_random_access { - return x.current_ == y.current_; + return x.current_ <=> y.current_; } friend constexpr auto operator-(const iterator& x, const iterator& y) requires all_random_access { - return std::get<0>(x.current_) - std::get<0>(y.current_); + return x.distance_to_it(y.current_, std::make_index_sequence()); } friend constexpr iterator operator+(iterator it, difference_type n) @@ -233,6 +233,15 @@ class zip_view : public std::ranges::view_interface> { ( (min = std::min(min, (std::get(current_) - std::get(sentinels)))) , ... ); return min; } + template + constexpr std::common_type_t, + std::ranges::range_difference_t>...> + distance_to_it(const iterator it, std::index_sequence<0, In...>) const { + auto min = std::get<0>(it.current_) - std::get<0>(current_); + + ( (min = std::min(min, (std::get(it.current_) - std::get(current_)))) , ... ); + return min; + } friend class zip_view; From 96aef8d4c7d5d45be24fd9c67d6051126ec9c915 Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Mon, 21 Oct 2024 13:58:29 +0200 Subject: [PATCH 19/47] Update include/oneapi/dpl/pstl/zip_view_impl.h Co-authored-by: Konstantin Boyarinov --- include/oneapi/dpl/pstl/zip_view_impl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/oneapi/dpl/pstl/zip_view_impl.h b/include/oneapi/dpl/pstl/zip_view_impl.h index 793fc3d6618..5f29dd544ab 100644 --- a/include/oneapi/dpl/pstl/zip_view_impl.h +++ b/include/oneapi/dpl/pstl/zip_view_impl.h @@ -84,7 +84,7 @@ class zip_view : public std::ranges::view_interface> { static auto apply_to_tuple(_F __f, _Tuple& __t) { - apply_to_tuple_impl([](auto...){}, __f, __t, std::make_index_sequence{}); + apply_to_tuple([](auto...){}, __f, __t); } public: From 9e1a1f2f0e936b905f743e136809c3c3cdcf047f Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Mon, 21 Oct 2024 13:58:35 +0200 Subject: [PATCH 20/47] Update include/oneapi/dpl/pstl/zip_view_impl.h Co-authored-by: Konstantin Boyarinov --- include/oneapi/dpl/pstl/zip_view_impl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/oneapi/dpl/pstl/zip_view_impl.h b/include/oneapi/dpl/pstl/zip_view_impl.h index 5f29dd544ab..32f72447b45 100644 --- a/include/oneapi/dpl/pstl/zip_view_impl.h +++ b/include/oneapi/dpl/pstl/zip_view_impl.h @@ -81,7 +81,7 @@ class zip_view : public std::ranges::view_interface> { } template - static auto + static decltype(auto) apply_to_tuple(_F __f, _Tuple& __t) { apply_to_tuple([](auto...){}, __f, __t); From 79461b6804229471d38e85a5c9bd6d6698dd0b58 Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Mon, 21 Oct 2024 13:58:46 +0200 Subject: [PATCH 21/47] Update include/oneapi/dpl/pstl/zip_view_impl.h Co-authored-by: Konstantin Boyarinov --- include/oneapi/dpl/pstl/zip_view_impl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/oneapi/dpl/pstl/zip_view_impl.h b/include/oneapi/dpl/pstl/zip_view_impl.h index 32f72447b45..9f9aeeb5bb0 100644 --- a/include/oneapi/dpl/pstl/zip_view_impl.h +++ b/include/oneapi/dpl/pstl/zip_view_impl.h @@ -89,7 +89,7 @@ class zip_view : public std::ranges::view_interface> { public: zip_view() = default; - constexpr zip_view(Views... views) : views_(views...) {} + constexpr zip_view(Views... views) : views_(std::move(views)...) {} template class iterator : declare_iterator_category { From 87df254a9d9bbb9e9629ae6e5a65351bfa97f6e9 Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Mon, 21 Oct 2024 13:58:54 +0200 Subject: [PATCH 22/47] Update include/oneapi/dpl/pstl/zip_view_impl.h Co-authored-by: Konstantin Boyarinov --- include/oneapi/dpl/pstl/zip_view_impl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/oneapi/dpl/pstl/zip_view_impl.h b/include/oneapi/dpl/pstl/zip_view_impl.h index 9f9aeeb5bb0..1c66652f22a 100644 --- a/include/oneapi/dpl/pstl/zip_view_impl.h +++ b/include/oneapi/dpl/pstl/zip_view_impl.h @@ -205,7 +205,7 @@ class zip_view : public std::ranges::view_interface> { friend constexpr iterator operator+(difference_type n, iterator it) { - return it+=n; + return it += n; } friend constexpr iterator operator-(iterator it, difference_type n) From f599738134b06763c11c10d7d841dbb5fdbb32e6 Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Mon, 21 Oct 2024 13:59:11 +0200 Subject: [PATCH 23/47] Update include/oneapi/dpl/pstl/zip_view_impl.h Co-authored-by: Konstantin Boyarinov --- include/oneapi/dpl/pstl/zip_view_impl.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/oneapi/dpl/pstl/zip_view_impl.h b/include/oneapi/dpl/pstl/zip_view_impl.h index 1c66652f22a..5835d2fedfb 100644 --- a/include/oneapi/dpl/pstl/zip_view_impl.h +++ b/include/oneapi/dpl/pstl/zip_view_impl.h @@ -123,7 +123,6 @@ class zip_view : public std::ranges::view_interface> { public: return_tuple_type operator*() const { - auto __tr = [](auto&&... __args) -> decltype(auto) { return return_tuple_type(__args...);}; return apply_to_tuple(__tr, [](auto it) -> decltype(auto) { return *it;}, current_); } From 1ee917b3d4f6ca725673d5a87af0b142a8bf0c85 Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Mon, 21 Oct 2024 13:59:17 +0200 Subject: [PATCH 24/47] Update include/oneapi/dpl/pstl/zip_view_impl.h Co-authored-by: Konstantin Boyarinov --- include/oneapi/dpl/pstl/zip_view_impl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/oneapi/dpl/pstl/zip_view_impl.h b/include/oneapi/dpl/pstl/zip_view_impl.h index 5835d2fedfb..3e2629e8ffa 100644 --- a/include/oneapi/dpl/pstl/zip_view_impl.h +++ b/include/oneapi/dpl/pstl/zip_view_impl.h @@ -209,7 +209,7 @@ class zip_view : public std::ranges::view_interface> { friend constexpr iterator operator-(iterator it, difference_type n) { - return it-=n; + return it -= n; } private: From e32e2868d1351478da4e8e06068b9fc0d5f7d45b Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Mon, 21 Oct 2024 13:59:28 +0200 Subject: [PATCH 25/47] Update include/oneapi/dpl/pstl/zip_view_impl.h Co-authored-by: Konstantin Boyarinov --- include/oneapi/dpl/pstl/zip_view_impl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/oneapi/dpl/pstl/zip_view_impl.h b/include/oneapi/dpl/pstl/zip_view_impl.h index 3e2629e8ffa..3ae6ac7f504 100644 --- a/include/oneapi/dpl/pstl/zip_view_impl.h +++ b/include/oneapi/dpl/pstl/zip_view_impl.h @@ -199,7 +199,7 @@ class zip_view : public std::ranges::view_interface> { friend constexpr iterator operator+(iterator it, difference_type n) { - return it+=n; + return it += n; } friend constexpr iterator operator+(difference_type n, iterator it) From c61d2f4ea1b0a1288aef2dfae1b7ee650142b34b Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Mon, 21 Oct 2024 14:11:54 +0200 Subject: [PATCH 26/47] Update include/oneapi/dpl/pstl/zip_view_impl.h Co-authored-by: Konstantin Boyarinov --- include/oneapi/dpl/pstl/zip_view_impl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/oneapi/dpl/pstl/zip_view_impl.h b/include/oneapi/dpl/pstl/zip_view_impl.h index 3ae6ac7f504..16286c15bef 100644 --- a/include/oneapi/dpl/pstl/zip_view_impl.h +++ b/include/oneapi/dpl/pstl/zip_view_impl.h @@ -122,7 +122,7 @@ class zip_view : public std::ranges::view_interface> { : current_(iterators...) {} public: - return_tuple_type operator*() const { + constexpr return_tuple_type operator*() const { auto __tr = [](auto&&... __args) -> decltype(auto) { return return_tuple_type(__args...);}; return apply_to_tuple(__tr, [](auto it) -> decltype(auto) { return *it;}, current_); } From a3953e3281814bc1ec67c533f6295cc1efa35c69 Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Mon, 21 Oct 2024 14:12:08 +0200 Subject: [PATCH 27/47] Update include/oneapi/dpl/pstl/zip_view_impl.h Co-authored-by: Konstantin Boyarinov --- include/oneapi/dpl/pstl/zip_view_impl.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/oneapi/dpl/pstl/zip_view_impl.h b/include/oneapi/dpl/pstl/zip_view_impl.h index 16286c15bef..6e9856fe502 100644 --- a/include/oneapi/dpl/pstl/zip_view_impl.h +++ b/include/oneapi/dpl/pstl/zip_view_impl.h @@ -149,7 +149,6 @@ class zip_view : public std::ranges::view_interface> { } constexpr iterator& operator--() requires all_bidirectional { - zip_view::apply_to_tuple([](auto& it) { return --it; }, current_); return *this; } From 751c149b982cbedd14f2a7f64962a51a712d2e75 Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Mon, 21 Oct 2024 14:16:51 +0200 Subject: [PATCH 28/47] [oneDPL][ranges][zip_view] + std::get usage --- include/oneapi/dpl/pstl/zip_view_impl.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/oneapi/dpl/pstl/zip_view_impl.h b/include/oneapi/dpl/pstl/zip_view_impl.h index 6e9856fe502..d32662c16f8 100644 --- a/include/oneapi/dpl/pstl/zip_view_impl.h +++ b/include/oneapi/dpl/pstl/zip_view_impl.h @@ -70,7 +70,7 @@ class zip_view : public std::ranges::view_interface> { static decltype(auto) apply_to_tuple_impl(_ReturnAdapter __tr, _F __f, _Tuple& __t, std::index_sequence<_Ip...>) { - return __tr(__f(oneapi::dpl::__internal::get_impl<_Ip>()(__t))...); + return __tr(__f(std::get<_Ip>(__t))...); } template @@ -81,7 +81,7 @@ class zip_view : public std::ranges::view_interface> { } template - static decltype(auto) + static void apply_to_tuple(_F __f, _Tuple& __t) { apply_to_tuple([](auto...){}, __f, __t); From 8e0639c32a751aa1318c93925bce5912ba60564e Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Mon, 21 Oct 2024 14:22:56 +0200 Subject: [PATCH 29/47] [oneDPL][ranges][zip_view] + 'std::forward(__args)' usage --- include/oneapi/dpl/pstl/zip_view_impl.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/oneapi/dpl/pstl/zip_view_impl.h b/include/oneapi/dpl/pstl/zip_view_impl.h index d32662c16f8..41140b6a1aa 100644 --- a/include/oneapi/dpl/pstl/zip_view_impl.h +++ b/include/oneapi/dpl/pstl/zip_view_impl.h @@ -123,7 +123,8 @@ class zip_view : public std::ranges::view_interface> { public: constexpr return_tuple_type operator*() const { - auto __tr = [](auto&&... __args) -> decltype(auto) { return return_tuple_type(__args...);}; + auto __tr = [](auto&&... __args) -> decltype(auto) + { return return_tuple_type(std::forward(__args)...);}; return apply_to_tuple(__tr, [](auto it) -> decltype(auto) { return *it;}, current_); } From f4d9df48e5f80ab920858c898c4ec87f22da5a4b Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Mon, 21 Oct 2024 14:31:09 +0200 Subject: [PATCH 30/47] [oneDPL][ranges][zip_view] + 'minor change' for const/non const type definition --- include/oneapi/dpl/pstl/zip_view_impl.h | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/include/oneapi/dpl/pstl/zip_view_impl.h b/include/oneapi/dpl/pstl/zip_view_impl.h index 41140b6a1aa..d45fd5fb1cb 100644 --- a/include/oneapi/dpl/pstl/zip_view_impl.h +++ b/include/oneapi/dpl/pstl/zip_view_impl.h @@ -102,13 +102,15 @@ class zip_view : public std::ranges::view_interface> { std::forward_iterator_tag, std::input_iterator_tag>>>; - using value_type = std::conditional_t...>, - tuple_type...>>; + using value_type = std::conditional_t...>, + tuple_type...>>; - using difference_type = std::conditional_t...>, - std::common_type_t...>>; - using return_tuple_type = std::conditional_t>::reference...>, - tuple_type>::reference...>>; + using difference_type = std::conditional_t...>, + std::common_type_t...>>; + + using return_tuple_type = std::conditional_t>::reference...>, + tuple_type>::reference...>>; iterator() = default; @@ -303,9 +305,9 @@ class zip_view : public std::ranges::view_interface> { tuple_type...>>; end_type end_; - }; // class sentinel + }; // class sentinel - constexpr auto begin() requires (std::ranges::range && ...) // !simple_view? + constexpr auto begin() requires (std::ranges::range && ...) { auto __tr = [](auto... __args) { return iterator(__args...);}; return apply_to_tuple(__tr, std::ranges::begin, views_); @@ -317,7 +319,7 @@ class zip_view : public std::ranges::view_interface> { return apply_to_tuple(__tr, std::ranges::begin, views_); } - constexpr auto end() requires (std::ranges::range && ...) // requires !simple_view { + constexpr auto end() requires (std::ranges::range && ...) { if constexpr (!zip_is_common) { From 46287a97129b83b8d061c1566dfeea4ecc9e5b58 Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Tue, 22 Oct 2024 16:25:32 +0200 Subject: [PATCH 31/47] [oneDPL][ranges][zip_view] + fix operator<=> implementation --- include/oneapi/dpl/pstl/zip_view_impl.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/oneapi/dpl/pstl/zip_view_impl.h b/include/oneapi/dpl/pstl/zip_view_impl.h index d45fd5fb1cb..8df66df08fc 100644 --- a/include/oneapi/dpl/pstl/zip_view_impl.h +++ b/include/oneapi/dpl/pstl/zip_view_impl.h @@ -190,7 +190,11 @@ class zip_view : public std::ranges::view_interface> { friend constexpr auto operator<=>(const iterator& x, const iterator& y) requires all_random_access { - return x.current_ <=> y.current_; + if (x.current_ < y.current_) + return -1; + else if (x.current_ == y.current_) + return 0; + return 1; //x.current > y.current_ } friend constexpr auto operator-(const iterator& x, const iterator& y) From fe9f46e70c462bc4bfb3383693fa0058b8372b0c Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Fri, 25 Oct 2024 17:20:08 +0200 Subject: [PATCH 32/47] [oneDPL][ranges][zip_view][test] removed cbegin(), cend() test cases because they are supported only with C++23 --- test/parallel_api/ranges/std_ranges_zip_view.pass.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp b/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp index eb65ab140cd..46d82849b82 100644 --- a/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp +++ b/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp @@ -32,9 +32,6 @@ void test_zip_view_base_op() static_assert(std::random_access_iterator); static_assert(std::sentinel_for); - static_assert(std::random_access_iterator); - static_assert(std::sentinel_for); - EXPECT_TRUE(zip_view.end() - zip_view.begin() == max_n/2, "Difference operation between an iterator and a sentinel (zip_view) returns a wrong result."); From c99b57df6e3956ed5b257158f3cec5adf7fa08ca Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Fri, 25 Oct 2024 18:12:45 +0200 Subject: [PATCH 33/47] [oneDPL][ranges][zip_view][test] + front(), back() methods check --- test/parallel_api/ranges/std_ranges_zip_view.pass.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp b/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp index 46d82849b82..43b28e01b7a 100644 --- a/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp +++ b/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp @@ -40,6 +40,9 @@ void test_zip_view_base_op() EXPECT_TRUE(std::ranges::size(zip_view) == max_n/2, "zip_view::size method returns a wrong result."); EXPECT_TRUE((bool)zip_view, "zip_view::operator bool() method returns a wrong result."); + + EXPECT_TRUE(zip_view[0] == zip_view.front(), "zip_view::front method returns a wrong result."); + EXPECT_TRUE(zip_view[z_v.size() - 1] == zip_view.back(), "zip_view::back method returns a wrong result.") } #endif //_ENABLE_STD_RANGES_TESTING From 13454ca0e6a7c0d95b2fe36597c7c01f89babc39 Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Tue, 29 Oct 2024 11:20:43 +0100 Subject: [PATCH 34/47] [oneDPL][ranges][zip_view][test] + empty constructor call check --- test/parallel_api/ranges/std_ranges_zip_view.pass.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp b/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp index 43b28e01b7a..4450c4dd9f9 100644 --- a/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp +++ b/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp @@ -42,7 +42,11 @@ void test_zip_view_base_op() EXPECT_TRUE((bool)zip_view, "zip_view::operator bool() method returns a wrong result."); EXPECT_TRUE(zip_view[0] == zip_view.front(), "zip_view::front method returns a wrong result."); - EXPECT_TRUE(zip_view[z_v.size() - 1] == zip_view.back(), "zip_view::back method returns a wrong result.") + EXPECT_TRUE(zip_view[zip_view.size() - 1] == zip_view.back(), "zip_view::back method returns a wrong result.") + + using zip_view_t = dpl_ranges::zip_view>; + auto zip_view_0 = zip_view_t(); + EXPECT_TRUE(zip_view_0.empty(), "zip_view::empty() method returns a wrong result."); } #endif //_ENABLE_STD_RANGES_TESTING From ba8bdb71673fb8303c0a7c7d5a32e04d06f4db7e Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Wed, 30 Oct 2024 17:55:56 +0100 Subject: [PATCH 35/47] [oneDPL][ranges][zip_view][test] + ; --- test/parallel_api/ranges/std_ranges_zip_view.pass.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp b/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp index 4450c4dd9f9..e1da7b1146f 100644 --- a/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp +++ b/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp @@ -42,7 +42,7 @@ void test_zip_view_base_op() EXPECT_TRUE((bool)zip_view, "zip_view::operator bool() method returns a wrong result."); EXPECT_TRUE(zip_view[0] == zip_view.front(), "zip_view::front method returns a wrong result."); - EXPECT_TRUE(zip_view[zip_view.size() - 1] == zip_view.back(), "zip_view::back method returns a wrong result.") + EXPECT_TRUE(zip_view[zip_view.size() - 1] == zip_view.back(), "zip_view::back method returns a wrong result."); using zip_view_t = dpl_ranges::zip_view>; auto zip_view_0 = zip_view_t(); From 3d1753f7634b97c47937a3ff45f28c4a1338473d Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Mon, 4 Nov 2024 16:22:51 +0100 Subject: [PATCH 36/47] [oneDPL][ranges][zip_view][test] const for compare_with_sentinels --- include/oneapi/dpl/pstl/zip_view_impl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/oneapi/dpl/pstl/zip_view_impl.h b/include/oneapi/dpl/pstl/zip_view_impl.h index 8df66df08fc..dcdce7421b2 100644 --- a/include/oneapi/dpl/pstl/zip_view_impl.h +++ b/include/oneapi/dpl/pstl/zip_view_impl.h @@ -225,7 +225,7 @@ class zip_view : public std::ranges::view_interface> { } template - constexpr bool compare_with_sentinels(const SentinelsTuple& sentinels, std::index_sequence) { + constexpr bool compare_with_sentinels(const SentinelsTuple& sentinels, std::index_sequence) const { return ( (std::get(current_) == std::get(sentinels)) || ... ); } From f824af94d6bccb271eea435748b1623f1abe3e38 Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Wed, 6 Nov 2024 18:47:41 +0100 Subject: [PATCH 37/47] [oneDPL][ranges][zip_view][test] a fix for zip_view::iterator::operator- --- include/oneapi/dpl/pstl/zip_view_impl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/oneapi/dpl/pstl/zip_view_impl.h b/include/oneapi/dpl/pstl/zip_view_impl.h index dcdce7421b2..8a65e372640 100644 --- a/include/oneapi/dpl/pstl/zip_view_impl.h +++ b/include/oneapi/dpl/pstl/zip_view_impl.h @@ -200,7 +200,7 @@ class zip_view : public std::ranges::view_interface> { friend constexpr auto operator-(const iterator& x, const iterator& y) requires all_random_access { - return x.distance_to_it(y.current_, std::make_index_sequence()); + return y.distance_to_it(x.current_, std::make_index_sequence()); } friend constexpr iterator operator+(iterator it, difference_type n) From 120d1e64885dcb7438a94386a440203a856db4d4 Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Fri, 8 Nov 2024 14:55:02 +0100 Subject: [PATCH 38/47] [oneDPL][rfc][zip_view] + std::ranges::range_reference_t usage; it fixes some issues --- include/oneapi/dpl/pstl/zip_view_impl.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/include/oneapi/dpl/pstl/zip_view_impl.h b/include/oneapi/dpl/pstl/zip_view_impl.h index 8a65e372640..710da9e8608 100644 --- a/include/oneapi/dpl/pstl/zip_view_impl.h +++ b/include/oneapi/dpl/pstl/zip_view_impl.h @@ -108,9 +108,8 @@ class zip_view : public std::ranges::view_interface> { using difference_type = std::conditional_t...>, std::common_type_t...>>; - using return_tuple_type = std::conditional_t>::reference...>, - tuple_type>::reference...>>; + using return_tuple_type = std::conditional_t...>, + tuple_type...>>; iterator() = default; From 1c1cbbfce92fb29340b7d8e818e89ad90a03443b Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Fri, 8 Nov 2024 18:13:39 +0100 Subject: [PATCH 39/47] [oneDPL][ranges][zip_view][test] + minor changes --- test/parallel_api/ranges/std_ranges_zip_view.pass.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp b/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp index e1da7b1146f..f3fac936e9b 100644 --- a/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp +++ b/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp @@ -43,10 +43,11 @@ void test_zip_view_base_op() EXPECT_TRUE(zip_view[0] == zip_view.front(), "zip_view::front method returns a wrong result."); EXPECT_TRUE(zip_view[zip_view.size() - 1] == zip_view.back(), "zip_view::back method returns a wrong result."); + EXPECT_TRUE(!zip_view.empty(), "zip_view::empty() method returns a wrong result."); using zip_view_t = dpl_ranges::zip_view>; auto zip_view_0 = zip_view_t(); - EXPECT_TRUE(zip_view_0.empty(), "zip_view::empty() method returns a wrong result."); + EXPECT_TRUE(!zip_view_0.empty(), "zip_view::empty() method returns a wrong result."); } #endif //_ENABLE_STD_RANGES_TESTING From 504db9a5e6d590cb35b9607d137eb2f65e2171c5 Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Fri, 15 Nov 2024 16:46:10 +0100 Subject: [PATCH 40/47] [oneDPL][zip_view] + minor improvements --- include/oneapi/dpl/pstl/zip_view_impl.h | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/include/oneapi/dpl/pstl/zip_view_impl.h b/include/oneapi/dpl/pstl/zip_view_impl.h index 710da9e8608..c0531c716de 100644 --- a/include/oneapi/dpl/pstl/zip_view_impl.h +++ b/include/oneapi/dpl/pstl/zip_view_impl.h @@ -61,11 +61,9 @@ struct declare_iterator_category { template requires ((std::ranges::view && ... ) && (sizeof...(Views) > 0)) class zip_view : public std::ranges::view_interface> { -public: template using tuple_type = oneapi::dpl::__internal::tuple; -private: template static decltype(auto) apply_to_tuple_impl(_ReturnAdapter __tr, _F __f, _Tuple& __t, std::index_sequence<_Ip...>) @@ -92,7 +90,7 @@ class zip_view : public std::ranges::view_interface> { constexpr zip_view(Views... views) : views_(std::move(views)...) {} template - class iterator : declare_iterator_category { + class iterator : declare_iterator_category { public: using iterator_concept = std::conditional_t, std::random_access_iterator_tag, @@ -108,9 +106,6 @@ class zip_view : public std::ranges::view_interface> { using difference_type = std::conditional_t...>, std::common_type_t...>>; - using return_tuple_type = std::conditional_t...>, - tuple_type...>>; - iterator() = default; constexpr iterator(iterator i) @@ -123,13 +118,17 @@ class zip_view : public std::ranges::view_interface> { : current_(iterators...) {} public: - constexpr return_tuple_type operator*() const { - auto __tr = [](auto&&... __args) -> decltype(auto) - { return return_tuple_type(std::forward(__args)...);}; + constexpr decltype(auto) operator*() const { + auto __tr = [](auto&&... __args) -> decltype(auto) { + using return_tuple_type = std::conditional_t< + !Const, tuple_type...>, + tuple_type...>>; + return return_tuple_type(std::forward(__args)...); + }; return apply_to_tuple(__tr, [](auto it) -> decltype(auto) { return *it;}, current_); } - constexpr return_tuple_type operator[]( difference_type n ) const + constexpr decltype(auto) operator[]( difference_type n ) const requires all_random_access { return *(*this + n); @@ -372,7 +371,7 @@ class zip_view : public std::ranges::view_interface> { return apply_to_tuple(__tr, std::ranges::size, views_); } - constexpr auto size() const requires (std::ranges::sized_range && ...) + constexpr auto size() const requires (std::ranges::sized_range && ...) { return const_cast(this)->size(); } From b2e40d2f12777295015d30f63010fd016697e912 Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Tue, 19 Nov 2024 17:17:22 +0100 Subject: [PATCH 41/47] [oneDPL][ranges][zip_view][test] + EXPECT_TRUE usage --- test/parallel_api/ranges/std_ranges_zip_view.pass.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp b/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp index f3fac936e9b..469512db277 100644 --- a/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp +++ b/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp @@ -76,11 +76,11 @@ main() std::sort(zip_view_sort.begin(), zip_view_sort.begin() + max_n, [](const auto& val1, const auto& val2) { return std::get<0>(val1) > std::get<0>(val2); }); for(int i = 0; i < max_n; ++i) - assert(std::get<0>(zip_view_sort[i]) == max_n - 1 - i); + EXPECT_TRUE(std::get<0>(zip_view_sort[i]) == max_n - 1 - i, "Wrong effect for std::sort with zip_view."); std::ranges::sort(zip_view_sort, std::less{}, [](auto&& val) { return std::get<0>(val); }); for(int i = 0; i < max_n; ++i) - assert(std::get<0>(zip_view_sort[i]) == i); + EXPECT_TRUE(std::get<0>(zip_view_sort[i]) == i, "Wrong effect for std::ranges::sort with zip_view."); static_assert(std::ranges::random_access_range); static_assert(std::random_access_iterator); From 78897588be0358ed08fae776876525cded64d2c1 Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Mon, 2 Dec 2024 13:04:13 +0100 Subject: [PATCH 42/47] [oneDPL][ranges][zip_view] + operator oneapi::dpl::zip_iterator() --- include/oneapi/dpl/pstl/zip_view_impl.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/oneapi/dpl/pstl/zip_view_impl.h b/include/oneapi/dpl/pstl/zip_view_impl.h index c0531c716de..2a7d88f8e60 100644 --- a/include/oneapi/dpl/pstl/zip_view_impl.h +++ b/include/oneapi/dpl/pstl/zip_view_impl.h @@ -23,6 +23,7 @@ #include #include "tuple_impl.h" +#include "iterator_impl.h" namespace oneapi { @@ -118,6 +119,13 @@ class zip_view : public std::ranges::view_interface> { : current_(iterators...) {} public: + template + operator oneapi::dpl::zip_iterator() const + { + auto __tr = [](auto&&... __args) -> decltype(auto) { return oneapi::dpl::make_zip_iterator(__args...);}; + return apply_to_tuple(__tr, [](auto it) -> decltype(auto) { return it;}, current_); + } + constexpr decltype(auto) operator*() const { auto __tr = [](auto&&... __args) -> decltype(auto) { using return_tuple_type = std::conditional_t< From 4ec45741a342fb6f5aa8fa4e641b015798dc8bd8 Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Mon, 2 Dec 2024 14:22:08 +0100 Subject: [PATCH 43/47] [oneDPL][ranges][zip_view][test] + check conversion to oneapi::dpl::zip_iterator --- test/parallel_api/ranges/std_ranges_zip_view.pass.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp b/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp index 469512db277..3e4bc3366ab 100644 --- a/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp +++ b/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp @@ -74,6 +74,8 @@ main() auto zip_view_sort = dpl_ranges::zip(data, data); + oneapi::dpl::zip_iterator zip_it = zip_view_sort.begin(); //check conversion to oneapi::dpl::zip_iterator + std::sort(zip_view_sort.begin(), zip_view_sort.begin() + max_n, [](const auto& val1, const auto& val2) { return std::get<0>(val1) > std::get<0>(val2); }); for(int i = 0; i < max_n; ++i) EXPECT_TRUE(std::get<0>(zip_view_sort[i]) == max_n - 1 - i, "Wrong effect for std::sort with zip_view."); From 263cbd6d55084bc675adb057c6a99fc7b45319d6 Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Thu, 5 Dec 2024 14:54:40 +0100 Subject: [PATCH 44/47] [oneDPL][ranges][zip_view][test] + EXPECT_TRUE usage --- test/parallel_api/ranges/std_ranges_zip_view.pass.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp b/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp index 3e4bc3366ab..ff101fd22b0 100644 --- a/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp +++ b/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp @@ -89,7 +89,7 @@ main() test_std_ranges::call_with_host_policies(dpl_ranges::sort, zip_view_sort, std::greater{}, [](const auto& val) { return std::get<0>(val); }); for(int i = 0; i < max_n; ++i) - assert(std::get<0>(zip_view_sort[i]) == max_n - 1 - i); + EXPECT_TRUE(std::get<0>(zip_view_sort[i]) == max_n - 1 - i, "Wrong effect for oneapi::dpl::ranges::sort with zip_view."); #endif //_ENABLE_STD_RANGES_TESTING From d91266781aba330c811fc89e39e87bcd73f13682 Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Thu, 16 Jan 2025 12:44:14 +0100 Subject: [PATCH 45/47] [oneDPL][ranges][zip_view] + clang format --- include/oneapi/dpl/pstl/tuple_impl.h | 2 +- include/oneapi/dpl/pstl/zip_view_impl.h | 310 ++++++++++++++---------- 2 files changed, 178 insertions(+), 134 deletions(-) diff --git a/include/oneapi/dpl/pstl/tuple_impl.h b/include/oneapi/dpl/pstl/tuple_impl.h index 01b5237bdf7..34aa9e0ae06 100644 --- a/include/oneapi/dpl/pstl/tuple_impl.h +++ b/include/oneapi/dpl/pstl/tuple_impl.h @@ -500,7 +500,7 @@ struct tuple next = other.next; return *this; } - + template tuple& operator=(const tuple& other) const diff --git a/include/oneapi/dpl/pstl/zip_view_impl.h b/include/oneapi/dpl/pstl/zip_view_impl.h index 2a7d88f8e60..7d279fe6341 100644 --- a/include/oneapi/dpl/pstl/zip_view_impl.h +++ b/include/oneapi/dpl/pstl/zip_view_impl.h @@ -18,12 +18,12 @@ #if _ONEDPL_CPP20_RANGES_PRESENT -#include -#include -#include +# include +# include +# include -#include "tuple_impl.h" -#include "iterator_impl.h" +# include "tuple_impl.h" +# include "iterator_impl.h" namespace oneapi { @@ -34,34 +34,34 @@ namespace ranges { template -concept all_forward = ( std::ranges::forward_range> && ... ); +concept all_forward = (std::ranges::forward_range> && ...); template -concept all_bidirectional = ( std::ranges::bidirectional_range> && ... ); +concept all_bidirectional = (std::ranges::bidirectional_range> && ...); template -concept all_random_access = ( std::ranges::random_access_range> && ... ); +concept all_random_access = (std::ranges::random_access_range> && ...); template -concept zip_is_common = - (sizeof...(Rs) == 1 && ( std::ranges::common_range && ... )) - || - (!(std::ranges::bidirectional_range && ...) && (std::ranges::common_range && ...)) - || - ((std::ranges::random_access_range && ...) && (std::ranges::sized_range && ...)); +concept zip_is_common = (sizeof...(Rs) == 1 && (std::ranges::common_range && ...)) || + (!(std::ranges::bidirectional_range && ...) && (std::ranges::common_range && ...)) || + ((std::ranges::random_access_range && ...) && (std::ranges::sized_range && ...)); template -struct declare_iterator_category {}; +struct declare_iterator_category +{ +}; template - requires all_forward -struct declare_iterator_category { +requires all_forward struct declare_iterator_category +{ using iterator_category = std::input_iterator_tag; }; template - requires ((std::ranges::view && ... ) && (sizeof...(Views) > 0)) -class zip_view : public std::ranges::view_interface> { +requires((std::ranges::view && ...) && (sizeof...(Views) > 0)) class zip_view + : public std::ranges::view_interface> +{ template using tuple_type = oneapi::dpl::__internal::tuple; @@ -83,118 +83,137 @@ class zip_view : public std::ranges::view_interface> { static void apply_to_tuple(_F __f, _Tuple& __t) { - apply_to_tuple([](auto...){}, __f, __t); + apply_to_tuple([](auto...) {}, __f, __t); } -public: + public: zip_view() = default; constexpr zip_view(Views... views) : views_(std::move(views)...) {} template - class iterator : declare_iterator_category { - public: - using iterator_concept = std::conditional_t, - std::random_access_iterator_tag, - std::conditional_t, - std::bidirectional_iterator_tag, - std::conditional_t, - std::forward_iterator_tag, - std::input_iterator_tag>>>; + class iterator : declare_iterator_category + { + public: + using iterator_concept = std::conditional_t< + all_random_access, std::random_access_iterator_tag, + std::conditional_t< + all_bidirectional, std::bidirectional_iterator_tag, + std::conditional_t, std::forward_iterator_tag, std::input_iterator_tag>>>; using value_type = std::conditional_t...>, - tuple_type...>>; + tuple_type...>>; - using difference_type = std::conditional_t...>, - std::common_type_t...>>; + using difference_type = + std::conditional_t...>, + std::common_type_t...>>; iterator() = default; - constexpr iterator(iterator i) - requires Const && (std::convertible_to, std::ranges::iterator_t> && ...) - : current_(std::move(i.current_)) {} + constexpr iterator(iterator i) requires Const && + (std::convertible_to, std::ranges::iterator_t> && ...) + : current_(std::move(i.current_)) + { + } - private: + private: template - constexpr iterator(const Iterators&... iterators) - : current_(iterators...) {} - public: + constexpr iterator(const Iterators&... iterators) : current_(iterators...) + { + } + public: template operator oneapi::dpl::zip_iterator() const { - auto __tr = [](auto&&... __args) -> decltype(auto) { return oneapi::dpl::make_zip_iterator(__args...);}; - return apply_to_tuple(__tr, [](auto it) -> decltype(auto) { return it;}, current_); + auto __tr = [](auto&&... __args) -> decltype(auto) { return oneapi::dpl::make_zip_iterator(__args...); }; + return apply_to_tuple(__tr, [](auto it) -> decltype(auto) { return it; }, current_); } - constexpr decltype(auto) operator*() const { + constexpr decltype(auto) + operator*() const + { auto __tr = [](auto&&... __args) -> decltype(auto) { - using return_tuple_type = std::conditional_t< - !Const, tuple_type...>, - tuple_type...>>; - return return_tuple_type(std::forward(__args)...); - }; - return apply_to_tuple(__tr, [](auto it) -> decltype(auto) { return *it;}, current_); + using return_tuple_type = + std::conditional_t...>, + tuple_type...>>; + return return_tuple_type(std::forward(__args)...); + }; + return apply_to_tuple(__tr, [](auto it) -> decltype(auto) { return *it; }, current_); } - constexpr decltype(auto) operator[]( difference_type n ) const - requires all_random_access + constexpr decltype(auto) + operator[](difference_type n) const requires all_random_access { return *(*this + n); - } + } - constexpr iterator& operator++() { + constexpr iterator& + operator++() + { zip_view::apply_to_tuple([](auto& it) { return ++it; }, current_); return *this; } - constexpr void operator++(int) { + constexpr void + operator++(int) + { ++*this; } - constexpr iterator operator++(int) requires all_forward { + constexpr iterator + operator++(int) requires all_forward + { auto tmp = *this; ++*this; return tmp; } - constexpr iterator& operator--() requires all_bidirectional { + constexpr iterator& + operator--() requires all_bidirectional + { zip_view::apply_to_tuple([](auto& it) { return --it; }, current_); return *this; } - constexpr iterator operator--(int) requires all_bidirectional { + constexpr iterator + operator--(int) requires all_bidirectional + { auto tmp = *this; --*this; return tmp; } - constexpr iterator& operator+=(difference_type n) - requires all_random_access + constexpr iterator& + operator+=(difference_type n) requires all_random_access { zip_view::apply_to_tuple([n](auto& it) { return it += n; }, current_); return *this; } - constexpr iterator& operator-=(difference_type n) - requires all_random_access + constexpr iterator& + operator-=(difference_type n) requires all_random_access { zip_view::apply_to_tuple([n](auto& it) { return it -= n; }, current_); return *this; } - friend constexpr bool operator==(const iterator& x, const iterator& y) - requires ( std::equality_comparable, - std::ranges::iterator_t>> && ... ) + friend constexpr bool + operator==(const iterator& x, const iterator& y) requires( + std::equality_comparable< + std::conditional_t, std::ranges::iterator_t>>&&...) { - if constexpr (all_bidirectional) { + if constexpr (all_bidirectional) + { return x.current_ == y.current_; - } else { + } + else + { return x.compare_equal(y, std::make_index_sequence()); } } - friend constexpr auto operator<=>(const iterator& x, const iterator& y) - requires all_random_access + friend constexpr auto + operator<=>(const iterator& x, const iterator& y) requires all_random_access { if (x.current_ < y.current_) return -1; @@ -203,137 +222,155 @@ class zip_view : public std::ranges::view_interface> { return 1; //x.current > y.current_ } - friend constexpr auto operator-(const iterator& x, const iterator& y) - requires all_random_access + friend constexpr auto + operator-(const iterator& x, const iterator& y) requires all_random_access { return y.distance_to_it(x.current_, std::make_index_sequence()); } - friend constexpr iterator operator+(iterator it, difference_type n) + friend constexpr iterator + operator+(iterator it, difference_type n) { return it += n; } - friend constexpr iterator operator+(difference_type n, iterator it) + friend constexpr iterator + operator+(difference_type n, iterator it) { return it += n; } - friend constexpr iterator operator-(iterator it, difference_type n) + friend constexpr iterator + operator-(iterator it, difference_type n) { return it -= n; } - private: + private: template - constexpr bool compare_equal(iterator y, std::index_sequence) { + constexpr bool + compare_equal(iterator y, std::index_sequence) + { return ((std::get(current_) == std::get(y.current_)) && ...); } template - constexpr bool compare_with_sentinels(const SentinelsTuple& sentinels, std::index_sequence) const { - return ( (std::get(current_) == std::get(sentinels)) || ... ); + constexpr bool + compare_with_sentinels(const SentinelsTuple& sentinels, std::index_sequence) const + { + return ((std::get(current_) == std::get(sentinels)) || ...); } template constexpr std::common_type_t, - std::ranges::range_difference_t>...> - distance_to_sentinels(const SentinelsTuple& sentinels, std::index_sequence<0, In...>) { + std::ranges::range_difference_t>...> + distance_to_sentinels(const SentinelsTuple& sentinels, std::index_sequence<0, In...>) + { auto min = std::get<0>(current_) - std::get<0>(sentinels); - ( (min = std::min(min, (std::get(current_) - std::get(sentinels)))) , ... ); + ((min = std::min(min, (std::get(current_) - std::get(sentinels)))), ...); return min; } template constexpr std::common_type_t, - std::ranges::range_difference_t>...> - distance_to_it(const iterator it, std::index_sequence<0, In...>) const { + std::ranges::range_difference_t>...> + distance_to_it(const iterator it, std::index_sequence<0, In...>) const + { auto min = std::get<0>(it.current_) - std::get<0>(current_); - ( (min = std::min(min, (std::get(it.current_) - std::get(current_)))) , ... ); + ((min = std::min(min, (std::get(it.current_) - std::get(current_)))), ...); return min; } friend class zip_view; using current_type = std::conditional_t...>, - tuple_type...>>; + tuple_type...>>; current_type current_; }; // class iterator template - class sentinel { - public: + class sentinel + { + public: sentinel() = default; - constexpr sentinel(sentinel i) - requires Const && - ( std::convertible_to, std::ranges::sentinel_t> && ... ) - : end_(std::move(i.end_)) {} + constexpr sentinel(sentinel i) requires Const && + (std::convertible_to, std::ranges::sentinel_t> && ...) + : end_(std::move(i.end_)) + { + } - private: + private: template - constexpr sentinel(const Sentinels&... sentinels) - : end_(sentinels...) {} - public: + constexpr sentinel(const Sentinels&... sentinels) : end_(sentinels...) + { + } + + public: template - requires (std::sentinel_for, - std::ranges::sentinel_t>, - std::conditional_t, - std::ranges::iterator_t>> && ...) - friend constexpr bool operator==(const iterator& x, const sentinel& y) + requires(std::sentinel_for< + std::conditional_t, std::ranges::sentinel_t>, + std::conditional_t, + std::ranges::iterator_t>>&&...) friend constexpr bool + operator==(const iterator& x, const sentinel& y) { return x.compare_with_sentinels(y.end_, std::make_index_sequence()); } template - requires (std::sized_sentinel_for, - std::ranges::sentinel_t>, - std::conditional_t, - std::ranges::iterator_t>> && ...) - friend constexpr std::common_type_t, - std::ranges::range_difference_t>...> - operator-(const iterator& x, const sentinel& y) { + requires(std::sized_sentinel_for< + std::conditional_t, std::ranges::sentinel_t>, + std::conditional_t, + std::ranges::iterator_t>>&&...) friend constexpr std:: + common_type_t, + std::ranges::range_difference_t>...> + operator-(const iterator& x, const sentinel& y) + { return x.distance_to_sentinels(y.end_, std::make_index_sequence()); } template - requires (std::sized_sentinel_for, - std::ranges::sentinel_t>, - std::conditional_t, - std::ranges::iterator_t>> && ...) - friend constexpr std::common_type_t, - std::ranges::range_difference_t>...> - operator-(const sentinel& y, const iterator& x) { + requires(std::sized_sentinel_for< + std::conditional_t, std::ranges::sentinel_t>, + std::conditional_t, + std::ranges::iterator_t>>&&...) friend constexpr std:: + common_type_t, + std::ranges::range_difference_t>...> + operator-(const sentinel& y, const iterator& x) + { return -(x - y); } - private: + private: friend class zip_view; using end_type = std::conditional_t...>, - tuple_type...>>; + tuple_type...>>; end_type end_; }; // class sentinel - constexpr auto begin() requires (std::ranges::range && ...) + constexpr auto + begin() requires(std::ranges::range&&...) { - auto __tr = [](auto... __args) { return iterator(__args...);}; + auto __tr = [](auto... __args) { return iterator(__args...); }; return apply_to_tuple(__tr, std::ranges::begin, views_); } - constexpr auto begin() const requires ( std::ranges::range && ... ) + constexpr auto + begin() const requires(std::ranges::range&&...) { - auto __tr = [](auto... __args) { return iterator(__args...);}; + auto __tr = [](auto... __args) { return iterator(__args...); }; return apply_to_tuple(__tr, std::ranges::begin, views_); } - constexpr auto end() requires (std::ranges::range && ...) + constexpr auto + end() requires(std::ranges::range&&...) { if constexpr (!zip_is_common) { - auto __tr = [](auto... __args) { return sentinel(__args...);}; + auto __tr = [](auto... __args) { return sentinel(__args...); }; return apply_to_tuple(__tr, std::ranges::end, views_); } else if constexpr ((std::ranges::random_access_range && ...)) @@ -344,18 +381,19 @@ class zip_view : public std::ranges::view_interface> { } else { - auto __tr = [](auto... __args) { return iterator(__args...);}; + auto __tr = [](auto... __args) { return iterator(__args...); }; return apply_to_tuple(__tr, std::ranges::end, views_); } } - constexpr auto end() const requires (std::ranges::range && ...) + constexpr auto + end() const requires(std::ranges::range&&...) { if constexpr (!zip_is_common) { - auto __tr = [](auto... __args) { return sentinel(__args...);}; + auto __tr = [](auto... __args) { return sentinel(__args...); }; return apply_to_tuple(__tr, std::ranges::end, views_); - } + } else if constexpr ((std::ranges::random_access_range && ...)) { auto it = begin(); @@ -364,35 +402,41 @@ class zip_view : public std::ranges::view_interface> { } else { - auto __tr = [](auto... __args) { return iterator(__args...);}; + auto __tr = [](auto... __args) { return iterator(__args...); }; return apply_to_tuple(__tr, std::ranges::end, views_); } } - constexpr auto size() requires (std::ranges::sized_range && ...) + constexpr auto + size() requires(std::ranges::sized_range&&...) { - auto __tr = [](auto... __args) { + auto __tr = [](auto... __args) { using CT = std::make_unsigned_t>; return std::ranges::min({CT(__args)...}); - }; + }; return apply_to_tuple(__tr, std::ranges::size, views_); } - constexpr auto size() const requires (std::ranges::sized_range && ...) + constexpr auto + size() const requires(std::ranges::sized_range&&...) { return const_cast(this)->size(); } -private: + + private: tuple_type views_; }; // class zip_view template zip_view(Rs&&...) -> zip_view...>; -struct zip_fn { +struct zip_fn +{ template - constexpr auto operator()( Rs&&... rs ) const { + constexpr auto + operator()(Rs&&... rs) const + { return zip_view...>(std::forward(rs)...); } }; From ad4066e53850be9c0eaccac58ca967d2f105c2af Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Thu, 16 Jan 2025 15:43:39 +0100 Subject: [PATCH 46/47] [oneDPL][ranges][zip_view][test] + result checks --- .../ranges/std_ranges_zip_view.pass.cpp | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp b/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp index ff101fd22b0..9fe8a7daa58 100644 --- a/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp +++ b/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp @@ -64,32 +64,46 @@ main() int data[max_n] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; auto zip_view = dpl_ranges::zip(data, std::views::iota(0, max_n)) | std::views::take(5); - std::ranges::for_each(zip_view, test_std_ranges::f_mutuable, [](const auto& val) { return std::get<1>(val); }); + std::ranges::for_each(zip_view, test_std_ranges::f_mutuable, [](auto&& val) ->decltype(auto) { return std::get<0>(val); }); + for(int i = 0; i < zip_view.size(); ++i) + EXPECT_TRUE(std::get<0>(zip_view[i]) == i*i && std::get<1>(zip_view[i]) == i, "Wrong effect for std::ranges::for_each with zip_view."); - test_std_ranges::call_with_host_policies(dpl_ranges::for_each, zip_view, test_std_ranges::f_mutuable, [](const auto& val) { return std::get<1>(val); }); + test_std_ranges::call_with_host_policies(dpl_ranges::for_each, zip_view, test_std_ranges::f_mutuable, + [](const auto& val) { return std::get<1>(val); }); #if TEST_DPCPP_BACKEND_PRESENT - dpl_ranges::for_each(test_std_ranges::dpcpp_policy(), zip_view, test_std_ranges::f_mutuable, [](const auto& val) { return std::get<1>(val); }); + dpl_ranges::for_each(test_std_ranges::dpcpp_policy(), zip_view, test_std_ranges::f_mutuable, + [](const auto& val) { return std::get<1>(val); }); #endif + { + int data[max_n] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; auto zip_view_sort = dpl_ranges::zip(data, data); oneapi::dpl::zip_iterator zip_it = zip_view_sort.begin(); //check conversion to oneapi::dpl::zip_iterator - std::sort(zip_view_sort.begin(), zip_view_sort.begin() + max_n, [](const auto& val1, const auto& val2) { return std::get<0>(val1) > std::get<0>(val2); }); + std::sort(zip_view_sort.begin(), zip_view_sort.begin() + max_n, + [](const auto& val1, const auto& val2) { return std::get<0>(val1) > std::get<0>(val2); }); + for(int i = 0; i < max_n; ++i) - EXPECT_TRUE(std::get<0>(zip_view_sort[i]) == max_n - 1 - i, "Wrong effect for std::sort with zip_view."); + EXPECT_TRUE(std::get<0>(zip_view_sort[i]) == max_n - 1 - i && std::get<1>(zip_view_sort[i]) == max_n - 1 - i, + "Wrong effect for std::sort with zip_view."); std::ranges::sort(zip_view_sort, std::less{}, [](auto&& val) { return std::get<0>(val); }); for(int i = 0; i < max_n; ++i) - EXPECT_TRUE(std::get<0>(zip_view_sort[i]) == i, "Wrong effect for std::ranges::sort with zip_view."); + EXPECT_TRUE(std::get<0>(zip_view_sort[i]) == i && std::get<1>(zip_view_sort[i]) == i, + "Wrong effect for std::ranges::sort with zip_view."); static_assert(std::ranges::random_access_range); static_assert(std::random_access_iterator); - test_std_ranges::call_with_host_policies(dpl_ranges::sort, zip_view_sort, std::greater{}, [](const auto& val) { return std::get<0>(val); }); + test_std_ranges::call_with_host_policies(dpl_ranges::sort, zip_view_sort, std::greater{}, + [](const auto& val) { return std::get<0>(val); }); + for(int i = 0; i < max_n; ++i) - EXPECT_TRUE(std::get<0>(zip_view_sort[i]) == max_n - 1 - i, "Wrong effect for oneapi::dpl::ranges::sort with zip_view."); + EXPECT_TRUE(std::get<0>(zip_view_sort[i]) == max_n - 1 - i && std::get<1>(zip_view_sort[i]) == max_n - 1 - i, + "Wrong effect for oneapi::dpl::ranges::sort with zip_view."); + } #endif //_ENABLE_STD_RANGES_TESTING From 372a29f4a470964bc526806a101f2298d91a2b1f Mon Sep 17 00:00:00 2001 From: MikeDvorskiy Date: Wed, 5 Feb 2025 15:33:19 +0100 Subject: [PATCH 47/47] [oneDPL][ranges][zip_view] + LLVM tests for ranges::zip_view (from C++23 std library) --- .../ranges/range.zip/begin.pass.cpp | 118 + .../range.zip/borrowing.compile.pass.cpp | 48 + .../ranges/range.zip/cpo.pass.cpp | 93 + .../ranges/range.zip/ctad.compile.pass.cpp | 50 + .../ranges/range.zip/ctor.default.pass.cpp | 82 + .../ranges/range.zip/ctor.views.pass.cpp | 109 + .../ranges/range.zip/end.pass.cpp | 405 ++++ .../ranges/range.zip/general.pass.cpp | 69 + .../range.zip/iterator/arithmetic.pass.cpp | 152 ++ .../range.zip/iterator/compare.pass.cpp | 268 +++ .../range.zip/iterator/ctor.other.pass.cpp | 72 + .../range.zip/iterator/decrement.pass.cpp | 104 + .../ranges/range.zip/iterator/deref.pass.cpp | 97 + .../range.zip/iterator/increment.pass.cpp | 144 ++ .../iterator/it_ctor.default.pass.cpp | 83 + .../range.zip/iterator/iter_move.pass.cpp | 86 + .../range.zip/iterator/iter_swap.pass.cpp | 97 + .../iterator/member_types.compile.pass.cpp | 206 ++ .../range.zip/iterator/singular.pass.cpp | 93 + .../range.zip/iterator/subscript.pass.cpp | 76 + .../range.zip/range.concept.compile.pass.cpp | 338 +++ .../ranges/range.zip/sentinel/eq.pass.cpp | 160 ++ .../ranges/range.zip/sentinel/minus.pass.cpp | 243 +++ .../sentinel/sen_ctor.default.pass.cpp | 59 + .../sentinel/sen_ctor.other.pass.cpp | 84 + .../ranges/range.zip/size.pass.cpp | 111 + test/parallel_api/ranges/range.zip/types.h | 438 ++++ test/support/double_move_tracker.h | 43 + test/support/test_iterators.h | 1896 +++++++++++++---- test/support/test_macros.h | 38 + test/support/test_range.h | 109 + test/support/type_algorithms.h | 149 ++ 32 files changed, 5747 insertions(+), 373 deletions(-) create mode 100644 test/parallel_api/ranges/range.zip/begin.pass.cpp create mode 100644 test/parallel_api/ranges/range.zip/borrowing.compile.pass.cpp create mode 100644 test/parallel_api/ranges/range.zip/cpo.pass.cpp create mode 100644 test/parallel_api/ranges/range.zip/ctad.compile.pass.cpp create mode 100644 test/parallel_api/ranges/range.zip/ctor.default.pass.cpp create mode 100644 test/parallel_api/ranges/range.zip/ctor.views.pass.cpp create mode 100644 test/parallel_api/ranges/range.zip/end.pass.cpp create mode 100644 test/parallel_api/ranges/range.zip/general.pass.cpp create mode 100644 test/parallel_api/ranges/range.zip/iterator/arithmetic.pass.cpp create mode 100644 test/parallel_api/ranges/range.zip/iterator/compare.pass.cpp create mode 100644 test/parallel_api/ranges/range.zip/iterator/ctor.other.pass.cpp create mode 100644 test/parallel_api/ranges/range.zip/iterator/decrement.pass.cpp create mode 100644 test/parallel_api/ranges/range.zip/iterator/deref.pass.cpp create mode 100644 test/parallel_api/ranges/range.zip/iterator/increment.pass.cpp create mode 100644 test/parallel_api/ranges/range.zip/iterator/it_ctor.default.pass.cpp create mode 100644 test/parallel_api/ranges/range.zip/iterator/iter_move.pass.cpp create mode 100644 test/parallel_api/ranges/range.zip/iterator/iter_swap.pass.cpp create mode 100644 test/parallel_api/ranges/range.zip/iterator/member_types.compile.pass.cpp create mode 100644 test/parallel_api/ranges/range.zip/iterator/singular.pass.cpp create mode 100644 test/parallel_api/ranges/range.zip/iterator/subscript.pass.cpp create mode 100644 test/parallel_api/ranges/range.zip/range.concept.compile.pass.cpp create mode 100644 test/parallel_api/ranges/range.zip/sentinel/eq.pass.cpp create mode 100644 test/parallel_api/ranges/range.zip/sentinel/minus.pass.cpp create mode 100644 test/parallel_api/ranges/range.zip/sentinel/sen_ctor.default.pass.cpp create mode 100644 test/parallel_api/ranges/range.zip/sentinel/sen_ctor.other.pass.cpp create mode 100644 test/parallel_api/ranges/range.zip/size.pass.cpp create mode 100644 test/parallel_api/ranges/range.zip/types.h create mode 100644 test/support/double_move_tracker.h create mode 100644 test/support/test_range.h create mode 100644 test/support/type_algorithms.h diff --git a/test/parallel_api/ranges/range.zip/begin.pass.cpp b/test/parallel_api/ranges/range.zip/begin.pass.cpp new file mode 100644 index 00000000000..4a3e75e7ea2 --- /dev/null +++ b/test/parallel_api/ranges/range.zip/begin.pass.cpp @@ -0,0 +1,118 @@ +//===----------------------------------------------------------------------===// +// +// 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 auto begin() requires (!(simple-view && ...)); +// constexpr auto begin() const requires (range && ...); + +#include + +#include +#include +#include +#include +#include "types.h" + +//#include "zip_view_impl.h" +#include + +namespace std +{ +namespace ranges +{ +using oneapi::dpl::ranges::zip_view; +} +} + +template +concept HasConstBegin = requires(const T& ct) { ct.begin(); }; + +template +concept HasBegin = requires(T& t) { t.begin(); }; + +template +concept HasConstAndNonConstBegin = + HasConstBegin && + requires(T& t, const T& ct) { requires !std::same_as; }; + +template +concept HasOnlyNonConstBegin = HasBegin && ! +HasConstBegin; + +template +concept HasOnlyConstBegin = HasConstBegin && ! +HasConstAndNonConstBegin; + +struct NoConstBeginView : 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 + std::ranges::zip_view v(SizedRandomAccessView{buffer}, std::views::iota(0), std::ranges::single_view(2.)); + 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 + std::ranges::zip_view v(SizedRandomAccessView{buffer}, std::ranges::empty_view()); + assert(v.begin() == v.end()); + } + + { + // underlying ranges all model simple-view + std::ranges::zip_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(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(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/test/parallel_api/ranges/range.zip/borrowing.compile.pass.cpp b/test/parallel_api/ranges/range.zip/borrowing.compile.pass.cpp new file mode 100644 index 00000000000..c17075984bb --- /dev/null +++ b/test/parallel_api/ranges/range.zip/borrowing.compile.pass.cpp @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// inline constexpr bool enable_borrowed_range> = +// (enable_borrowed_range && ...); + +#include + +#include + +namespace std +{ +namespace ranges +{ +using oneapi::dpl::ranges::zip_view; +} +} + +struct Borrowed : std::ranges::view_base { + int* begin() const; + int* end() const; +}; + +template <> +inline constexpr bool std::ranges::enable_borrowed_range = true; + +static_assert(std::ranges::borrowed_range); + +struct NonBorrowed : std::ranges::view_base { + int* begin() const; + int* end() const; +}; +static_assert(!std::ranges::borrowed_range); + +// test borrowed_range +static_assert(std::ranges::borrowed_range>); +static_assert(std::ranges::borrowed_range>); +static_assert(!std::ranges::borrowed_range>); +static_assert(!std::ranges::borrowed_range>); +static_assert(!std::ranges::borrowed_range>); diff --git a/test/parallel_api/ranges/range.zip/cpo.pass.cpp b/test/parallel_api/ranges/range.zip/cpo.pass.cpp new file mode 100644 index 00000000000..934d0c65852 --- /dev/null +++ b/test/parallel_api/ranges/range.zip/cpo.pass.cpp @@ -0,0 +1,93 @@ +//===----------------------------------------------------------------------===// +// +// 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::views::zip + +#include + +#include +#include +#include +#include +#include + +#include "types.h" + +#include + +namespace std +{ +namespace ranges +{ +using oneapi::dpl::ranges::zip_view; +} + +} + +namespace _std = oneapi::dpl::ranges; + +static_assert(std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert( + std::is_invocable_v>); +static_assert(!std::is_invocable_v); + +constexpr bool test() { + { + // zip zero arguments + auto v = _std::views::zip(); + assert(std::ranges::empty(v)); + static_assert(std::is_same_v>>); + } + + { + // zip a view + int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + std::same_as> decltype(auto) v = + _std::views::zip(SizedRandomAccessView{buffer}); + assert(std::ranges::size(v) == 8); + static_assert(std::is_same_v, std::tuple>); + } + + { + // zip a viewable range + std::array a{1, 2, 3}; + std::same_as>>> decltype(auto) v = + _std::views::zip(a); + assert(&(std::get<0>(*v.begin())) == &(a[0])); + static_assert(std::is_same_v, std::tuple>); + } + + { + // zip the zip_view + int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + std::same_as> decltype(auto) v = + _std::views::zip(SizedRandomAccessView{buffer}, SizedRandomAccessView{buffer}); + + std::same_as< + std::ranges::zip_view>> decltype(auto) v2 = + _std::views::zip(v); + +#ifdef _LIBCPP_VERSION // libc++ doesn't implement P2165R4 yet + static_assert(std::is_same_v, std::tuple>>); +#else + static_assert(std::is_same_v, std::tuple>>); +#endif + } + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/test/parallel_api/ranges/range.zip/ctad.compile.pass.cpp b/test/parallel_api/ranges/range.zip/ctad.compile.pass.cpp new file mode 100644 index 00000000000..dbeac2179a9 --- /dev/null +++ b/test/parallel_api/ranges/range.zip/ctad.compile.pass.cpp @@ -0,0 +1,50 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// zip_view(Rs&&...) -> zip_view...>; + +#include +#include +#include + +#include + +namespace std +{ +namespace ranges +{ +using oneapi::dpl::ranges::zip_view; +} + +} + +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::zip_view(Container{}, View{}, c)), + std::ranges::zip_view, View, std::ranges::ref_view>>); +} diff --git a/test/parallel_api/ranges/range.zip/ctor.default.pass.cpp b/test/parallel_api/ranges/range.zip/ctor.default.pass.cpp new file mode 100644 index 00000000000..2b23fac3467 --- /dev/null +++ b/test/parallel_api/ranges/range.zip/ctor.default.pass.cpp @@ -0,0 +1,82 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// zip_view() = default; + +#include + +#include +#include +#include + +#include + +namespace std +{ +namespace ranges +{ +using oneapi::dpl::ranges::zip_view; +} + +} + +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, zip iterator's =default would be implicitly deleted. +static_assert(std::is_default_constructible_v>); +static_assert( + std::is_default_constructible_v>); +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::zip_view; + View v = View(); // the default constructor is not explicit + assert(v.size() == 3); + auto it = v.begin(); +#ifdef _LIBCPP_VERSION // libc++ doesn't implement P2165R4 yet + using Value = std::pair; +#else + using Value = std::tuple; +#endif + assert(*it++ == Value(buff[0], buff[0])); + assert(*it++ == Value(buff[1], buff[1])); + assert(*it == Value(buff[2], buff[2])); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/test/parallel_api/ranges/range.zip/ctor.views.pass.cpp b/test/parallel_api/ranges/range.zip/ctor.views.pass.cpp new file mode 100644 index 00000000000..757109b3096 --- /dev/null +++ b/test/parallel_api/ranges/range.zip/ctor.views.pass.cpp @@ -0,0 +1,109 @@ +//===----------------------------------------------------------------------===// +// +// 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 zip_view(Views...) + +#include +#include + +#include "types.h" + +#include +namespace std +{ +namespace ranges +{ +using oneapi::dpl::ranges::zip_view; +} + +} + +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::zip_view v{View1{buffer1}, View2{buffer2}}; + auto [i, j] = *v.begin(); + assert(i == buffer1[0]); + assert(j == buffer2[0]); +}; + +constexpr bool test() { + + int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + int buffer2[4] = {9, 8, 7, 6}; + + { + // constructor from views + std::ranges::zip_view v(SizedRandomAccessView{buffer}, std::views::iota(0), std::ranges::single_view(2.)); + auto [i, j, k] = *v.begin(); + assert(i == 1); + assert(j == 0); + assert(k == 2.0); + } + + { + // arguments are moved once + MoveAwareView mv; + std::ranges::zip_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(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/test/parallel_api/ranges/range.zip/end.pass.cpp b/test/parallel_api/ranges/range.zip/end.pass.cpp new file mode 100644 index 00000000000..d89b0ae47ac --- /dev/null +++ b/test/parallel_api/ranges/range.zip/end.pass.cpp @@ -0,0 +1,405 @@ +//===----------------------------------------------------------------------===// +// +// 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 auto end() requires(!(simple-view && ...)) +// constexpr auto end() const requires(range&&...) + +#include +#include + +#include "types.h" + +#include +namespace std +{ +namespace ranges +{ +using oneapi::dpl::ranges::zip_view; +} + +} + +// ID | simple | common | bidi | random | sized | #views | v.end() | as_const(v) +// | | | | access | | | | .end() +// ---|--------|--------|------|--------|-------|--------|----------------|--------------- +// 1 | Y | Y | Y | Y | Y | 1 | iterator | iterator +// 2 | Y | Y | Y | Y | Y | >1 | iterator | iterator +// 3 | Y | N | Y | Y | N | 1 | sentinel | sentinel +// 4 | Y | N | Y | Y | N | >1 | sentinel | sentinel +// 5 | Y | Y | Y | N | Y | 1 | iterator | iterator +// 6 | Y | Y | Y | N | Y | >1 | sentinel | sentinel +// 7 | Y | Y | Y | N | N | 1 | iterator | iterator +// 8 | Y | Y | Y | N | N | >1 | sentinel | sentinel +// 9 | Y | Y | N | N | Y | 1 | iterator | iterator +// 10 | Y | Y | N | N | Y | >1 | iterator | iterator +// 11 | Y | Y | N | N | N | 1 | iterator | iterator +// 12 | Y | Y | N | N | N | >1 | iterator | iterator +// 13 | Y | N | Y | Y | Y | 1 | iterator | iterator +// 14 | Y | N | Y | Y | Y | >1 | iterator | iterator +// 15 | Y | N | Y | N | Y | 1 | sentinel | sentinel +// 16 | Y | N | Y | N | Y | >1 | sentinel | sentinel +// 17 | Y | N | Y | N | N | 1 | sentinel | sentinel +// 18 | Y | N | Y | N | N | >1 | sentinel | sentinel +// 19 | Y | N | N | N | Y | 1 | sentinel | sentinel +// 20 | Y | N | N | N | Y | >1 | sentinel | sentinel +// 21 | Y | N | N | N | N | 1 | sentinel | sentinel +// 22 | Y | N | N | N | N | >1 | sentinel | sentinel +// 23 | N | Y | Y | Y | Y | 1 | iterator| iterator +// 24 | N | Y | Y | Y | Y | >1 | iterator| iterator +// 25 | N | N | Y | Y | N | 1 | sentinel| sentinel +// 26 | N | N | Y | Y | N | >1 | sentinel| sentinel +// 27 | N | Y | Y | N | Y | 1 | iterator| iterator +// 28 | N | Y | Y | N | Y | >1 | sentinel| sentinel +// 29 | N | Y | Y | N | N | 1 | iterator| iterator +// 30 | N | Y | Y | N | N | >1 | sentinel| sentinel +// 31 | N | Y | N | N | Y | 1 | iterator| iterator +// 32 | N | Y | N | N | Y | >1 | iterator| iterator +// 33 | N | Y | N | N | N | 1 | iterator| iterator +// 34 | N | Y | N | N | N | >1 | iterator| iterator +// 35 | N | N | Y | Y | Y | 1 | iterator| iterator +// 36 | N | N | Y | Y | Y | >1 | iterator| iterator +// 37 | N | N | Y | N | Y | 1 | sentinel| sentinel +// 38 | N | N | Y | N | Y | >1 | sentinel| sentinel +// 39 | N | N | Y | N | N | 1 | sentinel| sentinel +// 40 | N | N | Y | N | N | >1 | sentinel| sentinel +// 41 | N | N | N | N | Y | 1 | sentinel| sentinel +// 42 | N | N | N | N | Y | >1 | sentinel| sentinel +// 43 | N | N | N | N | N | 1 | sentinel| sentinel +// 44 | N | N | N | N | N | >1 | sentinel| sentinel + +constexpr bool test() { + int buffer1[5] = {1, 2, 3, 4, 5}; + int buffer2[1] = {1}; + int buffer3[3] = {1, 2, 3}; + { + // test ID 1 + std::ranges::zip_view v{SimpleCommonRandomAccessSized(buffer1)}; + static_assert(std::ranges::common_range); + assert(v.begin() + 5 == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 2 + std::ranges::zip_view v{SimpleCommonRandomAccessSized(buffer1), SimpleCommonRandomAccessSized(buffer2)}; + static_assert(std::ranges::common_range); + assert(v.begin() + 1 == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 3 + std::ranges::zip_view v{NonSizedRandomAccessView(buffer1)}; + static_assert(!std::ranges::common_range); + assert(v.begin() + 5 == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 4 + std::ranges::zip_view v{NonSizedRandomAccessView(buffer1), NonSizedRandomAccessView(buffer3)}; + static_assert(!std::ranges::common_range); + assert(v.begin() + 3 == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 5 + std::ranges::zip_view v{SizedBidiCommon(buffer1)}; + static_assert(std::ranges::common_range); + assert(std::next(v.begin(), 5) == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 6 + std::ranges::zip_view v{SizedBidiCommon(buffer1), SizedBidiCommon(buffer2)}; + static_assert(!std::ranges::common_range); + assert(++v.begin() == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 7 + std::ranges::zip_view v{BidiCommonView(buffer1)}; + static_assert(std::ranges::common_range); + assert(std::next(v.begin(), 5) == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 8 + std::ranges::zip_view v{BidiCommonView(buffer1), BidiCommonView(buffer2)}; + static_assert(!std::ranges::common_range); + assert(++v.begin() == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 9 + std::ranges::zip_view v{ForwardSizedView(buffer1)}; + static_assert(std::ranges::common_range); + assert(std::next(v.begin(), 5) == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 10 + std::ranges::zip_view v{ForwardSizedView(buffer1), ForwardSizedView(buffer2)}; + static_assert(std::ranges::common_range); + assert(++v.begin() == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 11 + std::ranges::zip_view v{InputCommonView(buffer1)}; + static_assert(std::ranges::common_range); + assert(std::ranges::next(v.begin(), 5) == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 12 + std::ranges::zip_view v{InputCommonView(buffer1), InputCommonView(buffer2)}; + static_assert(std::ranges::common_range); + assert(++v.begin() == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 13 + std::ranges::zip_view v{SimpleNonCommonRandomAccessSized(buffer1)}; + static_assert(std::ranges::common_range); + assert(v.begin() + 5 == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 14 + std::ranges::zip_view v{SimpleNonCommonRandomAccessSized(buffer1), SimpleNonCommonRandomAccessSized(buffer2)}; + static_assert(std::ranges::common_range); + assert(v.begin() + 1 == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 15 + std::ranges::zip_view v{SizedBidiNonCommonView(buffer1)}; + static_assert(!std::ranges::common_range); + assert(std::next(v.begin(), 5) == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 16 + std::ranges::zip_view v{SizedBidiNonCommonView(buffer1), SizedBidiNonCommonView(buffer2)}; + static_assert(!std::ranges::common_range); + assert(++v.begin() == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 17 + std::ranges::zip_view v{BidiNonCommonView(buffer1)}; + static_assert(!std::ranges::common_range); + assert(std::next(v.begin(), 5) == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 18 + std::ranges::zip_view v{BidiNonCommonView(buffer1), BidiNonCommonView(buffer2)}; + static_assert(!std::ranges::common_range); + assert(++v.begin() == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 19 + std::ranges::zip_view v{ForwardSizedNonCommon(buffer1)}; + static_assert(!std::ranges::common_range); + assert(std::next(v.begin(), 5) == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 20 + std::ranges::zip_view v{ForwardSizedNonCommon(buffer1), ForwardSizedNonCommon(buffer2)}; + static_assert(!std::ranges::common_range); + assert(++v.begin() == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 21 + std::ranges::zip_view v{InputNonCommonView(buffer1)}; + static_assert(!std::ranges::common_range); + assert(std::ranges::next(v.begin(), 5) == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 22 + std::ranges::zip_view v{InputNonCommonView(buffer1), InputNonCommonView(buffer2)}; + static_assert(!std::ranges::common_range); + assert(++v.begin() == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 23 + std::ranges::zip_view v{NonSimpleCommonRandomAccessSized(buffer1)}; + static_assert(std::ranges::common_range); + assert(v.begin() + 5 == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 24 + std::ranges::zip_view v{NonSimpleCommonRandomAccessSized(buffer1), NonSimpleCommonRandomAccessSized(buffer2)}; + static_assert(std::ranges::common_range); + assert(v.begin() + 1 == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 25 + std::ranges::zip_view v{NonSimpleNonSizedRandomAccessView(buffer1)}; + static_assert(!std::ranges::common_range); + assert(v.begin() + 5 == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 26 + std::ranges::zip_view v{NonSimpleNonSizedRandomAccessView(buffer1), NonSimpleNonSizedRandomAccessView(buffer3)}; + static_assert(!std::ranges::common_range); + assert(v.begin() + 3 == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 27 + std::ranges::zip_view v{NonSimpleSizedBidiCommon(buffer1)}; + static_assert(std::ranges::common_range); + assert(std::next(v.begin(), 5) == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 28 + std::ranges::zip_view v{NonSimpleSizedBidiCommon(buffer1), NonSimpleSizedBidiCommon(buffer2)}; + static_assert(!std::ranges::common_range); + assert(++v.begin() == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 29 + std::ranges::zip_view v{NonSimpleBidiCommonView(buffer1)}; + static_assert(std::ranges::common_range); + assert(std::next(v.begin(), 5) == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 30 + std::ranges::zip_view v{NonSimpleBidiCommonView(buffer1), NonSimpleBidiCommonView(buffer2)}; + static_assert(!std::ranges::common_range); + assert(++v.begin() == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 31 + std::ranges::zip_view v{NonSimpleForwardSizedView(buffer1)}; + static_assert(std::ranges::common_range); + assert(std::next(v.begin(), 5) == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 32 + std::ranges::zip_view v{NonSimpleForwardSizedView(buffer1), NonSimpleForwardSizedView(buffer2)}; + static_assert(std::ranges::common_range); + assert(++v.begin() == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 33 + std::ranges::zip_view v{NonSimpleInputCommonView(buffer1)}; + static_assert(std::ranges::common_range); + assert(std::ranges::next(v.begin(), 5) == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 34 + std::ranges::zip_view v{NonSimpleInputCommonView(buffer1), NonSimpleInputCommonView(buffer2)}; + static_assert(std::ranges::common_range); + assert(++v.begin() == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 35 + std::ranges::zip_view v{NonSimpleNonCommonRandomAccessSized(buffer1)}; + static_assert(std::ranges::common_range); + assert(v.begin() + 5 == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 36 + std::ranges::zip_view v{NonSimpleNonCommonRandomAccessSized(buffer1), NonSimpleNonCommonRandomAccessSized(buffer2)}; + static_assert(std::ranges::common_range); + assert(v.begin() + 1 == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 37 + std::ranges::zip_view v{NonSimpleSizedBidiNonCommonView(buffer1)}; + static_assert(!std::ranges::common_range); + assert(std::next(v.begin(), 5) == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 38 + std::ranges::zip_view v{NonSimpleSizedBidiNonCommonView(buffer1), NonSimpleSizedBidiNonCommonView(buffer2)}; + static_assert(!std::ranges::common_range); + assert(++v.begin() == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 39 + std::ranges::zip_view v{NonSimpleBidiNonCommonView(buffer1)}; + static_assert(!std::ranges::common_range); + assert(std::next(v.begin(), 5) == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 40 + std::ranges::zip_view v{NonSimpleBidiNonCommonView(buffer1), NonSimpleBidiNonCommonView(buffer2)}; + static_assert(!std::ranges::common_range); + assert(++v.begin() == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 41 + std::ranges::zip_view v{NonSimpleForwardSizedNonCommon(buffer1)}; + static_assert(!std::ranges::common_range); + assert(std::next(v.begin(), 5) == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 42 + std::ranges::zip_view v{NonSimpleForwardSizedNonCommon(buffer1), NonSimpleForwardSizedNonCommon(buffer2)}; + static_assert(!std::ranges::common_range); + assert(++v.begin() == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 43 + std::ranges::zip_view v{NonSimpleInputNonCommonView(buffer1)}; + static_assert(!std::ranges::common_range); + assert(std::ranges::next(v.begin(), 5) == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 44 + std::ranges::zip_view v{NonSimpleInputNonCommonView(buffer1), NonSimpleInputNonCommonView(buffer2)}; + static_assert(!std::ranges::common_range); + assert(++v.begin() == v.end()); + static_assert(!std::is_same_v); + } + { + // end should go to the minimum length when zip is common and random_access sized + std::ranges::zip_view v(std::views::iota(0, 4), std::views::iota(0, 8)); + auto it = --(v.end()); + auto [x, y] = *it; + assert(x == 3); + assert(y == 3); // y should not go to the end "7" + } + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/test/parallel_api/ranges/range.zip/general.pass.cpp b/test/parallel_api/ranges/range.zip/general.pass.cpp new file mode 100644 index 00000000000..284ff8f4611 --- /dev/null +++ b/test/parallel_api/ranges/range.zip/general.pass.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// Some basic examples of how zip_view might be used in the wild. This is a general +// collection of sample algorithms and functions that try to mock general usage of +// this view. + +#include + +#include +#include +#include +#include +#include + +#include "types.h" + +#include +namespace std +{ +namespace ranges +{ +using oneapi::dpl::ranges::zip_view; +} + +} + +namespace _std = oneapi::dpl::ranges; + +int main(int, char**) { + { + std::ranges::zip_view v{ + std::array{1, 2}, + std::vector{4, 5, 6}, + std::array{7}, + }; + assert(std::ranges::size(v) == 1); + assert(*v.begin() == std::make_tuple(1, 4, 7)); + } + { + using namespace std::string_literals; + std::vector v{1, 2, 3, 4}; + std::array a{"abc"s, "def"s, "gh"s}; + auto view = _std::views::zip(v, a); + auto it = view.begin(); + assert(&(std::get<0>(*it)) == &(v[0])); + assert(&(std::get<1>(*it)) == &(a[0])); + + ++it; + assert(&(std::get<0>(*it)) == &(v[1])); + assert(&(std::get<1>(*it)) == &(a[1])); + + ++it; + assert(&(std::get<0>(*it)) == &(v[2])); + assert(&(std::get<1>(*it)) == &(a[2])); + + ++it; + assert(it == view.end()); + } + + return 0; +} diff --git a/test/parallel_api/ranges/range.zip/iterator/arithmetic.pass.cpp b/test/parallel_api/ranges/range.zip/iterator/arithmetic.pass.cpp new file mode 100644 index 00000000000..10839aea4c2 --- /dev/null +++ b/test/parallel_api/ranges/range.zip/iterator/arithmetic.pass.cpp @@ -0,0 +1,152 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// x += n; +// x + n; +// n + x; +// x -= n; +// x - n; +// x - y; +// All the arithmetic operators have the constraint `requires all-random-access;`, +// except `operator-(x, y)` which instead has the constraint +// `requires (sized_sentinel_for>, +// iterator_t>> && ...);` + +#include + +#include +#include +#include + +#include "../types.h" + +#include +namespace std +{ +namespace ranges +{ +using oneapi::dpl::ranges::zip_view; +} + +} + +template +concept canPlusEqual = requires(T& t, U& u) { t += u; }; + +template +concept canMinusEqual = requires(T& t, U& u) { t -= u; }; + +constexpr bool test() { + int buffer1[5] = {1, 2, 3, 4, 5}; + int buffer2[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + + SizedRandomAccessView a{buffer1}; + static_assert(std::ranges::random_access_range); + std::array b{4.1, 3.2, 4.3, 0.1, 0.2}; + static_assert(std::ranges::contiguous_range); + { + // operator+(x, n) and operator+= + std::ranges::zip_view v(a, b); + auto it1 = v.begin(); + + auto it2 = it1 + 3; + auto [x2, y2] = *it2; + assert(&x2 == &(a[3])); + assert(&y2 == &(b[3])); + + auto it3 = 3 + it1; + auto [x3, y3] = *it3; + assert(&x3 == &(a[3])); + assert(&y3 == &(b[3])); + + it1 += 3; + assert(it1 == it2); + auto [x1, y1] = *it2; + assert(&x1 == &(a[3])); + assert(&y1 == &(b[3])); + + using Iter = decltype(it1); + static_assert(canPlusEqual); + } + + { + // operator-(x, n) and operator-= + std::ranges::zip_view v(a, b); + auto it1 = v.end(); + + auto it2 = it1 - 3; + auto [x2, y2] = *it2; + assert(&x2 == &(a[2])); + assert(&y2 == &(b[2])); + + it1 -= 3; + assert(it1 == it2); + auto [x1, y1] = *it2; + assert(&x1 == &(a[2])); + assert(&y1 == &(b[2])); + + using Iter = decltype(it1); + static_assert(canMinusEqual); + } + + { + // operator-(x, y) + std::ranges::zip_view v(a, b); + assert((v.end() - v.begin()) == 5); + + auto it1 = v.begin() + 2; + auto it2 = v.end() - 1; + assert((it1 - it2) == -2); + } + + { + // in this case sentinel is computed by getting each of the underlying sentinels, so the distance + // between begin and end for each of the underlying iterators can be different + std::ranges::zip_view v{ForwardSizedView(buffer1), ForwardSizedView(buffer2)}; + using View = decltype(v); + static_assert(std::ranges::common_range); + static_assert(!std::ranges::random_access_range); + + auto it1 = v.begin(); + auto it2 = v.end(); + // it1 : + // it2 : + assert((it1 - it2) == -5); + assert((it2 - it1) == 5); + } + + { + // One of the ranges is not random access + std::ranges::zip_view v(a, b, ForwardSizedView{buffer1}); + using Iter = decltype(v.begin()); + static_assert(!std::invocable, Iter, std::intptr_t>); + static_assert(!std::invocable, std::intptr_t, Iter>); + static_assert(!canPlusEqual); + static_assert(!std::invocable, Iter, std::intptr_t>); + static_assert(std::invocable, Iter, Iter>); + static_assert(!canMinusEqual); + } + + { + // One of the ranges does not have sized sentinel + std::ranges::zip_view v(a, b, InputCommonView{buffer1}); + using Iter = decltype(v.begin()); + static_assert(!std::invocable, Iter, Iter>); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/test/parallel_api/ranges/range.zip/iterator/compare.pass.cpp b/test/parallel_api/ranges/range.zip/iterator/compare.pass.cpp new file mode 100644 index 00000000000..73576cc3639 --- /dev/null +++ b/test/parallel_api/ranges/range.zip/iterator/compare.pass.cpp @@ -0,0 +1,268 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// friend constexpr bool operator==(const iterator& x, const iterator& y) +// requires (equality_comparable>> && ...); +// friend constexpr bool operator<(const iterator& x, const iterator& y) +// requires all-random-access; +// friend constexpr bool operator>(const iterator& x, const iterator& y) +// requires all-random-access; +// friend constexpr bool operator<=(const iterator& x, const iterator& y) +// requires all-random-access; +// friend constexpr bool operator>=(const iterator& x, const iterator& y) +// requires all-random-access; +// friend constexpr auto operator<=>(const iterator& x, const iterator& y) +// requires all-random-access && +// (three_way_comparable>> && ...); + +#include +#include + +#include "test_iterators.h" +#include "test_range.h" + +#include "../types.h" + +#include +namespace std +{ +namespace ranges +{ +using oneapi::dpl::ranges::zip_view; +} + +} + +namespace _std = oneapi::dpl::ranges; + +// This is for testing that zip iterator never calls underlying iterator's >, >=, <=, !=. +// The spec indicates that zip iterator's >= is negating zip iterator's < instead of calling underlying iterator's >=. +// Declare all the operations >, >=, <= etc to make it satisfy random_access_iterator concept, +// but not define them. If the zip iterator's >,>=, <=, etc isn't implemented in the way defined by the standard +// but instead calling underlying iterator's >,>=,<=, we will get a linker error for the runtime tests and +// non-constant expression for the compile time tests. +struct LessThanIterator { + int* it_ = nullptr; + LessThanIterator() = default; + constexpr LessThanIterator(int* it) : it_(it) {} + + using iterator_category = std::random_access_iterator_tag; + using value_type = int; + using difference_type = std::intptr_t; + + constexpr int& operator*() const { return *it_; } + constexpr int& operator[](difference_type n) const { return it_[n]; } + constexpr LessThanIterator& operator++() { + ++it_; + return *this; + } + constexpr LessThanIterator& operator--() { + --it_; + return *this; + } + constexpr LessThanIterator operator++(int) { return LessThanIterator(it_++); } + constexpr LessThanIterator operator--(int) { return LessThanIterator(it_--); } + + constexpr LessThanIterator& operator+=(difference_type n) { + it_ += n; + return *this; + } + constexpr LessThanIterator& operator-=(difference_type n) { + it_ -= n; + return *this; + } + + constexpr friend LessThanIterator operator+(LessThanIterator x, difference_type n) { + x += n; + return x; + } + constexpr friend LessThanIterator operator+(difference_type n, LessThanIterator x) { + x += n; + return x; + } + constexpr friend LessThanIterator operator-(LessThanIterator x, difference_type n) { + x -= n; + return x; + } + constexpr friend difference_type operator-(LessThanIterator x, LessThanIterator y) { return x.it_ - y.it_; } + + constexpr friend bool operator==(LessThanIterator const&, LessThanIterator const&) = default; + friend bool operator!=(LessThanIterator const&, LessThanIterator const&); + + constexpr friend bool operator<(LessThanIterator const& x, LessThanIterator const& y) { return x.it_ < y.it_; } + friend bool operator<=(LessThanIterator const&, LessThanIterator const&); + friend bool operator>(LessThanIterator const&, LessThanIterator const&); + friend bool operator>=(LessThanIterator const&, LessThanIterator const&); +}; +static_assert(std::random_access_iterator); + +struct SmallerThanRange : IntBufferView { + using IntBufferView::IntBufferView; + constexpr LessThanIterator begin() const { return {buffer_}; } + constexpr LessThanIterator end() const { return {buffer_ + size_}; } +}; +static_assert(std::ranges::random_access_range); + +struct ForwardCommonView : IntBufferView { + using IntBufferView::IntBufferView; + using iterator = forward_iterator; + + constexpr iterator begin() const { return iterator(buffer_); } + constexpr iterator end() const { return iterator(buffer_ + size_); } +}; + +constexpr void compareOperatorTest(auto&& iter1, auto&& iter2) { + assert(!(iter1 < iter1)); + assert(iter1 < iter2); + assert(!(iter2 < iter1)); + assert(iter1 <= iter1); + assert(iter1 <= iter2); + assert(!(iter2 <= iter1)); + assert(!(iter1 > iter1)); + assert(!(iter1 > iter2)); + assert(iter2 > iter1); + assert(iter1 >= iter1); + assert(!(iter1 >= iter2)); + assert(iter2 >= iter1); + assert(iter1 == iter1); + assert(!(iter1 == iter2)); + assert(iter2 == iter2); + assert(!(iter1 != iter1)); + assert(iter1 != iter2); + assert(!(iter2 != iter2)); +} + +constexpr void inequalityOperatorsDoNotExistTest(auto&& iter1, auto&& iter2) { + using Iter1 = decltype(iter1); + using Iter2 = decltype(iter2); + static_assert(!std::is_invocable_v, Iter1, Iter2>); + static_assert(!std::is_invocable_v, Iter1, Iter2>); + static_assert(!std::is_invocable_v, Iter1, Iter2>); + static_assert(!std::is_invocable_v, Iter1, Iter2>); +} + +constexpr bool test() { + { + // Test a new-school iterator with operator<=>; the iterator should also have operator<=>. + using It = three_way_contiguous_iterator; + using SubRange = std::ranges::subrange; + static_assert(std::three_way_comparable); + using R = std::ranges::zip_view; + static_assert(std::three_way_comparable>); + + int a[] = {1, 2, 3, 4}; + int b[] = {5, 6, 7, 8, 9}; + auto r = _std::views::zip(SubRange(It(a), It(a + 4)), SubRange(It(b), It(b + 5))); + auto iter1 = r.begin(); + auto iter2 = iter1 + 1; + + compareOperatorTest(iter1, iter2); + + assert((iter1 <=> iter2) == std::strong_ordering::less); + assert((iter1 <=> iter1) == std::strong_ordering::equal); + assert((iter2 <=> iter1) == std::strong_ordering::greater); + } + + { + // Test an old-school iterator with no operator<=>; the transform iterator shouldn't have + // operator<=> either. + using It = random_access_iterator; + using Subrange = std::ranges::subrange; + static_assert(!std::three_way_comparable); + using R = std::ranges::zip_view; +#ifdef _LIBCPP_VERSION + // libc++ hasn't implemented LWG-3692 "zip_view::iterator's operator<=> is overconstrained" + static_assert(!std::three_way_comparable>); +#else + static_assert(std::three_way_comparable>); +#endif + + int a[] = {1, 2, 3, 4}; + int b[] = {5, 6, 7, 8, 9}; + auto r = _std::views::zip(Subrange(It(a), It(a + 4)), Subrange(It(b), It(b + 5))); + auto iter1 = r.begin(); + auto iter2 = iter1 + 1; + + compareOperatorTest(iter1, iter2); + } + + { + // non random_access_range + int buffer1[1] = {1}; + int buffer2[2] = {1, 2}; + + std::ranges::zip_view v{InputCommonView(buffer1), InputCommonView(buffer2)}; + using View = decltype(v); + static_assert(!std::ranges::forward_range); + static_assert(std::ranges::input_range); + static_assert(std::ranges::common_range); + + auto it1 = v.begin(); + auto it2 = v.end(); + assert(it1 != it2); + + ++it1; + assert(it1 == it2); + + inequalityOperatorsDoNotExistTest(it1, it2); + } + + { + // in this case sentinel is computed by getting each of the underlying sentinel, so only one + // underlying iterator is comparing equal + int buffer1[1] = {1}; + int buffer2[2] = {1, 2}; + std::ranges::zip_view v{ForwardCommonView(buffer1), ForwardCommonView(buffer2)}; + using View = decltype(v); + static_assert(std::ranges::common_range); + static_assert(!std::ranges::bidirectional_range); + + auto it1 = v.begin(); + auto it2 = v.end(); + assert(it1 != it2); + + ++it1; + // it1: + // it2: + assert(it1 == it2); + + inequalityOperatorsDoNotExistTest(it1, it2); + } + + { + // only < and == are needed + int a[] = {1, 2, 3, 4}; + int b[] = {5, 6, 7, 8, 9}; + auto r = _std::views::zip(SmallerThanRange(a), SmallerThanRange(b)); + auto iter1 = r.begin(); + auto iter2 = iter1 + 1; + + compareOperatorTest(iter1, iter2); + } + + { + // underlying iterator does not support == + using IterNoEqualView = BasicView, sentinel_wrapper>>; + int buffer[] = {1}; + std::ranges::zip_view r(IterNoEqualView{buffer}); + auto it = r.begin(); + using Iter = decltype(it); + static_assert(!weakly_equality_comparable_with); + inequalityOperatorsDoNotExistTest(it, it); + } + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/test/parallel_api/ranges/range.zip/iterator/ctor.other.pass.cpp b/test/parallel_api/ranges/range.zip/iterator/ctor.other.pass.cpp new file mode 100644 index 00000000000..ff30e6f380b --- /dev/null +++ b/test/parallel_api/ranges/range.zip/iterator/ctor.other.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 + +// constexpr iterator(iterator i) +// requires Const && (convertible_to, +// iterator_t>> && ...); + +#include + +#include +#include + +#include "../types.h" + +#include +namespace std +{ +namespace ranges +{ +using oneapi::dpl::ranges::zip_view; +} + +} + +using ConstIterIncompatibleView = BasicView, forward_iterator, + random_access_iterator, random_access_iterator>; +static_assert(!std::convertible_to, + std::ranges::iterator_t>); + +constexpr bool test() { + int buffer[3] = {1, 2, 3}; + + { + std::ranges::zip_view v(NonSimpleCommon{buffer}); + auto iter1 = v.begin(); + std::ranges::iterator_t iter2 = iter1; + assert(iter1 == iter2); + + static_assert(!std::is_same_v); + + // We cannot create a non-const iterator from a const iterator. + static_assert(!std::constructible_from); + } + + { + // underlying non-const to const not convertible + std::ranges::zip_view v(ConstIterIncompatibleView{buffer}); + auto iter1 = v.begin(); + auto iter2 = std::as_const(v).begin(); + + static_assert(!std::is_same_v); + + static_assert(!std::constructible_from); + static_assert(!std::constructible_from); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/test/parallel_api/ranges/range.zip/iterator/decrement.pass.cpp b/test/parallel_api/ranges/range.zip/iterator/decrement.pass.cpp new file mode 100644 index 00000000000..da72633fcc8 --- /dev/null +++ b/test/parallel_api/ranges/range.zip/iterator/decrement.pass.cpp @@ -0,0 +1,104 @@ +//===----------------------------------------------------------------------===// +// +// 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& operator--() requires all-bidirectional; +// constexpr iterator operator--(int) requires all-bidirectional; + +#include +#include +#include +#include + +#include "../types.h" + +#include +namespace std +{ +namespace ranges +{ +using oneapi::dpl::ranges::zip_view; +} + +} + +template +concept canDecrement = requires(Iter it) { --it; } || requires(Iter it) { it--; }; + +struct NonBidi : IntBufferView { + using IntBufferView::IntBufferView; + using iterator = forward_iterator; + constexpr iterator begin() const { return iterator(buffer_); } + constexpr sentinel_wrapper end() const { return sentinel_wrapper(iterator(buffer_ + size_)); } +}; + +constexpr bool test() { + std::array a{1, 2, 3, 4}; + std::array b{4.1, 3.2, 4.3}; + { + // all random access + std::ranges::zip_view v(a, b, std::views::iota(0, 5)); + auto it = v.end(); + using Iter = decltype(it); + + static_assert(std::is_same_v); + auto& it_ref = --it; + assert(&it_ref == &it); + + assert(&(std::get<0>(*it)) == &(a[2])); + assert(&(std::get<1>(*it)) == &(b[2])); + assert(std::get<2>(*it) == 2); + + static_assert(std::is_same_v); + it--; + assert(&(std::get<0>(*it)) == &(a[1])); + assert(&(std::get<1>(*it)) == &(b[1])); + assert(std::get<2>(*it) == 1); + } + + { + // all bidi+ + int buffer[2] = {1, 2}; + + std::ranges::zip_view v(BidiCommonView{buffer}, std::views::iota(0, 5)); + auto it = v.begin(); + using Iter = decltype(it); + + ++it; + ++it; + + static_assert(std::is_same_v); + auto& it_ref = --it; + assert(&it_ref == &it); + + assert(it == ++v.begin()); + + static_assert(std::is_same_v); + auto tmp = it--; + assert(it == v.begin()); + assert(tmp == ++v.begin()); + } + + { + // non bidi + int buffer[3] = {4, 5, 6}; + std::ranges::zip_view v(a, NonBidi{buffer}); + using Iter = std::ranges::iterator_t; + static_assert(!canDecrement); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/test/parallel_api/ranges/range.zip/iterator/deref.pass.cpp b/test/parallel_api/ranges/range.zip/iterator/deref.pass.cpp new file mode 100644 index 00000000000..d41c58603fb --- /dev/null +++ b/test/parallel_api/ranges/range.zip/iterator/deref.pass.cpp @@ -0,0 +1,97 @@ +//===----------------------------------------------------------------------===// +// +// 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 auto operator*() const; + +#include +#include +#include +#include + +#include "../types.h" + +#include +namespace std +{ +namespace ranges +{ +using oneapi::dpl::ranges::zip_view; +} + +} + +constexpr bool test() { + std::array a{1, 2, 3, 4}; + std::array b{4.1, 3.2, 4.3}; + { + // single range + std::ranges::zip_view v(a); + auto it = v.begin(); + assert(&(std::get<0>(*it)) == &(a[0])); + static_assert(std::is_same_v>); + } + + { + // operator* is const + std::ranges::zip_view v(a); + const auto it = v.begin(); + assert(&(std::get<0>(*it)) == &(a[0])); + } + + { + // two ranges with different types + std::ranges::zip_view v(a, b); + auto it = v.begin(); + auto [x, y] = *it; + assert(&x == &(a[0])); + assert(&y == &(b[0])); +#ifdef _LIBCPP_VERSION // libc++ doesn't implement P2165R4 yet + static_assert(std::is_same_v>); +#else + static_assert(std::is_same_v>); +#endif + + x = 5; + y = 0.1; + assert(a[0] == 5); + assert(b[0] == 0.1); + } + + { + // underlying range with prvalue range_reference_t + std::ranges::zip_view v(a, b, std::views::iota(0, 5)); + auto it = v.begin(); + assert(&(std::get<0>(*it)) == &(a[0])); + assert(&(std::get<1>(*it)) == &(b[0])); + assert(std::get<2>(*it) == 0); + static_assert(std::is_same_v>); + } + + { + // const-correctness + std::ranges::zip_view v(a, std::as_const(a)); + auto it = v.begin(); + assert(&(std::get<0>(*it)) == &(a[0])); + assert(&(std::get<1>(*it)) == &(a[0])); +#ifdef _LIBCPP_VERSION // libc++ doesn't implement P2165R4 yet + static_assert(std::is_same_v>); +#else + static_assert(std::is_same_v>); +#endif + } + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/test/parallel_api/ranges/range.zip/iterator/increment.pass.cpp b/test/parallel_api/ranges/range.zip/iterator/increment.pass.cpp new file mode 100644 index 00000000000..f7967015ce6 --- /dev/null +++ b/test/parallel_api/ranges/range.zip/iterator/increment.pass.cpp @@ -0,0 +1,144 @@ +//===----------------------------------------------------------------------===// +// +// 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& operator++(); +// constexpr void operator++(int); +// constexpr iterator operator++(int) requires all_forward; + +#include +#include +#include +#include + +#include "../types.h" + +#include +namespace std +{ +namespace ranges +{ +using oneapi::dpl::ranges::zip_view; +} + +} + +struct InputRange : IntBufferView { + using IntBufferView::IntBufferView; + using iterator = cpp20_input_iterator; + constexpr iterator begin() const { return iterator(buffer_); } + constexpr sentinel_wrapper end() const { return sentinel_wrapper(iterator(buffer_ + size_)); } +}; + +constexpr bool test() { + std::array a{1, 2, 3, 4}; + std::array b{4.1, 3.2, 4.3}; + { + // random/contiguous + std::ranges::zip_view v(a, b, std::views::iota(0, 5)); + auto it = v.begin(); + using Iter = decltype(it); + + assert(&(std::get<0>(*it)) == &(a[0])); + assert(&(std::get<1>(*it)) == &(b[0])); + assert(std::get<2>(*it) == 0); + + static_assert(std::is_same_v); + + auto& it_ref = ++it; + assert(&it_ref == &it); + + assert(&(std::get<0>(*it)) == &(a[1])); + assert(&(std::get<1>(*it)) == &(b[1])); + assert(std::get<2>(*it) == 1); + + static_assert(std::is_same_v); + auto original = it; + auto copy = it++; + assert(original == copy); + assert(&(std::get<0>(*it)) == &(a[2])); + assert(&(std::get<1>(*it)) == &(b[2])); + assert(std::get<2>(*it) == 2); + } + + { + // bidi + int buffer[2] = {1, 2}; + + std::ranges::zip_view v(BidiCommonView{buffer}); + auto it = v.begin(); + using Iter = decltype(it); + + assert(&(std::get<0>(*it)) == &(buffer[0])); + + static_assert(std::is_same_v); + auto& it_ref = ++it; + assert(&it_ref == &it); + assert(&(std::get<0>(*it)) == &(buffer[1])); + + static_assert(std::is_same_v); + auto original = it; + auto copy = it++; + assert(copy == original); + assert(&(std::get<0>(*it)) == &(buffer[2])); + } + + { + // forward + int buffer[2] = {1, 2}; + + std::ranges::zip_view v(ForwardSizedView{buffer}); + auto it = v.begin(); + using Iter = decltype(it); + + assert(&(std::get<0>(*it)) == &(buffer[0])); + + static_assert(std::is_same_v); + auto& it_ref = ++it; + assert(&it_ref == &it); + assert(&(std::get<0>(*it)) == &(buffer[1])); + + static_assert(std::is_same_v); + auto original = it; + auto copy = it++; + assert(copy == original); + assert(&(std::get<0>(*it)) == &(buffer[2])); + } + + { + // all input+ + int buffer[3] = {4, 5, 6}; + std::ranges::zip_view v(a, InputRange{buffer}); + auto it = v.begin(); + using Iter = decltype(it); + + assert(&(std::get<0>(*it)) == &(a[0])); + assert(&(std::get<1>(*it)) == &(buffer[0])); + + static_assert(std::is_same_v); + auto& it_ref = ++it; + assert(&it_ref == &it); + assert(&(std::get<0>(*it)) == &(a[1])); + assert(&(std::get<1>(*it)) == &(buffer[1])); + + static_assert(std::is_same_v); + it++; + assert(&(std::get<0>(*it)) == &(a[2])); + assert(&(std::get<1>(*it)) == &(buffer[2])); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/test/parallel_api/ranges/range.zip/iterator/it_ctor.default.pass.cpp b/test/parallel_api/ranges/range.zip/iterator/it_ctor.default.pass.cpp new file mode 100644 index 00000000000..07910289553 --- /dev/null +++ b/test/parallel_api/ranges/range.zip/iterator/it_ctor.default.pass.cpp @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// iterator() = default; + +#include +#include + +#include "../types.h" + +#include +namespace std +{ +namespace ranges +{ +using oneapi::dpl::ranges::zip_view; +} + +} + +struct PODIter { + int i; // deliberately uninitialised + + using iterator_category = std::random_access_iterator_tag; + using value_type = int; + using difference_type = std::intptr_t; + + constexpr int operator*() const { return i; } + + constexpr PODIter& operator++() { return *this; } + constexpr void operator++(int) {} + + friend constexpr bool operator==(const PODIter&, const PODIter&) = default; +}; + +struct IterDefaultCtrView : std::ranges::view_base { + PODIter begin() const; + PODIter end() const; +}; + +struct IterNoDefaultCtrView : std::ranges::view_base { + cpp20_input_iterator begin() const; + sentinel_wrapper> end() const; +}; + +template +using zip_iter = std::ranges::iterator_t>; + +static_assert(!std::default_initializable>); +static_assert(!std::default_initializable>); +static_assert(!std::default_initializable>); +static_assert(std::default_initializable>); +static_assert(std::default_initializable>); + +constexpr bool test() { + using ZipIter = zip_iter; + { + ZipIter iter; + auto [x] = *iter; + assert(x == 0); // PODIter has to be initialised to have value 0 + } + + { + ZipIter iter = {}; + auto [x] = *iter; + assert(x == 0); // PODIter has to be initialised to have value 0 + } + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/test/parallel_api/ranges/range.zip/iterator/iter_move.pass.cpp b/test/parallel_api/ranges/range.zip/iterator/iter_move.pass.cpp new file mode 100644 index 00000000000..3fa6d3a563f --- /dev/null +++ b/test/parallel_api/ranges/range.zip/iterator/iter_move.pass.cpp @@ -0,0 +1,86 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// friend constexpr auto iter_move(const iterator& i) noexcept(see below); + +#include +#include +#include +#include +#include + +#include "../types.h" + +#include +namespace std +{ +namespace ranges +{ +using oneapi::dpl::ranges::zip_view; +} + +} + +struct ThrowingMove { + ThrowingMove() = default; + ThrowingMove(ThrowingMove&&) {} +}; + +constexpr bool test() { + { + // underlying iter_move noexcept + std::array a1{1, 2, 3, 4}; + const std::array a2{3.0, 4.0}; + + std::ranges::zip_view v(a1, a2, std::views::iota(3L)); + assert(std::ranges::iter_move(v.begin()) == std::make_tuple(1, 3.0, 3L)); + static_assert(std::is_same_v>); + + auto it = v.begin(); + static_assert(noexcept(std::ranges::iter_move(it))); + } + + { + // underlying iter_move may throw + auto throwingMoveRange = + std::views::iota(0, 2) | std::views::transform([](auto) noexcept { return ThrowingMove{}; }); + std::ranges::zip_view v(throwingMoveRange); + auto it = v.begin(); + static_assert(!noexcept(std::ranges::iter_move(it))); + } + + { + // underlying iterators' iter_move are called through ranges::iter_move + adltest::IterMoveSwapRange r1{}, r2{}; + assert(r1.iter_move_called_times == 0); + assert(r2.iter_move_called_times == 0); + std::ranges::zip_view v(r1, r2); + auto it = v.begin(); + { + [[maybe_unused]] auto&& i = std::ranges::iter_move(it); + assert(r1.iter_move_called_times == 1); + assert(r2.iter_move_called_times == 1); + } + { + [[maybe_unused]] auto&& i = std::ranges::iter_move(it); + assert(r1.iter_move_called_times == 2); + assert(r2.iter_move_called_times == 2); + } + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/test/parallel_api/ranges/range.zip/iterator/iter_swap.pass.cpp b/test/parallel_api/ranges/range.zip/iterator/iter_swap.pass.cpp new file mode 100644 index 00000000000..9f983ca5b22 --- /dev/null +++ b/test/parallel_api/ranges/range.zip/iterator/iter_swap.pass.cpp @@ -0,0 +1,97 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// friend constexpr void iter_swap(const iterator& l, const iterator& r) noexcept(see below) +// requires (indirectly_swappable>> && ...); + +#include +#include +#include + +#include "../types.h" + +#include +namespace std +{ +namespace ranges +{ +using oneapi::dpl::ranges::zip_view; +} + +} + +struct ThrowingMove { + ThrowingMove() = default; + ThrowingMove(ThrowingMove&&) {} + ThrowingMove& operator=(ThrowingMove&&){return *this;} +}; + +constexpr bool test() { + { + std::array a1{1, 2, 3, 4}; + std::array a2{0.1, 0.2, 0.3}; + std::ranges::zip_view v(a1, a2); + auto iter1 = v.begin(); + auto iter2 = ++v.begin(); + + std::ranges::iter_swap(iter1, iter2); + + assert(a1[0] == 2); + assert(a1[1] == 1); + assert(a2[0] == 0.2); + assert(a2[1] == 0.1); + + auto [x1, y1] = *iter1; + assert(&x1 == &a1[0]); + assert(&y1 == &a2[0]); + + auto [x2, y2] = *iter2; + assert(&x2 == &a1[1]); + assert(&y2 == &a2[1]); + + static_assert(noexcept(std::ranges::iter_swap(iter1, iter2))); + } + + { + // underlying iter_swap may throw + std::array iterSwapMayThrow{}; + std::ranges::zip_view v(iterSwapMayThrow); + auto iter1 = v.begin(); + auto iter2 = ++v.begin(); + static_assert(!noexcept(std::ranges::iter_swap(iter1, iter2))); + } + + { + // underlying iterators' iter_move are called through ranges::iter_swap + adltest::IterMoveSwapRange r1, r2; + assert(r1.iter_swap_called_times == 0); + assert(r2.iter_swap_called_times == 0); + + std::ranges::zip_view v{r1, r2}; + auto it1 = v.begin(); + auto it2 = std::ranges::next(it1, 3); + + std::ranges::iter_swap(it1, it2); + assert(r1.iter_swap_called_times == 2); + assert(r2.iter_swap_called_times == 2); + + std::ranges::iter_swap(it1, it2); + assert(r1.iter_swap_called_times == 4); + assert(r2.iter_swap_called_times == 4); + } + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/test/parallel_api/ranges/range.zip/iterator/member_types.compile.pass.cpp b/test/parallel_api/ranges/range.zip/iterator/member_types.compile.pass.cpp new file mode 100644 index 00000000000..5eee6a9574e --- /dev/null +++ b/test/parallel_api/ranges/range.zip/iterator/member_types.compile.pass.cpp @@ -0,0 +1,206 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// Iterator traits and member typedefs in zip_view::. + +#include +#include +#include + +#include "test_iterators.h" + +#include "../types.h" + +#include +namespace std +{ +namespace ranges +{ +using oneapi::dpl::ranges::zip_view; +} + +} + +template +struct ForwardView : std::ranges::view_base { + forward_iterator begin() const; + sentinel_wrapper> end() const; +}; + +template +struct InputView : std::ranges::view_base { + cpp17_input_iterator begin() const; + sentinel_wrapper> end() const; +}; + +template +concept HasIterCategory = requires { typename T::iterator_category; }; + +template +struct DiffTypeIter { + using iterator_category = std::input_iterator_tag; + using value_type = int; + using difference_type = T; + + int operator*() const; + DiffTypeIter& operator++(); + void operator++(int); + friend constexpr bool operator==(DiffTypeIter, DiffTypeIter) = default; +}; + +template +struct DiffTypeRange { + DiffTypeIter begin() const; + DiffTypeIter end() const; +}; + +struct Foo {}; +struct Bar {}; + +struct ConstVeryDifferentRange { + int* begin(); + int* end(); + + forward_iterator begin() const; + forward_iterator end() const; +}; + +void test() { + int buffer[] = {1, 2, 3, 4}; + { + // 2 views should have pair value_type + // random_access_iterator_tag + std::ranges::zip_view v(buffer, buffer); + using Iter = decltype(v.begin()); + + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); +#ifdef _LIBCPP_VERSION // libc++ doesn't implement P2165R4 yet + static_assert(std::is_same_v>); +#else + static_assert(std::is_same_v>); +#endif + static_assert(HasIterCategory); + } + + { + // !=2 views should have tuple value_type + std::ranges::zip_view v(buffer, buffer, buffer); + using Iter = decltype(v.begin()); + + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v>); + static_assert(HasIterCategory); + } + + { + // bidirectional_iterator_tag + std::ranges::zip_view v(BidiCommonView{buffer}); + using Iter = decltype(v.begin()); + + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v>); + } + + { + // forward_iterator_tag + using Iter = std::ranges::iterator_t>>; + + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v>); + static_assert(HasIterCategory); + } + + { + // nested zip_view + std::ranges::zip_view v(buffer, buffer); + std::ranges::zip_view v2(buffer, v); + using Iter = decltype(v2.begin()); + + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); +#ifdef _LIBCPP_VERSION // libc++ doesn't implement P2165R4 yet + static_assert(std::is_same_v>>); +#else + static_assert(std::is_same_v>>); +#endif + static_assert(HasIterCategory); + } + + { + // input_iterator_tag + using Iter = std::ranges::iterator_t>>; + + static_assert(std::is_same_v); + static_assert(!HasIterCategory); + static_assert(std::is_same_v); + static_assert(std::is_same_v>); + } + + { + // difference_type of single view + std::ranges::zip_view v{DiffTypeRange{}}; + using Iter = decltype(v.begin()); + static_assert(std::is_same_v); + } + + { + // difference_type of multiple views should be the common type + std::ranges::zip_view v{DiffTypeRange{}, DiffTypeRange{}}; + using Iter = decltype(v.begin()); + static_assert(std::is_same_v>); + } + + const std::array foos{Foo{}}; + std::array bars{Bar{}, Bar{}}; + { + // value_type of single view + std::ranges::zip_view v{foos}; + using Iter = decltype(v.begin()); + static_assert(std::is_same_v>); + } + + { + // value_type of multiple views with different value_type + std::ranges::zip_view v{foos, bars}; + using Iter = decltype(v.begin()); +#ifdef _LIBCPP_VERSION // libc++ doesn't implement P2165R4 yet + static_assert(std::is_same_v>); +#else + static_assert(std::is_same_v>); +#endif + } + + { + // const-iterator different from iterator + std::ranges::zip_view v{ConstVeryDifferentRange{}}; + using Iter = decltype(v.begin()); + using ConstIter = decltype(std::as_const(v).begin()); + + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v>); + + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v>); + } + +} diff --git a/test/parallel_api/ranges/range.zip/iterator/singular.pass.cpp b/test/parallel_api/ranges/range.zip/iterator/singular.pass.cpp new file mode 100644 index 00000000000..f38f3efc8f7 --- /dev/null +++ b/test/parallel_api/ranges/range.zip/iterator/singular.pass.cpp @@ -0,0 +1,93 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: no-exceptions + +// If the invocation of any non-const member function of `iterator` exits via an +// exception, the iterator acquires a singular value. + +#include + +#include + +#include "../types.h" + +#include +namespace std +{ +namespace ranges +{ +using oneapi::dpl::ranges::zip_view; +} + +} + +struct ThrowOnIncrementIterator { + int* it_; + + using value_type = int; + using difference_type = std::intptr_t; + using iterator_concept = std::input_iterator_tag; + + ThrowOnIncrementIterator() = default; + explicit ThrowOnIncrementIterator(int* it) : it_(it) {} + + ThrowOnIncrementIterator& operator++() { + ++it_; + throw 5; + return *this; + } + void operator++(int) { ++it_; } + + int& operator*() const { return *it_; } + + friend bool operator==(ThrowOnIncrementIterator const&, ThrowOnIncrementIterator const&) = default; +}; + +struct ThrowOnIncrementView : IntBufferView { + ThrowOnIncrementIterator begin() const { return ThrowOnIncrementIterator{buffer_}; } + ThrowOnIncrementIterator end() const { return ThrowOnIncrementIterator{buffer_ + size_}; } +}; + +// Cannot run the test at compile time because it is not allowed to throw exceptions +void test() { + int buffer[] = {1, 2, 3}; + { + // zip iterator should be able to be destroyed after member function throws + std::ranges::zip_view v{ThrowOnIncrementView{buffer}}; + auto it = v.begin(); + try { + ++it; + assert(false); // should not be reached as the above expression should throw. + } catch (int e) { + assert(e == 5); + } + } + + { + // zip iterator should be able to be assigned after member function throws + std::ranges::zip_view v{ThrowOnIncrementView{buffer}}; + auto it = v.begin(); + try { + ++it; + assert(false); // should not be reached as the above expression should throw. + } catch (int e) { + assert(e == 5); + } + it = v.begin(); + auto [x] = *it; + assert(x == 1); + } +} + +int main(int, char**) { + test(); + + return 0; +} diff --git a/test/parallel_api/ranges/range.zip/iterator/subscript.pass.cpp b/test/parallel_api/ranges/range.zip/iterator/subscript.pass.cpp new file mode 100644 index 00000000000..cf462195423 --- /dev/null +++ b/test/parallel_api/ranges/range.zip/iterator/subscript.pass.cpp @@ -0,0 +1,76 @@ +//===----------------------------------------------------------------------===// +// +// 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 auto operator[](difference_type n) const requires +// all_random_access + +#include +#include + +#include "../types.h" + +#include +namespace std +{ +namespace ranges +{ +using oneapi::dpl::ranges::zip_view; +} + +constexpr bool test() { + int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + + { + // random_access_range + std::ranges::zip_view v(SizedRandomAccessView{buffer}, std::views::iota(0)); + auto it = v.begin(); + assert(it[0] == *it); + assert(it[2] == *(it + 2)); + assert(it[4] == *(it + 4)); + +#ifdef _LIBCPP_VERSION // libc++ doesn't implement P2165R4 yet + static_assert(std::is_same_v>); +#else + static_assert(std::is_same_v>); +#endif + } + + { + // contiguous_range + std::ranges::zip_view v(ContiguousCommonView{buffer}, ContiguousCommonView{buffer}); + auto it = v.begin(); + assert(it[0] == *it); + assert(it[2] == *(it + 2)); + assert(it[4] == *(it + 4)); + +#ifdef _LIBCPP_VERSION // libc++ doesn't implement P2165R4 yet + static_assert(std::is_same_v>); +#else + static_assert(std::is_same_v>); +#endif + } + + { + // non random_access_range + std::ranges::zip_view v(BidiCommonView{buffer}); + auto iter = v.begin(); + const auto canSubscript = [](auto&& it) { return requires { it[0]; }; }; + static_assert(!canSubscript(iter)); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/test/parallel_api/ranges/range.zip/range.concept.compile.pass.cpp b/test/parallel_api/ranges/range.zip/range.concept.compile.pass.cpp new file mode 100644 index 00000000000..74e4ae7a8ab --- /dev/null +++ b/test/parallel_api/ranges/range.zip/range.concept.compile.pass.cpp @@ -0,0 +1,338 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// test if zip_view models input_range, forward_range, bidirectional_range, +// random_access_range, contiguous_range, common_range +// sized_range + +#include +#include +#include +#include +#include + +#include "types.h" + +#include +namespace std +{ +namespace ranges +{ +using oneapi::dpl::ranges::zip_view; +} + +} + + +void testConceptPair() { + int buffer1[2] = {1, 2}; + int buffer2[3] = {1, 2, 3}; + { + std::ranges::zip_view v{ContiguousCommonView{buffer1}, ContiguousCommonView{buffer2}}; + using View = decltype(v); + static_assert(std::ranges::random_access_range); + static_assert(!std::ranges::contiguous_range); + static_assert(std::ranges::common_range); + static_assert(std::ranges::sized_range); + } + + { + std::ranges::zip_view v{ContiguousNonCommonView{buffer1}, ContiguousNonCommonView{buffer2}}; + using View = decltype(v); + static_assert(std::ranges::random_access_range); + static_assert(!std::ranges::contiguous_range); + static_assert(!std::ranges::common_range); + static_assert(!std::ranges::sized_range); + } + + { + std::ranges::zip_view v{ContiguousNonCommonSized{buffer1}, ContiguousNonCommonSized{buffer2}}; + using View = decltype(v); + static_assert(std::ranges::random_access_range); + static_assert(!std::ranges::contiguous_range); + static_assert(std::ranges::common_range); + static_assert(std::ranges::sized_range); + } + + { + std::ranges::zip_view v{SizedRandomAccessView{buffer1}, ContiguousCommonView{buffer2}}; + using View = decltype(v); + static_assert(std::ranges::random_access_range); + static_assert(!std::ranges::contiguous_range); + static_assert(std::ranges::common_range); + static_assert(std::ranges::sized_range); + } + + { + std::ranges::zip_view v{SizedRandomAccessView{buffer1}, SizedRandomAccessView{buffer2}}; + using View = decltype(v); + static_assert(std::ranges::random_access_range); + static_assert(!std::ranges::contiguous_range); + static_assert(std::ranges::common_range); + static_assert(std::ranges::sized_range); + } + + { + std::ranges::zip_view v{NonSizedRandomAccessView{buffer1}, NonSizedRandomAccessView{buffer2}}; + using View = decltype(v); + static_assert(std::ranges::random_access_range); + static_assert(!std::ranges::contiguous_range); + static_assert(!std::ranges::common_range); + static_assert(!std::ranges::sized_range); + } + + { + std::ranges::zip_view v{BidiCommonView{buffer1}, SizedRandomAccessView{buffer2}}; + using View = decltype(v); + static_assert(std::ranges::bidirectional_range); + static_assert(!std::ranges::random_access_range); + static_assert(!std::ranges::common_range); + static_assert(!std::ranges::sized_range); + } + + { + std::ranges::zip_view v{BidiCommonView{buffer1}, BidiCommonView{buffer2}}; + using View = decltype(v); + static_assert(std::ranges::bidirectional_range); + static_assert(!std::ranges::random_access_range); + static_assert(!std::ranges::common_range); + static_assert(!std::ranges::sized_range); + } + + { + std::ranges::zip_view v{BidiCommonView{buffer1}, ForwardSizedView{buffer2}}; + using View = decltype(v); + static_assert(std::ranges::forward_range); + static_assert(!std::ranges::bidirectional_range); + static_assert(std::ranges::common_range); + static_assert(!std::ranges::sized_range); + } + + { + std::ranges::zip_view v{BidiNonCommonView{buffer1}, ForwardSizedView{buffer2}}; + using View = decltype(v); + static_assert(std::ranges::forward_range); + static_assert(!std::ranges::bidirectional_range); + static_assert(!std::ranges::common_range); + static_assert(!std::ranges::sized_range); + } + + { + std::ranges::zip_view v{ForwardSizedView{buffer1}, ForwardSizedView{buffer2}}; + using View = decltype(v); + static_assert(std::ranges::forward_range); + static_assert(!std::ranges::bidirectional_range); + static_assert(std::ranges::common_range); + static_assert(std::ranges::sized_range); + } + + { + std::ranges::zip_view v{ForwardSizedNonCommon{buffer1}, ForwardSizedView{buffer2}}; + using View = decltype(v); + static_assert(std::ranges::forward_range); + static_assert(!std::ranges::bidirectional_range); + static_assert(!std::ranges::common_range); + static_assert(std::ranges::sized_range); + } + + { + std::ranges::zip_view v{InputCommonView{buffer1}, ForwardSizedView{buffer2}}; + using View = decltype(v); + static_assert(std::ranges::input_range); + static_assert(!std::ranges::forward_range); + static_assert(std::ranges::common_range); + static_assert(!std::ranges::sized_range); + } + + { + std::ranges::zip_view v{InputCommonView{buffer1}, InputCommonView{buffer2}}; + using View = decltype(v); + static_assert(std::ranges::input_range); + static_assert(!std::ranges::forward_range); + static_assert(std::ranges::common_range); + static_assert(!std::ranges::sized_range); + } + + { + std::ranges::zip_view v{InputNonCommonView{buffer1}, InputCommonView{buffer2}}; + using View = decltype(v); + static_assert(std::ranges::input_range); + static_assert(!std::ranges::forward_range); + static_assert(!std::ranges::common_range); + static_assert(!std::ranges::sized_range); + } +} + +void testConceptTuple() { + int buffer1[2] = {1, 2}; + int buffer2[3] = {1, 2, 3}; + int buffer3[4] = {1, 2, 3, 4}; + + { + std::ranges::zip_view v{ContiguousCommonView{buffer1}, ContiguousCommonView{buffer2}, + ContiguousCommonView{buffer3}}; + using View = decltype(v); + static_assert(std::ranges::random_access_range); + static_assert(!std::ranges::contiguous_range); + static_assert(std::ranges::common_range); + static_assert(std::ranges::sized_range); + } + + { + std::ranges::zip_view v{ContiguousNonCommonView{buffer1}, ContiguousNonCommonView{buffer2}, + ContiguousNonCommonView{buffer3}}; + using View = decltype(v); + static_assert(std::ranges::random_access_range); + static_assert(!std::ranges::contiguous_range); + static_assert(!std::ranges::common_range); + static_assert(!std::ranges::sized_range); + } + + { + std::ranges::zip_view v{ContiguousNonCommonSized{buffer1}, ContiguousNonCommonSized{buffer2}, + ContiguousNonCommonSized{buffer3}}; + using View = decltype(v); + static_assert(std::ranges::random_access_range); + static_assert(!std::ranges::contiguous_range); + static_assert(std::ranges::common_range); + static_assert(std::ranges::sized_range); + } + + { + std::ranges::zip_view v{SizedRandomAccessView{buffer1}, ContiguousCommonView{buffer2}, + ContiguousCommonView{buffer3}}; + using View = decltype(v); + static_assert(std::ranges::random_access_range); + static_assert(!std::ranges::contiguous_range); + static_assert(std::ranges::common_range); + static_assert(std::ranges::sized_range); + } + + { + std::ranges::zip_view v{SizedRandomAccessView{buffer1}, SizedRandomAccessView{buffer2}, + SizedRandomAccessView{buffer3}}; + using View = decltype(v); + static_assert(std::ranges::random_access_range); + static_assert(!std::ranges::contiguous_range); + static_assert(std::ranges::common_range); + static_assert(std::ranges::sized_range); + } + + { + std::ranges::zip_view v{NonSizedRandomAccessView{buffer1}, NonSizedRandomAccessView{buffer2}, + NonSizedRandomAccessView{buffer3}}; + using View = decltype(v); + static_assert(std::ranges::random_access_range); + static_assert(!std::ranges::contiguous_range); + static_assert(!std::ranges::common_range); + static_assert(!std::ranges::sized_range); + } + + { + std::ranges::zip_view v{BidiCommonView{buffer1}, SizedRandomAccessView{buffer2}, SizedRandomAccessView{buffer3}}; + using View = decltype(v); + static_assert(std::ranges::bidirectional_range); + static_assert(!std::ranges::random_access_range); + static_assert(!std::ranges::common_range); + static_assert(!std::ranges::sized_range); + } + + { + std::ranges::zip_view v{BidiCommonView{buffer1}, BidiCommonView{buffer2}, BidiCommonView{buffer3}}; + using View = decltype(v); + static_assert(std::ranges::bidirectional_range); + static_assert(!std::ranges::random_access_range); + static_assert(!std::ranges::common_range); + static_assert(!std::ranges::sized_range); + } + + { + std::ranges::zip_view v{BidiCommonView{buffer1}, ForwardSizedView{buffer2}, ForwardSizedView{buffer3}}; + using View = decltype(v); + static_assert(std::ranges::forward_range); + static_assert(!std::ranges::bidirectional_range); + static_assert(std::ranges::common_range); + static_assert(!std::ranges::sized_range); + } + + { + std::ranges::zip_view v{BidiNonCommonView{buffer1}, ForwardSizedView{buffer2}, ForwardSizedView{buffer3}}; + using View = decltype(v); + static_assert(std::ranges::forward_range); + static_assert(!std::ranges::bidirectional_range); + static_assert(!std::ranges::common_range); + static_assert(!std::ranges::sized_range); + } + + { + std::ranges::zip_view v{ForwardSizedView{buffer1}, ForwardSizedView{buffer2}, ForwardSizedView{buffer3}}; + using View = decltype(v); + static_assert(std::ranges::forward_range); + static_assert(!std::ranges::bidirectional_range); + static_assert(std::ranges::common_range); + static_assert(std::ranges::sized_range); + } + + { + std::ranges::zip_view v{ForwardSizedNonCommon{buffer1}, ForwardSizedView{buffer2}, ForwardSizedView{buffer3}}; + using View = decltype(v); + static_assert(std::ranges::forward_range); + static_assert(!std::ranges::bidirectional_range); + static_assert(!std::ranges::common_range); + static_assert(std::ranges::sized_range); + } + + { + std::ranges::zip_view v{InputCommonView{buffer1}, ForwardSizedView{buffer2}, ForwardSizedView{buffer3}}; + using View = decltype(v); + static_assert(std::ranges::input_range); + static_assert(!std::ranges::forward_range); + static_assert(std::ranges::common_range); + static_assert(!std::ranges::sized_range); + } + + { + std::ranges::zip_view v{InputCommonView{buffer1}, InputCommonView{buffer2}, InputCommonView{buffer3}}; + using View = decltype(v); + static_assert(std::ranges::input_range); + static_assert(!std::ranges::forward_range); + static_assert(std::ranges::common_range); + static_assert(!std::ranges::sized_range); + } + + { + std::ranges::zip_view v{InputNonCommonView{buffer1}, InputCommonView{buffer2}, InputCommonView{buffer3}}; + using View = decltype(v); + static_assert(std::ranges::input_range); + static_assert(!std::ranges::forward_range); + static_assert(!std::ranges::common_range); + static_assert(!std::ranges::sized_range); + } +} + +using OutputIter = cpp17_output_iterator; +static_assert(std::output_iterator); + +struct OutputView : std::ranges::view_base { + OutputIter begin() const; + sentinel_wrapper end() const; +}; +static_assert(std::ranges::output_range); +static_assert(!std::ranges::input_range); + +template +concept zippable = requires { + typename std::ranges::zip_view; +}; + +// output_range is not supported +static_assert(!zippable); +static_assert(!zippable); +static_assert(zippable); diff --git a/test/parallel_api/ranges/range.zip/sentinel/eq.pass.cpp b/test/parallel_api/ranges/range.zip/sentinel/eq.pass.cpp new file mode 100644 index 00000000000..22e8cf3b870 --- /dev/null +++ b/test/parallel_api/ranges/range.zip/sentinel/eq.pass.cpp @@ -0,0 +1,160 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// requires sentinel_for, iterator_t>> +// friend constexpr bool operator==(const iterator& x, const sentinel& y); + +#include +#include +#include +#include + +#include "../types.h" +#include "test_range.h" + +#include +namespace std +{ +namespace ranges +{ +using oneapi::dpl::ranges::zip_view; +} +} + +using Iterator = random_access_iterator; +using ConstIterator = random_access_iterator; + +template +struct ComparableSentinel { + + using Iter = std::conditional_t; + Iter iter_; + + explicit ComparableSentinel() = default; + constexpr explicit ComparableSentinel(const Iter& it) : iter_(it) {} + + constexpr friend bool operator==(const Iterator& i, const ComparableSentinel& s) { return base(i) == base(s.iter_); } + + constexpr friend bool operator==(const ConstIterator& i, const ComparableSentinel& s) { + return base(i) == base(s.iter_); + } +}; + +struct ComparableView : IntBufferView { + using IntBufferView::IntBufferView; + + constexpr auto begin() { return Iterator(buffer_); } + constexpr auto begin() const { return ConstIterator(buffer_); } + constexpr auto end() { return ComparableSentinel(Iterator(buffer_ + size_)); } + constexpr auto end() const { return ComparableSentinel(ConstIterator(buffer_ + size_)); } +}; + +struct ConstIncompatibleView : std::ranges::view_base { + cpp17_input_iterator begin(); + forward_iterator begin() const; + sentinel_wrapper> end(); + sentinel_wrapper> end() const; +}; + +constexpr bool test() { + int buffer1[4] = {1, 2, 3, 4}; + int buffer2[5] = {1, 2, 3, 4, 5}; + int buffer3[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + { + // simple-view: const and non-const have the same iterator/sentinel type + std::ranges::zip_view v{SimpleNonCommon(buffer1), SimpleNonCommon(buffer2), SimpleNonCommon(buffer3)}; + static_assert(!std::ranges::common_range); + static_assert(simple_view); + + assert(v.begin() != v.end()); + assert(v.begin() + 1 != v.end()); + assert(v.begin() + 2 != v.end()); + assert(v.begin() + 3 != v.end()); + assert(v.begin() + 4 == v.end()); + } + + { + // !simple-view: const and non-const have different iterator/sentinel types + std::ranges::zip_view v{NonSimpleNonCommon(buffer1), SimpleNonCommon(buffer2), SimpleNonCommon(buffer3)}; + static_assert(!std::ranges::common_range); + static_assert(!simple_view); + + assert(v.begin() != v.end()); + assert(v.begin() + 4 == v.end()); + + // const_iterator (const int*) converted to iterator (int*) + assert(v.begin() + 4 == std::as_const(v).end()); + + using Iter = std::ranges::iterator_t; + using ConstIter = std::ranges::iterator_t; + static_assert(!std::is_same_v); + using Sentinel = std::ranges::sentinel_t; + using ConstSentinel = std::ranges::sentinel_t; + static_assert(!std::is_same_v); + + static_assert(weakly_equality_comparable_with); + static_assert(!weakly_equality_comparable_with); + static_assert(weakly_equality_comparable_with); + static_assert(weakly_equality_comparable_with); + } + + { + // underlying const/non-const sentinel can be compared with both const/non-const iterator + std::ranges::zip_view v{ComparableView(buffer1), ComparableView(buffer2)}; + static_assert(!std::ranges::common_range); + static_assert(!simple_view); + + assert(v.begin() != v.end()); + assert(v.begin() + 4 == v.end()); + assert(std::as_const(v).begin() + 4 == v.end()); + assert(std::as_const(v).begin() + 4 == std::as_const(v).end()); + assert(v.begin() + 4 == std::as_const(v).end()); + + using Iter = std::ranges::iterator_t; + using ConstIter = std::ranges::iterator_t; + static_assert(!std::is_same_v); + using Sentinel = std::ranges::sentinel_t; + using ConstSentinel = std::ranges::sentinel_t; + static_assert(!std::is_same_v); + + static_assert(weakly_equality_comparable_with); + static_assert(weakly_equality_comparable_with); + static_assert(weakly_equality_comparable_with); + static_assert(weakly_equality_comparable_with); + } + + { + // underlying const/non-const sentinel cannot be compared with non-const/const iterator + std::ranges::zip_view v{ComparableView(buffer1), ConstIncompatibleView{}}; + static_assert(!std::ranges::common_range); + static_assert(!simple_view); + + using Iter = std::ranges::iterator_t; + using ConstIter = std::ranges::iterator_t; + static_assert(!std::is_same_v); + using Sentinel = std::ranges::sentinel_t; + using ConstSentinel = std::ranges::sentinel_t; + static_assert(!std::is_same_v); + + static_assert(weakly_equality_comparable_with); + static_assert(!weakly_equality_comparable_with); + static_assert(!weakly_equality_comparable_with); + static_assert(weakly_equality_comparable_with); + } + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/test/parallel_api/ranges/range.zip/sentinel/minus.pass.cpp b/test/parallel_api/ranges/range.zip/sentinel/minus.pass.cpp new file mode 100644 index 00000000000..aa5bd1da153 --- /dev/null +++ b/test/parallel_api/ranges/range.zip/sentinel/minus.pass.cpp @@ -0,0 +1,243 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// requires(sized_sentinel_for>, +// iterator_t>>&&...) +// friend constexpr common_type_t>...> +// operator-(const iterator&, const sentinel&) +// +// template +// requires(sized_sentinel_for>, +// iterator_t>>&&...) +// friend constexpr common_type_t>...> +// operator-(const sentinel&, const iterator&) + +#include +#include +#include +#include +#include + +#include "../types.h" + +#include +namespace std +{ +namespace ranges +{ +using oneapi::dpl::ranges::zip_view; +} +} + +template +struct convertible_forward_sized_iterator { + Base it_ = nullptr; + + using iterator_category = std::forward_iterator_tag; + using value_type = int; + using difference_type = std::intptr_t; + + convertible_forward_sized_iterator() = default; + constexpr convertible_forward_sized_iterator(Base it) : it_(it) {} + + template U> + constexpr convertible_forward_sized_iterator(const convertible_forward_sized_iterator& it) : it_(it.it_) {} + + constexpr decltype(*Base{}) operator*() const { return *it_; } + + constexpr convertible_forward_sized_iterator& operator++() { + ++it_; + return *this; + } + constexpr convertible_forward_sized_iterator operator++(int) { return forward_sized_iterator(it_++); } + + friend constexpr bool operator==(const convertible_forward_sized_iterator&, + const convertible_forward_sized_iterator&) = default; + + friend constexpr difference_type operator-(const convertible_forward_sized_iterator& x, + const convertible_forward_sized_iterator& y) { + return x.it_ - y.it_; + } +}; +static_assert(std::forward_iterator>); + +template +struct convertible_sized_sentinel { + Base base_; + explicit convertible_sized_sentinel() = default; + constexpr convertible_sized_sentinel(const Base& it) : base_(it) {} + + template U> + constexpr convertible_sized_sentinel(const convertible_sized_sentinel& other) : base_(other.base_) {} + + template + requires(std::convertible_to || std::convertible_to) + friend constexpr bool operator==(const convertible_sized_sentinel& s, const U& base) { + return s.base_ == base; + } + template + requires(std::convertible_to || std::convertible_to) + friend constexpr auto operator-(const convertible_sized_sentinel& s, const U& i) { + return s.base_ - i; + } + + template + requires(std::convertible_to || std::convertible_to) + friend constexpr auto operator-(const U& i, const convertible_sized_sentinel& s) { + return i - s.base_; + } +}; +static_assert(std::sized_sentinel_for>, + convertible_forward_sized_iterator<>>); +static_assert(std::sized_sentinel_for>, + convertible_forward_sized_iterator>); +static_assert(std::sized_sentinel_for>, + convertible_forward_sized_iterator>); + +struct ConstCompatibleForwardSized : IntBufferView { + using IntBufferView::IntBufferView; + + using iterator = convertible_forward_sized_iterator; + using const_iterator = convertible_forward_sized_iterator; + + constexpr iterator begin() { return {buffer_}; } + constexpr const_iterator begin() const { return {buffer_}; } + constexpr convertible_sized_sentinel end() { return iterator{buffer_ + size_}; } + constexpr convertible_sized_sentinel end() const { return const_iterator{buffer_ + size_}; } +}; + +// clang-format off +template +concept HasMinus = std::invocable,const T&, const U&>; + +template +concept SentinelHasMinus = HasMinus, std::ranges::iterator_t>; +// clang-format on + +constexpr bool test() { + int buffer1[5] = {1, 2, 3, 4, 5}; + + { + // simple-view + std::ranges::zip_view v{ForwardSizedNonCommon(buffer1)}; + static_assert(!std::ranges::common_range); + static_assert(simple_view); + + auto it = v.begin(); + auto st = v.end(); + assert(st - it == 5); + assert(st - std::ranges::next(it, 1) == 4); + + assert(it - st == -5); + assert(std::ranges::next(it, 1) - st == -4); + static_assert(SentinelHasMinus); + } + + { + // shortest range + std::ranges::zip_view v(std::views::iota(0, 3), ForwardSizedNonCommon(buffer1)); + static_assert(!std::ranges::common_range); + auto it = v.begin(); + auto st = v.end(); + assert(st - it == 3); + assert(st - std::ranges::next(it, 1) == 2); + + assert(it - st == -3); + assert(std::ranges::next(it, 1) - st == -2); + static_assert(SentinelHasMinus); + } + + { + // underlying sentinel does not model sized_sentinel_for + std::ranges::zip_view v(std::views::iota(0), SizedRandomAccessView(buffer1)); + static_assert(!std::ranges::common_range); + static_assert(!SentinelHasMinus); + } + + { + // const incompatible: + // underlying const sentinels cannot subtract underlying iterators + // underlying sentinels cannot subtract underlying const iterators + std::ranges::zip_view v(NonSimpleForwardSizedNonCommon{buffer1}); + static_assert(!std::ranges::common_range); + static_assert(!simple_view); + + using Iter = std::ranges::iterator_t; + using ConstIter = std::ranges::iterator_t; + static_assert(!std::is_same_v); + using Sentinel = std::ranges::sentinel_t; + using ConstSentinel = std::ranges::sentinel_t; + static_assert(!std::is_same_v); + + static_assert(HasMinus); + static_assert(HasMinus); + static_assert(HasMinus); + static_assert(HasMinus); + auto it = v.begin(); + auto const_it = std::as_const(v).begin(); + auto st = v.end(); + auto const_st = std::as_const(v).end(); + assert(it - st == -5); + assert(st - it == 5); + assert(const_it - const_st == -5); + assert(const_st - const_it == 5); + + static_assert(!HasMinus); + static_assert(!HasMinus); + static_assert(!HasMinus); + static_assert(!HasMinus); + } + + { + // const compatible allow non-const to const conversion + std::ranges::zip_view v(ConstCompatibleForwardSized{buffer1}); + static_assert(!std::ranges::common_range); + static_assert(!simple_view); + + using Iter = std::ranges::iterator_t; + using ConstIter = std::ranges::iterator_t; + static_assert(!std::is_same_v); + using Sentinel = std::ranges::sentinel_t; + using ConstSentinel = std::ranges::sentinel_t; + static_assert(!std::is_same_v); + + static_assert(HasMinus); + static_assert(HasMinus); + static_assert(HasMinus); + static_assert(HasMinus); + static_assert(HasMinus); + static_assert(HasMinus); + static_assert(HasMinus); + static_assert(HasMinus); + + auto it = v.begin(); + auto const_it = std::as_const(v).begin(); + auto st = v.end(); + auto const_st = std::as_const(v).end(); + + assert(it - st == -5); + assert(st - it == 5); + assert(const_it - const_st == -5); + assert(const_st - const_it == 5); + assert(it - const_st == -5); + assert(const_st - it == 5); + assert(const_it - st == -5); + assert(st - const_it == 5); + } + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/test/parallel_api/ranges/range.zip/sentinel/sen_ctor.default.pass.cpp b/test/parallel_api/ranges/range.zip/sentinel/sen_ctor.default.pass.cpp new file mode 100644 index 00000000000..557887a4156 --- /dev/null +++ b/test/parallel_api/ranges/range.zip/sentinel/sen_ctor.default.pass.cpp @@ -0,0 +1,59 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// sentinel() = default; + +#include +#include +#include + +#include +namespace std +{ +namespace ranges +{ +using oneapi::dpl::ranges::zip_view; +} +} + +struct PODSentinel { + bool b; // deliberately uninitialised + + friend constexpr bool operator==(int*, const PODSentinel& s) { return s.b; } +}; + +struct Range : std::ranges::view_base { + int* begin() const; + PODSentinel end(); +}; + +constexpr bool test() { + { + using R = std::ranges::zip_view; + using Sentinel = std::ranges::sentinel_t; + static_assert(!std::is_same_v>); + + std::ranges::iterator_t it; + + Sentinel s1; + assert(it != s1); // PODSentinel.b is initialised to false + + Sentinel s2 = {}; + assert(it != s2); // PODSentinel.b is initialised to false + } + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/test/parallel_api/ranges/range.zip/sentinel/sen_ctor.other.pass.cpp b/test/parallel_api/ranges/range.zip/sentinel/sen_ctor.other.pass.cpp new file mode 100644 index 00000000000..1384c65bcbc --- /dev/null +++ b/test/parallel_api/ranges/range.zip/sentinel/sen_ctor.other.pass.cpp @@ -0,0 +1,84 @@ +//===----------------------------------------------------------------------===// +// +// 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 sentinel(sentinel s); + +#include +#include + +#include "../types.h" + +#include +namespace std +{ +namespace ranges +{ +using oneapi::dpl::ranges::zip_view; +} +} + +template +struct convertible_sentinel_wrapper { + explicit convertible_sentinel_wrapper() = default; + constexpr convertible_sentinel_wrapper(const T& it) : it_(it) {} + + template + requires std::convertible_to + constexpr convertible_sentinel_wrapper(const convertible_sentinel_wrapper& other) : it_(other.it_) {} + + constexpr friend bool operator==(convertible_sentinel_wrapper const& self, const T& other) { + return self.it_ == other; + } + T it_; +}; + +struct NonSimpleNonCommonConvertibleView : IntBufferView { + using IntBufferView::IntBufferView; + + constexpr int* begin() { return buffer_; } + constexpr const int* begin() const { return buffer_; } + constexpr convertible_sentinel_wrapper end() { return convertible_sentinel_wrapper(buffer_ + size_); } + constexpr convertible_sentinel_wrapper end() const { + return convertible_sentinel_wrapper(buffer_ + size_); + } +}; + +static_assert(!std::ranges::common_range); +static_assert(std::ranges::random_access_range); +static_assert(!std::ranges::sized_range); +static_assert(std::convertible_to, + std::ranges::sentinel_t>); +static_assert(!simple_view); + +constexpr bool test() { + int buffer1[4] = {1, 2, 3, 4}; + int buffer2[5] = {1, 2, 3, 4, 5}; + std::ranges::zip_view v{NonSimpleNonCommonConvertibleView(buffer1), NonSimpleNonCommonConvertibleView(buffer2)}; + static_assert(!std::ranges::common_range); + auto sent1 = v.end(); + std::ranges::sentinel_t sent2 = sent1; + static_assert(!std::is_same_v); + + assert(v.begin() != sent2); + assert(std::as_const(v).begin() != sent2); + assert(v.begin() + 4 == sent2); + assert(std::as_const(v).begin() + 4 == sent2); + + // Cannot create a non-const iterator from a const iterator. + static_assert(!std::constructible_from); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/test/parallel_api/ranges/range.zip/size.pass.cpp b/test/parallel_api/ranges/range.zip/size.pass.cpp new file mode 100644 index 00000000000..123d895712c --- /dev/null +++ b/test/parallel_api/ranges/range.zip/size.pass.cpp @@ -0,0 +1,111 @@ +//===----------------------------------------------------------------------===// +// +// 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 auto size() requires(sized_range&&...) +// constexpr auto size() const requires(sized_range&&...) + +#include + +#include +#include +#include + +#include "test_iterators.h" +#include "types.h" + +#include +namespace std +{ +namespace ranges +{ +using oneapi::dpl::ranges::zip_view; +} + +} + +namespace _std = oneapi::dpl::ranges; + +int buffer[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; +struct View : std::ranges::view_base { + std::size_t size_ = 0; + constexpr View(std::size_t s) : size_(s) {} + constexpr auto begin() const { return buffer; } + constexpr auto end() const { return buffer + size_; } +}; + +struct SizedNonConst : std::ranges::view_base { + using iterator = forward_iterator; + std::size_t size_ = 0; + constexpr SizedNonConst(std::size_t s) : size_(s) {} + constexpr auto begin() const { return iterator{buffer}; } + constexpr auto end() const { return iterator{buffer + size_}; } + constexpr std::size_t size() { return size_; } +}; + +struct StrangeSizeView : std::ranges::view_base { + constexpr auto begin() const { return buffer; } + constexpr auto end() const { return buffer + 8; } + + constexpr auto size() { return 5; } + constexpr auto size() const { return 6; } +}; + +constexpr bool test() { + { + // single range + std::ranges::zip_view v(View(8)); + assert(v.size() == 8); + assert(std::as_const(v).size() == 8); + } + + { + // multiple ranges same type + std::ranges::zip_view v(View(2), View(3)); + assert(v.size() == 2); + assert(std::as_const(v).size() == 2); + } + + { + // multiple ranges different types + std::ranges::zip_view v(std::views::iota(0, 500), View(3)); + assert(v.size() == 3); + assert(std::as_const(v).size() == 3); + } + + { + // const-view non-sized range + std::ranges::zip_view v(SizedNonConst(2), View(3)); + assert(v.size() == 2); + static_assert(std::ranges::sized_range); + static_assert(!std::ranges::sized_range); + } + + { + // const/non-const has different sizes + std::ranges::zip_view v(StrangeSizeView{}); + assert(v.size() == 5); + assert(std::as_const(v).size() == 6); + } + + { + // underlying range not sized + std::ranges::zip_view v(InputCommonView{buffer}); + static_assert(!std::ranges::sized_range); + static_assert(!std::ranges::sized_range); + } + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/test/parallel_api/ranges/range.zip/types.h b/test/parallel_api/ranges/range.zip/types.h new file mode 100644 index 00000000000..f312c2bdf8c --- /dev/null +++ b/test/parallel_api/ranges/range.zip/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_ZIP_TYPES_H +#define TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_ZIP_TYPES_H + +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" +#include "test_range.h" + +//#if TEST_STD_VER <= 20 +//# error "range.zip/types.h" can only be included in builds supporting C++20 +//#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_ZIP_TYPES_H diff --git a/test/support/double_move_tracker.h b/test/support/double_move_tracker.h new file mode 100644 index 00000000000..fac575d9df0 --- /dev/null +++ b/test/support/double_move_tracker.h @@ -0,0 +1,43 @@ +//===----------------------------------------------------------------------===// +// +// 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_SUPPORT_DOUBLE_MOVE_TRACKER_H +#define TEST_SUPPORT_DOUBLE_MOVE_TRACKER_H + +#include + +#include "test_macros.h" + +namespace support { + +struct double_move_tracker { + TEST_CONSTEXPR double_move_tracker() : moved_from_(false) {} + + double_move_tracker(double_move_tracker const&) = default; + + TEST_CONSTEXPR_CXX14 double_move_tracker(double_move_tracker&& other) : moved_from_(false) { + assert(!other.moved_from_); + other.moved_from_ = true; + } + + double_move_tracker& operator=(double_move_tracker const&) = default; + + TEST_CONSTEXPR_CXX14 double_move_tracker& operator=(double_move_tracker&& other) { + assert(!other.moved_from_); + other.moved_from_ = true; + moved_from_ = false; + return *this; + } + +private: + bool moved_from_; +}; + +} // namespace support + +#endif // TEST_SUPPORT_DOUBLE_MOVE_TRACKER_H diff --git a/test/support/test_iterators.h b/test/support/test_iterators.h index d52c20b1566..df1c69d583e 100644 --- a/test/support/test_iterators.h +++ b/test/support/test_iterators.h @@ -13,520 +13,1670 @@ // //===----------------------------------------------------------------------===// -#ifndef _TEST_ITERATORS_H -#define _TEST_ITERATORS_H +#ifndef SUPPORT_TEST_ITERATORS_H +#define SUPPORT_TEST_ITERATORS_H +#include +#include +#include #include -#include +#include +#include +#include +#include -#define DELETE_FUNCTION = delete +#include "double_move_tracker.h" +#include "test_macros.h" +#include "type_algorithms.h" + +// This iterator meets C++20's Cpp17OutputIterator requirements, as described +// in Table 90 ([output.iterators]). template -class output_iterator +class cpp17_output_iterator { It it_; + support::double_move_tracker tracker_; - template - friend class output_iterator; - - public: - typedef ::std::output_iterator_tag iterator_category; - typedef void value_type; - typedef typename ::std::iterator_traits::difference_type difference_type; - typedef typename ::std::iterator_traits::pointer pointer; - typedef typename ::std::iterator_traits::reference reference; + template friend class cpp17_output_iterator; +public: + typedef std::output_iterator_tag iterator_category; + typedef void value_type; + typedef typename std::iterator_traits::difference_type difference_type; + typedef It pointer; + typedef typename std::iterator_traits::reference reference; - It - base() const - { - return it_; - } + TEST_CONSTEXPR explicit cpp17_output_iterator(It it) : it_(std::move(it)) {} - output_iterator() {} - explicit output_iterator(It it) : it_(it) {} template - output_iterator(const output_iterator& u) : it_(u.it_) - { + TEST_CONSTEXPR cpp17_output_iterator(const cpp17_output_iterator& u) : it_(u.it_), tracker_(u.tracker_) {} + + template ::value>::type> + TEST_CONSTEXPR_CXX14 cpp17_output_iterator(cpp17_output_iterator&& u) + : it_(std::move(u.it_)), tracker_(std::move(u.tracker_)) { + u.it_ = U(); } - reference operator*() const { return *it_; } + TEST_CONSTEXPR reference operator*() const {return *it_;} - output_iterator& - operator++() - { - ++it_; - return *this; - } - output_iterator - operator++(int) - { - output_iterator tmp(*this); - ++(*this); - return tmp; - } + TEST_CONSTEXPR_CXX14 cpp17_output_iterator& operator++() {++it_; return *this;} + TEST_CONSTEXPR_CXX14 cpp17_output_iterator operator++(int) {return cpp17_output_iterator(it_++);} + + friend TEST_CONSTEXPR It base(const cpp17_output_iterator& i) { return i.it_; } template - void operator,(T const &) DELETE_FUNCTION; + void operator,(T const &) = delete; }; - +#if TEST_STD_VER > 14 template -class input_iterator +cpp17_output_iterator(It) -> cpp17_output_iterator; +#endif + +#if TEST_STD_VER > 17 + static_assert(std::output_iterator, int>); +#endif + +// This iterator meets C++20's Cpp17InputIterator requirements, as described +// in Table 89 ([input.iterators]). +template +class cpp17_input_iterator { + typedef std::iterator_traits Traits; It it_; + support::double_move_tracker tracker_; - template - friend class input_iterator; + template friend class cpp17_input_iterator; +public: + typedef std::input_iterator_tag iterator_category; + typedef typename Traits::value_type value_type; + typedef typename Traits::difference_type difference_type; + typedef It pointer; + typedef typename Traits::reference reference; - public: - typedef ::std::input_iterator_tag iterator_category; - typedef typename ::std::iterator_traits::value_type value_type; - typedef typename ::std::iterator_traits::difference_type difference_type; - typedef typename ::std::iterator_traits::pointer pointer; - typedef typename ::std::iterator_traits::reference reference; + TEST_CONSTEXPR explicit cpp17_input_iterator(It it) : it_(it) {} - constexpr It - base() const - { - return it_; - } + template + TEST_CONSTEXPR cpp17_input_iterator(const cpp17_input_iterator& u) : it_(u.it_), tracker_(u.tracker_) {} - constexpr input_iterator() : it_() {} - explicit constexpr input_iterator(It it) : it_(it) {} - template - constexpr input_iterator(const input_iterator& u) : it_(u.it_) - { + template ::value>::type> + TEST_CONSTEXPR_CXX14 cpp17_input_iterator(cpp17_input_iterator&& u) + : it_(std::move(u.it_)), tracker_(std::move(u.tracker_)) { + u.it_ = U(); } - constexpr reference operator*() const { return *it_; } - constexpr pointer operator->() const - { - if constexpr (::std::is_pointer_v) - { - return it_; - } - else - { - return it_.operator->(); - } - } + TEST_CONSTEXPR reference operator*() const {return *it_;} - constexpr input_iterator& - operator++() - { - ++it_; - return *this; - } - constexpr input_iterator - operator++(int) - { - input_iterator tmp(*this); - ++(*this); - return tmp; - } + TEST_CONSTEXPR_CXX14 cpp17_input_iterator& operator++() {++it_; return *this;} + TEST_CONSTEXPR_CXX14 cpp17_input_iterator operator++(int) {return cpp17_input_iterator(it_++);} - friend constexpr bool - operator==(const input_iterator& x, const input_iterator& y) - { - return x.it_ == y.it_; - } - friend constexpr bool - operator!=(const input_iterator& x, const input_iterator& y) - { - return !(x == y); - } + friend TEST_CONSTEXPR bool operator==(const cpp17_input_iterator& x, const cpp17_input_iterator& y) {return x.it_ == y.it_;} + friend TEST_CONSTEXPR bool operator!=(const cpp17_input_iterator& x, const cpp17_input_iterator& y) {return x.it_ != y.it_;} + + friend TEST_CONSTEXPR It base(const cpp17_input_iterator& i) { return i.it_; } template - void operator,(T const &) DELETE_FUNCTION; + void operator,(T const &) = delete; }; +#if TEST_STD_VER > 14 +template +cpp17_input_iterator(It) -> cpp17_input_iterator; +#endif -template -inline bool constexpr -operator==(const input_iterator& x, const input_iterator& y) -{ - return x.base() == y.base(); -} - -template -inline bool constexpr -operator!=(const input_iterator& x, const input_iterator& y) -{ - return !(x == y); -} +#if TEST_STD_VER > 17 + static_assert(std::input_iterator>); +#endif template class forward_iterator { It it_; + support::double_move_tracker tracker_; - template - friend class forward_iterator; + template friend class forward_iterator; +public: + typedef std::forward_iterator_tag iterator_category; + typedef typename std::iterator_traits::value_type value_type; + typedef typename std::iterator_traits::difference_type difference_type; + typedef It pointer; + typedef typename std::iterator_traits::reference reference; - public: - typedef ::std::forward_iterator_tag iterator_category; - typedef typename ::std::iterator_traits::value_type value_type; - typedef typename ::std::iterator_traits::difference_type difference_type; - typedef typename ::std::iterator_traits::pointer pointer; - typedef typename ::std::iterator_traits::reference reference; + TEST_CONSTEXPR forward_iterator() : it_() {} + TEST_CONSTEXPR explicit forward_iterator(It it) : it_(it) {} - constexpr It - base() const - { - return it_; + template + TEST_CONSTEXPR forward_iterator(const forward_iterator& u) : it_(u.it_), tracker_(u.tracker_) {} + + template ::value>::type> + TEST_CONSTEXPR_CXX14 forward_iterator(forward_iterator&& other) + : it_(std::move(other.it_)), tracker_(std::move(other.tracker_)) { + other.it_ = U(); } - constexpr forward_iterator() : it_() {} - explicit constexpr forward_iterator(It it) : it_(it) {} + TEST_CONSTEXPR reference operator*() const {return *it_;} + + TEST_CONSTEXPR_CXX14 forward_iterator& operator++() {++it_; return *this;} + TEST_CONSTEXPR_CXX14 forward_iterator operator++(int) {return forward_iterator(it_++);} + + friend TEST_CONSTEXPR bool operator==(const forward_iterator& x, const forward_iterator& y) {return x.it_ == y.it_;} + friend TEST_CONSTEXPR bool operator!=(const forward_iterator& x, const forward_iterator& y) {return x.it_ != y.it_;} + + friend TEST_CONSTEXPR It base(const forward_iterator& i) { return i.it_; } + + template + void operator,(T const &) = delete; +}; +#if TEST_STD_VER > 14 +template +forward_iterator(It) -> forward_iterator; +#endif + +template +class bidirectional_iterator +{ + It it_; + support::double_move_tracker tracker_; + + template friend class bidirectional_iterator; +public: + typedef std::bidirectional_iterator_tag iterator_category; + typedef typename std::iterator_traits::value_type value_type; + typedef typename std::iterator_traits::difference_type difference_type; + typedef It pointer; + typedef typename std::iterator_traits::reference reference; + + TEST_CONSTEXPR bidirectional_iterator() : it_() {} + TEST_CONSTEXPR explicit bidirectional_iterator(It it) : it_(it) {} + template - constexpr forward_iterator(const forward_iterator& u) : it_(u.it_) - { - } + TEST_CONSTEXPR bidirectional_iterator(const bidirectional_iterator& u) : it_(u.it_), tracker_(u.tracker_) {} - constexpr reference operator*() const { return *it_; } - constexpr pointer operator->() const - { - if constexpr (::std::is_pointer_v) - { - return it_; - } - else - { - return it_.operator->(); - } + template ::value>::type> + TEST_CONSTEXPR_CXX14 bidirectional_iterator(bidirectional_iterator&& u) + : it_(std::move(u.it_)), tracker_(std::move(u.tracker_)) { + u.it_ = U(); } - constexpr forward_iterator& - operator++() - { - ++it_; - return *this; - } - constexpr forward_iterator - operator++(int) - { - forward_iterator tmp(*this); - ++(*this); - return tmp; - } + TEST_CONSTEXPR reference operator*() const {return *it_;} - friend constexpr bool - operator==(const forward_iterator& x, const forward_iterator& y) - { - return x.it_ == y.it_; - } - friend constexpr bool - operator!=(const forward_iterator& x, const forward_iterator& y) - { - return !(x == y); - } + TEST_CONSTEXPR_CXX14 bidirectional_iterator& operator++() {++it_; return *this;} + TEST_CONSTEXPR_CXX14 bidirectional_iterator& operator--() {--it_; return *this;} + TEST_CONSTEXPR_CXX14 bidirectional_iterator operator++(int) {return bidirectional_iterator(it_++);} + TEST_CONSTEXPR_CXX14 bidirectional_iterator operator--(int) {return bidirectional_iterator(it_--);} + + friend TEST_CONSTEXPR bool operator==(const bidirectional_iterator& x, const bidirectional_iterator& y) {return x.it_ == y.it_;} + friend TEST_CONSTEXPR bool operator!=(const bidirectional_iterator& x, const bidirectional_iterator& y) {return x.it_ != y.it_;} + + friend TEST_CONSTEXPR It base(const bidirectional_iterator& i) { return i.it_; } template - void operator,(T const &) DELETE_FUNCTION; + void operator,(T const &) = delete; }; +#if TEST_STD_VER > 14 +template +bidirectional_iterator(It) -> bidirectional_iterator; +#endif -template -inline bool constexpr -operator==(const forward_iterator& x, const forward_iterator& y) +template +class random_access_iterator { - return x.base() == y.base(); -} + It it_; + support::double_move_tracker tracker_; -template -inline bool constexpr -operator!=(const forward_iterator& x, const forward_iterator& y) -{ - return !(x == y); -} + template friend class random_access_iterator; +public: + typedef std::random_access_iterator_tag iterator_category; + typedef typename std::iterator_traits::value_type value_type; + typedef typename std::iterator_traits::difference_type difference_type; + typedef It pointer; + typedef typename std::iterator_traits::reference reference; + + TEST_CONSTEXPR random_access_iterator() : it_() {} + TEST_CONSTEXPR explicit random_access_iterator(It it) : it_(it) {} + + template + TEST_CONSTEXPR random_access_iterator(const random_access_iterator& u) : it_(u.it_), tracker_(u.tracker_) {} + + template ::value>::type> + TEST_CONSTEXPR_CXX14 random_access_iterator(random_access_iterator&& u) + : it_(std::move(u.it_)), tracker_(std::move(u.tracker_)) { + u.it_ = U(); + } + TEST_CONSTEXPR_CXX14 reference operator*() const {return *it_;} + TEST_CONSTEXPR_CXX14 reference operator[](difference_type n) const {return it_[n];} + + TEST_CONSTEXPR_CXX14 random_access_iterator& operator++() {++it_; return *this;} + TEST_CONSTEXPR_CXX14 random_access_iterator& operator--() {--it_; return *this;} + TEST_CONSTEXPR_CXX14 random_access_iterator operator++(int) {return random_access_iterator(it_++);} + TEST_CONSTEXPR_CXX14 random_access_iterator operator--(int) {return random_access_iterator(it_--);} + + TEST_CONSTEXPR_CXX14 random_access_iterator& operator+=(difference_type n) {it_ += n; return *this;} + TEST_CONSTEXPR_CXX14 random_access_iterator& operator-=(difference_type n) {it_ -= n; return *this;} + friend TEST_CONSTEXPR_CXX14 random_access_iterator operator+(random_access_iterator x, difference_type n) {x += n; return x;} + friend TEST_CONSTEXPR_CXX14 random_access_iterator operator+(difference_type n, random_access_iterator x) {x += n; return x;} + friend TEST_CONSTEXPR_CXX14 random_access_iterator operator-(random_access_iterator x, difference_type n) {x -= n; return x;} + friend TEST_CONSTEXPR difference_type operator-(random_access_iterator x, random_access_iterator y) {return x.it_ - y.it_;} + + friend TEST_CONSTEXPR bool operator==(const random_access_iterator& x, const random_access_iterator& y) {return x.it_ == y.it_;} + friend TEST_CONSTEXPR bool operator!=(const random_access_iterator& x, const random_access_iterator& y) {return x.it_ != y.it_;} + friend TEST_CONSTEXPR bool operator< (const random_access_iterator& x, const random_access_iterator& y) {return x.it_ < y.it_;} + friend TEST_CONSTEXPR bool operator<=(const random_access_iterator& x, const random_access_iterator& y) {return x.it_ <= y.it_;} + friend TEST_CONSTEXPR bool operator> (const random_access_iterator& x, const random_access_iterator& y) {return x.it_ > y.it_;} + friend TEST_CONSTEXPR bool operator>=(const random_access_iterator& x, const random_access_iterator& y) {return x.it_ >= y.it_;} + + friend TEST_CONSTEXPR It base(const random_access_iterator& i) { return i.it_; } + + template + void operator,(T const &) = delete; +}; +#if TEST_STD_VER > 14 template -class bidirectional_iterator +random_access_iterator(It) -> random_access_iterator; +#endif + +#if TEST_STD_VER > 17 + +template +class cpp20_random_access_iterator { + It it_; + support::double_move_tracker tracker_; + + template + friend class cpp20_random_access_iterator; + +public: + using iterator_category = std::input_iterator_tag; + using iterator_concept = std::random_access_iterator_tag; + using value_type = typename std::iterator_traits::value_type; + using difference_type = typename std::iterator_traits::difference_type; + + constexpr cpp20_random_access_iterator() : it_() {} + constexpr explicit cpp20_random_access_iterator(It it) : it_(it) {} + + template + constexpr cpp20_random_access_iterator(const cpp20_random_access_iterator& u) : it_(u.it_), tracker_(u.tracker_) {} + + template + constexpr cpp20_random_access_iterator(cpp20_random_access_iterator&& u) + : it_(std::move(u.it_)), tracker_(std::move(u.tracker_)) { + u.it_ = U(); + } + + constexpr decltype(auto) operator*() const { return *it_; } + constexpr decltype(auto) operator[](difference_type n) const { return it_[n]; } + + constexpr cpp20_random_access_iterator& operator++() { + ++it_; + return *this; + } + constexpr cpp20_random_access_iterator& operator--() { + --it_; + return *this; + } + constexpr cpp20_random_access_iterator operator++(int) { return cpp20_random_access_iterator(it_++); } + constexpr cpp20_random_access_iterator operator--(int) { return cpp20_random_access_iterator(it_--); } + + constexpr cpp20_random_access_iterator& operator+=(difference_type n) { + it_ += n; + return *this; + } + constexpr cpp20_random_access_iterator& operator-=(difference_type n) { + it_ -= n; + return *this; + } + friend constexpr cpp20_random_access_iterator operator+(cpp20_random_access_iterator x, difference_type n) { + x += n; + return x; + } + friend constexpr cpp20_random_access_iterator operator+(difference_type n, cpp20_random_access_iterator x) { + x += n; + return x; + } + friend constexpr cpp20_random_access_iterator operator-(cpp20_random_access_iterator x, difference_type n) { + x -= n; + return x; + } + friend constexpr difference_type operator-(cpp20_random_access_iterator x, cpp20_random_access_iterator y) { + return x.it_ - y.it_; + } + + friend constexpr bool operator==(const cpp20_random_access_iterator& x, const cpp20_random_access_iterator& y) { + return x.it_ == y.it_; + } + friend constexpr bool operator!=(const cpp20_random_access_iterator& x, const cpp20_random_access_iterator& y) { + return x.it_ != y.it_; + } + friend constexpr bool operator<(const cpp20_random_access_iterator& x, const cpp20_random_access_iterator& y) { + return x.it_ < y.it_; + } + friend constexpr bool operator<=(const cpp20_random_access_iterator& x, const cpp20_random_access_iterator& y) { + return x.it_ <= y.it_; + } + friend constexpr bool operator>(const cpp20_random_access_iterator& x, const cpp20_random_access_iterator& y) { + return x.it_ > y.it_; + } + friend constexpr bool operator>=(const cpp20_random_access_iterator& x, const cpp20_random_access_iterator& y) { + return x.it_ >= y.it_; + } + + friend constexpr It base(const cpp20_random_access_iterator& i) { return i.it_; } + + template + void operator,(T const&) = delete; +}; +template +cpp20_random_access_iterator(It) -> cpp20_random_access_iterator; + +static_assert(std::random_access_iterator>); + +template +class contiguous_iterator { + It it_; + support::double_move_tracker tracker_; + + template + friend class contiguous_iterator; + +public: + using iterator_category = std::contiguous_iterator_tag; + using value_type = typename std::iterator_traits::value_type; + using difference_type = typename std::iterator_traits::difference_type; + using pointer = typename std::iterator_traits::pointer; + using reference = typename std::iterator_traits::reference; + using element_type = value_type; + + constexpr It base() const { return it_; } + + constexpr contiguous_iterator() : it_() {} + constexpr explicit contiguous_iterator(It it) : it_(it) {} + + template + constexpr contiguous_iterator(const contiguous_iterator& u) : it_(u.it_), tracker_(u.tracker_) {} + + template ::value>::type> + constexpr contiguous_iterator(contiguous_iterator&& u) : it_(std::move(u.it_)), tracker_(std::move(u.tracker_)) { + u.it_ = U(); + } + + constexpr reference operator*() const { return *it_; } + constexpr pointer operator->() const { return it_; } + constexpr reference operator[](difference_type n) const { return it_[n]; } + + constexpr contiguous_iterator& operator++() { + ++it_; + return *this; + } + constexpr contiguous_iterator& operator--() { + --it_; + return *this; + } + constexpr contiguous_iterator operator++(int) { return contiguous_iterator(it_++); } + constexpr contiguous_iterator operator--(int) { return contiguous_iterator(it_--); } + + constexpr contiguous_iterator& operator+=(difference_type n) { + it_ += n; + return *this; + } + constexpr contiguous_iterator& operator-=(difference_type n) { + it_ -= n; + return *this; + } + friend constexpr contiguous_iterator operator+(contiguous_iterator x, difference_type n) { + x += n; + return x; + } + friend constexpr contiguous_iterator operator+(difference_type n, contiguous_iterator x) { + x += n; + return x; + } + friend constexpr contiguous_iterator operator-(contiguous_iterator x, difference_type n) { + x -= n; + return x; + } + friend constexpr difference_type operator-(contiguous_iterator x, contiguous_iterator y) { return x.it_ - y.it_; } + + friend constexpr bool operator==(const contiguous_iterator& x, const contiguous_iterator& y) { + return x.it_ == y.it_; + } + friend constexpr bool operator!=(const contiguous_iterator& x, const contiguous_iterator& y) { + return x.it_ != y.it_; + } + friend constexpr bool operator<(const contiguous_iterator& x, const contiguous_iterator& y) { return x.it_ < y.it_; } + friend constexpr bool operator<=(const contiguous_iterator& x, const contiguous_iterator& y) { + return x.it_ <= y.it_; + } + friend constexpr bool operator>(const contiguous_iterator& x, const contiguous_iterator& y) { return x.it_ > y.it_; } + friend constexpr bool operator>=(const contiguous_iterator& x, const contiguous_iterator& y) { + return x.it_ >= y.it_; + } + + // Note no operator<=>, use three_way_contiguous_iterator for testing operator<=> + + friend constexpr It base(const contiguous_iterator& i) { return i.it_; } + + template + void operator,(T const&) = delete; +}; +template +contiguous_iterator(It) -> contiguous_iterator; + +template +class three_way_contiguous_iterator { + static_assert(std::is_pointer_v, "Things probably break in this case"); + It it_; + support::double_move_tracker tracker_; - template - friend class bidirectional_iterator; + template friend class three_way_contiguous_iterator; +public: + typedef std::contiguous_iterator_tag iterator_category; + typedef typename std::iterator_traits::value_type value_type; + typedef typename std::iterator_traits::difference_type difference_type; + typedef It pointer; + typedef typename std::iterator_traits::reference reference; + typedef typename std::remove_pointer::type element_type; - public: - typedef ::std::bidirectional_iterator_tag iterator_category; - typedef typename ::std::iterator_traits::value_type value_type; - typedef typename ::std::iterator_traits::difference_type difference_type; - typedef typename ::std::iterator_traits::pointer pointer; - typedef typename ::std::iterator_traits::reference reference; + constexpr It base() const {return it_;} - constexpr It - base() const - { - return it_; - } + constexpr three_way_contiguous_iterator() : it_() {} + constexpr explicit three_way_contiguous_iterator(It it) : it_(it) {} - constexpr bidirectional_iterator() : it_() {} - explicit constexpr bidirectional_iterator(It it) : it_(it) {} template - constexpr bidirectional_iterator(const bidirectional_iterator& u) : it_(u.it_) - { + constexpr three_way_contiguous_iterator(const three_way_contiguous_iterator& u) + : it_(u.it_), tracker_(u.tracker_) {} + + template ::value>::type> + constexpr three_way_contiguous_iterator(three_way_contiguous_iterator&& u) + : it_(std::move(u.it_)), tracker_(std::move(u.tracker_)) { + u.it_ = U(); } - constexpr reference operator*() const { return *it_; } - constexpr pointer operator->() const - { - if constexpr (::std::is_pointer_v) - { - return it_; + constexpr reference operator*() const {return *it_;} + constexpr pointer operator->() const {return it_;} + constexpr reference operator[](difference_type n) const {return it_[n];} + + constexpr three_way_contiguous_iterator& operator++() {++it_; return *this;} + constexpr three_way_contiguous_iterator& operator--() {--it_; return *this;} + constexpr three_way_contiguous_iterator operator++(int) {return three_way_contiguous_iterator(it_++);} + constexpr three_way_contiguous_iterator operator--(int) {return three_way_contiguous_iterator(it_--);} + + constexpr three_way_contiguous_iterator& operator+=(difference_type n) {it_ += n; return *this;} + constexpr three_way_contiguous_iterator& operator-=(difference_type n) {it_ -= n; return *this;} + friend constexpr three_way_contiguous_iterator operator+(three_way_contiguous_iterator x, difference_type n) {x += n; return x;} + friend constexpr three_way_contiguous_iterator operator+(difference_type n, three_way_contiguous_iterator x) {x += n; return x;} + friend constexpr three_way_contiguous_iterator operator-(three_way_contiguous_iterator x, difference_type n) {x -= n; return x;} + friend constexpr difference_type operator-(three_way_contiguous_iterator x, three_way_contiguous_iterator y) {return x.it_ - y.it_;} + + friend constexpr auto operator<=>(const three_way_contiguous_iterator& x, const three_way_contiguous_iterator& y) {return x.it_ <=> y.it_;} + friend constexpr bool operator==(const three_way_contiguous_iterator& x, const three_way_contiguous_iterator& y) {return x.it_ == y.it_;} + + template + void operator,(T const &) = delete; +}; +template +three_way_contiguous_iterator(It) -> three_way_contiguous_iterator; +#endif // TEST_STD_VER > 17 + +template // ADL base() for everything else (including pointers) +TEST_CONSTEXPR Iter base(Iter i) { return i; } + +template +struct ThrowingIterator { + typedef std::bidirectional_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + typedef const T value_type; + typedef const T * pointer; + typedef const T & reference; + + enum ThrowingAction { TAIncrement, TADecrement, TADereference, TAAssignment, TAComparison }; + + TEST_CONSTEXPR ThrowingIterator() + : begin_(nullptr), end_(nullptr), current_(nullptr), action_(TADereference), index_(0) {} + TEST_CONSTEXPR explicit ThrowingIterator(const T* first, const T* last, int index = 0, + ThrowingAction action = TADereference) + : begin_(first), end_(last), current_(first), action_(action), index_(index) {} + TEST_CONSTEXPR ThrowingIterator(const ThrowingIterator &rhs) + : begin_(rhs.begin_), end_(rhs.end_), current_(rhs.current_), action_(rhs.action_), index_(rhs.index_) {} + + TEST_CONSTEXPR_CXX14 ThrowingIterator& operator=(const ThrowingIterator& rhs) { + if (action_ == TAAssignment && --index_ < 0) { +#ifndef TEST_HAS_NO_EXCEPTIONS + throw std::runtime_error("throw from iterator assignment"); +#else + assert(false); +#endif } - else - { - return it_.operator->(); + begin_ = rhs.begin_; + end_ = rhs.end_; + current_ = rhs.current_; + action_ = rhs.action_; + index_ = rhs.index_; + return *this; + } + + TEST_CONSTEXPR_CXX14 reference operator*() const { + if (action_ == TADereference && --index_ < 0) { +#ifndef TEST_HAS_NO_EXCEPTIONS + throw std::runtime_error("throw from iterator dereference"); +#else + assert(false); +#endif } + return *current_; } - constexpr bidirectional_iterator& - operator++() - { - ++it_; + TEST_CONSTEXPR_CXX14 ThrowingIterator& operator++() { + if (action_ == TAIncrement && --index_ < 0) { +#ifndef TEST_HAS_NO_EXCEPTIONS + throw std::runtime_error("throw from iterator increment"); +#else + assert(false); +#endif + } + ++current_; return *this; } - constexpr bidirectional_iterator - operator++(int) - { - bidirectional_iterator tmp(*this); + + TEST_CONSTEXPR_CXX14 ThrowingIterator operator++(int) { + ThrowingIterator temp = *this; ++(*this); - return tmp; + return temp; } - constexpr bidirectional_iterator& - operator--() - { - --it_; + TEST_CONSTEXPR_CXX14 ThrowingIterator& operator--() { + if (action_ == TADecrement && --index_ < 0) { +#ifndef TEST_HAS_NO_EXCEPTIONS + throw std::runtime_error("throw from iterator decrement"); +#else + assert(false); +#endif + } + --current_; return *this; } - constexpr bidirectional_iterator - operator--(int) - { - bidirectional_iterator tmp(*this); + + TEST_CONSTEXPR_CXX14 ThrowingIterator operator--(int) { + ThrowingIterator temp = *this; --(*this); - return tmp; + return temp; } - friend constexpr bool operator==(const bidirectional_iterator& x, const bidirectional_iterator& y) - {return x.it_ == y.it_;} - friend constexpr bool operator!=(const bidirectional_iterator& x, const bidirectional_iterator& y) - {return !(x == y);} + TEST_CONSTEXPR_CXX14 friend bool operator==(const ThrowingIterator& a, const ThrowingIterator& b) { + if (a.action_ == TAComparison && --a.index_ < 0) { +#ifndef TEST_HAS_NO_EXCEPTIONS + throw std::runtime_error("throw from iterator comparison"); +#else + assert(false); +#endif + } + bool atEndL = a.current_ == a.end_; + bool atEndR = b.current_ == b.end_; + if (atEndL != atEndR) return false; // one is at the end (or empty), the other is not. + if (atEndL) return true; // both are at the end (or empty) + return a.current_ == b.current_; + } - template - void operator,(T const &) DELETE_FUNCTION; + TEST_CONSTEXPR friend bool operator!=(const ThrowingIterator& a, const ThrowingIterator& b) { + return !(a == b); + } + + template + void operator,(T2 const &) = delete; + +private: + const T* begin_; + const T* end_; + const T* current_; + ThrowingAction action_; + mutable int index_; }; -template -inline bool constexpr -operator==(const bidirectional_iterator& x, const bidirectional_iterator& y) -{ - return x.base() == y.base(); -} +template +struct NonThrowingIterator { + typedef std::bidirectional_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + typedef const T value_type; + typedef const T * pointer; + typedef const T & reference; + + NonThrowingIterator() + : begin_(nullptr), end_(nullptr), current_(nullptr) {} + explicit NonThrowingIterator(const T *first, const T *last) + : begin_(first), end_(last), current_(first) {} + NonThrowingIterator(const NonThrowingIterator& rhs) + : begin_(rhs.begin_), end_(rhs.end_), current_(rhs.current_) {} + + NonThrowingIterator& operator=(const NonThrowingIterator& rhs) TEST_NOEXCEPT { + begin_ = rhs.begin_; + end_ = rhs.end_; + current_ = rhs.current_; + return *this; + } -template -inline bool constexpr -operator!=(const bidirectional_iterator& x, const bidirectional_iterator& y) -{ - return !(x == y); -} + reference operator*() const TEST_NOEXCEPT { + return *current_; + } + + NonThrowingIterator& operator++() TEST_NOEXCEPT { + ++current_; + return *this; + } + + NonThrowingIterator operator++(int) TEST_NOEXCEPT { + NonThrowingIterator temp = *this; + ++(*this); + return temp; + } + + NonThrowingIterator & operator--() TEST_NOEXCEPT { + --current_; + return *this; + } + + NonThrowingIterator operator--(int) TEST_NOEXCEPT { + NonThrowingIterator temp = *this; + --(*this); + return temp; + } + + friend bool operator==(const NonThrowingIterator& a, const NonThrowingIterator& b) TEST_NOEXCEPT { + bool atEndL = a.current_ == a.end_; + bool atEndR = b.current_ == b.end_; + if (atEndL != atEndR) return false; // one is at the end (or empty), the other is not. + if (atEndL) return true; // both are at the end (or empty) + return a.current_ == b.current_; + } + + friend bool operator!=(const NonThrowingIterator& a, const NonThrowingIterator& b) TEST_NOEXCEPT { + return !(a == b); + } + + template + void operator,(T2 const &) = delete; + +private: + const T *begin_; + const T *end_; + const T *current_; +}; + +#if TEST_STD_VER > 17 template -class random_access_iterator +class cpp20_input_iterator { It it_; + support::double_move_tracker tracker_; - template - friend class random_access_iterator; +public: + using value_type = std::iter_value_t; + using difference_type = std::iter_difference_t; + using iterator_concept = std::input_iterator_tag; + + constexpr explicit cpp20_input_iterator(It it) : it_(it) {} + cpp20_input_iterator(cpp20_input_iterator&&) = default; + cpp20_input_iterator& operator=(cpp20_input_iterator&&) = default; + constexpr decltype(auto) operator*() const { return *it_; } + constexpr cpp20_input_iterator& operator++() { ++it_; return *this; } + constexpr void operator++(int) { ++it_; } + + friend constexpr It base(const cpp20_input_iterator& i) { return i.it_; } + + template + void operator,(T const &) = delete; +}; +template +cpp20_input_iterator(It) -> cpp20_input_iterator; + +static_assert(std::input_iterator>); + +template +struct iter_value_or_void { using type = void; }; + +template +struct iter_value_or_void { + using type = std::iter_value_t; +}; + +template +class cpp20_output_iterator { + It it_; + support::double_move_tracker tracker_; + +public: + using difference_type = std::iter_difference_t; + + constexpr explicit cpp20_output_iterator(It it) : it_(it) {} + cpp20_output_iterator(cpp20_output_iterator&&) = default; + cpp20_output_iterator& operator=(cpp20_output_iterator&&) = default; + + constexpr decltype(auto) operator*() const { return *it_; } + constexpr cpp20_output_iterator& operator++() { + ++it_; + return *this; + } + constexpr cpp20_output_iterator operator++(int) { return cpp20_output_iterator(it_++); } + + friend constexpr It base(const cpp20_output_iterator& i) { return i.it_; } + + template + void operator,(T const&) = delete; +}; +template +cpp20_output_iterator(It) -> cpp20_output_iterator; - public: - typedef ::std::random_access_iterator_tag iterator_category; - typedef typename ::std::iterator_traits::value_type value_type; - typedef typename ::std::iterator_traits::difference_type difference_type; - typedef typename ::std::iterator_traits::pointer pointer; - typedef typename ::std::iterator_traits::reference reference; +static_assert(std::output_iterator, int>); - constexpr It - base() const +# if TEST_STD_VER >= 20 + +// An `input_iterator` that can be used in a `std::ranges::common_range` +template +struct common_input_iterator { + Base it_; + + using value_type = std::iter_value_t; + using difference_type = std::intptr_t; + using iterator_concept = std::input_iterator_tag; + + constexpr common_input_iterator() = default; + constexpr explicit common_input_iterator(Base it) : it_(it) {} + + constexpr common_input_iterator& operator++() { + ++it_; + return *this; + } + constexpr void operator++(int) { ++it_; } + + constexpr decltype(auto) operator*() const { return *it_; } + + friend constexpr bool operator==(common_input_iterator const&, common_input_iterator const&) = default; +}; + +# endif // TEST_STD_VER >= 20 + +struct IteratorOpCounts { + std::size_t increments = 0; ///< Number of times the iterator moved forward (++it, it++, it+=positive, it-=negative). + std::size_t decrements = 0; ///< Number of times the iterator moved backward (--it, it--, it-=positive, it+=negative). + std::size_t zero_moves = 0; ///< Number of times a call was made to move the iterator by 0 positions (it+=0, it-=0). + std::size_t equal_cmps = 0; ///< Total number of calls to op== or op!=. If compared against a sentinel object, that + /// sentinel object must call the `record_equality_comparison` function so that the + /// comparison is counted correctly. +}; + +// Iterator adaptor that records its operation counts in a IteratorOpCounts +template +class operation_counting_iterator { +public: + using value_type = typename iter_value_or_void::type; + using difference_type = std::iter_difference_t; + using iterator_concept = + std::conditional_t, std::contiguous_iterator_tag, + std::conditional_t, std::random_access_iterator_tag, + std::conditional_t, std::bidirectional_iterator_tag, + std::conditional_t, std::forward_iterator_tag, + std::conditional_t, std::input_iterator_tag, + /* else */ std::output_iterator_tag + >>>>>; + using iterator_category = iterator_concept; + + operation_counting_iterator() + requires std::default_initializable + = default; + + constexpr explicit operation_counting_iterator(It const& it, IteratorOpCounts* counts = nullptr) + : base_(base(it)), counts_(counts) {} + + constexpr operation_counting_iterator(const operation_counting_iterator& o) { *this = o; } + constexpr operation_counting_iterator(operation_counting_iterator&& o) { *this = o; } + + constexpr operation_counting_iterator& operator=(const operation_counting_iterator& o) = default; + constexpr operation_counting_iterator& operator=(operation_counting_iterator&& o) { return *this = o; } + + friend constexpr It base(operation_counting_iterator const& it) { return It(it.base_); } + + constexpr decltype(auto) operator*() const { return *It(base_); } + + constexpr decltype(auto) operator[](difference_type n) const { return It(base_)[n]; } + + constexpr operation_counting_iterator& operator++() { + It tmp(base_); + base_ = base(++tmp); + moved_by(1); + return *this; + } + + constexpr void operator++(int) { ++*this; } + + constexpr operation_counting_iterator operator++(int) + requires std::forward_iterator { - return it_; + auto temp = *this; + ++*this; + return temp; } - constexpr random_access_iterator() : it_() {} - explicit constexpr random_access_iterator(It it) : it_(it) {} - template - constexpr random_access_iterator(const random_access_iterator& u) : it_(u.it_) + constexpr operation_counting_iterator& operator--() + requires std::bidirectional_iterator { + It tmp(base_); + base_ = base(--tmp); + moved_by(-1); + return *this; } - constexpr reference operator*() const { return *it_; } - constexpr pointer operator->() const + constexpr operation_counting_iterator operator--(int) + requires std::bidirectional_iterator { - if constexpr (::std::is_pointer_v) - { - return it_; - } - else - { - return it_.operator->(); - } + auto temp = *this; + --*this; + return temp; } - constexpr random_access_iterator& - operator++() + constexpr operation_counting_iterator& operator+=(difference_type const n) + requires std::random_access_iterator { - ++it_; - return *this; + It tmp(base_); + base_ = base(tmp += n); + moved_by(n); + return *this; } - constexpr random_access_iterator - operator++(int) + + constexpr operation_counting_iterator& operator-=(difference_type const n) + requires std::random_access_iterator { - random_access_iterator tmp(*this); - ++(*this); - return tmp; + It tmp(base_); + base_ = base(tmp -= n); + moved_by(-n); + return *this; } - constexpr random_access_iterator& - operator--() + friend constexpr operation_counting_iterator operator+(operation_counting_iterator it, difference_type n) + requires std::random_access_iterator { - --it_; - return *this; + return it += n; } - constexpr random_access_iterator - operator--(int) + + friend constexpr operation_counting_iterator operator+(difference_type n, operation_counting_iterator it) + requires std::random_access_iterator { - random_access_iterator tmp(*this); - --(*this); - return tmp; + return it += n; } - constexpr random_access_iterator& - operator+=(difference_type n) + friend constexpr operation_counting_iterator operator-(operation_counting_iterator it, difference_type n) + requires std::random_access_iterator { - it_ += n; - return *this; + return it -= n; } - constexpr random_access_iterator - operator+(difference_type n) const + + friend constexpr difference_type + operator-(operation_counting_iterator const& x, operation_counting_iterator const& y) + requires std::sized_sentinel_for { - random_access_iterator tmp(*this); - tmp += n; - return tmp; + return base(x) - base(y); } - friend constexpr random_access_iterator - operator+(difference_type n, random_access_iterator x) + + constexpr void record_equality_comparison() const { + if (counts_ != nullptr) + ++counts_->equal_cmps; + } + + constexpr bool operator==(operation_counting_iterator const& other) const + requires std::sentinel_for { - x += n; - return x; + record_equality_comparison(); + return It(base_) == It(other.base_); } - constexpr random_access_iterator& - operator-=(difference_type n) + + friend constexpr bool operator<(operation_counting_iterator const& x, operation_counting_iterator const& y) + requires std::random_access_iterator { - return *this += -n; + return It(x.base_) < It(y.base_); } - constexpr random_access_iterator - operator-(difference_type n) const + + friend constexpr bool operator>(operation_counting_iterator const& x, operation_counting_iterator const& y) + requires std::random_access_iterator { - random_access_iterator tmp(*this); - tmp -= n; - return tmp; + return It(x.base_) > It(y.base_); } - constexpr reference operator[](difference_type n) const { return it_[n]; } + friend constexpr bool operator<=(operation_counting_iterator const& x, operation_counting_iterator const& y) + requires std::random_access_iterator + { + return It(x.base_) <= It(y.base_); + } + + friend constexpr bool operator>=(operation_counting_iterator const& x, operation_counting_iterator const& y) + requires std::random_access_iterator + { + return It(x.base_) >= It(y.base_); + } template - void operator,(T const &) DELETE_FUNCTION; + void operator,(T const &) = delete; + +private: + constexpr void moved_by(difference_type n) { + if (counts_ == nullptr) + return; + if (n > 0) + ++counts_->increments; + else if (n < 0) + ++counts_->decrements; + else + ++counts_->zero_moves; + } + + decltype(base(std::declval())) base_; + IteratorOpCounts* counts_ = nullptr; }; +template +operation_counting_iterator(It) -> operation_counting_iterator; -template -inline bool constexpr -operator==(const random_access_iterator& x, const random_access_iterator& y) -{ - return x.base() == y.base(); -} +#endif // TEST_STD_VER > 17 -template -inline bool constexpr -operator!=(const random_access_iterator& x, const random_access_iterator& y) -{ - return !(x == y); -} +#if TEST_STD_VER > 17 +template +class sentinel_wrapper { +public: + explicit sentinel_wrapper() = default; + constexpr explicit sentinel_wrapper(const It& it) : base_(base(it)) {} + constexpr bool operator==(const It& other) const { + // If supported, record statistics about the equality operator call + // inside `other`. + if constexpr (requires { other.record_equality_comparison(); }) { + other.record_equality_comparison(); + } + return base_ == base(other); + } + friend constexpr It base(const sentinel_wrapper& s) { return It(s.base_); } +private: + decltype(base(std::declval())) base_; +}; +template +sentinel_wrapper(It) -> sentinel_wrapper; -template -inline bool constexpr -operator<(const random_access_iterator& x, const random_access_iterator& y) -{ - return x.base() < y.base(); -} +template +class sized_sentinel { +public: + explicit sized_sentinel() = default; + constexpr explicit sized_sentinel(const It& it) : base_(base(it)) {} + constexpr bool operator==(const It& other) const { return base_ == base(other); } + friend constexpr auto operator-(const sized_sentinel& s, const It& i) { return s.base_ - base(i); } + friend constexpr auto operator-(const It& i, const sized_sentinel& s) { return base(i) - s.base_; } + friend constexpr It base(const sized_sentinel& s) { return It(s.base_); } +private: + decltype(base(std::declval())) base_; +}; +template +sized_sentinel(It) -> sized_sentinel; + +namespace adl { + +class Iterator { + public: + using value_type = int; + using reference = int&; + using difference_type = std::ptrdiff_t; + + private: + value_type* ptr_ = nullptr; + int* iter_moves_ = nullptr; + int* iter_swaps_ = nullptr; + + constexpr Iterator(int* p, int* iter_moves, int* iter_swaps) + : ptr_(p) + , iter_moves_(iter_moves) + , iter_swaps_(iter_swaps) {} + + public: + constexpr Iterator() = default; + static constexpr Iterator TrackMoves(int* p, int& iter_moves) { + return Iterator(p, &iter_moves, /*iter_swaps=*/nullptr); + } + static constexpr Iterator TrackSwaps(int& iter_swaps) { + return Iterator(/*p=*/nullptr, /*iter_moves=*/nullptr, &iter_swaps); + } + static constexpr Iterator TrackSwaps(int* p, int& iter_swaps) { + return Iterator(p, /*iter_moves=*/nullptr, &iter_swaps); + } + + constexpr int iter_moves() const { assert(iter_moves_); return *iter_moves_; } + constexpr int iter_swaps() const { assert(iter_swaps_); return *iter_swaps_; } + + constexpr value_type& operator*() const { return *ptr_; } + constexpr reference operator[](difference_type n) const { return ptr_[n]; } + + friend constexpr Iterator operator+(Iterator i, difference_type n) { + return Iterator(i.ptr_ + n, i.iter_moves_, i.iter_swaps_); + } + friend constexpr Iterator operator+(difference_type n, Iterator i) { + return i + n; + } + constexpr Iterator operator-(difference_type n) const { + return Iterator(ptr_ - n, iter_moves_, iter_swaps_); + } + constexpr difference_type operator-(Iterator rhs) const { + return ptr_ - rhs.ptr_; + } + constexpr Iterator& operator+=(difference_type n) { + ptr_ += n; + return *this; + } + constexpr Iterator& operator-=(difference_type n) { + ptr_ -= n; + return *this; + } + + constexpr Iterator& operator++() { ++ptr_; return *this; } + constexpr Iterator operator++(int) { + Iterator prev = *this; + ++ptr_; + return prev; + } + + constexpr Iterator& operator--() { --ptr_; return *this; } + constexpr Iterator operator--(int) { + Iterator prev = *this; + --ptr_; + return prev; + } + + constexpr friend void iter_swap(Iterator a, Iterator b) { + std::swap(a.ptr_, b.ptr_); + if (a.iter_swaps_) { + ++(*a.iter_swaps_); + } + } -template -inline bool constexpr -operator<=(const random_access_iterator& x, const random_access_iterator& y) -{ - return !(y < x); -} + constexpr friend value_type&& iter_move(Iterator iter) { + if (iter.iter_moves_) { + ++(*iter.iter_moves_); + } + return std::move(*iter); + } + + constexpr friend bool operator==(const Iterator& lhs, const Iterator& rhs) { + return lhs.ptr_ == rhs.ptr_; + } + constexpr friend auto operator<=>(const Iterator& lhs, const Iterator& rhs) { + return lhs.ptr_ <=> rhs.ptr_; + } +}; -template -inline bool constexpr -operator>(const random_access_iterator& x, const random_access_iterator& y) -{ - return y < x; -} +} // namespace adl + +template +class rvalue_iterator { +public: + using iterator_category = std::input_iterator_tag; + using iterator_concept = std::random_access_iterator_tag; + using difference_type = std::ptrdiff_t; + using reference = T&&; + using value_type = T; + + rvalue_iterator() = default; + constexpr rvalue_iterator(T* it) : it_(it) {} + + constexpr reference operator*() const { return std::move(*it_); } + + constexpr rvalue_iterator& operator++() { + ++it_; + return *this; + } + + constexpr rvalue_iterator operator++(int) { + auto tmp = *this; + ++it_; + return tmp; + } + + constexpr rvalue_iterator& operator--() { + --it_; + return *this; + } + + constexpr rvalue_iterator operator--(int) { + auto tmp = *this; + --it_; + return tmp; + } + + constexpr rvalue_iterator operator+(difference_type n) const { + auto tmp = *this; + tmp.it += n; + return tmp; + } + + constexpr friend rvalue_iterator operator+(difference_type n, rvalue_iterator iter) { + iter += n; + return iter; + } + + constexpr rvalue_iterator operator-(difference_type n) const { + auto tmp = *this; + tmp.it -= n; + return tmp; + } + + constexpr difference_type operator-(const rvalue_iterator& other) const { return it_ - other.it_; } + + constexpr rvalue_iterator& operator+=(difference_type n) { + it_ += n; + return *this; + } + + constexpr rvalue_iterator& operator-=(difference_type n) { + it_ -= n; + return *this; + } + + constexpr reference operator[](difference_type n) const { return std::move(it_[n]); } + + auto operator<=>(const rvalue_iterator&) const noexcept = default; + +private: + T* it_; +}; -template -inline bool constexpr -operator>=(const random_access_iterator& x, const random_access_iterator& y) -{ - return !(x < y); -} +template +rvalue_iterator(T*) -> rvalue_iterator; + +static_assert(std::random_access_iterator>); + +// Proxy +// ====================================================================== +// Proxy that can wrap a value or a reference. It simulates C++23's tuple +// but simplified to just hold one argument. +// Note that unlike tuple, this class deliberately doesn't have special handling +// of swap to cause a compilation error if it's used in an algorithm that relies +// on plain swap instead of ranges::iter_swap. +// This class is useful for testing that if algorithms support proxy iterator +// properly, i.e. calling ranges::iter_swap and ranges::iter_move instead of +// plain swap and std::move. +template +struct Proxy; + +template +inline constexpr bool IsProxy = false; + +template +inline constexpr bool IsProxy> = true; + +template +struct Proxy { + T data; + + constexpr T& getData() & { return data; } + + constexpr const T& getData() const& { return data; } + + constexpr T&& getData() && { return static_cast(data); } + + constexpr const T&& getData() const&& { return static_cast(data); } + + template + requires std::constructible_from + constexpr Proxy(U&& u) : data{std::forward(u)} {} + + // This constructor covers conversion from cvref of Proxy, including non-const/const versions of copy/move constructor + template + requires(IsProxy> && std::constructible_from().getData())>) + constexpr Proxy(Other&& other) : data{std::forward(other).getData()} {} + + template + requires(IsProxy> && std::assignable_from().getData())>) + constexpr Proxy& operator=(Other&& other) { + data = std::forward(other).getData(); + return *this; + } + + // const assignment required to make ProxyIterator model std::indirectly_writable + template + requires(IsProxy> && std::assignable_from().getData())>) + constexpr const Proxy& operator=(Other&& other) const { + data = std::forward(other).getData(); + return *this; + } + + // If `T` is a reference type, the implicitly-generated assignment operator will be deleted (and would take precedence + // over the templated `operator=` above because it's a better match). + constexpr Proxy& operator=(const Proxy& rhs) { + data = rhs.data; + return *this; + } + + // no specialised swap function that takes const Proxy& and no specialised const member swap + // Calling swap(Proxy{}, Proxy{}) would fail (pass prvalues) + + // Compare operators are defined for the convenience of the tests + friend constexpr bool operator==(const Proxy&, const Proxy&) + requires (std::equality_comparable && !std::is_reference_v) + = default; + + // Helps compare e.g. `Proxy` and `Proxy`. Note that the default equality comparison operator is deleted + // when `T` is a reference type. + template + friend constexpr bool operator==(const Proxy& lhs, const Proxy& rhs) + requires std::equality_comparable_with, std::decay_t> { + return lhs.data == rhs.data; + } + + friend constexpr auto operator<=>(const Proxy&, const Proxy&) + requires (std::three_way_comparable && !std::is_reference_v) + = default; + + // Helps compare e.g. `Proxy` and `Proxy`. Note that the default 3-way comparison operator is deleted when + // `T` is a reference type. + template + friend constexpr auto operator<=>(const Proxy& lhs, const Proxy& rhs) + requires std::three_way_comparable_with, std::decay_t> { + return lhs.data <=> rhs.data; + } +}; + +// This is to make ProxyIterator model `std::indirectly_readable` +template class TQual, template class UQual> + requires requires { typename std::common_reference_t, UQual>; } +struct std::basic_common_reference, Proxy, TQual, UQual> { + using type = Proxy, UQual>>; +}; template -inline typename ::std::iterator_traits::difference_type constexpr -operator-(const random_access_iterator& x, const random_access_iterator& y) -{ - return x.base() - y.base(); + requires requires { typename std::common_type_t; } +struct std::common_type, Proxy> { + using type = Proxy>; +}; + +// ProxyIterator +// ====================================================================== +// It wraps `Base` iterator and when dereferenced it returns a Proxy +// It simulates C++23's zip_view::iterator but simplified to just wrap +// one base iterator. +// Note it forwards value_type, iter_move, iter_swap. e.g if the base +// iterator is int*, +// operator* -> Proxy +// iter_value_t -> Proxy +// iter_move -> Proxy +template +struct ProxyIteratorBase {}; + +template + requires std::derived_from< + typename std::iterator_traits::iterator_category, + std::input_iterator_tag> +struct ProxyIteratorBase { + using iterator_category = std::input_iterator_tag; +}; + +template +consteval auto get_iterator_concept() { + if constexpr (std::random_access_iterator) { + return std::random_access_iterator_tag{}; + } else if constexpr (std::bidirectional_iterator) { + return std::bidirectional_iterator_tag{}; + } else if constexpr (std::forward_iterator) { + return std::forward_iterator_tag{}; + } else { + return std::input_iterator_tag{}; + } } +template +struct ProxyIterator : ProxyIteratorBase { + Base base_; + + using iterator_concept = decltype(get_iterator_concept()); + using value_type = Proxy>; + using difference_type = std::iter_difference_t; + + ProxyIterator() + requires std::default_initializable + = default; + + constexpr ProxyIterator(Base base) : base_{std::move(base)} {} + + template + requires std::constructible_from + constexpr ProxyIterator(T&& t) : base_{std::forward(t)} {} + + friend constexpr decltype(auto) base(const ProxyIterator& p) { return base(p.base_); } + + // Specialization of iter_move + // If operator* returns Proxy, iter_move will return Proxy + // Note std::move(*it) returns Proxy&&, which is not what we want as + // it will likely result in a copy rather than a move + friend constexpr Proxy> iter_move(const ProxyIterator& p) noexcept { + return {std::ranges::iter_move(p.base_)}; + } + + // Specialization of iter_swap + // Note std::swap(*x, *y) would fail to compile as operator* returns prvalues + // and std::swap takes non-const lvalue references + friend constexpr void iter_swap(const ProxyIterator& x, const ProxyIterator& y) noexcept { + std::ranges::iter_swap(x.base_, y.base_); + } + + // to satisfy input_iterator + constexpr Proxy> operator*() const { return {*base_}; } + + constexpr ProxyIterator& operator++() { + ++base_; + return *this; + } + + constexpr void operator++(int) { ++*this; } + + friend constexpr bool operator==(const ProxyIterator& x, const ProxyIterator& y) + requires std::equality_comparable { + return x.base_ == y.base_; + } + + // to satisfy forward_iterator + constexpr ProxyIterator operator++(int) + requires std::forward_iterator { + auto tmp = *this; + ++*this; + return tmp; + } + + // to satisfy bidirectional_iterator + constexpr ProxyIterator& operator--() + requires std::bidirectional_iterator { + --base_; + return *this; + } + + constexpr ProxyIterator operator--(int) + requires std::bidirectional_iterator { + auto tmp = *this; + --*this; + return tmp; + } + + // to satisfy random_access_iterator + constexpr ProxyIterator& operator+=(difference_type n) + requires std::random_access_iterator { + base_ += n; + return *this; + } + + constexpr ProxyIterator& operator-=(difference_type n) + requires std::random_access_iterator { + base_ -= n; + return *this; + } + + constexpr Proxy> operator[](difference_type n) const + requires std::random_access_iterator { + return {base_[n]}; + } + + friend constexpr bool operator<(const ProxyIterator& x, const ProxyIterator& y) + requires std::random_access_iterator { + return x.base_ < y.base_; + } + + friend constexpr bool operator>(const ProxyIterator& x, const ProxyIterator& y) + requires std::random_access_iterator { + return x.base_ > y.base_; + } + + friend constexpr bool operator<=(const ProxyIterator& x, const ProxyIterator& y) + requires std::random_access_iterator { + return x.base_ <= y.base_; + } + + friend constexpr bool operator>=(const ProxyIterator& x, const ProxyIterator& y) + requires std::random_access_iterator { + return x.base_ >= y.base_; + } + + friend constexpr auto operator<=>(const ProxyIterator& x, const ProxyIterator& y) + requires(std::random_access_iterator && std::three_way_comparable) { + return x.base_ <=> y.base_; + } + + friend constexpr ProxyIterator operator+(const ProxyIterator& x, difference_type n) + requires std::random_access_iterator { + return ProxyIterator{x.base_ + n}; + } + + friend constexpr ProxyIterator operator+(difference_type n, const ProxyIterator& x) + requires std::random_access_iterator { + return ProxyIterator{n + x.base_}; + } + + friend constexpr ProxyIterator operator-(const ProxyIterator& x, difference_type n) + requires std::random_access_iterator { + return ProxyIterator{x.base_ - n}; + } + + friend constexpr difference_type operator-(const ProxyIterator& x, const ProxyIterator& y) + requires std::random_access_iterator { + return x.base_ - y.base_; + } +}; +template +ProxyIterator(Base) -> ProxyIterator; + +static_assert(std::indirectly_readable>); +static_assert(std::indirectly_writable, Proxy>); +static_assert(std::indirectly_writable, Proxy>); + template -inline constexpr Iter -base(output_iterator i) -{ - return i.base(); -} +using Cpp20InputProxyIterator = ProxyIterator>; template -inline constexpr Iter -base(input_iterator i) -{ - return i.base(); -} +using ForwardProxyIterator = ProxyIterator>; template -inline constexpr Iter -base(forward_iterator i) -{ - return i.base(); -} +using BidirectionalProxyIterator = ProxyIterator>; template -inline constexpr Iter -base(bidirectional_iterator i) -{ - return i.base(); -} +using RandomAccessProxyIterator = ProxyIterator>; template -inline constexpr Iter -base(random_access_iterator i) -{ - return i.base(); -} +using ContiguousProxyIterator = ProxyIterator>; -template // everything else -inline constexpr Iter -base(Iter i) -{ - return i; -} +template +struct ProxySentinel { + BaseSent base_; + + ProxySentinel() = default; + constexpr ProxySentinel(BaseSent base) : base_{std::move(base)} {} + + template + requires std::equality_comparable_with + friend constexpr bool operator==(const ProxyIterator& p, const ProxySentinel& sent) { + return p.base_ == sent.base_; + } +}; +template +ProxySentinel(BaseSent) -> ProxySentinel; + +template + requires std::ranges::view +struct ProxyRange { + Base base_; + + constexpr auto begin() { return ProxyIterator{std::ranges::begin(base_)}; } + + constexpr auto end() { return ProxySentinel{std::ranges::end(base_)}; } + + constexpr auto begin() const + requires std::ranges::input_range { + return ProxyIterator{std::ranges::begin(base_)}; + } + + constexpr auto end() const + requires std::ranges::input_range { + return ProxySentinel{std::ranges::end(base_)}; + } +}; + +template + requires std::ranges::viewable_range +ProxyRange(R&&) -> ProxyRange>; + +#endif // TEST_STD_VER > 17 + +#if TEST_STD_VER >= 17 + +namespace util { +template +class iterator_wrapper { + Iter iter_; + + using iter_traits = std::iterator_traits; + +public: + using iterator_category = typename iter_traits::iterator_category; + using value_type = typename iter_traits::value_type; + using difference_type = typename iter_traits::difference_type; + using pointer = typename iter_traits::pointer; + using reference = typename iter_traits::reference; + + constexpr iterator_wrapper() : iter_() {} + constexpr explicit iterator_wrapper(Iter iter) : iter_(iter) {} + + decltype(*iter_) operator*() { return *iter_; } + decltype(*iter_) operator*() const { return *iter_; } + + decltype(iter_[0]) operator[](difference_type v) const { + return iter_[v]; + } + + Derived& operator++() { + ++iter_; + return static_cast(*this); + } + + Derived operator++(int) { + auto tmp = static_cast(*this); + ++(*this); + return tmp; + } + + Derived& operator--() { + --iter_; + return static_cast(*this); + } + + Derived operator--(int) { + auto tmp = static_cast(*this); + --(*this); + return tmp; + } + + Derived& operator+=(difference_type i) { + iter_ += i; + return static_cast(*this); + } + + Derived& operator-=(difference_type i) { + iter_ -= i; + return static_cast(*this); + } + + friend decltype(iter_ - iter_) operator-(const iterator_wrapper& lhs, const iterator_wrapper& rhs) { + return lhs.iter_ - rhs.iter_; + } + + friend Derived operator-(Derived iter, difference_type i) { + iter.iter_ -= i; + return iter; + } + + friend Derived operator+(Derived iter, difference_type i) { + iter.iter_ += i; + return iter; + } + + friend Derived operator+(difference_type i, Derived iter) { return iter + i; } + + friend bool operator==(const iterator_wrapper& lhs, const iterator_wrapper& rhs) { return lhs.iter_ == rhs.iter_; } + friend bool operator!=(const iterator_wrapper& lhs, const iterator_wrapper& rhs) { return lhs.iter_ != rhs.iter_; } + + friend bool operator>(const iterator_wrapper& lhs, const iterator_wrapper& rhs) { return lhs.iter_ > rhs.iter_; } + friend bool operator<(const iterator_wrapper& lhs, const iterator_wrapper& rhs) { return lhs.iter_ < rhs.iter_; } + friend bool operator<=(const iterator_wrapper& lhs, const iterator_wrapper& rhs) { return lhs.iter_ <= rhs.iter_; } + friend bool operator>=(const iterator_wrapper& lhs, const iterator_wrapper& rhs) { return lhs.iter_ >= rhs.iter_; } +}; + +class iterator_error : std::runtime_error { +public: + iterator_error(const char* what) : std::runtime_error(what) {} +}; + +#ifndef TEST_HAS_NO_EXCEPTIONS +template +class throw_on_move_iterator : public iterator_wrapper, Iter> { + using base = iterator_wrapper, Iter>; + + int moves_until_throw_ = 0; + +public: + using difference_type = typename base::difference_type; + using value_type = typename base::value_type; + using iterator_category = typename base::iterator_category; + + throw_on_move_iterator() = default; + throw_on_move_iterator(Iter iter, int moves_until_throw) + : base(std::move(iter)), moves_until_throw_(moves_until_throw) {} + + throw_on_move_iterator(const throw_on_move_iterator& other) : base(other) {} + throw_on_move_iterator& operator=(const throw_on_move_iterator& other) { + static_cast(*this) = other; + return *this; + } + + throw_on_move_iterator(throw_on_move_iterator&& other) + : base(std::move(other)), moves_until_throw_(other.moves_until_throw_ - 1) { + if (moves_until_throw_ == -1) + throw iterator_error("throw_on_move_iterator"); + } + + throw_on_move_iterator& operator=(throw_on_move_iterator&& other) { + moves_until_throw_ = other.moves_until_throw_ - 1; + if (moves_until_throw_ == -1) + throw iterator_error("throw_on_move_iterator"); + return *this; + } +}; + +template +throw_on_move_iterator(Iter) -> throw_on_move_iterator; +#endif // TEST_HAS_NO_EXCEPTIONS +} // namespace util + +#endif // TEST_STD_VER >= 17 + +namespace types { +template +using random_access_iterator_list = + type_list= 20 + contiguous_iterator, +#endif + random_access_iterator >; + +template +using bidirectional_iterator_list = + concatenate_t, type_list > >; + +template +using forward_iterator_list = concatenate_t, type_list > >; + +template +using cpp17_input_iterator_list = concatenate_t, type_list > >; + +#if TEST_STD_VER >= 20 +template +using cpp20_input_iterator_list = + concatenate_t, type_list, cpp17_input_iterator>>; +#endif +} // namespace types -#undef DELETE_FUNCTION -#endif // _TEST_ITERATORS_H +#endif // SUPPORT_TEST_ITERATORS_H diff --git a/test/support/test_macros.h b/test/support/test_macros.h index 88ed4adf38f..7fd7f9c3cd6 100644 --- a/test/support/test_macros.h +++ b/test/support/test_macros.h @@ -380,4 +380,42 @@ inline void DoNotOptimize(Tp const& value) { #define TEST_PREPARE_CALLABLE(std_algo_name) \ [](auto&&... __args) { return std_algo_name(std::forward(__args)...); } +#if TEST_STD_VER >= 14 +# define TEST_CONSTEXPR_CXX14 constexpr +#else +# define TEST_CONSTEXPR_CXX14 +#endif + +#if TEST_STD_VER >= 11 +# define TEST_ALIGNOF(...) alignof(__VA_ARGS__) +# define TEST_ALIGNAS(...) alignas(__VA_ARGS__) +# define TEST_CONSTEXPR constexpr +# define TEST_NOEXCEPT noexcept +# define TEST_NOEXCEPT_FALSE noexcept(false) +# define TEST_NOEXCEPT_COND(...) noexcept(__VA_ARGS__) +#else +# if defined(TEST_COMPILER_CLANG) +# define TEST_ALIGNOF(...) _Alignof(__VA_ARGS__) +# else +# define TEST_ALIGNOF(...) __alignof(__VA_ARGS__) +# endif +# define TEST_ALIGNAS(...) __attribute__((__aligned__(__VA_ARGS__))) +# define TEST_CONSTEXPR +# define TEST_NOEXCEPT throw() +# define TEST_NOEXCEPT_FALSE +# define TEST_NOEXCEPT_COND(...) +#endif + +#if TEST_STD_VER >= 17 +# define TEST_CONSTEXPR_CXX17 constexpr +#else +# define TEST_CONSTEXPR_CXX17 +#endif + +#if TEST_STD_VER >= 20 +# define TEST_CONSTEXPR_CXX20 constexpr +#else +# define TEST_CONSTEXPR_CXX20 +#endif + #endif // _SUPPORT_TEST_MACROS_H diff --git a/test/support/test_range.h b/test/support/test_range.h new file mode 100644 index 00000000000..4efa26f2664 --- /dev/null +++ b/test/support/test_range.h @@ -0,0 +1,109 @@ +//===----------------------------------------------------------------------===// +// +// 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 LIBCXX_TEST_SUPPORT_TEST_RANGE_H +#define LIBCXX_TEST_SUPPORT_TEST_RANGE_H + +#include +#include +#include +#include +#include + +#include "test_iterators.h" + +#if TEST_STD_VER < 17 +# error "test/support/test_range.h" can only be included in builds supporting ranges +#endif + +struct sentinel { + bool operator==(std::input_or_output_iterator auto const&) const; +}; + +template