From c4a3ccfbad090ad8314aa8ad53092edc8d5432bc Mon Sep 17 00:00:00 2001 From: James Smith Date: Thu, 28 Sep 2023 10:11:15 -0400 Subject: [PATCH 01/36] [libc++] Implement ranges::iota and ranges::out_value_result --- libcxx/include/CMakeLists.txt | 2 + libcxx/include/__algorithm/out_value_result.h | 52 +++++++++ libcxx/include/__numeric/ranges_iota.h | 53 +++++++++ libcxx/include/algorithm | 4 + libcxx/include/numeric | 1 + libcxx/include/version | 2 +- .../out_value_result.pass.cpp | 102 ++++++++++++++++++ .../numeric.iota/ranges.iota.pass.cpp | 52 +++++++++ 8 files changed, 267 insertions(+), 1 deletion(-) create mode 100644 libcxx/include/__algorithm/out_value_result.h create mode 100644 libcxx/include/__numeric/ranges_iota.h create mode 100644 libcxx/test/std/algorithms/algorithms.results/out_value_result.pass.cpp create mode 100644 libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 2ec755236dbae..c6eb03f1d68e9 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -63,6 +63,7 @@ set(files __algorithm/next_permutation.h __algorithm/none_of.h __algorithm/nth_element.h + __algorithm/out_value_result.h __algorithm/partial_sort.h __algorithm/partial_sort_copy.h __algorithm/partition.h @@ -561,6 +562,7 @@ set(files __numeric/partial_sum.h __numeric/pstl_reduce.h __numeric/pstl_transform_reduce.h + __numeric/ranges_iota.h __numeric/reduce.h __numeric/transform_exclusive_scan.h __numeric/transform_inclusive_scan.h diff --git a/libcxx/include/__algorithm/out_value_result.h b/libcxx/include/__algorithm/out_value_result.h new file mode 100644 index 0000000000000..8baffec7b9ef4 --- /dev/null +++ b/libcxx/include/__algorithm/out_value_result.h @@ -0,0 +1,52 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_OUT_VALUE_RESULT_H +#define _LIBCPP___ALGORITHM_OUT_VALUE_RESULT_H + +#include <__concepts/convertible_to.h> +#include <__config> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +namespace ranges { + +template +struct out_value_result { + _LIBCPP_NO_UNIQUE_ADDRESS _OutIter1 out; + _LIBCPP_NO_UNIQUE_ADDRESS _ValType1 value; + + template + requires convertible_to && convertible_to + constexpr operator out_value_result<_OutIter2, _ValType2>() const& { return {out, value}; } + + template + requires convertible_to<_OutIter1, _OutIter2> && convertible_to<_ValType1, _ValType2> + constexpr operator out_value_result<_OutIter2, _ValType2>() && { return {std::move(out), std::move(value)}; } +}; + +} // namespace ranges + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_OUT_VALUE_RESULT_H diff --git a/libcxx/include/__numeric/ranges_iota.h b/libcxx/include/__numeric/ranges_iota.h new file mode 100644 index 0000000000000..20311a68c2a34 --- /dev/null +++ b/libcxx/include/__numeric/ranges_iota.h @@ -0,0 +1,53 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___NUMERIC_RANGES_IOTA_H +#define _LIBCPP___NUMERIC_RANGES_IOTA_H + +#include <__algorithm/out_value_result.h> +#include <__config> +#include <__ranges/concepts.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 +namespace ranges { +template +using iota_result = ranges::out_value_result<_Out, _Tp>; + +struct __iota_fn { + template _Sent, weakly_incrementable _Tp> + requires indirectly_writable<_Out, const _Tp&> + constexpr iota_result<_Out, _Tp> operator()(_Out __first, _Sent __last, _Tp __value) const { + while (__first != __last) { + *__first = static_cast(__value); + ++__first; + ++__value; + } + return {std::move(__first), std::move(__value)}; + } + + template _Range> + constexpr iota_result, _Tp> operator()(_Range&& __r, _Tp __value) const { + return (*this)(ranges::begin(__r), ranges::end(__r), std::move(__value)); + } +}; + +inline constexpr __iota_fn iota{}; +} // namespace ranges + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___NUMERIC_RANGES_IOTA_H diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm index 69ba9537dda69..42f01a99a02cc 100644 --- a/libcxx/include/algorithm +++ b/libcxx/include/algorithm @@ -42,6 +42,9 @@ namespace ranges { template struct in_found_result; // since C++20 + template + struct out_value_result; // since C++23 + template S, class Proj = identity, indirect_strict_weak_order> Comp = ranges::less> // since C++20 constexpr I min_element(I first, S last, Comp comp = {}, Proj proj = {}); @@ -1817,6 +1820,7 @@ template #include <__algorithm/next_permutation.h> #include <__algorithm/none_of.h> #include <__algorithm/nth_element.h> +#include <__algorithm/out_value_result.h> #include <__algorithm/partial_sort.h> #include <__algorithm/partial_sort_copy.h> #include <__algorithm/partition.h> diff --git a/libcxx/include/numeric b/libcxx/include/numeric index 3fcf6cefdb4b8..363dfd229df54 100644 --- a/libcxx/include/numeric +++ b/libcxx/include/numeric @@ -160,6 +160,7 @@ template #include <__numeric/partial_sum.h> #include <__numeric/pstl_reduce.h> #include <__numeric/pstl_transform_reduce.h> +#include <__numeric/ranges_iota.h> #include <__numeric/reduce.h> #include <__numeric/transform_exclusive_scan.h> #include <__numeric/transform_inclusive_scan.h> diff --git a/libcxx/include/version b/libcxx/include/version index e5a995366a7aa..164c60dfd6af6 100644 --- a/libcxx/include/version +++ b/libcxx/include/version @@ -436,7 +436,7 @@ __cpp_lib_within_lifetime 202306L # define __cpp_lib_ranges_as_rvalue 202207L // # define __cpp_lib_ranges_chunk 202202L # define __cpp_lib_ranges_chunk_by 202202L -// # define __cpp_lib_ranges_iota 202202L +# define __cpp_lib_ranges_iota 202202L // # define __cpp_lib_ranges_join_with 202202L # define __cpp_lib_ranges_repeat 202207L // # define __cpp_lib_ranges_slide 202202L diff --git a/libcxx/test/std/algorithms/algorithms.results/out_value_result.pass.cpp b/libcxx/test/std/algorithms/algorithms.results/out_value_result.pass.cpp new file mode 100644 index 0000000000000..189149b0b4acb --- /dev/null +++ b/libcxx/test/std/algorithms/algorithms.results/out_value_result.pass.cpp @@ -0,0 +1,102 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// struct out_value_result; + +#include +#include +#include + +#include "MoveOnly.h" + +struct A { + explicit A(int); +}; +// no implicit conversion +static_assert(!std::is_constructible_v, std::ranges::out_value_result>); + +struct B { + B(int); +}; +// implicit conversion +static_assert(std::is_constructible_v, std::ranges::out_value_result>); +static_assert(std::is_constructible_v, std::ranges::out_value_result&>); +static_assert( + std::is_constructible_v, const std::ranges::out_value_result>); +static_assert( + std::is_constructible_v, const std::ranges::out_value_result&>); + +struct C { + C(int&); +}; +static_assert(!std::is_constructible_v, std::ranges::out_value_result&>); + +// has to be convertible via const& +static_assert( + std::is_convertible_v&, std::ranges::out_value_result>); +static_assert( + std::is_convertible_v&, std::ranges::out_value_result>); +static_assert( + std::is_convertible_v&&, std::ranges::out_value_result>); +static_assert( + std::is_convertible_v&&, std::ranges::out_value_result>); + +// should be move constructible +static_assert(std::is_move_constructible_v>); +static_assert(std::is_move_constructible_v>); + +struct NotConvertible {}; +// conversions should not work if there is no conversion +static_assert(!std::is_convertible_v, + std::ranges::out_value_result>); +static_assert(!std::is_convertible_v, + std::ranges::out_value_result>); + +template +struct ConvertibleFrom { + constexpr ConvertibleFrom(T c) : content{c} {} + T content; +}; + +constexpr bool test() { + { + std::ranges::out_value_result res{10, 1}; + assert(res.out == 10); + assert(res.value == 1); + std::ranges::out_value_result, ConvertibleFrom> res2 = res; + assert(res2.out.content == 10); + assert(res2.value.content == 1); + } + { + std::ranges::out_value_result res{MoveOnly{}, 10}; + assert(res.out.get() == 1); + assert(res.value == 10); + auto res2 = std::move(res); + assert(res.out.get() == 0); + assert(res.value == 10); + assert(res2.out.get() == 1); + assert(res2.value == 10); + } + { + auto [min, max] = std::ranges::out_value_result{1, 2}; + assert(min == 1); + assert(max == 2); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp new file mode 100644 index 0000000000000..1e2a6970adb35 --- /dev/null +++ b/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp @@ -0,0 +1,52 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// Testing std::ranges::iota + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" + +// This is pulled directly from the std::iota test +template +TEST_CONSTEXPR_CXX20 void test0() { + int ia[] = {1, 2, 3, 4, 5}; + int ir[] = {5, 6, 7, 8, 9}; + const unsigned s = sizeof(ia) / sizeof(ia[0]); + std::ranges::iota(InIter(ia), InIter(ia + s), 5); + for (unsigned i = 0; i < s; ++i) + assert(ia[i] == ir[i]); +} + +TEST_CONSTEXPR_CXX20 bool test0() { + test0 >(); + test0 >(); + test0 >(); + test0(); + + return true; +} + +TEST_CONSTEXPR_CXX20 void test1() { + std::array ia = {1, 2, 3, 4, 5}; + std::array ir = {5, 6, 7, 8, 9}; + std::ranges::iota(ia, 5); + for (unsigned i = 0; i < ir.size(); ++i) + assert(ia[i] == ir[i]); +} + +int main(int, char**) { + test0(); + test1(); + return 0; +} \ No newline at end of file From 574c94ce4f7eed06013a5e5d1460da1d148cc7cd Mon Sep 17 00:00:00 2001 From: James Smith Date: Fri, 29 Sep 2023 14:11:49 -0400 Subject: [PATCH 02/36] [libc++] Implement ranges::iota: update module and docs info --- libcxx/docs/FeatureTestMacroTable.rst | 2 +- libcxx/include/module.modulemap.in | 1 + libcxx/modules/std/numeric.inc | 8 ++++++-- libcxx/utils/generate_feature_test_macro_components.py | 1 - 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst index e1b4172b22c53..ebb18dc7bed9b 100644 --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -348,7 +348,7 @@ Status --------------------------------------------------- ----------------- ``__cpp_lib_ranges_chunk_by`` ``202202L`` --------------------------------------------------- ----------------- - ``__cpp_lib_ranges_iota`` *unimplemented* + ``__cpp_lib_ranges_iota`` ``202202L`` --------------------------------------------------- ----------------- ``__cpp_lib_ranges_join_with`` *unimplemented* --------------------------------------------------- ----------------- diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in index 6d9bb8653fcb5..b092cc7c0e93b 100644 --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -1602,6 +1602,7 @@ module std_private_numeric_pstl_transform_reduce [system] { export * } module std_private_numeric_reduce [system] { header "__numeric/reduce.h" } +module std_private_numeric_ranges_iota [system] { header "__numeric/ranges_iota.h" } module std_private_numeric_transform_exclusive_scan [system] { header "__numeric/transform_exclusive_scan.h" } module std_private_numeric_transform_inclusive_scan [system] { header "__numeric/transform_inclusive_scan.h" } module std_private_numeric_transform_reduce [system] { header "__numeric/transform_reduce.h" } diff --git a/libcxx/modules/std/numeric.inc b/libcxx/modules/std/numeric.inc index d2b7688d4e5f1..9204e8d871593 100644 --- a/libcxx/modules/std/numeric.inc +++ b/libcxx/modules/std/numeric.inc @@ -42,8 +42,12 @@ export namespace std { using std::iota; namespace ranges { - // using std::ranges::iota_result; - // using std::ranges::iota; + +#if _LIBCPP_STD_VER >= 23 + using std::ranges::iota; + using std::ranges::iota_result; +#endif // _LIBCPP_STD_VER >= 23 + } // namespace ranges // [numeric.ops.gcd], greatest common divisor diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py index ac342aff0beb7..9fd50d66edbe3 100755 --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -806,7 +806,6 @@ def add_version_header(tc): "name": "__cpp_lib_ranges_iota", "values": {"c++23": 202202}, "headers": ["numeric"], - "unimplemented": True, }, { "name": "__cpp_lib_ranges_join_with", From e4cfe00cb1b348d5a3515ef907c7c87334c6824c Mon Sep 17 00:00:00 2001 From: James Smith Date: Fri, 29 Sep 2023 16:50:46 -0400 Subject: [PATCH 03/36] [libc++] Implement ranges::iota: fixing formatting issues for out_value_result --- libcxx/include/__algorithm/out_value_result.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libcxx/include/__algorithm/out_value_result.h b/libcxx/include/__algorithm/out_value_result.h index 8baffec7b9ef4..a99d206f7035f 100644 --- a/libcxx/include/__algorithm/out_value_result.h +++ b/libcxx/include/__algorithm/out_value_result.h @@ -34,11 +34,15 @@ struct out_value_result { template requires convertible_to && convertible_to - constexpr operator out_value_result<_OutIter2, _ValType2>() const& { return {out, value}; } + constexpr operator out_value_result<_OutIter2, _ValType2>() const& { + return {out, value}; + } template requires convertible_to<_OutIter1, _OutIter2> && convertible_to<_ValType1, _ValType2> - constexpr operator out_value_result<_OutIter2, _ValType2>() && { return {std::move(out), std::move(value)}; } + constexpr operator out_value_result<_OutIter2, _ValType2>() && { + return {std::move(out), std::move(value)}; + } }; } // namespace ranges From 7cdfea2d5acf553345ee0c506ce9e3914cbb3ed0 Mon Sep 17 00:00:00 2001 From: James Smith Date: Sat, 7 Oct 2023 12:04:32 -0400 Subject: [PATCH 04/36] [libc++] Implement ranges::iota: Cleaning up tests for ranges::iota and out_value_result. Updating Cxx23Papers.csv too. --- libcxx/docs/Status/Cxx23Papers.csv | 2 +- libcxx/include/__numeric/ranges_iota.h | 3 +- libcxx/modules/std/algorithm.inc | 2 +- .../out_value_result.pass.cpp | 104 ++++++++++------ .../numeric.iota/ranges.iota.pass.cpp | 117 ++++++++++++++++-- 5 files changed, 171 insertions(+), 57 deletions(-) diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv index 9cb49fd5176ea..4618908cfb739 100644 --- a/libcxx/docs/Status/Cxx23Papers.csv +++ b/libcxx/docs/Status/Cxx23Papers.csv @@ -46,7 +46,7 @@ "`P2255R2 `__","LWG","A type trait to detect reference binding to temporary","February 2022","","" "`P2273R3 `__","LWG","Making ``std::unique_ptr`` constexpr","February 2022","|Complete|","16.0" "`P2387R3 `__","LWG","Pipe support for user-defined range adaptors","February 2022","","","|ranges|" -"`P2440R1 `__","LWG","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","February 2022","","","|ranges|" +"`P2440R1 `__","LWG","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","February 2022","|In progress|","","|ranges|" "`P2441R2 `__","LWG","``views::join_with``","February 2022","","","|ranges|" "`P2442R1 `__","LWG","Windowing range adaptors: ``views::chunk`` and ``views::slide``","February 2022","","","|ranges|" "`P2443R1 `__","LWG","``views::chunk_by``","February 2022","|Complete|","18.0","|ranges|" diff --git a/libcxx/include/__numeric/ranges_iota.h b/libcxx/include/__numeric/ranges_iota.h index 20311a68c2a34..a8c069832da7e 100644 --- a/libcxx/include/__numeric/ranges_iota.h +++ b/libcxx/include/__numeric/ranges_iota.h @@ -13,6 +13,7 @@ #include <__algorithm/out_value_result.h> #include <__config> #include <__ranges/concepts.h> +#include <__utility/as_const.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -30,7 +31,7 @@ struct __iota_fn { requires indirectly_writable<_Out, const _Tp&> constexpr iota_result<_Out, _Tp> operator()(_Out __first, _Sent __last, _Tp __value) const { while (__first != __last) { - *__first = static_cast(__value); + *__first = std::as_const(__value); ++__first; ++__value; } diff --git a/libcxx/modules/std/algorithm.inc b/libcxx/modules/std/algorithm.inc index b7900d15c10c2..62ce8cf02c14f 100644 --- a/libcxx/modules/std/algorithm.inc +++ b/libcxx/modules/std/algorithm.inc @@ -18,7 +18,7 @@ export namespace std { using std::ranges::in_out_result; // using std::ranges::in_value_result; using std::ranges::min_max_result; - // using std::ranges::out_value_result; + using std::ranges::out_value_result; } // namespace ranges // [alg.nonmodifying], non-modifying sequence operations diff --git a/libcxx/test/std/algorithms/algorithms.results/out_value_result.pass.cpp b/libcxx/test/std/algorithms/algorithms.results/out_value_result.pass.cpp index 189149b0b4acb..3a930bb063f97 100644 --- a/libcxx/test/std/algorithms/algorithms.results/out_value_result.pass.cpp +++ b/libcxx/test/std/algorithms/algorithms.results/out_value_result.pass.cpp @@ -17,48 +17,25 @@ #include "MoveOnly.h" -struct A { - explicit A(int); +// +// Helper structs +// + +// only explicit construction +struct IterTypeExplicit { + explicit IterTypeExplicit(int*); }; -// no implicit conversion -static_assert(!std::is_constructible_v, std::ranges::out_value_result>); -struct B { - B(int); +// implicit construction +struct IterTypeImplicit { + IterTypeImplicit(int*); }; -// implicit conversion -static_assert(std::is_constructible_v, std::ranges::out_value_result>); -static_assert(std::is_constructible_v, std::ranges::out_value_result&>); -static_assert( - std::is_constructible_v, const std::ranges::out_value_result>); -static_assert( - std::is_constructible_v, const std::ranges::out_value_result&>); - -struct C { - C(int&); + +struct IterTypeImplicitRef { + IterTypeImplicitRef(int&); }; -static_assert(!std::is_constructible_v, std::ranges::out_value_result&>); - -// has to be convertible via const& -static_assert( - std::is_convertible_v&, std::ranges::out_value_result>); -static_assert( - std::is_convertible_v&, std::ranges::out_value_result>); -static_assert( - std::is_convertible_v&&, std::ranges::out_value_result>); -static_assert( - std::is_convertible_v&&, std::ranges::out_value_result>); - -// should be move constructible -static_assert(std::is_move_constructible_v>); -static_assert(std::is_move_constructible_v>); struct NotConvertible {}; -// conversions should not work if there is no conversion -static_assert(!std::is_convertible_v, - std::ranges::out_value_result>); -static_assert(!std::is_convertible_v, - std::ranges::out_value_result>); template struct ConvertibleFrom { @@ -66,6 +43,51 @@ struct ConvertibleFrom { T content; }; +// +constexpr void test_constraints() { + // requires convertible_to && convertible_to + static_assert( + std::is_constructible_v, std::ranges::out_value_result>); + + // test failure when implicit conversion isn't allowed + static_assert(!std::is_constructible_v, + std::ranges::out_value_result>); + + // test success when implicit conversion is allowed, checking combinations of value, reference, and const + static_assert(std::is_constructible_v, + std::ranges::out_value_result>); + static_assert(std::is_constructible_v, + std::ranges::out_value_result const>); + static_assert(std::is_constructible_v, + std::ranges::out_value_result&>); + static_assert(std::is_constructible_v, + std::ranges::out_value_result const&>); + + static_assert(!std::is_constructible_v, + std::ranges::out_value_result&>); + + // has to be convertible via const& + static_assert( + std::is_convertible_v&, std::ranges::out_value_result>); + static_assert( + std::is_convertible_v&, std::ranges::out_value_result>); + static_assert( + std::is_convertible_v&&, std::ranges::out_value_result>); + static_assert(std::is_convertible_v&&, + std::ranges::out_value_result>); + + // should be move constructible + static_assert(std::is_move_constructible_v>); + static_assert(std::is_move_constructible_v>); + + // conversions should not work if there is no conversion + static_assert(!std::is_convertible_v, + std::ranges::out_value_result>); + static_assert(!std::is_convertible_v, + std::ranges::out_value_result>); +} + +// Test results constexpr bool test() { { std::ranges::out_value_result res{10, 1}; @@ -86,17 +108,17 @@ constexpr bool test() { assert(res2.value == 10); } { - auto [min, max] = std::ranges::out_value_result{1, 2}; - assert(min == 1); - assert(max == 2); + auto [out, val] = std::ranges::out_value_result{1, 2}; + assert(out == 1); + assert(val == 2); } return true; } int main(int, char**) { + test_constraints(); test(); static_assert(test()); - return 0; -} +} \ No newline at end of file diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp index 1e2a6970adb35..85f99942e97b2 100644 --- a/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp +++ b/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp @@ -12,41 +12,132 @@ #include #include +#include #include #include "test_macros.h" #include "test_iterators.h" +#include "almost_satisfies_types.h" + +// Concepts to check different overloads of std::ranges::iota +template +concept HasIotaIter = requires(Iter&& iter, Sent&& sent, Value&& val) { + std::ranges::iota(std::forward(iter), std::forward(sent), std::forward(val)); +}; + +template +concept HasIotaRange = requires(Range&& range, Value&& val) { + std::ranges::iota(std::forward(range), std::forward(val)); +}; + +constexpr void test_constraints() { + // Test constraints of the iterator/sentinel overload + // ================================================== + static_assert(HasIotaIter); + + // !input_or_output_iterator + static_assert(!HasIotaIter); + + // !sentinel_for + static_assert(!HasIotaIter); + static_assert(!HasIotaIter); + + // !weakly_incrementable + static_assert(!HasIotaIter); + + // !indirectly writable + static_assert(!HasIotaIter); + + // Test constraints for the range overload + // ======================================= + static_assert(HasIotaRange, int>); + + // !weakly_incrementable + static_assert(!HasIotaRange, WeaklyIncrementableNotMovable>); + + // !ranges::output_range + static_assert(!HasIotaRange, OutputIteratorNotIndirectlyWritable>); +} // This is pulled directly from the std::iota test -template -TEST_CONSTEXPR_CXX20 void test0() { +template +constexpr void test0() { int ia[] = {1, 2, 3, 4, 5}; int ir[] = {5, 6, 7, 8, 9}; const unsigned s = sizeof(ia) / sizeof(ia[0]); - std::ranges::iota(InIter(ia), InIter(ia + s), 5); - for (unsigned i = 0; i < s; ++i) - assert(ia[i] == ir[i]); + std::ranges::iota(InOutIter(ia), InOutIter(ia + s), 5); + assert(std::ranges::equal(ia, ir)); } -TEST_CONSTEXPR_CXX20 bool test0() { +constexpr bool test0() { + // TODO why don't these work? + // test0, sentinel_wrapper>>(); + // test0, sentinel_wrapper>>(); + // test0, sentinel_wrapper>>(); + // test0, sentinel_wrapper>>(); test0 >(); test0 >(); test0 >(); + test0>(); test0(); return true; } -TEST_CONSTEXPR_CXX20 void test1() { - std::array ia = {1, 2, 3, 4, 5}; - std::array ir = {5, 6, 7, 8, 9}; - std::ranges::iota(ia, 5); - for (unsigned i = 0; i < ir.size(); ++i) - assert(ia[i] == ir[i]); +template +constexpr void test_result(std::array input, int starting_value, std::array const expected) { + { // (iterator, sentinel) overload + auto in_begin = Iter(input.data()); + auto in_end = Sent(Iter(input.data() + input.size())); + std::same_as> decltype(auto) result = + std::ranges::iota(std::move(in_begin), std::move(in_end), starting_value); + assert(result.out == in_end); + if constexpr (expected.size() > 0) { + assert(result.value == expected.back() + 1); + } else { + assert(result.value == starting_value); + } + assert(std::ranges::equal(input, expected)); + } + + { // (range) overload + auto in_begin = Iter(input.data()); + auto in_end = Sent(Iter(input.data() + input.size())); + auto range = std::ranges::subrange(std::move(in_begin), std::move(in_end)); + + std::same_as> decltype(auto) result = + std::ranges::iota(range, starting_value); + assert(result.out == in_end); + if constexpr (expected.size() > 0) { + assert(result.value == expected.back() + 1); + } else { + assert(result.value == starting_value); + } + assert(std::ranges::equal(input, expected)); + } +} + +constexpr bool test_results() { + using Iter = forward_iterator; + using Sent = sentinel_wrapper; + + // Empty + test_result({}, 0, {}); + // 1-element sequence + test_result({1}, 0, {0}); + // Longer sequence + test_result({1, 2, 3, 4, 5}, 0, {0, 1, 2, 3, 4}); + + return true; } int main(int, char**) { + test_constraints(); + test0(); - test1(); + static_assert(test0()); + + test_results(); + static_assert(test_results()); return 0; } \ No newline at end of file From a1d015c2affa40bb5f5313cdaed46c5a8cd4b243 Mon Sep 17 00:00:00 2001 From: James Smith Date: Sat, 7 Oct 2023 12:35:20 -0400 Subject: [PATCH 05/36] [libc++] Implement ranges::iota: Cleaning up tests for ranges::iota and adding testing for more iterators --- .../numeric.iota/ranges.iota.pass.cpp | 53 ++++++------------- 1 file changed, 17 insertions(+), 36 deletions(-) diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp index 85f99942e97b2..611293debbf73 100644 --- a/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp +++ b/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp @@ -59,31 +59,6 @@ constexpr void test_constraints() { static_assert(!HasIotaRange, OutputIteratorNotIndirectlyWritable>); } -// This is pulled directly from the std::iota test -template -constexpr void test0() { - int ia[] = {1, 2, 3, 4, 5}; - int ir[] = {5, 6, 7, 8, 9}; - const unsigned s = sizeof(ia) / sizeof(ia[0]); - std::ranges::iota(InOutIter(ia), InOutIter(ia + s), 5); - assert(std::ranges::equal(ia, ir)); -} - -constexpr bool test0() { - // TODO why don't these work? - // test0, sentinel_wrapper>>(); - // test0, sentinel_wrapper>>(); - // test0, sentinel_wrapper>>(); - // test0, sentinel_wrapper>>(); - test0 >(); - test0 >(); - test0 >(); - test0>(); - test0(); - - return true; -} - template constexpr void test_result(std::array input, int starting_value, std::array const expected) { { // (iterator, sentinel) overload @@ -100,7 +75,10 @@ constexpr void test_result(std::array input, int starting_value, std::ar assert(std::ranges::equal(input, expected)); } - { // (range) overload + // The range overload adds the additional constraint that it must be an outputrange + // so skip this for the input iterators we test + if constexpr (!std::is_same_v> && + !std::is_same_v>) { // (range) overload auto in_begin = Iter(input.data()); auto in_end = Sent(Iter(input.data() + input.size())); auto range = std::ranges::subrange(std::move(in_begin), std::move(in_end)); @@ -117,27 +95,30 @@ constexpr void test_result(std::array input, int starting_value, std::ar } } -constexpr bool test_results() { - using Iter = forward_iterator; - using Sent = sentinel_wrapper; - +template > +constexpr void test_results() { // Empty test_result({}, 0, {}); // 1-element sequence test_result({1}, 0, {0}); // Longer sequence test_result({1, 2, 3, 4, 5}, 0, {0, 1, 2, 3, 4}); +} - return true; +void test_results() { + test_results>(); + test_results>(); + test_results>(); + test_results>(); + test_results>(); + test_results>(); + test_results>(); + test_results>(); + test_results(); } int main(int, char**) { test_constraints(); - - test0(); - static_assert(test0()); - test_results(); - static_assert(test_results()); return 0; } \ No newline at end of file From ab4c67d3537379aab5117ac8dad232c5072991e9 Mon Sep 17 00:00:00 2001 From: James Smith Date: Sat, 7 Oct 2023 12:40:02 -0400 Subject: [PATCH 06/36] [libc++] Implement ranges::iota: Using clang-format-17 to make CI checks happy --- .../numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp index 611293debbf73..3a7bc4319bebd 100644 --- a/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp +++ b/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp @@ -26,9 +26,8 @@ concept HasIotaIter = requires(Iter&& iter, Sent&& sent, Value&& val) { }; template -concept HasIotaRange = requires(Range&& range, Value&& val) { - std::ranges::iota(std::forward(range), std::forward(val)); -}; +concept HasIotaRange = + requires(Range&& range, Value&& val) { std::ranges::iota(std::forward(range), std::forward(val)); }; constexpr void test_constraints() { // Test constraints of the iterator/sentinel overload From a455f42dbd6b97b8b6ccf41fad2ff9aae054fe0e Mon Sep 17 00:00:00 2001 From: James Smith Date: Tue, 24 Oct 2023 20:39:52 -0400 Subject: [PATCH 07/36] [libc++] Implement ranges::iota: Adding helper function to implementation and updating docs. --- libcxx/docs/Status/RangesAlgorithms.csv | 1 + libcxx/docs/Status/RangesMajorFeatures.csv | 1 + libcxx/include/__numeric/ranges_iota.h | 24 +++++++++++++++---- .../out_value_result.pass.cpp | 2 +- .../numeric.iota/ranges.iota.pass.cpp | 7 +++--- 5 files changed, 26 insertions(+), 9 deletions(-) diff --git a/libcxx/docs/Status/RangesAlgorithms.csv b/libcxx/docs/Status/RangesAlgorithms.csv index 17c8953bf8d85..e6dda790bf158 100644 --- a/libcxx/docs/Status/RangesAlgorithms.csv +++ b/libcxx/docs/Status/RangesAlgorithms.csv @@ -10,3 +10,4 @@ C++23,`shift_right `_,Unassigned,No patch yet,Not sta C++23,`iota (algorithm) `_,Unassigned,No patch yet,Not started C++23,`fold `_,Unassigned,No patch yet,Not started C++23,`contains `_,Zijun Zhao,No patch yet,In Progress +C++23,`ranges::iota `_, James E T Smith, `PR68494 `_, In Progress diff --git a/libcxx/docs/Status/RangesMajorFeatures.csv b/libcxx/docs/Status/RangesMajorFeatures.csv index 259a0218ce15e..5dd93a60fa7bd 100644 --- a/libcxx/docs/Status/RangesMajorFeatures.csv +++ b/libcxx/docs/Status/RangesMajorFeatures.csv @@ -2,3 +2,4 @@ Standard,Name,Assignee,CL,Status C++23,`ranges::to `_,Konstantin Varlamov,`D142335 `_,Complete C++23,`Pipe support for user-defined range adaptors `_,Unassigned,No patch yet,Not started C++23,`Formatting Ranges `_,Mark de Wever,Various,Complete +C++23, `ranges::iota `_, James E T Smith, `PR68494 `_, In Progress \ No newline at end of file diff --git a/libcxx/include/__numeric/ranges_iota.h b/libcxx/include/__numeric/ranges_iota.h index a8c069832da7e..eca5712b3d0d4 100644 --- a/libcxx/include/__numeric/ranges_iota.h +++ b/libcxx/include/__numeric/ranges_iota.h @@ -14,6 +14,7 @@ #include <__config> #include <__ranges/concepts.h> #include <__utility/as_const.h> +#include <__utility/move.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -26,10 +27,12 @@ namespace ranges { template using iota_result = ranges::out_value_result<_Out, _Tp>; +namespace __ranges_iota { struct __iota_fn { - template _Sent, weakly_incrementable _Tp> - requires indirectly_writable<_Out, const _Tp&> - constexpr iota_result<_Out, _Tp> operator()(_Out __first, _Sent __last, _Tp __value) const { +private: + // Private helper function + template + _LIBCPP_HIDE_FROM_ABI static constexpr iota_result<_Out, _Tp> __iota_impl(_Out __first, _Sent __last, _Tp __value) { while (__first != __last) { *__first = std::as_const(__value); ++__first; @@ -38,13 +41,24 @@ struct __iota_fn { return {std::move(__first), std::move(__value)}; } +public: + // Public facing interfaces + template _Sent, weakly_incrementable _Tp> + requires indirectly_writable<_Out, const _Tp&> + constexpr iota_result<_Out, _Tp> operator()(_Out __first, _Sent __last, _Tp __value) const { + return __iota_impl(std::move(__first), std::move(__last), std::move(__value)); + } + template _Range> constexpr iota_result, _Tp> operator()(_Range&& __r, _Tp __value) const { - return (*this)(ranges::begin(__r), ranges::end(__r), std::move(__value)); + return __iota_impl(ranges::begin(__r), ranges::end(__r), std::move(__value)); } }; +} // namespace __ranges_iota -inline constexpr __iota_fn iota{}; +inline namespace __cpo { +inline constexpr auto iota = __ranges_iota::__iota_fn{}; +} // namespace __cpo } // namespace ranges #endif // _LIBCPP_STD_VER >= 23 diff --git a/libcxx/test/std/algorithms/algorithms.results/out_value_result.pass.cpp b/libcxx/test/std/algorithms/algorithms.results/out_value_result.pass.cpp index 3a930bb063f97..e1d203929be73 100644 --- a/libcxx/test/std/algorithms/algorithms.results/out_value_result.pass.cpp +++ b/libcxx/test/std/algorithms/algorithms.results/out_value_result.pass.cpp @@ -121,4 +121,4 @@ int main(int, char**) { test(); static_assert(test()); return 0; -} \ No newline at end of file +} diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp index 3a7bc4319bebd..7aedf7ee05844 100644 --- a/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp +++ b/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp @@ -26,8 +26,9 @@ concept HasIotaIter = requires(Iter&& iter, Sent&& sent, Value&& val) { }; template -concept HasIotaRange = - requires(Range&& range, Value&& val) { std::ranges::iota(std::forward(range), std::forward(val)); }; +concept HasIotaRange = requires(Range&& range, Value&& val) { + std::ranges::iota(std::forward(range), std::forward(val)); +}; constexpr void test_constraints() { // Test constraints of the iterator/sentinel overload @@ -120,4 +121,4 @@ int main(int, char**) { test_constraints(); test_results(); return 0; -} \ No newline at end of file +} From 08e3c77d3b7395fc7e78156b693faa72879ca5a0 Mon Sep 17 00:00:00 2001 From: James Smith Date: Thu, 26 Oct 2023 16:53:08 -0400 Subject: [PATCH 08/36] [libc++] Implement ranges::iota: Adding tests to ranges_robust_against_* tests (proxy iterators is failing currently). --- libcxx/include/__numeric/ranges_iota.h | 7 +-- ...result_alias_declarations.compile.pass.cpp | 7 ++- .../ranges_robust_against_dangling.pass.cpp | 43 +++++++++++-------- ...es_robust_against_proxy_iterators.pass.cpp | 22 ++++++---- 4 files changed, 49 insertions(+), 30 deletions(-) diff --git a/libcxx/include/__numeric/ranges_iota.h b/libcxx/include/__numeric/ranges_iota.h index eca5712b3d0d4..9e55c1d1ea892 100644 --- a/libcxx/include/__numeric/ranges_iota.h +++ b/libcxx/include/__numeric/ranges_iota.h @@ -44,13 +44,14 @@ struct __iota_fn { public: // Public facing interfaces template _Sent, weakly_incrementable _Tp> - requires indirectly_writable<_Out, const _Tp&> - constexpr iota_result<_Out, _Tp> operator()(_Out __first, _Sent __last, _Tp __value) const { + requires indirectly_writable<_Out, const _Tp&> _LIBCPP_HIDE_FROM_ABI static constexpr iota_result<_Out, _Tp> + operator()(_Out __first, _Sent __last, _Tp __value) { return __iota_impl(std::move(__first), std::move(__last), std::move(__value)); } template _Range> - constexpr iota_result, _Tp> operator()(_Range&& __r, _Tp __value) const { + _LIBCPP_HIDE_FROM_ABI static constexpr iota_result, _Tp> + operator()(_Range&& __r, _Tp __value) { return __iota_impl(ranges::begin(__r), ranges::end(__r), std::move(__value)); } }; diff --git a/libcxx/test/std/algorithms/ranges_result_alias_declarations.compile.pass.cpp b/libcxx/test/std/algorithms/ranges_result_alias_declarations.compile.pass.cpp index a72c3a374c504..6f82d8f8e7191 100644 --- a/libcxx/test/std/algorithms/ranges_result_alias_declarations.compile.pass.cpp +++ b/libcxx/test/std/algorithms/ranges_result_alias_declarations.compile.pass.cpp @@ -13,9 +13,12 @@ // ensure that all result alias declarations are defined #include +#include #include #include +#include "test_macros.h" + using namespace std::ranges; static_assert(std::is_same_v, for_each_result>); @@ -59,4 +62,6 @@ static_assert(std::is_same_v, minmax_element_result>); static_assert(std::is_same_v, next_permutation_result>); static_assert(std::is_same_v, prev_permutation_result>); -// static_assert(std::is_same_v, iota_result>); +#if TEST_STD_VER >= 23 +static_assert(std::is_same_v, iota_result>); +#endif diff --git a/libcxx/test/std/algorithms/ranges_robust_against_dangling.pass.cpp b/libcxx/test/std/algorithms/ranges_robust_against_dangling.pass.cpp index 1057c747990d6..64db7933cd3d3 100644 --- a/libcxx/test/std/algorithms/ranges_robust_against_dangling.pass.cpp +++ b/libcxx/test/std/algorithms/ranges_robust_against_dangling.pass.cpp @@ -13,7 +13,7 @@ // Range algorithms should return `std::ranges::dangling` when given a dangling range. #include - +#include #include #include #include @@ -23,6 +23,7 @@ #include #include "test_iterators.h" +#include "test_macros.h" struct NonBorrowedRange { using Iter = int*; @@ -41,22 +42,22 @@ struct NonBorrowedRange { using R = NonBorrowedRange; // (dangling_in, ...) -template -constexpr void dangling_1st(Func&& func, Input& in, Args&& ...args) { +template +constexpr void dangling_1st(Func&& func, Input& in, Args&&... args) { decltype(auto) result = func(R(in), std::forward(args)...); static_assert(std::same_as); } // (in, dangling_in, ...) -template -constexpr void dangling_2nd(Func&& func, Input& in1, Input& in2, Args&& ...args) { +template +constexpr void dangling_2nd(Func&& func, Input& in1, Input& in2, Args&&... args) { decltype(auto) result = func(in1, R(in2), std::forward(args)...); static_assert(std::same_as); } // (dangling_in1, dangling_in2, ...) -template -constexpr void dangling_both(Func&& func, Input& in1, Input& in2, Args&& ...args) { +template +constexpr void dangling_both(Func&& func, Input& in1, Input& in2, Args&&... args) { decltype(auto) result = func(R(in1), R(in2), std::forward(args)...); static_assert(std::same_as); } @@ -68,23 +69,24 @@ constexpr bool test_all() { using std::ranges::dangling; using std::ranges::binary_transform_result; - using std::ranges::copy_result; using std::ranges::copy_backward_result; using std::ranges::copy_if_result; + using std::ranges::copy_result; using std::ranges::for_each_result; using std::ranges::merge_result; using std::ranges::minmax_result; using std::ranges::mismatch_result; - using std::ranges::move_result; using std::ranges::move_backward_result; + using std::ranges::move_result; using std::ranges::next_permutation_result; + using std::ranges::out_value_result; using std::ranges::partial_sort_copy_result; using std::ranges::partition_copy_result; using std::ranges::prev_permutation_result; - using std::ranges::remove_copy_result; using std::ranges::remove_copy_if_result; - using std::ranges::replace_copy_result; + using std::ranges::remove_copy_result; using std::ranges::replace_copy_if_result; + using std::ranges::replace_copy_result; using std::ranges::reverse_copy_result; using std::ranges::rotate_copy_result; using std::ranges::set_difference_result; @@ -95,20 +97,20 @@ constexpr bool test_all() { using std::ranges::unary_transform_result; using std::ranges::unique_copy_result; - auto unary_pred = [](int i) { return i > 0; }; + auto unary_pred = [](int i) { return i > 0; }; auto binary_pred = [](int i, int j) { return i < j; }; - auto gen = [] { return 42; }; + auto gen = [] { return 42; }; - std::array in = {1, 2, 3}; + std::array in = {1, 2, 3}; std::array in2 = {4, 5, 6}; auto mid = in.begin() + 1; std::array output = {7, 8, 9, 10, 11, 12}; - auto out = output.begin(); - auto out2 = output.begin() + 1; + auto out = output.begin(); + auto out2 = output.begin() + 1; - int x = 2; + int x = 2; std::size_t count = 1; dangling_1st(std::ranges::find, in, x); @@ -140,7 +142,8 @@ constexpr bool test_all() { dangling_1st(std::ranges::fill, in, x); { // transform std::array out_transform = {false, true, true}; - dangling_1st>(std::ranges::transform, in, out_transform.begin(), unary_pred); + dangling_1st>( + std::ranges::transform, in, out_transform.begin(), unary_pred); dangling_1st>( std::ranges::transform, in, in2, out_transform.begin(), binary_pred); dangling_2nd>( @@ -206,6 +209,10 @@ constexpr bool test_all() { dangling_1st>(std::ranges::prev_permutation, in); dangling_1st>(std::ranges::next_permutation, in); +#if TEST_STD_VER >= 23 + dangling_1st< out_value_result>(std::ranges::iota, in, x); +#endif + return true; } diff --git a/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp b/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp index 5c8aa0153a63c..638a6398883d2 100644 --- a/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp +++ b/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp @@ -14,6 +14,7 @@ // a customization point) rather than plain `swap` (which might not work with certain valid iterators). #include +#include #include #include @@ -28,22 +29,22 @@ #include "test_macros.h" // (in, ...) -template -constexpr void test(Func&& func, Input& in, Args&& ...args) { +template +constexpr void test(Func&& func, Input& in, Args&&... args) { (void)func(in.begin(), in.end(), std::forward(args)...); (void)func(in, std::forward(args)...); } // (in1, in2, ...) -template -constexpr void test(Func&& func, Range1& r1, Range2& r2, Args&& ...args) { +template +constexpr void test(Func&& func, Range1& r1, Range2& r2, Args&&... args) { (void)func(r1.begin(), r1.end(), r2.begin(), r2.end(), std::forward(args)...); (void)func(r1, r2, std::forward(args)...); } // (in, mid, ...) -template -constexpr void test_mid(Func&& func, Input& in, std::ranges::iterator_t mid, Args&& ...args) { +template +constexpr void test_mid(Func&& func, Input& in, std::ranges::iterator_t mid, Args&&... args) { (void)func(in.begin(), mid, in.end(), std::forward(args)...); (void)func(in, mid, std::forward(args)...); } @@ -68,9 +69,9 @@ constexpr void run_tests() { Proxy x{num}; int count = 1; - auto unary_pred = [](const Proxy&) { return true; }; + auto unary_pred = [](const Proxy&) { return true; }; auto binary_func = [](const Proxy&, const Proxy&) -> Proxy { return Proxy(T()); }; - auto gen = [] { return Proxy(T{42}); }; + auto gen = [] { return Proxy(T{42}); }; test(std::ranges::any_of, in, unary_pred); test(std::ranges::all_of, in, unary_pred); @@ -100,6 +101,11 @@ constexpr void run_tests() { test(std::ranges::search, in, in2); test(std::ranges::search_n, in, count, x); test(std::ranges::find_end, in, in2); +#if TEST_STD_VER >= 23 + if constexpr (std::copyable) { + test(std::ranges::iota, in, x); + } +#endif test(std::ranges::is_partitioned, in, unary_pred); test(std::ranges::is_sorted, in); test(std::ranges::is_sorted_until, in); From 67fcac1fa4e47ac7231d4aa755596e01eb73036c Mon Sep 17 00:00:00 2001 From: James Smith Date: Thu, 26 Oct 2023 17:23:38 -0400 Subject: [PATCH 09/36] [libc++] Implement ranges::iota: Fixing formatting problems --- libcxx/include/__numeric/ranges_iota.h | 4 ++-- .../numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/libcxx/include/__numeric/ranges_iota.h b/libcxx/include/__numeric/ranges_iota.h index 9e55c1d1ea892..fccb36396a057 100644 --- a/libcxx/include/__numeric/ranges_iota.h +++ b/libcxx/include/__numeric/ranges_iota.h @@ -44,8 +44,8 @@ struct __iota_fn { public: // Public facing interfaces template _Sent, weakly_incrementable _Tp> - requires indirectly_writable<_Out, const _Tp&> _LIBCPP_HIDE_FROM_ABI static constexpr iota_result<_Out, _Tp> - operator()(_Out __first, _Sent __last, _Tp __value) { + requires indirectly_writable<_Out, const _Tp&> + _LIBCPP_HIDE_FROM_ABI static constexpr iota_result<_Out, _Tp> operator()(_Out __first, _Sent __last, _Tp __value) { return __iota_impl(std::move(__first), std::move(__last), std::move(__value)); } diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp index 7aedf7ee05844..f3cd022943caf 100644 --- a/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp +++ b/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp @@ -26,9 +26,8 @@ concept HasIotaIter = requires(Iter&& iter, Sent&& sent, Value&& val) { }; template -concept HasIotaRange = requires(Range&& range, Value&& val) { - std::ranges::iota(std::forward(range), std::forward(val)); -}; +concept HasIotaRange = + requires(Range&& range, Value&& val) { std::ranges::iota(std::forward(range), std::forward(val)); }; constexpr void test_constraints() { // Test constraints of the iterator/sentinel overload From b13278430d0be6d4b4f14a8260b3dd12dbfa872e Mon Sep 17 00:00:00 2001 From: James Smith Date: Thu, 26 Oct 2023 18:41:21 -0400 Subject: [PATCH 10/36] [libc++] Implement ranges::iota: Addressing comments about out_value_result tests from https://reviews.llvm.org/D121436 --- libcxx/include/__algorithm/out_value_result.h | 4 +- .../no_unique_address.compile.pass.cpp | 4 + .../out_value_result.pass.cpp | 80 +++++++++++-------- 3 files changed, 53 insertions(+), 35 deletions(-) diff --git a/libcxx/include/__algorithm/out_value_result.h b/libcxx/include/__algorithm/out_value_result.h index a99d206f7035f..9e1e0e07286d4 100644 --- a/libcxx/include/__algorithm/out_value_result.h +++ b/libcxx/include/__algorithm/out_value_result.h @@ -34,13 +34,13 @@ struct out_value_result { template requires convertible_to && convertible_to - constexpr operator out_value_result<_OutIter2, _ValType2>() const& { + _LIBCPP_HIDE_FROM_ABI constexpr operator out_value_result<_OutIter2, _ValType2>() const& { return {out, value}; } template requires convertible_to<_OutIter1, _OutIter2> && convertible_to<_ValType1, _ValType2> - constexpr operator out_value_result<_OutIter2, _ValType2>() && { + _LIBCPP_HIDE_FROM_ABI constexpr operator out_value_result<_OutIter2, _ValType2>() && { return {std::move(out), std::move(value)}; } }; diff --git a/libcxx/test/std/algorithms/algorithms.results/no_unique_address.compile.pass.cpp b/libcxx/test/std/algorithms/algorithms.results/no_unique_address.compile.pass.cpp index 8e0a81959f27c..c67b937590544 100644 --- a/libcxx/test/std/algorithms/algorithms.results/no_unique_address.compile.pass.cpp +++ b/libcxx/test/std/algorithms/algorithms.results/no_unique_address.compile.pass.cpp @@ -53,6 +53,10 @@ static_assert(sizeof(std::ranges::in_out_out_result) == 2); static_assert(sizeof(std::ranges::in_out_out_result) == sizeof(int)); static_assert(sizeof(std::ranges::in_out_out_result) == 3); +static_assert(sizeof(std::ranges::out_value_result) == sizeof(int)); +static_assert(sizeof(std::ranges::out_value_result) == sizeof(int)); +static_assert(sizeof(std::ranges::out_value_result) == 2); + // In min_max_result both elements have the same type, so they can't have the same address. // So the only way to test that [[no_unique_address]] is used is to have it in another struct struct MinMaxNoUniqueAddress { diff --git a/libcxx/test/std/algorithms/algorithms.results/out_value_result.pass.cpp b/libcxx/test/std/algorithms/algorithms.results/out_value_result.pass.cpp index e1d203929be73..99dfbd42050d1 100644 --- a/libcxx/test/std/algorithms/algorithms.results/out_value_result.pass.cpp +++ b/libcxx/test/std/algorithms/algorithms.results/out_value_result.pass.cpp @@ -17,6 +17,8 @@ #include "MoveOnly.h" +using std::ranges::out_value_result; + // // Helper structs // @@ -43,62 +45,61 @@ struct ConvertibleFrom { T content; }; +// Standard layout classes can't have virtual functions +struct NonStandardLayoutTypeBase { + virtual ~NonStandardLayoutTypeBase(); +}; +struct NonStandardLayoutType : public NonStandardLayoutTypeBase {}; + // constexpr void test_constraints() { // requires convertible_to && convertible_to - static_assert( - std::is_constructible_v, std::ranges::out_value_result>); + static_assert(std::is_constructible_v, out_value_result>); // test failure when implicit conversion isn't allowed - static_assert(!std::is_constructible_v, - std::ranges::out_value_result>); + static_assert(!std::is_constructible_v, out_value_result>); // test success when implicit conversion is allowed, checking combinations of value, reference, and const - static_assert(std::is_constructible_v, - std::ranges::out_value_result>); - static_assert(std::is_constructible_v, - std::ranges::out_value_result const>); - static_assert(std::is_constructible_v, - std::ranges::out_value_result&>); - static_assert(std::is_constructible_v, - std::ranges::out_value_result const&>); - - static_assert(!std::is_constructible_v, - std::ranges::out_value_result&>); + static_assert(std::is_constructible_v, out_value_result>); + static_assert(std::is_constructible_v, out_value_result const>); + static_assert(std::is_constructible_v, out_value_result&>); + static_assert(std::is_constructible_v, out_value_result const&>); + + static_assert(!std::is_constructible_v, out_value_result&>); // has to be convertible via const& - static_assert( - std::is_convertible_v&, std::ranges::out_value_result>); - static_assert( - std::is_convertible_v&, std::ranges::out_value_result>); - static_assert( - std::is_convertible_v&&, std::ranges::out_value_result>); - static_assert(std::is_convertible_v&&, - std::ranges::out_value_result>); + static_assert(std::is_convertible_v&, out_value_result>); + static_assert(std::is_convertible_v&, out_value_result>); + static_assert(std::is_convertible_v&&, out_value_result>); + static_assert(std::is_convertible_v&&, out_value_result>); // should be move constructible - static_assert(std::is_move_constructible_v>); - static_assert(std::is_move_constructible_v>); + static_assert(std::is_move_constructible_v>); + static_assert(std::is_move_constructible_v>); // conversions should not work if there is no conversion - static_assert(!std::is_convertible_v, - std::ranges::out_value_result>); - static_assert(!std::is_convertible_v, - std::ranges::out_value_result>); + static_assert(!std::is_convertible_v, out_value_result>); + static_assert(!std::is_convertible_v, out_value_result>); + + // check standard layout + static_assert(std::is_standard_layout_v>); + static_assert(!std::is_standard_layout_v>); } // Test results constexpr bool test() { { - std::ranges::out_value_result res{10, 1}; + // Check that conversion operator works + out_value_result res{10, 1}; assert(res.out == 10); assert(res.value == 1); - std::ranges::out_value_result, ConvertibleFrom> res2 = res; + out_value_result, ConvertibleFrom> res2 = res; assert(res2.out.content == 10); assert(res2.value.content == 1); } { - std::ranges::out_value_result res{MoveOnly{}, 10}; + // Check that out_value_result isn't overconstrained w.r.t. move/copy constructors + out_value_result res{MoveOnly{}, 10}; assert(res.out.get() == 1); assert(res.value == 10); auto res2 = std::move(res); @@ -108,10 +109,23 @@ constexpr bool test() { assert(res2.value == 10); } { - auto [out, val] = std::ranges::out_value_result{1, 2}; + // Check structured binding + auto [out, val] = out_value_result{1, 2}; assert(out == 1); assert(val == 2); } + { + // Check default construction + out_value_result res; + static_assert(std::is_same_v); + static_assert(std::is_same_v); + } + { + // Check aggregate initiazliation + out_value_result res = {1, 2}; + assert(res.out == 1); + assert(res.value == 2); + } return true; } From 88e271a619f555d56f99f50c1e2b0172727914c7 Mon Sep 17 00:00:00 2001 From: James Smith Date: Fri, 27 Oct 2023 19:03:47 -0400 Subject: [PATCH 11/36] [libc++] Implement ranges::iota: Updating Proxy in test_iterators.h to be weakly_incrementable for certain T (which we need to test ranges::iota). test_iterators.h is not formatted because a lot of the code outside of my changes would get reformatted and I don't want to overcomplicate the diff. --- libcxx/test/support/test_iterators.h | 56 +++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 5 deletions(-) diff --git a/libcxx/test/support/test_iterators.h b/libcxx/test/support/test_iterators.h index 1133b9597d09c..7559e347d90f5 100644 --- a/libcxx/test/support/test_iterators.h +++ b/libcxx/test/support/test_iterators.h @@ -1083,6 +1083,31 @@ rvalue_iterator(T*) -> rvalue_iterator; static_assert(std::random_access_iterator>); +// The ProxyDiffTBase allows us to conditionally specify Proxy::difference_type +// which we need in certain situations. For example when we want +// std::weakly_incrementable> to be true. +template +struct ProxyDiffTBase {}; + +template + requires requires { std::iter_difference_t{}; } +struct ProxyDiffTBase { + using difference_type = std::iter_difference_t; +}; + +// These concepts allow us to conditionally add the pre-/postfix operators +// when T also supports those member functions. Like ProxyDiffTBase, this +// is necessary when we want std::weakly_incrementable> to be true. +template +concept HasPreIncrementOp = requires(T const& obj) { + ++obj; +}; + +template +concept HasPostIncrementOp = requires(T const& obj) { + obj++; +}; + // Proxy // ====================================================================== // Proxy that can wrap a value or a reference. It simulates C++23's tuple @@ -1093,6 +1118,7 @@ static_assert(std::random_access_iterator>); // 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; @@ -1103,7 +1129,7 @@ template inline constexpr bool IsProxy> = true; template -struct Proxy { +struct Proxy : ProxyDiffTBase { T data; constexpr T& getData() & { return data; } @@ -1149,9 +1175,11 @@ struct Proxy { // 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&) + friend constexpr bool operator==(const Proxy& lhs, const Proxy& rhs) requires (std::equality_comparable && !std::is_reference_v) - = default; + { + return lhs.data == rhs.data; + }; // Helps compare e.g. `Proxy` and `Proxy`. Note that the default equality comparison operator is deleted // when `T` is a reference type. @@ -1161,9 +1189,11 @@ struct Proxy { return lhs.data == rhs.data; } - friend constexpr auto operator<=>(const Proxy&, const Proxy&) + friend constexpr auto operator<=>(const Proxy& lhs, const Proxy& rhs) requires (std::three_way_comparable && !std::is_reference_v) - = default; + { + return lhs.data <=> rhs.data; + }; // Helps compare e.g. `Proxy` and `Proxy`. Note that the default 3-way comparison operator is deleted when // `T` is a reference type. @@ -1172,6 +1202,22 @@ struct Proxy { requires std::three_way_comparable_with, std::decay_t> { return lhs.data <=> rhs.data; } + + // Needed to allow certain types to be weakly_incremental + constexpr Proxy& operator++() + requires(HasPreIncrementOp) + { + ++data; + return *this; + } + + constexpr Proxy operator++(int) + requires(HasPostIncrementOp) + { + Proxy tmp = *this; + operator++(); + return tmp; + } }; // This is to make ProxyIterator model `std::indirectly_readable` From ff5bf791be9d650495151edd7c126b0827722e79 Mon Sep 17 00:00:00 2001 From: James Smith Date: Sat, 28 Oct 2023 11:44:15 -0400 Subject: [PATCH 12/36] [libc++] Implement ranges::iota: Fixing some of the buildkite errors, modules are still not working locally --- .../out_value_result.pass.cpp | 2 +- .../numeric.version.compile.pass.cpp | 32 ++++++------------- .../version.version.compile.pass.cpp | 32 ++++++------------- 3 files changed, 21 insertions(+), 45 deletions(-) diff --git a/libcxx/test/std/algorithms/algorithms.results/out_value_result.pass.cpp b/libcxx/test/std/algorithms/algorithms.results/out_value_result.pass.cpp index 99dfbd42050d1..f935fc54feb64 100644 --- a/libcxx/test/std/algorithms/algorithms.results/out_value_result.pass.cpp +++ b/libcxx/test/std/algorithms/algorithms.results/out_value_result.pass.cpp @@ -122,7 +122,7 @@ constexpr bool test() { } { // Check aggregate initiazliation - out_value_result res = {1, 2}; + out_value_result res = {1, 2}; assert(res.out == 1); assert(res.value == 2); } diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/numeric.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/numeric.version.compile.pass.cpp index 60004b06c5ff5..75ab121a24161 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/numeric.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/numeric.version.compile.pass.cpp @@ -180,17 +180,11 @@ # endif # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_ranges_iota -# error "__cpp_lib_ranges_iota should be defined in c++23" -# endif -# if __cpp_lib_ranges_iota != 202202L -# error "__cpp_lib_ranges_iota should have the value 202202L in c++23" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_ranges_iota -# error "__cpp_lib_ranges_iota should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_ranges_iota +# error "__cpp_lib_ranges_iota should be defined in c++23" +# endif +# if __cpp_lib_ranges_iota != 202202L +# error "__cpp_lib_ranges_iota should have the value 202202L in c++23" # endif #elif TEST_STD_VER > 23 @@ -229,17 +223,11 @@ # endif # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_ranges_iota -# error "__cpp_lib_ranges_iota should be defined in c++26" -# endif -# if __cpp_lib_ranges_iota != 202202L -# error "__cpp_lib_ranges_iota should have the value 202202L in c++26" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_ranges_iota -# error "__cpp_lib_ranges_iota should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_ranges_iota +# error "__cpp_lib_ranges_iota should be defined in c++26" +# endif +# if __cpp_lib_ranges_iota != 202202L +# error "__cpp_lib_ranges_iota should have the value 202202L in c++26" # endif #endif // TEST_STD_VER > 23 diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp index ed86c555221c5..56c294683538f 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp @@ -4972,17 +4972,11 @@ # error "__cpp_lib_ranges_chunk_by should have the value 202202L in c++23" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_ranges_iota -# error "__cpp_lib_ranges_iota should be defined in c++23" -# endif -# if __cpp_lib_ranges_iota != 202202L -# error "__cpp_lib_ranges_iota should have the value 202202L in c++23" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_ranges_iota -# error "__cpp_lib_ranges_iota should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_ranges_iota +# error "__cpp_lib_ranges_iota should be defined in c++23" +# endif +# if __cpp_lib_ranges_iota != 202202L +# error "__cpp_lib_ranges_iota should have the value 202202L in c++23" # endif # if !defined(_LIBCPP_VERSION) @@ -6507,17 +6501,11 @@ # error "__cpp_lib_ranges_chunk_by should have the value 202202L in c++26" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_ranges_iota -# error "__cpp_lib_ranges_iota should be defined in c++26" -# endif -# if __cpp_lib_ranges_iota != 202202L -# error "__cpp_lib_ranges_iota should have the value 202202L in c++26" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_ranges_iota -# error "__cpp_lib_ranges_iota should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_ranges_iota +# error "__cpp_lib_ranges_iota should be defined in c++26" +# endif +# if __cpp_lib_ranges_iota != 202202L +# error "__cpp_lib_ranges_iota should have the value 202202L in c++26" # endif # if !defined(_LIBCPP_VERSION) From b8f07b8fcb63cf88320734e8c7c2d98fcbc0e800 Mon Sep 17 00:00:00 2001 From: James Smith Date: Mon, 30 Oct 2023 11:23:39 -0400 Subject: [PATCH 13/36] [libc++] Implement ranges::iota: Explicitly adding #include for ranges::borrowed_iterator_t which was missing from module builds. Not sure why this hasn't caused problems before --- libcxx/include/__numeric/ranges_iota.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libcxx/include/__numeric/ranges_iota.h b/libcxx/include/__numeric/ranges_iota.h index fccb36396a057..914d67a6d443b 100644 --- a/libcxx/include/__numeric/ranges_iota.h +++ b/libcxx/include/__numeric/ranges_iota.h @@ -13,6 +13,7 @@ #include <__algorithm/out_value_result.h> #include <__config> #include <__ranges/concepts.h> +#include <__ranges/dangling.h> #include <__utility/as_const.h> #include <__utility/move.h> From a4d34fd33830c1302200b87e6776299881957754 Mon Sep 17 00:00:00 2001 From: James Smith Date: Mon, 30 Oct 2023 12:04:02 -0400 Subject: [PATCH 14/36] [libc++] Implement ranges::iota: Explicitly adding #include for ranges::begin because the module builds are complaining that it's missing --- libcxx/include/__numeric/ranges_iota.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libcxx/include/__numeric/ranges_iota.h b/libcxx/include/__numeric/ranges_iota.h index 914d67a6d443b..3b92d4e94554a 100644 --- a/libcxx/include/__numeric/ranges_iota.h +++ b/libcxx/include/__numeric/ranges_iota.h @@ -12,6 +12,7 @@ #include <__algorithm/out_value_result.h> #include <__config> +#include <__ranges/access.h> #include <__ranges/concepts.h> #include <__ranges/dangling.h> #include <__utility/as_const.h> From 815324428d4eaeebffa369ee881333be010488e9 Mon Sep 17 00:00:00 2001 From: James Smith Date: Mon, 30 Oct 2023 20:59:36 -0400 Subject: [PATCH 15/36] [libc++] Implement ranges::iota: Adding #ifdef _LIBCPP_STD_VER >= 23 checks around out_value_result tests. --- libcxx/modules/std/algorithm.inc | 2 ++ .../algorithms.results/no_unique_address.compile.pass.cpp | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/libcxx/modules/std/algorithm.inc b/libcxx/modules/std/algorithm.inc index 62ce8cf02c14f..3ee048e3f8170 100644 --- a/libcxx/modules/std/algorithm.inc +++ b/libcxx/modules/std/algorithm.inc @@ -18,7 +18,9 @@ export namespace std { using std::ranges::in_out_result; // using std::ranges::in_value_result; using std::ranges::min_max_result; +#if _LIBCPP_STD_VER >= 23 using std::ranges::out_value_result; +#endif } // namespace ranges // [alg.nonmodifying], non-modifying sequence operations diff --git a/libcxx/test/std/algorithms/algorithms.results/no_unique_address.compile.pass.cpp b/libcxx/test/std/algorithms/algorithms.results/no_unique_address.compile.pass.cpp index c67b937590544..83a9e4c7da902 100644 --- a/libcxx/test/std/algorithms/algorithms.results/no_unique_address.compile.pass.cpp +++ b/libcxx/test/std/algorithms/algorithms.results/no_unique_address.compile.pass.cpp @@ -53,10 +53,11 @@ static_assert(sizeof(std::ranges::in_out_out_result) == 2); static_assert(sizeof(std::ranges::in_out_out_result) == sizeof(int)); static_assert(sizeof(std::ranges::in_out_out_result) == 3); +#if _LIBCPP_STD_VER >= 23 static_assert(sizeof(std::ranges::out_value_result) == sizeof(int)); static_assert(sizeof(std::ranges::out_value_result) == sizeof(int)); static_assert(sizeof(std::ranges::out_value_result) == 2); - +#endif // In min_max_result both elements have the same type, so they can't have the same address. // So the only way to test that [[no_unique_address]] is used is to have it in another struct struct MinMaxNoUniqueAddress { From a872e3978d4ac876739dbf2e3abcd55668e49fd6 Mon Sep 17 00:00:00 2001 From: James Smith Date: Sat, 4 Nov 2023 18:00:58 -0400 Subject: [PATCH 16/36] [libc++] Implement ranges::iota: Missing a few more #if TEST_STD_VER >= 23 statments in tests (several c++20 tests were failing on buildkite) --- .../std/algorithms/algorithms.results/out_value_result.pass.cpp | 2 +- .../test/std/algorithms/ranges_robust_against_dangling.pass.cpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/libcxx/test/std/algorithms/algorithms.results/out_value_result.pass.cpp b/libcxx/test/std/algorithms/algorithms.results/out_value_result.pass.cpp index f935fc54feb64..bc8c665950f43 100644 --- a/libcxx/test/std/algorithms/algorithms.results/out_value_result.pass.cpp +++ b/libcxx/test/std/algorithms/algorithms.results/out_value_result.pass.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03, c++11, c++14, c++17, C++20 +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 // template // struct out_value_result; diff --git a/libcxx/test/std/algorithms/ranges_robust_against_dangling.pass.cpp b/libcxx/test/std/algorithms/ranges_robust_against_dangling.pass.cpp index 64db7933cd3d3..05c598da24163 100644 --- a/libcxx/test/std/algorithms/ranges_robust_against_dangling.pass.cpp +++ b/libcxx/test/std/algorithms/ranges_robust_against_dangling.pass.cpp @@ -79,7 +79,9 @@ constexpr bool test_all() { using std::ranges::move_backward_result; using std::ranges::move_result; using std::ranges::next_permutation_result; +#if TEST_STD_VER >= 23 using std::ranges::out_value_result; +#endif using std::ranges::partial_sort_copy_result; using std::ranges::partition_copy_result; using std::ranges::prev_permutation_result; From b84859b6a3e5f15c541734da313704eed3a97c69 Mon Sep 17 00:00:00 2001 From: James Smith Date: Sun, 5 Nov 2023 07:38:22 -0500 Subject: [PATCH 17/36] [libc++] Implement ranges::iota: Removing several of the ranges_robust_against_* files from ignore_format.txt. --- libcxx/utils/data/ignore_format.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/libcxx/utils/data/ignore_format.txt b/libcxx/utils/data/ignore_format.txt index 1eb3bf5d5e867..cdc9d667a332b 100644 --- a/libcxx/utils/data/ignore_format.txt +++ b/libcxx/utils/data/ignore_format.txt @@ -1288,9 +1288,7 @@ libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp libcxx/test/std/algorithms/alg.sorting/alg.three.way/lexicographical_compare_three_way_comp.pass.cpp libcxx/test/std/algorithms/alg.sorting/alg.three.way/lexicographical_compare_three_way.pass.cpp libcxx/test/std/algorithms/alg.sorting/sortable_helpers.h -libcxx/test/std/algorithms/ranges_robust_against_dangling.pass.cpp libcxx/test/std/algorithms/ranges_robust_against_differing_projections.pass.cpp -libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp libcxx/test/std/algorithms/robust_against_adl.compile.pass.cpp libcxx/test/std/algorithms/robust_against_adl_on_new.pass.cpp libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp From 72125eaf8f7e1bd728013c5189948339efb7e4d6 Mon Sep 17 00:00:00 2001 From: James Smith Date: Mon, 18 Dec 2023 15:53:41 -0500 Subject: [PATCH 18/36] [libc++] Implement ranges::iota: Updating with upstream and adding std::out_value_result to modulemap --- libcxx/include/module.modulemap.in | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in index 5113e2f30470f..e69eb02bce97a 100644 --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -713,6 +713,7 @@ module std_private_algorithm_move_backward [system module std_private_algorithm_next_permutation [system] { header "__algorithm/next_permutation.h" } module std_private_algorithm_none_of [system] { header "__algorithm/none_of.h" } module std_private_algorithm_nth_element [system] { header "__algorithm/nth_element.h" } +module std_private_algorithm_out_value_result [system] { header "__algorithm/out_value_result.h" } module std_private_algorithm_partial_sort [system] { header "__algorithm/partial_sort.h" } module std_private_algorithm_partial_sort_copy [system] { header "__algorithm/partial_sort_copy.h" } module std_private_algorithm_partition [system] { header "__algorithm/partition.h" } @@ -1580,7 +1581,10 @@ module std_private_numeric_pstl_transform_reduce [system] { export * } module std_private_numeric_reduce [system] { header "__numeric/reduce.h" } -module std_private_numeric_ranges_iota [system] { header "__numeric/ranges_iota.h" } +module std_private_numeric_ranges_iota [system] { + header "__numeric/ranges_iota.h" + export std_private_algorithm_out_value_result +} module std_private_numeric_transform_exclusive_scan [system] { header "__numeric/transform_exclusive_scan.h" } module std_private_numeric_transform_inclusive_scan [system] { header "__numeric/transform_inclusive_scan.h" } module std_private_numeric_transform_reduce [system] { header "__numeric/transform_reduce.h" } From 028ce92e61f1e6cbcf72db2d51e32072055c2738 Mon Sep 17 00:00:00 2001 From: James Smith Date: Tue, 19 Dec 2023 16:36:00 -0500 Subject: [PATCH 19/36] [libc++] Implement ranges::iota: Fixing formatting problems with test_iterators.h --- libcxx/test/support/test_iterators.h | 32 ++++++++++++---------------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/libcxx/test/support/test_iterators.h b/libcxx/test/support/test_iterators.h index f49c90f4141e6..6bae0a4c9def4 100644 --- a/libcxx/test/support/test_iterators.h +++ b/libcxx/test/support/test_iterators.h @@ -1090,23 +1090,19 @@ template struct ProxyDiffTBase {}; template - requires requires { std::iter_difference_t{}; } + requires requires { std::iter_difference_t{}; } struct ProxyDiffTBase { - using difference_type = std::iter_difference_t; + using difference_type = std::iter_difference_t; }; // These concepts allow us to conditionally add the pre-/postfix operators -// when T also supports those member functions. Like ProxyDiffTBase, this +// when T also supports those member functions. Like ProxyDiffTBase, this // is necessary when we want std::weakly_incrementable> to be true. template -concept HasPreIncrementOp = requires(T const& obj) { - ++obj; -}; +concept HasPreIncrementOp = requires(T const& obj) { ++obj; }; template -concept HasPostIncrementOp = requires(T const& obj) { - obj++; -}; +concept HasPostIncrementOp = requires(T const& obj) { obj++; }; // Proxy // ====================================================================== @@ -1176,7 +1172,7 @@ struct Proxy : ProxyDiffTBase { // Compare operators are defined for the convenience of the tests friend constexpr bool operator==(const Proxy& lhs, const Proxy& rhs) - requires (std::equality_comparable && !std::is_reference_v) + requires(std::equality_comparable && !std::is_reference_v) { return lhs.data == rhs.data; }; @@ -1190,7 +1186,7 @@ struct Proxy : ProxyDiffTBase { } friend constexpr auto operator<=>(const Proxy& lhs, const Proxy& rhs) - requires (std::three_way_comparable && !std::is_reference_v) + requires(std::three_way_comparable && !std::is_reference_v) { return lhs.data <=> rhs.data; }; @@ -1205,18 +1201,18 @@ struct Proxy : ProxyDiffTBase { // Needed to allow certain types to be weakly_incremental constexpr Proxy& operator++() - requires(HasPreIncrementOp) + requires(HasPreIncrementOp) { - ++data; - return *this; + ++data; + return *this; } constexpr Proxy operator++(int) - requires(HasPostIncrementOp) + requires(HasPostIncrementOp) { - Proxy tmp = *this; - operator++(); - return tmp; + Proxy tmp = *this; + operator++(); + return tmp; } }; From b3f260ec9db7cd7f61ecd694c73253308bc3c7e8 Mon Sep 17 00:00:00 2001 From: James Smith Date: Fri, 5 Jan 2024 16:31:00 -0500 Subject: [PATCH 20/36] [libc++] Implement ranges::iota: Improving ranges::iota tests and docs to address review comments --- libcxx/docs/Status/Cxx23.rst | 1 + libcxx/docs/Status/Cxx23Papers.csv | 2 +- .../numeric.iota/ranges.iota.pass.cpp | 134 ++++++++++++------ 3 files changed, 93 insertions(+), 44 deletions(-) diff --git a/libcxx/docs/Status/Cxx23.rst b/libcxx/docs/Status/Cxx23.rst index 3e6e33f08c7cc..c576f1809219e 100644 --- a/libcxx/docs/Status/Cxx23.rst +++ b/libcxx/docs/Status/Cxx23.rst @@ -49,6 +49,7 @@ Paper Status .. [#note-P2693R1] P2693R1: The formatter for ``std::thread::id`` is implemented. The formatter for ``stacktrace`` is not implemented, since ``stacktrace`` is not implemented yet. + .. [#note-P2400R1] P2400R1: ranges::shift_left and ranges::shift_right have not been implemented yet. .. _issues-status-cxx23: diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv index 67e95ae44dd51..db0ba4dbd3b9b 100644 --- a/libcxx/docs/Status/Cxx23Papers.csv +++ b/libcxx/docs/Status/Cxx23Papers.csv @@ -46,7 +46,7 @@ "`P2255R2 `__","LWG","A type trait to detect reference binding to temporary","February 2022","","" "`P2273R3 `__","LWG","Making ``std::unique_ptr`` constexpr","February 2022","|Complete|","16.0" "`P2387R3 `__","LWG","Pipe support for user-defined range adaptors","February 2022","","","|ranges|" -"`P2440R1 `__","LWG","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","February 2022","|In progress|","","|ranges|" +"`P2440R1 `__","LWG","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","February 2022","|In progress| [#note-P2400R1]_","","|ranges|" "`P2441R2 `__","LWG","``views::join_with``","February 2022","|In Progress|","","|ranges|" "`P2442R1 `__","LWG","Windowing range adaptors: ``views::chunk`` and ``views::slide``","February 2022","","","|ranges|" "`P2443R1 `__","LWG","``views::chunk_by``","February 2022","|Complete|","18.0","|ranges|" diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp index f3cd022943caf..80ba3493c5a7d 100644 --- a/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp +++ b/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp @@ -14,11 +14,16 @@ #include #include #include +#include // TODO RM #include "test_macros.h" #include "test_iterators.h" #include "almost_satisfies_types.h" +// +// Testing constraints +// + // Concepts to check different overloads of std::ranges::iota template concept HasIotaIter = requires(Iter&& iter, Sent&& sent, Value&& val) { @@ -29,41 +34,84 @@ template concept HasIotaRange = requires(Range&& range, Value&& val) { std::ranges::iota(std::forward(range), std::forward(val)); }; -constexpr void test_constraints() { - // Test constraints of the iterator/sentinel overload - // ================================================== - static_assert(HasIotaIter); +// Test constraints of the iterator/sentinel overload +// ================================================== +static_assert(HasIotaIter); - // !input_or_output_iterator - static_assert(!HasIotaIter); +// !input_or_output_iterator +static_assert(!HasIotaIter); - // !sentinel_for - static_assert(!HasIotaIter); - static_assert(!HasIotaIter); +// !sentinel_for +static_assert(!HasIotaIter); +static_assert(!HasIotaIter); - // !weakly_incrementable - static_assert(!HasIotaIter); +// !weakly_incrementable +static_assert(!HasIotaIter); - // !indirectly writable - static_assert(!HasIotaIter); +// !indirectly writable +static_assert(!HasIotaIter); - // Test constraints for the range overload - // ======================================= - static_assert(HasIotaRange, int>); +// Test constraints for the range overload +// ======================================= +static_assert(HasIotaRange, int>); - // !weakly_incrementable - static_assert(!HasIotaRange, WeaklyIncrementableNotMovable>); +// !weakly_incrementable +static_assert(!HasIotaRange, WeaklyIncrementableNotMovable>); - // !ranges::output_range - static_assert(!HasIotaRange, OutputIteratorNotIndirectlyWritable>); -} +// !ranges::output_range +static_assert(!HasIotaRange, OutputIteratorNotIndirectlyWritable>); + +// +// Testing results +// + +struct DangerousCopyAssign { + int val; + using difference_type = int; + + constexpr explicit DangerousCopyAssign(int v) : val(v) {} + + // Needed in postfix + constexpr DangerousCopyAssign(DangerousCopyAssign const& other) { this->val = other.val; } + + // mischievious copy assignment that we won't use if the + // std::as_const inside ranges::iota isn't working, this should perturb the + // results + constexpr DangerousCopyAssign& operator=(DangerousCopyAssign& a) { + ++a.val; + this->val = a.val; + return *this; + } + + // safe copy assignment std::as_const inside ranges::iota should ensure this + // overload gets called + constexpr DangerousCopyAssign& operator=(DangerousCopyAssign const& a) { + this->val = a.val; + return *this; + } -template -constexpr void test_result(std::array input, int starting_value, std::array const expected) { + constexpr bool operator==(DangerousCopyAssign const& rhs) { return this->val == rhs.val; } + + // prefix + constexpr DangerousCopyAssign& operator++() { + ++(this->val); + return *this; + } + + // postfix + constexpr DangerousCopyAssign operator++(int) { + auto tmp = *this; + ++this->val; + return tmp; + } +}; + +template +constexpr void test_result(std::array input, T starting_value, std::array const expected) { { // (iterator, sentinel) overload auto in_begin = Iter(input.data()); auto in_end = Sent(Iter(input.data() + input.size())); - std::same_as> decltype(auto) result = + std::same_as> decltype(auto) result = std::ranges::iota(std::move(in_begin), std::move(in_end), starting_value); assert(result.out == in_end); if constexpr (expected.size() > 0) { @@ -76,20 +124,16 @@ constexpr void test_result(std::array input, int starting_value, std::ar // The range overload adds the additional constraint that it must be an outputrange // so skip this for the input iterators we test - if constexpr (!std::is_same_v> && - !std::is_same_v>) { // (range) overload + if constexpr (!std::is_same_v> && + !std::is_same_v>) { // (range) overload auto in_begin = Iter(input.data()); auto in_end = Sent(Iter(input.data() + input.size())); auto range = std::ranges::subrange(std::move(in_begin), std::move(in_end)); - std::same_as> decltype(auto) result = + std::same_as> decltype(auto) result = std::ranges::iota(range, starting_value); assert(result.out == in_end); - if constexpr (expected.size() > 0) { - assert(result.value == expected.back() + 1); - } else { - assert(result.value == starting_value); - } + assert(result.value == starting_value + N); assert(std::ranges::equal(input, expected)); } } @@ -97,27 +141,31 @@ constexpr void test_result(std::array input, int starting_value, std::ar template > constexpr void test_results() { // Empty - test_result({}, 0, {}); + test_result({}, 0, {}); // 1-element sequence - test_result({1}, 0, {0}); + test_result({1}, 0, {0}); // Longer sequence - test_result({1, 2, 3, 4, 5}, 0, {0, 1, 2, 3, 4}); + test_result({1, 2, 3, 4, 5}, 0, {0, 1, 2, 3, 4}); +} + +constexpr void test_DangerousCopyAssign() { + using A = DangerousCopyAssign; + using Iter = contiguous_iterator; + std::array aa = {A{1}, A{2}, A{3}}; + std::array expected = {A{0}, A{1}, A{2}}; + std::ranges::iota(aa, A{0}); + auto proj_val = [](DangerousCopyAssign const& el) { return el.val; }; + assert(std::ranges::equal(aa, expected, std::ranges::equal_to{}, proj_val, proj_val)); } void test_results() { - test_results>(); - test_results>(); + types::for_each(types::cpp20_input_iterator_list{}, [] { test_results< Iter>(); }); test_results>(); test_results>(); - test_results>(); - test_results>(); - test_results>(); - test_results>(); - test_results(); + test_DangerousCopyAssign(); } int main(int, char**) { - test_constraints(); test_results(); return 0; } From be7faa6fb11c09822a9a855c7cf1aecab4f4c773 Mon Sep 17 00:00:00 2001 From: James Smith Date: Sat, 6 Jan 2024 14:41:37 -0500 Subject: [PATCH 21/36] [libc++] Implement ranges::iota: Removing unnecessary namespaces in ranges::iota impl and cleaning pu small other comments. --- libcxx/include/__numeric/ranges_iota.h | 6 +-- .../ranges_robust_against_dangling.pass.cpp | 47 +++++++++---------- .../numeric.iota/ranges.iota.pass.cpp | 47 +++++++++---------- 3 files changed, 46 insertions(+), 54 deletions(-) diff --git a/libcxx/include/__numeric/ranges_iota.h b/libcxx/include/__numeric/ranges_iota.h index 3b92d4e94554a..750964ff77a4c 100644 --- a/libcxx/include/__numeric/ranges_iota.h +++ b/libcxx/include/__numeric/ranges_iota.h @@ -29,7 +29,6 @@ namespace ranges { template using iota_result = ranges::out_value_result<_Out, _Tp>; -namespace __ranges_iota { struct __iota_fn { private: // Private helper function @@ -57,11 +56,8 @@ struct __iota_fn { return __iota_impl(ranges::begin(__r), ranges::end(__r), std::move(__value)); } }; -} // namespace __ranges_iota -inline namespace __cpo { -inline constexpr auto iota = __ranges_iota::__iota_fn{}; -} // namespace __cpo +inline constexpr auto iota = __iota_fn{}; } // namespace ranges #endif // _LIBCPP_STD_VER >= 23 diff --git a/libcxx/test/std/algorithms/ranges_robust_against_dangling.pass.cpp b/libcxx/test/std/algorithms/ranges_robust_against_dangling.pass.cpp index d91d4f83e5a0d..79631af03b218 100644 --- a/libcxx/test/std/algorithms/ranges_robust_against_dangling.pass.cpp +++ b/libcxx/test/std/algorithms/ranges_robust_against_dangling.pass.cpp @@ -13,11 +13,12 @@ // Range algorithms should return `std::ranges::dangling` when given a dangling range. #include -#include + #include #include #include #include +#include #include #include #include @@ -42,22 +43,22 @@ struct NonBorrowedRange { using R = NonBorrowedRange; // (dangling_in, ...) -template -constexpr void dangling_1st(Func&& func, Input& in, Args&&... args) { +template +constexpr void dangling_1st(Func&& func, Input& in, Args&& ...args) { decltype(auto) result = func(R(in), std::forward(args)...); static_assert(std::same_as); } // (in, dangling_in, ...) -template -constexpr void dangling_2nd(Func&& func, Input& in1, Input& in2, Args&&... args) { +template +constexpr void dangling_2nd(Func&& func, Input& in1, Input& in2, Args&& ...args) { decltype(auto) result = func(in1, R(in2), std::forward(args)...); static_assert(std::same_as); } // (dangling_in1, dangling_in2, ...) -template -constexpr void dangling_both(Func&& func, Input& in1, Input& in2, Args&&... args) { +template +constexpr void dangling_both(Func&& func, Input& in1, Input& in2, Args&& ...args) { decltype(auto) result = func(R(in1), R(in2), std::forward(args)...); static_assert(std::same_as); } @@ -69,15 +70,15 @@ constexpr bool test_all() { using std::ranges::dangling; using std::ranges::binary_transform_result; + using std::ranges::copy_result; using std::ranges::copy_backward_result; using std::ranges::copy_if_result; - using std::ranges::copy_result; using std::ranges::for_each_result; using std::ranges::merge_result; using std::ranges::minmax_result; using std::ranges::mismatch_result; - using std::ranges::move_backward_result; using std::ranges::move_result; + using std::ranges::move_backward_result; using std::ranges::next_permutation_result; #if TEST_STD_VER >= 23 using std::ranges::out_value_result; @@ -85,10 +86,10 @@ constexpr bool test_all() { using std::ranges::partial_sort_copy_result; using std::ranges::partition_copy_result; using std::ranges::prev_permutation_result; - using std::ranges::remove_copy_if_result; using std::ranges::remove_copy_result; - using std::ranges::replace_copy_if_result; + using std::ranges::remove_copy_if_result; using std::ranges::replace_copy_result; + using std::ranges::replace_copy_if_result; using std::ranges::reverse_copy_result; using std::ranges::rotate_copy_result; using std::ranges::set_difference_result; @@ -98,23 +99,23 @@ constexpr bool test_all() { using std::ranges::swap_ranges_result; using std::ranges::unary_transform_result; using std::ranges::unique_copy_result; - using InIter = std::array::iterator; + using InIter = std::array::iterator; using OutIter = std::array::iterator; - auto unary_pred = [](int i) { return i > 0; }; + auto unary_pred = [](int i) { return i > 0; }; auto binary_pred = [](int i, int j) { return i < j; }; - auto gen = [] { return 42; }; + auto gen = [] { return 42; }; - std::array in = {1, 2, 3}; + std::array in = {1, 2, 3}; std::array in2 = {4, 5, 6}; auto mid = in.data() + 1; std::array output = {7, 8, 9, 10, 11, 12}; - auto out = output.begin(); - auto out2 = output.begin() + 1; + auto out = output.begin(); + auto out2 = output.begin() + 1; - int x = 2; + int x = 2; std::size_t count = 1; dangling_1st(std::ranges::find, in, x); @@ -145,11 +146,10 @@ constexpr bool test_all() { dangling_1st>(std::ranges::move_backward, in, output.end()); dangling_1st(std::ranges::fill, in, x); { // transform - using OutTransformIter = std::array::iterator; + using OutTransformIter = std::array::iterator; std::array out_transform = {false, true, true}; - dangling_1st>( - std::ranges::transform, in, out_transform.begin(), unary_pred); - dangling_1st>( + dangling_1st>(std::ranges::transform, in, out_transform.begin(), unary_pred); + dangling_1st>( std::ranges::transform, in, in2, out_transform.begin(), binary_pred); dangling_2nd>( std::ranges::transform, in, in2, out_transform.begin(), binary_pred); @@ -169,8 +169,7 @@ constexpr bool test_all() { dangling_1st>(std::ranges::reverse_copy, in, out); dangling_1st>(std::ranges::rotate_copy, in, mid, out); dangling_1st>(std::ranges::unique_copy, in, out); - dangling_1st>( - std::ranges::partition_copy, in, out, out2, unary_pred); + dangling_1st>(std::ranges::partition_copy, in, out, out2, unary_pred); dangling_1st>(std::ranges::partial_sort_copy, in, in2); dangling_2nd>(std::ranges::partial_sort_copy, in, in2); dangling_both>(std::ranges::partial_sort_copy, in, in2); diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp index 80ba3493c5a7d..c24d77c347470 100644 --- a/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp +++ b/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp @@ -14,7 +14,6 @@ #include #include #include -#include // TODO RM #include "test_macros.h" #include "test_iterators.h" @@ -106,46 +105,44 @@ struct DangerousCopyAssign { } }; -template -constexpr void test_result(std::array input, T starting_value, std::array const expected) { +template +constexpr void test_result(std::array input, int starting_value, std::array const expected) { { // (iterator, sentinel) overload auto in_begin = Iter(input.data()); auto in_end = Sent(Iter(input.data() + input.size())); - std::same_as> decltype(auto) result = + std::same_as> decltype(auto) result = std::ranges::iota(std::move(in_begin), std::move(in_end), starting_value); assert(result.out == in_end); - if constexpr (expected.size() > 0) { - assert(result.value == expected.back() + 1); - } else { - assert(result.value == starting_value); - } + assert(result.value == starting_value + static_cast(N)); assert(std::ranges::equal(input, expected)); } - // The range overload adds the additional constraint that it must be an outputrange - // so skip this for the input iterators we test - if constexpr (!std::is_same_v> && - !std::is_same_v>) { // (range) overload - auto in_begin = Iter(input.data()); - auto in_end = Sent(Iter(input.data() + input.size())); - auto range = std::ranges::subrange(std::move(in_begin), std::move(in_end)); - - std::same_as> decltype(auto) result = - std::ranges::iota(range, starting_value); - assert(result.out == in_end); - assert(result.value == starting_value + N); - assert(std::ranges::equal(input, expected)); + { // (range) overload + // inthe range overload adds the additional constraint that it must be an outputrange + // so skip this for the input iterators we test + if constexpr (!std::is_same_v> && + !std::is_same_v>) { + auto in_begin = Iter(input.data()); + auto in_end = Sent(Iter(input.data() + input.size())); + auto range = std::ranges::subrange(std::move(in_begin), std::move(in_end)); + + std::same_as> decltype(auto) result = + std::ranges::iota(range, starting_value); + assert(result.out == in_end); + assert(result.value == starting_value + static_cast(N)); + assert(std::ranges::equal(input, expected)); + } } } template > constexpr void test_results() { // Empty - test_result({}, 0, {}); + test_result({}, 0, {}); // 1-element sequence - test_result({1}, 0, {0}); + test_result({1}, 0, {0}); // Longer sequence - test_result({1, 2, 3, 4, 5}, 0, {0, 1, 2, 3, 4}); + test_result({1, 2, 3, 4, 5}, 0, {0, 1, 2, 3, 4}); } constexpr void test_DangerousCopyAssign() { From 20b848b566499e7dbd0c1557a716a35ddce35170 Mon Sep 17 00:00:00 2001 From: James Smith Date: Mon, 15 Jan 2024 12:28:09 -0500 Subject: [PATCH 22/36] [libc++] Implement ranges::iota: Refactoring some of Proxy's member functions inside test_iterators.h. Some clean-up on ranges.iota.pass.cpp too. --- .../numeric.iota/ranges.iota.pass.cpp | 21 ++++------ libcxx/test/support/test_iterators.h | 41 +++++++++---------- 2 files changed, 29 insertions(+), 33 deletions(-) diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp index c24d77c347470..77d215e5eb4e3 100644 --- a/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp +++ b/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp @@ -120,18 +120,15 @@ constexpr void test_result(std::array input, int starting_value, std::ar { // (range) overload // inthe range overload adds the additional constraint that it must be an outputrange // so skip this for the input iterators we test - if constexpr (!std::is_same_v> && - !std::is_same_v>) { - auto in_begin = Iter(input.data()); - auto in_end = Sent(Iter(input.data() + input.size())); - auto range = std::ranges::subrange(std::move(in_begin), std::move(in_end)); - - std::same_as> decltype(auto) result = - std::ranges::iota(range, starting_value); - assert(result.out == in_end); - assert(result.value == starting_value + static_cast(N)); - assert(std::ranges::equal(input, expected)); - } + auto in_begin = Iter(input.data()); + auto in_end = Sent(Iter(input.data() + input.size())); + auto range = std::ranges::subrange(std::move(in_begin), std::move(in_end)); + + std::same_as> decltype(auto) result = + std::ranges::iota(range, starting_value); + assert(result.out == in_end); + assert(result.value == starting_value + static_cast(N)); + assert(std::ranges::equal(input, expected)); } } diff --git a/libcxx/test/support/test_iterators.h b/libcxx/test/support/test_iterators.h index 6bae0a4c9def4..e40352873954b 100644 --- a/libcxx/test/support/test_iterators.h +++ b/libcxx/test/support/test_iterators.h @@ -650,6 +650,7 @@ class cpp20_input_iterator constexpr decltype(auto) operator*() const { return *it_; } constexpr cpp20_input_iterator& operator++() { ++it_; return *this; } constexpr void operator++(int) { ++it_; } + constexpr cpp20_input_iterator operator++(int) requires(std::incrementable) { auto tmp = *this; ++it_; return tmp;} friend constexpr It base(const cpp20_input_iterator& i) { return i.it_; } @@ -1087,23 +1088,19 @@ static_assert(std::random_access_iterator>); // which we need in certain situations. For example when we want // std::weakly_incrementable> to be true. template -struct ProxyDiffTBase {}; +struct ProxyDiffTBase { + // Add default `operator<=>` so that the derived type, Proxy, can also use the default `operator<=>` + friend constexpr auto operator<=>(const ProxyDiffTBase&, const ProxyDiffTBase&) = default; +}; template requires requires { std::iter_difference_t{}; } struct ProxyDiffTBase { using difference_type = std::iter_difference_t; + // Add default `operator<=>` so that the derived type, Proxy, can also use the default `operator<=>` + friend constexpr auto operator<=>(const ProxyDiffTBase&, const ProxyDiffTBase&) = default; }; -// These concepts allow us to conditionally add the pre-/postfix operators -// when T also supports those member functions. Like ProxyDiffTBase, this -// is necessary when we want std::weakly_incrementable> to be true. -template -concept HasPreIncrementOp = requires(T const& obj) { ++obj; }; - -template -concept HasPostIncrementOp = requires(T const& obj) { obj++; }; - // Proxy // ====================================================================== // Proxy that can wrap a value or a reference. It simulates C++23's tuple @@ -1172,10 +1169,7 @@ struct Proxy : ProxyDiffTBase { // Compare operators are defined for the convenience of the tests friend constexpr bool operator==(const Proxy& lhs, const Proxy& rhs) - requires(std::equality_comparable && !std::is_reference_v) - { - return lhs.data == rhs.data; - }; + 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. @@ -1186,10 +1180,7 @@ struct Proxy : ProxyDiffTBase { } friend constexpr auto operator<=>(const Proxy& lhs, const Proxy& rhs) - requires(std::three_way_comparable && !std::is_reference_v) - { - return lhs.data <=> rhs.data; - }; + 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. @@ -1199,16 +1190,24 @@ struct Proxy : ProxyDiffTBase { return lhs.data <=> rhs.data; } - // Needed to allow certain types to be weakly_incremental + // Needed to allow certain types to be weakly_incrementable constexpr Proxy& operator++() - requires(HasPreIncrementOp) + requires(std::weakly_incrementable>) { ++data; return *this; } constexpr Proxy operator++(int) - requires(HasPostIncrementOp) + requires(std::incrementable>) + { + Proxy tmp = *this; + operator++(); + return tmp; + } + + void operator++(int) + requires(std::weakly_incrementable> && !std::incrementable>) { Proxy tmp = *this; operator++(); From 2803493cba2a05fce5b3379c8ba43989aa4eaf73 Mon Sep 17 00:00:00 2001 From: James Smith Date: Mon, 15 Jan 2024 15:43:12 -0500 Subject: [PATCH 23/36] [libc++] Implement ranges::iota: Undoing some problematic additions to cpp20_input_iterator and fixing formatting. --- .../numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp | 3 ++- libcxx/test/support/test_iterators.h | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp index 77d215e5eb4e3..557888e272eb0 100644 --- a/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp +++ b/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp @@ -153,9 +153,10 @@ constexpr void test_DangerousCopyAssign() { } void test_results() { - types::for_each(types::cpp20_input_iterator_list{}, [] { test_results< Iter>(); }); + types::for_each(types::cpp17_input_iterator_list{}, [] { test_results< Iter>(); }); test_results>(); test_results>(); + test_results>(); test_DangerousCopyAssign(); } diff --git a/libcxx/test/support/test_iterators.h b/libcxx/test/support/test_iterators.h index e40352873954b..b06f7a6433b8c 100644 --- a/libcxx/test/support/test_iterators.h +++ b/libcxx/test/support/test_iterators.h @@ -650,7 +650,6 @@ class cpp20_input_iterator constexpr decltype(auto) operator*() const { return *it_; } constexpr cpp20_input_iterator& operator++() { ++it_; return *this; } constexpr void operator++(int) { ++it_; } - constexpr cpp20_input_iterator operator++(int) requires(std::incrementable) { auto tmp = *this; ++it_; return tmp;} friend constexpr It base(const cpp20_input_iterator& i) { return i.it_; } @@ -1169,7 +1168,8 @@ struct Proxy : ProxyDiffTBase { // Compare operators are defined for the convenience of the tests friend constexpr bool operator==(const Proxy& lhs, const Proxy& rhs) - requires(std::equality_comparable && !std::is_reference_v) = default; + 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. @@ -1180,7 +1180,8 @@ struct Proxy : ProxyDiffTBase { } friend constexpr auto operator<=>(const Proxy& lhs, const Proxy& rhs) - requires(std::three_way_comparable && !std::is_reference_v) = default; + 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. From 5f0389c42b539cfc54d82176894b96b44ca1bd7b Mon Sep 17 00:00:00 2001 From: jamesETsmith Date: Sun, 28 Apr 2024 11:57:04 -0400 Subject: [PATCH 24/36] [libc++] Implement ranges::iota: Fixing review comments on ranges.iota.pass.cpp, still more work to do. --- .../ranges_robust_against_dangling.pass.cpp | 2 +- .../numeric.iota/ranges.iota.pass.cpp | 39 ++++++++++++------- libcxx/test/support/test_iterators.h | 7 ---- 3 files changed, 25 insertions(+), 23 deletions(-) diff --git a/libcxx/test/std/algorithms/ranges_robust_against_dangling.pass.cpp b/libcxx/test/std/algorithms/ranges_robust_against_dangling.pass.cpp index 79631af03b218..1d91172870277 100644 --- a/libcxx/test/std/algorithms/ranges_robust_against_dangling.pass.cpp +++ b/libcxx/test/std/algorithms/ranges_robust_against_dangling.pass.cpp @@ -215,7 +215,7 @@ constexpr bool test_all() { dangling_1st>(std::ranges::next_permutation, in); #if TEST_STD_VER >= 23 - dangling_1st< out_value_result>(std::ranges::iota, in, x); + dangling_1st>(std::ranges::iota, in, x); #endif return true; diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp index 557888e272eb0..96fed39a006f4 100644 --- a/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp +++ b/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp @@ -10,14 +10,15 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 -#include -#include #include #include +#include +#include +#include -#include "test_macros.h" -#include "test_iterators.h" #include "almost_satisfies_types.h" +#include "test_iterators.h" +#include "test_macros.h" // // Testing constraints @@ -73,9 +74,13 @@ struct DangerousCopyAssign { // Needed in postfix constexpr DangerousCopyAssign(DangerousCopyAssign const& other) { this->val = other.val; } - // mischievious copy assignment that we won't use if the - // std::as_const inside ranges::iota isn't working, this should perturb the - // results + /* + This class has a "mischievous" non-const overload of copy-assignment + operator that modifies the object being assigned from. `ranges::iota` + should not be invoking this overload thanks to the `std::as_const` in its + implementation. If for some reason it does invoke it, the values written + by ranges::iota will increment by 2 rather than 1. + */ constexpr DangerousCopyAssign& operator=(DangerousCopyAssign& a) { ++a.val; this->val = a.val; @@ -118,7 +123,7 @@ constexpr void test_result(std::array input, int starting_value, std::ar } { // (range) overload - // inthe range overload adds the additional constraint that it must be an outputrange + // in the range overload adds the additional constraint that it must be an output range // so skip this for the input iterators we test auto in_begin = Iter(input.data()); auto in_end = Sent(Iter(input.data() + input.size())); @@ -142,25 +147,29 @@ constexpr void test_results() { test_result({1, 2, 3, 4, 5}, 0, {0, 1, 2, 3, 4}); } -constexpr void test_DangerousCopyAssign() { - using A = DangerousCopyAssign; - using Iter = contiguous_iterator; - std::array aa = {A{1}, A{2}, A{3}}; +constexpr void test_danderous_copy_assign() { + using A = DangerousCopyAssign; + using Iter = contiguous_iterator; + + // If the dangerous non-const copy assignment is called, the final values in + // aa should increment by 2 rather than 1. + std::array aa = {A{0}, A{0}, A{0}}; std::array expected = {A{0}, A{1}, A{2}}; std::ranges::iota(aa, A{0}); auto proj_val = [](DangerousCopyAssign const& el) { return el.val; }; assert(std::ranges::equal(aa, expected, std::ranges::equal_to{}, proj_val, proj_val)); } -void test_results() { +constexpr bool test_results() { types::for_each(types::cpp17_input_iterator_list{}, [] { test_results< Iter>(); }); test_results>(); test_results>(); test_results>(); - test_DangerousCopyAssign(); + test_danderous_copy_assign(); + return true; } int main(int, char**) { - test_results(); + static_assert(test_results()); return 0; } diff --git a/libcxx/test/support/test_iterators.h b/libcxx/test/support/test_iterators.h index b06f7a6433b8c..6dbd90b8a3931 100644 --- a/libcxx/test/support/test_iterators.h +++ b/libcxx/test/support/test_iterators.h @@ -1207,13 +1207,6 @@ struct Proxy : ProxyDiffTBase { return tmp; } - void operator++(int) - requires(std::weakly_incrementable> && !std::incrementable>) - { - Proxy tmp = *this; - operator++(); - return tmp; - } }; // This is to make ProxyIterator model `std::indirectly_readable` From 79d6cc5d0906ed343b0111bda68d730ed76e8c13 Mon Sep 17 00:00:00 2001 From: jamesETsmith Date: Sun, 28 Apr 2024 15:38:53 -0400 Subject: [PATCH 25/36] [libc++] Implementing ranges::iota: Adding user-defined type tests and updating status docs. --- libcxx/docs/Status/Cxx23.rst | 2 +- libcxx/docs/Status/Cxx23Papers.csv | 2 +- .../numeric.iota/ranges.iota.pass.cpp | 47 ++++++++++++++++++- 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/libcxx/docs/Status/Cxx23.rst b/libcxx/docs/Status/Cxx23.rst index c576f1809219e..a17098b24692f 100644 --- a/libcxx/docs/Status/Cxx23.rst +++ b/libcxx/docs/Status/Cxx23.rst @@ -49,7 +49,7 @@ Paper Status .. [#note-P2693R1] P2693R1: The formatter for ``std::thread::id`` is implemented. The formatter for ``stacktrace`` is not implemented, since ``stacktrace`` is not implemented yet. - .. [#note-P2400R1] P2400R1: ranges::shift_left and ranges::shift_right have not been implemented yet. + .. [#note-P2440R1] P2440R1: ranges::shift_left and ranges::shift_right have not been implemented yet. .. _issues-status-cxx23: diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv index db0ba4dbd3b9b..b2755f2cd5a0d 100644 --- a/libcxx/docs/Status/Cxx23Papers.csv +++ b/libcxx/docs/Status/Cxx23Papers.csv @@ -46,7 +46,7 @@ "`P2255R2 `__","LWG","A type trait to detect reference binding to temporary","February 2022","","" "`P2273R3 `__","LWG","Making ``std::unique_ptr`` constexpr","February 2022","|Complete|","16.0" "`P2387R3 `__","LWG","Pipe support for user-defined range adaptors","February 2022","","","|ranges|" -"`P2440R1 `__","LWG","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","February 2022","|In progress| [#note-P2400R1]_","","|ranges|" +"`P2440R1 `__","LWG","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","February 2022","|In progress| [#note-P2440R1]_","","|ranges|" "`P2441R2 `__","LWG","``views::join_with``","February 2022","|In Progress|","","|ranges|" "`P2442R1 `__","LWG","Windowing range adaptors: ``views::chunk`` and ``views::slide``","February 2022","","","|ranges|" "`P2443R1 `__","LWG","``views::chunk_by``","February 2022","|Complete|","18.0","|ranges|" diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp index 96fed39a006f4..ffd29855a3369 100644 --- a/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp +++ b/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp @@ -147,9 +147,48 @@ constexpr void test_results() { test_result({1, 2, 3, 4, 5}, 0, {0, 1, 2, 3, 4}); } +constexpr void test_user_defined_type() { + // Simple non-fundamental type + struct UserDefinedType { + int val; + using difference_type = int; + + constexpr explicit UserDefinedType(int v) : val(v) {} + constexpr UserDefinedType(UserDefinedType const& other) { this->val = other.val; } + constexpr UserDefinedType& operator=(UserDefinedType const& a) { + this->val = a.val; + return *this; + } + + // prefix + constexpr UserDefinedType& operator++() { + ++(this->val); + return *this; + } + + // postfix + constexpr UserDefinedType operator++(int) { + auto tmp = *this; + ++this->val; + return tmp; + } + }; + + // Setup + using A = UserDefinedType; + std::array a = {A{0}, A{0}, A{0}, A{0}, A{0}}; + std::array expected = {A{0}, A{1}, A{2}, A{3}, A{4}}; + + // Fill with values + std::ranges::iota(a, A{0}); + auto proj_val = [](UserDefinedType const& el) { return el.val; }; + + // Check + assert(std::ranges::equal(a, expected, std::ranges::equal_to{}, proj_val, proj_val)); +} + constexpr void test_danderous_copy_assign() { - using A = DangerousCopyAssign; - using Iter = contiguous_iterator; + using A = DangerousCopyAssign; // If the dangerous non-const copy assignment is called, the final values in // aa should increment by 2 rather than 1. @@ -161,10 +200,14 @@ constexpr void test_danderous_copy_assign() { } constexpr bool test_results() { + // Tests on fundamental types types::for_each(types::cpp17_input_iterator_list{}, [] { test_results< Iter>(); }); test_results>(); test_results>(); test_results>(); + + // Tests on non-fundamental types + test_user_defined_type(); test_danderous_copy_assign(); return true; } From 07b818348152338b430b5bf154b2e4042014d605 Mon Sep 17 00:00:00 2001 From: jamesETsmith Date: Sun, 28 Apr 2024 16:56:13 -0400 Subject: [PATCH 26/36] [libc++] Implementing ranges::iota: Reverting to original strategy for ranges:iota implementation that doesn't use helper functions --- libcxx/include/__numeric/ranges_iota.h | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/libcxx/include/__numeric/ranges_iota.h b/libcxx/include/__numeric/ranges_iota.h index 750964ff77a4c..f7d854633c3fd 100644 --- a/libcxx/include/__numeric/ranges_iota.h +++ b/libcxx/include/__numeric/ranges_iota.h @@ -30,10 +30,10 @@ template using iota_result = ranges::out_value_result<_Out, _Tp>; struct __iota_fn { -private: - // Private helper function - template - _LIBCPP_HIDE_FROM_ABI static constexpr iota_result<_Out, _Tp> __iota_impl(_Out __first, _Sent __last, _Tp __value) { +public: + template _Sent, weakly_incrementable _Tp> + requires indirectly_writable<_Out, const _Tp&> + _LIBCPP_HIDE_FROM_ABI static constexpr iota_result<_Out, _Tp> operator()(_Out __first, _Sent __last, _Tp __value) { while (__first != __last) { *__first = std::as_const(__value); ++__first; @@ -42,18 +42,10 @@ struct __iota_fn { return {std::move(__first), std::move(__value)}; } -public: - // Public facing interfaces - template _Sent, weakly_incrementable _Tp> - requires indirectly_writable<_Out, const _Tp&> - _LIBCPP_HIDE_FROM_ABI static constexpr iota_result<_Out, _Tp> operator()(_Out __first, _Sent __last, _Tp __value) { - return __iota_impl(std::move(__first), std::move(__last), std::move(__value)); - } - template _Range> _LIBCPP_HIDE_FROM_ABI static constexpr iota_result, _Tp> operator()(_Range&& __r, _Tp __value) { - return __iota_impl(ranges::begin(__r), ranges::end(__r), std::move(__value)); + return __iota_fn::operator()(ranges::begin(__r), ranges::end(__r), std::move(__value)); } }; From fd814003e929322013c5b9679712f678e25c6709 Mon Sep 17 00:00:00 2001 From: jamesETsmith Date: Thu, 2 May 2024 21:15:33 -0400 Subject: [PATCH 27/36] [libc++] Implementing ranges::iota: Needed to include __undef_macros and missed one update in version.version.compile.pass.cpp --- libcxx/include/__numeric/ranges_iota.h | 5 +++++ .../version.version.compile.pass.cpp | 17 ++++++----------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/libcxx/include/__numeric/ranges_iota.h b/libcxx/include/__numeric/ranges_iota.h index f7d854633c3fd..b9f90dc5f3ae6 100644 --- a/libcxx/include/__numeric/ranges_iota.h +++ b/libcxx/include/__numeric/ranges_iota.h @@ -22,6 +22,9 @@ # pragma GCC system_header #endif +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + _LIBCPP_BEGIN_NAMESPACE_STD #if _LIBCPP_STD_VER >= 23 @@ -56,4 +59,6 @@ inline constexpr auto iota = __iota_fn{}; _LIBCPP_END_NAMESPACE_STD +_LIBCPP_POP_MACROS + #endif // _LIBCPP___NUMERIC_RANGES_IOTA_H diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp index c5ddb0143723e..128a883ff0979 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp @@ -5526,18 +5526,13 @@ # error "__cpp_lib_ranges_contains should have the value 202207L in c++23" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_ranges_iota -# error "__cpp_lib_ranges_iota should be defined in c++23" -# endif -# if __cpp_lib_ranges_iota != 202202L -# error "__cpp_lib_ranges_iota should have the value 202202L in c++23" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_ranges_iota -# error "__cpp_lib_ranges_iota should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_ranges_iota +# error "__cpp_lib_ranges_iota should be defined in c++23" # endif +# if __cpp_lib_ranges_iota != 202202L +# error "__cpp_lib_ranges_iota should have the value 202202L in c++23" +# endif + # if !defined(_LIBCPP_VERSION) # ifndef __cpp_lib_ranges_join_with From 3285f4e86efd1fd0295f1b033d37b63275a79e3a Mon Sep 17 00:00:00 2001 From: jamesETsmith Date: Fri, 3 May 2024 12:15:44 -0400 Subject: [PATCH 28/36] [libc++] Implementing ranges::iota: Fixing autogenerated version.version.compile.pass.cpp and formatting in test_iterators.h --- libcxx/include/version | 2 +- .../support.limits.general/version.version.compile.pass.cpp | 5 ++--- libcxx/test/support/test_iterators.h | 1 - 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/libcxx/include/version b/libcxx/include/version index a9835d0aa6644..003504aa1a63f 100644 --- a/libcxx/include/version +++ b/libcxx/include/version @@ -474,8 +474,8 @@ __cpp_lib_within_lifetime 202306L # define __cpp_lib_ranges_as_rvalue 202207L // # define __cpp_lib_ranges_chunk 202202L # define __cpp_lib_ranges_chunk_by 202202L -# define __cpp_lib_ranges_iota 202202L # define __cpp_lib_ranges_contains 202207L +# define __cpp_lib_ranges_iota 202202L // # define __cpp_lib_ranges_join_with 202202L # define __cpp_lib_ranges_repeat 202207L // # define __cpp_lib_ranges_slide 202202L diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp index 128a883ff0979..f5c721e9a1380 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp @@ -5533,7 +5533,6 @@ # error "__cpp_lib_ranges_iota should have the value 202202L in c++23" # endif - # if !defined(_LIBCPP_VERSION) # ifndef __cpp_lib_ranges_join_with # error "__cpp_lib_ranges_join_with should be defined in c++23" @@ -7316,10 +7315,10 @@ # endif # ifndef __cpp_lib_ranges_iota -# error "__cpp_lib_ranges_iota should be defined in c++23" +# error "__cpp_lib_ranges_iota should be defined in c++26" # endif # if __cpp_lib_ranges_iota != 202202L -# error "__cpp_lib_ranges_iota should have the value 202202L in c++23" +# error "__cpp_lib_ranges_iota should have the value 202202L in c++26" # endif # if !defined(_LIBCPP_VERSION) diff --git a/libcxx/test/support/test_iterators.h b/libcxx/test/support/test_iterators.h index 4d61cc5a6c64f..9a428d9f3f694 100644 --- a/libcxx/test/support/test_iterators.h +++ b/libcxx/test/support/test_iterators.h @@ -1222,7 +1222,6 @@ struct Proxy : ProxyDiffTBase { operator++(); return tmp; } - }; // This is to make ProxyIterator model `std::indirectly_readable` From 3f0670fa9237c8035b8c04e046853f12db315a8f Mon Sep 17 00:00:00 2001 From: jamesETsmith Date: Wed, 22 May 2024 09:25:11 -0400 Subject: [PATCH 29/36] [libc++] Implementing ranges::iota: Simplifying some tests, adding static_assert to others, and update status in the papers csv. --- libcxx/docs/Status/Cxx23Papers.csv | 2 +- .../algorithms.results/out_value_result.pass.cpp | 5 ++++- .../numeric.ops/numeric.iota/ranges.iota.pass.cpp | 15 ++++++--------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv index 65db8a6d41869..c01233e072488 100644 --- a/libcxx/docs/Status/Cxx23Papers.csv +++ b/libcxx/docs/Status/Cxx23Papers.csv @@ -46,7 +46,7 @@ "`P2255R2 `__","LWG","A type trait to detect reference binding to temporary","February 2022","","" "`P2273R3 `__","LWG","Making ``std::unique_ptr`` constexpr","February 2022","|Complete|","16.0" "`P2387R3 `__","LWG","Pipe support for user-defined range adaptors","February 2022","|Complete|","19.0","|ranges|" -"`P2440R1 `__","LWG","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","February 2022","|In progress| [#note-P2440R1]_","","|ranges|" +"`P2440R1 `__","LWG","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","February 2022","|Partial| [#note-P2440R1]_","","|ranges|" "`P2441R2 `__","LWG","``views::join_with``","February 2022","|In Progress|","","|ranges|" "`P2442R1 `__","LWG","Windowing range adaptors: ``views::chunk`` and ``views::slide``","February 2022","","","|ranges|" "`P2443R1 `__","LWG","``views::chunk_by``","February 2022","|Complete|","18.0","|ranges|" diff --git a/libcxx/test/std/algorithms/algorithms.results/out_value_result.pass.cpp b/libcxx/test/std/algorithms/algorithms.results/out_value_result.pass.cpp index bc8c665950f43..7bdbb7f60e9a2 100644 --- a/libcxx/test/std/algorithms/algorithms.results/out_value_result.pass.cpp +++ b/libcxx/test/std/algorithms/algorithms.results/out_value_result.pass.cpp @@ -52,7 +52,7 @@ struct NonStandardLayoutTypeBase { struct NonStandardLayoutType : public NonStandardLayoutTypeBase {}; // -constexpr void test_constraints() { +constexpr bool test_constraints() { // requires convertible_to && convertible_to static_assert(std::is_constructible_v, out_value_result>); @@ -84,6 +84,8 @@ constexpr void test_constraints() { // check standard layout static_assert(std::is_standard_layout_v>); static_assert(!std::is_standard_layout_v>); + + return true; } // Test results @@ -132,6 +134,7 @@ constexpr bool test() { int main(int, char**) { test_constraints(); + static_assert(test_constraints()); test(); static_assert(test()); return 0; diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp index ffd29855a3369..9fa50f1326f1d 100644 --- a/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp +++ b/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp @@ -78,14 +78,10 @@ struct DangerousCopyAssign { This class has a "mischievous" non-const overload of copy-assignment operator that modifies the object being assigned from. `ranges::iota` should not be invoking this overload thanks to the `std::as_const` in its - implementation. If for some reason it does invoke it, the values written - by ranges::iota will increment by 2 rather than 1. + implementation. If for some reason it does invoke it, there will be a compiler + error. */ - constexpr DangerousCopyAssign& operator=(DangerousCopyAssign& a) { - ++a.val; - this->val = a.val; - return *this; - } + constexpr DangerousCopyAssign& operator=(DangerousCopyAssign& a) = delete; // safe copy assignment std::as_const inside ranges::iota should ensure this // overload gets called @@ -187,7 +183,7 @@ constexpr void test_user_defined_type() { assert(std::ranges::equal(a, expected, std::ranges::equal_to{}, proj_val, proj_val)); } -constexpr void test_danderous_copy_assign() { +constexpr void test_dangerous_copy_assign() { using A = DangerousCopyAssign; // If the dangerous non-const copy assignment is called, the final values in @@ -208,11 +204,12 @@ constexpr bool test_results() { // Tests on non-fundamental types test_user_defined_type(); - test_danderous_copy_assign(); + test_dangerous_copy_assign(); return true; } int main(int, char**) { + test_results(); static_assert(test_results()); return 0; } From d50b7a127ddbde25cedcebb4b46d87b6450ffbf6 Mon Sep 17 00:00:00 2001 From: jamesETsmith Date: Wed, 24 Jul 2024 12:17:39 -0400 Subject: [PATCH 30/36] [libc++] Implementing ranges::iota: Accidentally manually updated the version.version.compile tests rather than generating it with the python script so the formatting was off --- .../support.limits.general/version.version.compile.pass.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp index 49472aa37f816..45c5ab6c2bfec 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp @@ -5686,7 +5686,6 @@ # endif # if __cpp_lib_ranges_iota != 202202L # error "__cpp_lib_ranges_iota should have the value 202202L in c++23" - # endif # if !defined(_LIBCPP_VERSION) @@ -7541,7 +7540,6 @@ # endif # if __cpp_lib_ranges_iota != 202202L # error "__cpp_lib_ranges_iota should have the value 202202L in c++26" - # endif # if !defined(_LIBCPP_VERSION) From b4008ade663383f2675a9675707392a5c321e6e6 Mon Sep 17 00:00:00 2001 From: jamesETsmith Date: Fri, 26 Jul 2024 13:46:57 -0400 Subject: [PATCH 31/36] [libc++] Implementing ranges::iota: Cleanup and addressing comments from @strega-nil --- libcxx/docs/Status/RangesAlgorithms.csv | 1 - libcxx/docs/Status/RangesMajorFeatures.csv | 1 - libcxx/include/__numeric/ranges_iota.h | 2 +- libcxx/include/algorithm | 6 +++--- .../ranges_result_alias_declarations.compile.pass.cpp | 3 +-- .../ranges_robust_against_proxy_iterators.pass.cpp | 2 +- libcxx/test/support/test_iterators.h | 4 ++-- 7 files changed, 8 insertions(+), 11 deletions(-) diff --git a/libcxx/docs/Status/RangesAlgorithms.csv b/libcxx/docs/Status/RangesAlgorithms.csv index 30268cf0297ff..0c417e014d7d7 100644 --- a/libcxx/docs/Status/RangesAlgorithms.csv +++ b/libcxx/docs/Status/RangesAlgorithms.csv @@ -9,7 +9,6 @@ C++23,`shift_left `_,Unassigned,No patch yet,Not star C++23,`shift_right `_,Unassigned,No patch yet,Not started C++23,`iota (algorithm) `_,Unassigned,No patch yet,Not started C++23,`fold `_,Unassigned,No patch yet,Not started -C++23,`contains `_,Zijun Zhao,No patch yet,In Progress C++23,`ranges::iota `_, James E T Smith, `PR68494 `_, In Progress C++23,`contains `_,Zijun Zhao, `#65148 `_,Complete C++23,`fold_left_with_iter `_,Christopher Di Bella,N/A,Complete diff --git a/libcxx/docs/Status/RangesMajorFeatures.csv b/libcxx/docs/Status/RangesMajorFeatures.csv index d4dc6ccdfbef0..d00fbce9edf48 100644 --- a/libcxx/docs/Status/RangesMajorFeatures.csv +++ b/libcxx/docs/Status/RangesMajorFeatures.csv @@ -2,5 +2,4 @@ Standard,Name,Assignee,CL,Status C++23,`ranges::to `_,Konstantin Varlamov,`D142335 `_,Complete C++23,`Pipe support for user-defined range adaptors `_,"Louis Dionne, Jakub Mazurkiewicz, and Xiaoyang Liu",Various,Complete C++23,`Formatting Ranges `_,Mark de Wever,Various,Complete -C++23, `ranges::iota `_, James E T Smith, `PR68494 `_, In Progress C++20,`Stashing stashing iterators for proper flattening `_,Jakub Mazurkiewicz,Various,In progress diff --git a/libcxx/include/__numeric/ranges_iota.h b/libcxx/include/__numeric/ranges_iota.h index b9f90dc5f3ae6..76381dbda4c97 100644 --- a/libcxx/include/__numeric/ranges_iota.h +++ b/libcxx/include/__numeric/ranges_iota.h @@ -48,7 +48,7 @@ struct __iota_fn { template _Range> _LIBCPP_HIDE_FROM_ABI static constexpr iota_result, _Tp> operator()(_Range&& __r, _Tp __value) { - return __iota_fn::operator()(ranges::begin(__r), ranges::end(__r), std::move(__value)); + return operator()(ranges::begin(__r), ranges::end(__r), std::move(__value)); } }; diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm index 6b489dddaa3b2..87c03f53d655e 100644 --- a/libcxx/include/algorithm +++ b/libcxx/include/algorithm @@ -42,12 +42,12 @@ namespace ranges { template struct in_found_result; // since C++20 - template - struct out_value_result; // since C++23 - template struct in_value_result; // since C++23 + template + struct out_value_result; // since C++23 + template S, class Proj = identity, indirect_strict_weak_order> Comp = ranges::less> // since C++20 constexpr I min_element(I first, S last, Comp comp = {}, Proj proj = {}); diff --git a/libcxx/test/std/algorithms/ranges_result_alias_declarations.compile.pass.cpp b/libcxx/test/std/algorithms/ranges_result_alias_declarations.compile.pass.cpp index e7b492b79a089..dcf25099dbc47 100644 --- a/libcxx/test/std/algorithms/ranges_result_alias_declarations.compile.pass.cpp +++ b/libcxx/test/std/algorithms/ranges_result_alias_declarations.compile.pass.cpp @@ -63,7 +63,6 @@ static_assert(std::is_same_v, next_permutation_result> static_assert(std::is_same_v, prev_permutation_result>); #if TEST_STD_VER >= 23 -static_assert(std::is_same_v, iota_result>); - static_assert(std::is_same_v, fold_left_with_iter_result>); +static_assert(std::is_same_v, iota_result>); #endif // TEST_STD_VER diff --git a/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp b/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp index b1628162c35c6..5360878242dc2 100644 --- a/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp +++ b/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp @@ -108,7 +108,7 @@ constexpr void run_tests() { test(std::ranges::search_n, in, count, x); test(std::ranges::find_end, in, in2); #if TEST_STD_VER >= 23 - if constexpr (std::copyable) { + if constexpr (std::weakly_incrementable) { test(std::ranges::iota, in, x); } #endif diff --git a/libcxx/test/support/test_iterators.h b/libcxx/test/support/test_iterators.h index c649a07dbd5f4..a4029795396a5 100644 --- a/libcxx/test/support/test_iterators.h +++ b/libcxx/test/support/test_iterators.h @@ -1198,7 +1198,7 @@ struct Proxy : ProxyDiffTBase { // Calling swap(Proxy{}, Proxy{}) would fail (pass prvalues) // Compare operators are defined for the convenience of the tests - friend constexpr bool operator==(const Proxy& lhs, const Proxy& rhs) + friend constexpr bool operator==(const Proxy&, const Proxy&) requires(std::equality_comparable && !std::is_reference_v) = default; @@ -1210,7 +1210,7 @@ struct Proxy : ProxyDiffTBase { return lhs.data == rhs.data; } - friend constexpr auto operator<=>(const Proxy& lhs, const Proxy& rhs) + friend constexpr auto operator<=>(const Proxy&, const Proxy&) requires(std::three_way_comparable && !std::is_reference_v) = default; From 8f5ffc30af9f2383052fa68380bfd7f4f49a2070 Mon Sep 17 00:00:00 2001 From: jamesETsmith Date: Thu, 27 Mar 2025 12:13:07 -0400 Subject: [PATCH 32/36] [libc++] Implementing ranges::iota: Including out_value_result got stripped from algorithm header, adding it back --- libcxx/include/algorithm | 1 + 1 file changed, 1 insertion(+) diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm index 3311ec5062812..45708b7d16a45 100644 --- a/libcxx/include/algorithm +++ b/libcxx/include/algorithm @@ -1937,6 +1937,7 @@ template # include <__algorithm/in_in_result.h> # include <__algorithm/in_out_out_result.h> # include <__algorithm/in_out_result.h> +# include <__algorithm/out_value_result.h> # include <__algorithm/lexicographical_compare_three_way.h> # include <__algorithm/min_max_result.h> # include <__algorithm/ranges_adjacent_find.h> From b99c8d84385bf732500b90455a6efb786f89a1da Mon Sep 17 00:00:00 2001 From: jamesETsmith Date: Tue, 1 Apr 2025 11:18:11 -0400 Subject: [PATCH 33/36] [libc++] Implementing ranges::iota: Needed to add __iterator/concepts.h for module builds to pass --- libcxx/docs/Status/Cxx23.rst | 17 +---------------- libcxx/docs/Status/Cxx23Papers.csv | 2 +- libcxx/docs/Status/RangesAlgorithms.csv | 19 ------------------- libcxx/include/__numeric/ranges_iota.h | 1 + 4 files changed, 3 insertions(+), 36 deletions(-) delete mode 100644 libcxx/docs/Status/RangesAlgorithms.csv diff --git a/libcxx/docs/Status/Cxx23.rst b/libcxx/docs/Status/Cxx23.rst index 04d636598cf5d..0f9d4bf0d1af8 100644 --- a/libcxx/docs/Status/Cxx23.rst +++ b/libcxx/docs/Status/Cxx23.rst @@ -34,25 +34,10 @@ Paper Status :header-rows: 1 :widths: auto -.. note:: - - .. [#note-P0533R9] P0533R9: ``isfinite``, ``isinf``, ``isnan`` and ``isnormal`` are implemented. - .. [#note-P1413R3] P1413R3: ``std::aligned_storage_t`` and ``std::aligned_union_t`` are marked deprecated, but - clang doesn't issue a diagnostic for deprecated using template declarations. - .. [#note-P2520R0] P2520R0: Libc++ implemented this paper as a DR in C++20 as well. - .. [#note-P2711R1] P2711R1: ``join_with_view`` hasn't been done yet since this type isn't implemented yet. - .. [#note-P2770R0] P2770R0: ``join_with_view`` hasn't been done yet since this type isn't implemented yet. - .. [#note-P2693R1] P2693R1: The formatter for ``std::thread::id`` is implemented. - The formatter for ``stacktrace`` is not implemented, since ``stacktrace`` is - not implemented yet. - .. [#note-P2440R1] P2440R1: ranges::shift_left and ranges::shift_right have not been implemented yet. - -.. _issues-status-cxx23: - Library Working Group Issues Status ==================================== .. csv-table:: :file: Cxx23Issues.csv :header-rows: 1 - :widths: auto + :widths: auto \ No newline at end of file diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv index bd124816c0f04..008eeabbcdd8e 100644 --- a/libcxx/docs/Status/Cxx23Papers.csv +++ b/libcxx/docs/Status/Cxx23Papers.csv @@ -46,7 +46,7 @@ "`P2255R2 `__","A type trait to detect reference binding to temporary","2022-02 (Virtual)","|Partial|","","Implemented the type traits only." "`P2273R3 `__","Making ``std::unique_ptr`` constexpr","2022-02 (Virtual)","|Complete|","16","" "`P2387R3 `__","Pipe support for user-defined range adaptors","2022-02 (Virtual)","|Complete|","19","" -"`P2440R1 `__","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","2022-02 (Virtual)","|Partial| [#note-P2440R1]_","","|ranges|" +"`P2440R1 `__","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","2022-02 (Virtual)","|Partial| ``std::ranges::shift_left`` and ``std::ranges::shift_right`` have not been implemented","","|ranges|" "`P2441R2 `__","``views::join_with``","2022-02 (Virtual)","|In Progress|","","" "`P2442R1 `__","Windowing range adaptors: ``views::chunk`` and ``views::slide``","2022-02 (Virtual)","","","" "`P2443R1 `__","``views::chunk_by``","2022-02 (Virtual)","|Complete|","18","" diff --git a/libcxx/docs/Status/RangesAlgorithms.csv b/libcxx/docs/Status/RangesAlgorithms.csv deleted file mode 100644 index 0c417e014d7d7..0000000000000 --- a/libcxx/docs/Status/RangesAlgorithms.csv +++ /dev/null @@ -1,19 +0,0 @@ -Standard,Algorithm,Assignee,CL,Status -C++20,all C++20 algorithms,N/A,N/A,✅ -C++23,`find_last `_,Nicole Mazzuca,`#99312 `_,Complete -C++23,`find_last_if `_,Nicole Mazzuca,`#99312 `_,Complete -C++23,`find_last_if_not `_,Nicole Mazzuca,`#99312 `_,Complete -C++23,`starts_with `_,Zijun Zhao,`D150735 `_,Complete -C++23,`ends_with `_,Zijun Zhao, `D150831 `_,Complete -C++23,`shift_left `_,Unassigned,No patch yet,Not started -C++23,`shift_right `_,Unassigned,No patch yet,Not started -C++23,`iota (algorithm) `_,Unassigned,No patch yet,Not started -C++23,`fold `_,Unassigned,No patch yet,Not started -C++23,`ranges::iota `_, James E T Smith, `PR68494 `_, In Progress -C++23,`contains `_,Zijun Zhao, `#65148 `_,Complete -C++23,`fold_left_with_iter `_,Christopher Di Bella,N/A,Complete -C++23,`fold_left `_,Christopher Di Bella,N/A,Complete -C++23,`fold_left_first_with_iter `_,Christopher Di Bella,N/A,In progress -C++23,`fold_left_first `_,Christopher Di Bella,N/A,In progress -C++23,`fold_right `_,Christopher Di Bella,N/A,In progress -C++23,`fold_right_last `_,Christopher Di Bella,N/A,In progress diff --git a/libcxx/include/__numeric/ranges_iota.h b/libcxx/include/__numeric/ranges_iota.h index 76381dbda4c97..bf53dd85fecef 100644 --- a/libcxx/include/__numeric/ranges_iota.h +++ b/libcxx/include/__numeric/ranges_iota.h @@ -12,6 +12,7 @@ #include <__algorithm/out_value_result.h> #include <__config> +#include <__iterator/concepts.h> #include <__ranges/access.h> #include <__ranges/concepts.h> #include <__ranges/dangling.h> From dc29b80f11c686040751b4f2320be469310eb2e7 Mon Sep 17 00:00:00 2001 From: jamesETsmith Date: Wed, 2 Apr 2025 12:27:24 -0400 Subject: [PATCH 34/36] [libc++] implementing ranges::iota: Fixing the Cxx23Paper.csv doc for ranges::iota --- libcxx/docs/Status/Cxx23Papers.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv index 008eeabbcdd8e..d4c8d0273f90a 100644 --- a/libcxx/docs/Status/Cxx23Papers.csv +++ b/libcxx/docs/Status/Cxx23Papers.csv @@ -46,7 +46,7 @@ "`P2255R2 `__","A type trait to detect reference binding to temporary","2022-02 (Virtual)","|Partial|","","Implemented the type traits only." "`P2273R3 `__","Making ``std::unique_ptr`` constexpr","2022-02 (Virtual)","|Complete|","16","" "`P2387R3 `__","Pipe support for user-defined range adaptors","2022-02 (Virtual)","|Complete|","19","" -"`P2440R1 `__","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","2022-02 (Virtual)","|Partial| ``std::ranges::shift_left`` and ``std::ranges::shift_right`` have not been implemented","","|ranges|" +"`P2440R1 `__","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","2022-02 (Virtual)","|Partial|","","``std::ranges::shift_left`` and ``std::ranges::shift_right`` have not been implemented" "`P2441R2 `__","``views::join_with``","2022-02 (Virtual)","|In Progress|","","" "`P2442R1 `__","Windowing range adaptors: ``views::chunk`` and ``views::slide``","2022-02 (Virtual)","","","" "`P2443R1 `__","``views::chunk_by``","2022-02 (Virtual)","|Complete|","18","" From e325de4d5c45439f903d7f728dfd9976db4c698a Mon Sep 17 00:00:00 2001 From: jamesETsmith Date: Wed, 2 Apr 2025 12:28:20 -0400 Subject: [PATCH 35/36] [libc++] implementing ranges::iota: Switching the wording in Cxx23Papers.csv --- libcxx/docs/Status/Cxx23Papers.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv index d4c8d0273f90a..923d8bf9341d0 100644 --- a/libcxx/docs/Status/Cxx23Papers.csv +++ b/libcxx/docs/Status/Cxx23Papers.csv @@ -46,7 +46,7 @@ "`P2255R2 `__","A type trait to detect reference binding to temporary","2022-02 (Virtual)","|Partial|","","Implemented the type traits only." "`P2273R3 `__","Making ``std::unique_ptr`` constexpr","2022-02 (Virtual)","|Complete|","16","" "`P2387R3 `__","Pipe support for user-defined range adaptors","2022-02 (Virtual)","|Complete|","19","" -"`P2440R1 `__","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","2022-02 (Virtual)","|Partial|","","``std::ranges::shift_left`` and ``std::ranges::shift_right`` have not been implemented" +"`P2440R1 `__","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","2022-02 (Virtual)","|Partial|","","Only ``ranges::iota`` is implemented." "`P2441R2 `__","``views::join_with``","2022-02 (Virtual)","|In Progress|","","" "`P2442R1 `__","Windowing range adaptors: ``views::chunk`` and ``views::slide``","2022-02 (Virtual)","","","" "`P2443R1 `__","``views::chunk_by``","2022-02 (Virtual)","|Complete|","18","" From 913a8d84adb13350f180cbdc46c4872ee6105fd8 Mon Sep 17 00:00:00 2001 From: jamesETsmith Date: Thu, 3 Apr 2025 09:55:30 -0400 Subject: [PATCH 36/36] [libc++] implementing ranges::iota: the header for out_value_result.h was out of order in the algorithm header which was triggering clang-fmt and clang-tidy CI failures --- libcxx/include/algorithm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm index 45708b7d16a45..bf67d3363a595 100644 --- a/libcxx/include/algorithm +++ b/libcxx/include/algorithm @@ -1937,9 +1937,9 @@ template # include <__algorithm/in_in_result.h> # include <__algorithm/in_out_out_result.h> # include <__algorithm/in_out_result.h> -# include <__algorithm/out_value_result.h> # include <__algorithm/lexicographical_compare_three_way.h> # include <__algorithm/min_max_result.h> +# include <__algorithm/out_value_result.h> # include <__algorithm/ranges_adjacent_find.h> # include <__algorithm/ranges_all_of.h> # include <__algorithm/ranges_any_of.h>