[libcxx-commits] [libcxx] [libc++] P2440R1: Implement ranges::iota (PR #109552)
via libcxx-commits
libcxx-commits at lists.llvm.org
Sat Sep 21 14:51:59 PDT 2024
https://github.com/PaulXiCao created https://github.com/llvm/llvm-project/pull/109552
The paper [P2440](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2440r1.html) introduces three groups of functions: `std::ranges::iota`, `std::ranges::shift_left`, and `std::ranges::shift_right`.
This mr implements `std::ranges::iota`. For reference:
- https://en.cppreference.com/w/cpp/algorithm/ranges/iota
- https://eel.is/c++draft/numeric.iota.
>From d3d7dd74bb3bab32e7331cfe0e25351a39224c32 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 21 Sep 2024 05:41:56 +0200
Subject: [PATCH 01/21] tests
---
.../numeric.iota/ranges_iota.pass.cpp | 58 +++++++++++++++++++
1 file changed, 58 insertions(+)
create mode 100644 libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges_iota.pass.cpp
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 00000000000000..a15c48722d8079
--- /dev/null
+++ b/libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges_iota.pass.cpp
@@ -0,0 +1,58 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// <numeric>
+
+// iota_result<O, T> iota(O first, S last, T value);
+
+#include <algorithm>
+#include <cassert>
+#include <numeric>
+#include <ranges>
+#include <vector>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+
+constexpr bool test() {
+ { // empty range
+ std::vector<int> vec;
+ constexpr int value = 42;
+ for (int i = 0; i < 2; ++i) {
+ const auto [last, final_value] =
+ (i == 0) ? std::ranges::iota(vec.begin(), vec.end(), value)
+ : std::ranges::iota<decltype(vec.begin())>(vec, value);
+ assert(vec.empty());
+ assert(last == vec.end());
+ assert(final_value == value);
+ }
+ }
+
+ { // non-empty range
+ constexpr int size = 3;
+ std::vector<int> vec(size);
+ constexpr int value = 42;
+ for (int i = 0; i < 2; ++i) {
+ const auto [last, final_value] =
+ (i == 0) ? std::ranges::iota(vec.begin(), vec.end(), value)
+ : std::ranges::iota<decltype(vec.begin())>(vec, value);
+ assert(std::ranges::equal(vec, std::vector{value, value + 1, value + 2}));
+ assert(last == vec.end());
+ assert(final_value == value + size);
+ }
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+}
>From a90a3405ac7e2f46370ef84465c95a5e9365da54 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 21 Sep 2024 05:42:25 +0200
Subject: [PATCH 02/21] first (straw-man) implementation for std::ranges::iota
---
libcxx/include/__numeric/iota.h | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/libcxx/include/__numeric/iota.h b/libcxx/include/__numeric/iota.h
index 27bd84e395a3a5..bdebfe56722c9c 100644
--- a/libcxx/include/__numeric/iota.h
+++ b/libcxx/include/__numeric/iota.h
@@ -11,6 +11,8 @@
#define _LIBCPP___NUMERIC_IOTA_H
#include <__config>
+#include <__ranges/access.h>
+#include <__utility/pair.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -25,6 +27,25 @@ iota(_ForwardIterator __first, _ForwardIterator __last, _Tp __value) {
*__first = __value;
}
+#if _LIBCPP_STD_VER >= 23
+namespace ranges {
+template <class O, class S, class T>
+constexpr pair<O, T> iota(O first, S last, T value) {
+ while (first != last) {
+ *first = value;
+ ++first;
+ ++value;
+ }
+ return {std::move(first), std::move(value)};
+}
+
+template <class O, class R, class T>
+constexpr pair<O, T> iota(R&& r, T value) {
+ return std::ranges::iota(std::ranges::begin(r), std::ranges::end(r), std::move(value));
+}
+} // namespace ranges
+#endif // _LIBCPP_STD_VER >= 23
+
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP___NUMERIC_IOTA_H
>From 2439dafc79626a31f1afe649110371d5cc92aa63 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 21 Sep 2024 21:57:30 +0200
Subject: [PATCH 03/21] constrain template arguments via proper concepts
---
libcxx/include/__numeric/iota.h | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/libcxx/include/__numeric/iota.h b/libcxx/include/__numeric/iota.h
index bdebfe56722c9c..c64cde4ca9fd62 100644
--- a/libcxx/include/__numeric/iota.h
+++ b/libcxx/include/__numeric/iota.h
@@ -11,7 +11,9 @@
#define _LIBCPP___NUMERIC_IOTA_H
#include <__config>
+#include <__iterator/concepts.h>
#include <__ranges/access.h>
+#include <__ranges/concepts.h>
#include <__utility/pair.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -29,7 +31,8 @@ iota(_ForwardIterator __first, _ForwardIterator __last, _Tp __value) {
#if _LIBCPP_STD_VER >= 23
namespace ranges {
-template <class O, class S, class T>
+template <input_or_output_iterator O, sentinel_for<O> S, weakly_incrementable T>
+ requires indirectly_writable<O, const T&>
constexpr pair<O, T> iota(O first, S last, T value) {
while (first != last) {
*first = value;
@@ -39,7 +42,7 @@ constexpr pair<O, T> iota(O first, S last, T value) {
return {std::move(first), std::move(value)};
}
-template <class O, class R, class T>
+template < input_or_output_iterator O, weakly_incrementable T, output_range<const T&> R >
constexpr pair<O, T> iota(R&& r, T value) {
return std::ranges::iota(std::ranges::begin(r), std::ranges::end(r), std::move(value));
}
>From e614e68ffd9891953fd994d0fa64bffce1bf669c Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 21 Sep 2024 22:07:26 +0200
Subject: [PATCH 04/21] uglify
---
libcxx/include/__numeric/iota.h | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/libcxx/include/__numeric/iota.h b/libcxx/include/__numeric/iota.h
index c64cde4ca9fd62..5c3a2e32020b8d 100644
--- a/libcxx/include/__numeric/iota.h
+++ b/libcxx/include/__numeric/iota.h
@@ -31,20 +31,20 @@ iota(_ForwardIterator __first, _ForwardIterator __last, _Tp __value) {
#if _LIBCPP_STD_VER >= 23
namespace ranges {
-template <input_or_output_iterator O, sentinel_for<O> S, weakly_incrementable T>
- requires indirectly_writable<O, const T&>
-constexpr pair<O, T> iota(O first, S last, T value) {
- while (first != last) {
- *first = value;
- ++first;
- ++value;
+template <input_or_output_iterator _O, sentinel_for<_O> _S, weakly_incrementable _T>
+ requires indirectly_writable<_O, const _T&>
+constexpr pair<_O, _T> iota(_O __first, _S __last, _T __value) {
+ while (__first != __last) {
+ *__first = __value;
+ ++__first;
+ ++__value;
}
- return {std::move(first), std::move(value)};
+ return {std::move(__first), std::move(__value)};
}
-template < input_or_output_iterator O, weakly_incrementable T, output_range<const T&> R >
-constexpr pair<O, T> iota(R&& r, T value) {
- return std::ranges::iota(std::ranges::begin(r), std::ranges::end(r), std::move(value));
+template < input_or_output_iterator _O, weakly_incrementable _T, output_range<const _T&> _R >
+constexpr pair<_O, _T> iota(_R&& __r, _T __value) {
+ return std::ranges::iota(std::ranges::begin(__r), std::ranges::end(__r), std::move(__value));
}
} // namespace ranges
#endif // _LIBCPP_STD_VER >= 23
>From 5ac194f5539ce3614ed64741d04b2e36b0fd5d79 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 21 Sep 2024 22:10:32 +0200
Subject: [PATCH 05/21] out_value_result
---
libcxx/include/CMakeLists.txt | 1 +
libcxx/include/__algorithm/out_value_result.h | 51 +++++++++++++++++++
libcxx/include/__numeric/iota.h | 10 ++--
3 files changed, 59 insertions(+), 3 deletions(-)
create mode 100644 libcxx/include/__algorithm/out_value_result.h
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 8c61009167ddce..5627588c3160ef 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -65,6 +65,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
diff --git a/libcxx/include/__algorithm/out_value_result.h b/libcxx/include/__algorithm/out_value_result.h
new file mode 100644
index 00000000000000..e67154599a8cda
--- /dev/null
+++ b/libcxx/include/__algorithm/out_value_result.h
@@ -0,0 +1,51 @@
+// -*- 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_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER >= 23
+
+namespace ranges {
+
+template <class _O, class _T>
+struct out_value_result {
+ _LIBCPP_NO_UNIQUE_ADDRESS _O out;
+ _LIBCPP_NO_UNIQUE_ADDRESS _T value;
+
+ template <class _O2, class _T2>
+ requires convertible_to<const _O&, _O2> && convertible_to<const _T&, _T2>
+ _LIBCPP_HIDE_FROM_ABI constexpr operator out_value_result<_O2, _T2>() const& {
+ return {out, value};
+ }
+
+ template <class _O2, class _T2>
+ requires convertible_to<_O, _O2> && convertible_to<_T, _T2>
+ _LIBCPP_HIDE_FROM_ABI constexpr operator out_value_result<_O2, _T2>() && {
+ return {std::move(out), std::move(value)};
+ }
+};
+
+} // namespace ranges
+
+#endif // _LIBCPP_STD_VER >= 23
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___ALGORITHM_OUT_VALUE_RESULT_H
diff --git a/libcxx/include/__numeric/iota.h b/libcxx/include/__numeric/iota.h
index 5c3a2e32020b8d..be93b3ff98b126 100644
--- a/libcxx/include/__numeric/iota.h
+++ b/libcxx/include/__numeric/iota.h
@@ -10,6 +10,7 @@
#ifndef _LIBCPP___NUMERIC_IOTA_H
#define _LIBCPP___NUMERIC_IOTA_H
+#include <__algorithm/out_value_result.h>
#include <__config>
#include <__iterator/concepts.h>
#include <__ranges/access.h>
@@ -31,9 +32,12 @@ iota(_ForwardIterator __first, _ForwardIterator __last, _Tp __value) {
#if _LIBCPP_STD_VER >= 23
namespace ranges {
+template < class _O, class _T >
+using iota_result = ranges::out_value_result<_O, _T>;
+
template <input_or_output_iterator _O, sentinel_for<_O> _S, weakly_incrementable _T>
requires indirectly_writable<_O, const _T&>
-constexpr pair<_O, _T> iota(_O __first, _S __last, _T __value) {
+constexpr iota_result<_O, _T> iota(_O __first, _S __last, _T __value) {
while (__first != __last) {
*__first = __value;
++__first;
@@ -42,8 +46,8 @@ constexpr pair<_O, _T> iota(_O __first, _S __last, _T __value) {
return {std::move(__first), std::move(__value)};
}
-template < input_or_output_iterator _O, weakly_incrementable _T, output_range<const _T&> _R >
-constexpr pair<_O, _T> iota(_R&& __r, _T __value) {
+template <weakly_incrementable _T, output_range<const _T&> _R >
+constexpr iota_result<ranges::borrowed_iterator_t<_R>, _T> iota(_R&& __r, _T __value) {
return std::ranges::iota(std::ranges::begin(__r), std::ranges::end(__r), std::move(__value));
}
} // namespace ranges
>From a6c92ca4effb2111de2e8c2a9581b16a306a08c3 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 21 Sep 2024 22:25:51 +0200
Subject: [PATCH 06/21] update tests
---
.../numerics/numeric.ops/numeric.iota/ranges_iota.pass.cpp | 6 ++----
1 file changed, 2 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 a15c48722d8079..cc484258488345 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
@@ -27,8 +27,7 @@ constexpr bool test() {
constexpr int value = 42;
for (int i = 0; i < 2; ++i) {
const auto [last, final_value] =
- (i == 0) ? std::ranges::iota(vec.begin(), vec.end(), value)
- : std::ranges::iota<decltype(vec.begin())>(vec, value);
+ (i == 0) ? std::ranges::iota(vec.begin(), vec.end(), value) : std::ranges::iota(vec, value);
assert(vec.empty());
assert(last == vec.end());
assert(final_value == value);
@@ -41,8 +40,7 @@ constexpr bool test() {
constexpr int value = 42;
for (int i = 0; i < 2; ++i) {
const auto [last, final_value] =
- (i == 0) ? std::ranges::iota(vec.begin(), vec.end(), value)
- : std::ranges::iota<decltype(vec.begin())>(vec, value);
+ (i == 0) ? std::ranges::iota(vec.begin(), vec.end(), value) : std::ranges::iota(vec, value);
assert(std::ranges::equal(vec, std::vector{value, value + 1, value + 2}));
assert(last == vec.end());
assert(final_value == value + size);
>From 200fc655bf117dda5a97f094e2b00af7fccfbad9 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 21 Sep 2024 22:29:13 +0200
Subject: [PATCH 07/21] make use of std::as_const()
---
libcxx/include/__numeric/iota.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/libcxx/include/__numeric/iota.h b/libcxx/include/__numeric/iota.h
index be93b3ff98b126..93b3535caa1af6 100644
--- a/libcxx/include/__numeric/iota.h
+++ b/libcxx/include/__numeric/iota.h
@@ -15,6 +15,7 @@
#include <__iterator/concepts.h>
#include <__ranges/access.h>
#include <__ranges/concepts.h>
+#include <__utility/as_const.h>
#include <__utility/pair.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -39,7 +40,7 @@ template <input_or_output_iterator _O, sentinel_for<_O> _S, weakly_incrementable
requires indirectly_writable<_O, const _T&>
constexpr iota_result<_O, _T> iota(_O __first, _S __last, _T __value) {
while (__first != __last) {
- *__first = __value;
+ *__first = std::as_const(__value);
++__first;
++__value;
}
>From 7020d5fa6c18d2eeeea1803ebbc540ba6086fa88 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 21 Sep 2024 22:33:06 +0200
Subject: [PATCH 08/21] cleanup namespace usage
---
libcxx/include/__numeric/iota.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libcxx/include/__numeric/iota.h b/libcxx/include/__numeric/iota.h
index 93b3535caa1af6..23bbc31305624c 100644
--- a/libcxx/include/__numeric/iota.h
+++ b/libcxx/include/__numeric/iota.h
@@ -34,7 +34,7 @@ iota(_ForwardIterator __first, _ForwardIterator __last, _Tp __value) {
#if _LIBCPP_STD_VER >= 23
namespace ranges {
template < class _O, class _T >
-using iota_result = ranges::out_value_result<_O, _T>;
+using iota_result = out_value_result<_O, _T>;
template <input_or_output_iterator _O, sentinel_for<_O> _S, weakly_incrementable _T>
requires indirectly_writable<_O, const _T&>
@@ -48,7 +48,7 @@ constexpr iota_result<_O, _T> iota(_O __first, _S __last, _T __value) {
}
template <weakly_incrementable _T, output_range<const _T&> _R >
-constexpr iota_result<ranges::borrowed_iterator_t<_R>, _T> iota(_R&& __r, _T __value) {
+constexpr iota_result<borrowed_iterator_t<_R>, _T> iota(_R&& __r, _T __value) {
return std::ranges::iota(std::ranges::begin(__r), std::ranges::end(__r), std::move(__value));
}
} // namespace ranges
>From 1797593f91b89b7f163ddacb9f2c8b2c1a42d1dd Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 21 Sep 2024 22:33:51 +0200
Subject: [PATCH 09/21] make use of _LIBCPP_HIDE_FROM_ABI
---
libcxx/include/__numeric/iota.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libcxx/include/__numeric/iota.h b/libcxx/include/__numeric/iota.h
index 23bbc31305624c..5f3b17a1062033 100644
--- a/libcxx/include/__numeric/iota.h
+++ b/libcxx/include/__numeric/iota.h
@@ -38,7 +38,7 @@ using iota_result = out_value_result<_O, _T>;
template <input_or_output_iterator _O, sentinel_for<_O> _S, weakly_incrementable _T>
requires indirectly_writable<_O, const _T&>
-constexpr iota_result<_O, _T> iota(_O __first, _S __last, _T __value) {
+_LIBCPP_HIDE_FROM_ABI constexpr iota_result<_O, _T> iota(_O __first, _S __last, _T __value) {
while (__first != __last) {
*__first = std::as_const(__value);
++__first;
@@ -48,7 +48,7 @@ constexpr iota_result<_O, _T> iota(_O __first, _S __last, _T __value) {
}
template <weakly_incrementable _T, output_range<const _T&> _R >
-constexpr iota_result<borrowed_iterator_t<_R>, _T> iota(_R&& __r, _T __value) {
+_LIBCPP_HIDE_FROM_ABI constexpr iota_result<borrowed_iterator_t<_R>, _T> iota(_R&& __r, _T __value) {
return std::ranges::iota(std::ranges::begin(__r), std::ranges::end(__r), std::move(__value));
}
} // namespace ranges
>From b47a764bb2042f5179f3a39cd1ba47d24cc788f6 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 21 Sep 2024 22:34:35 +0200
Subject: [PATCH 10/21] include header for std::move
---
libcxx/include/__numeric/iota.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/libcxx/include/__numeric/iota.h b/libcxx/include/__numeric/iota.h
index 5f3b17a1062033..f5fe4ae56f1649 100644
--- a/libcxx/include/__numeric/iota.h
+++ b/libcxx/include/__numeric/iota.h
@@ -16,6 +16,7 @@
#include <__ranges/access.h>
#include <__ranges/concepts.h>
#include <__utility/as_const.h>
+#include <__utility/move.h>
#include <__utility/pair.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
>From 3cf2e0ed5325c6eed21fb4cad8b54d3b1c3bf097 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 21 Sep 2024 22:38:36 +0200
Subject: [PATCH 11/21] header cleanup
---
libcxx/include/__numeric/iota.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/libcxx/include/__numeric/iota.h b/libcxx/include/__numeric/iota.h
index f5fe4ae56f1649..7b3ebdf3589a8e 100644
--- a/libcxx/include/__numeric/iota.h
+++ b/libcxx/include/__numeric/iota.h
@@ -17,7 +17,6 @@
#include <__ranges/concepts.h>
#include <__utility/as_const.h>
#include <__utility/move.h>
-#include <__utility/pair.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
>From 37cefdb5278fa8dc61fdc5c4edd50198e99333d8 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 21 Sep 2024 22:40:57 +0200
Subject: [PATCH 12/21] active feature macro
---
libcxx/include/version | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/include/version b/libcxx/include/version
index 5d679caac0b3b7..0ac8031b386a2a 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -489,7 +489,7 @@ __cpp_lib_void_t 201411L <type_traits>
# define __cpp_lib_ranges_chunk_by 202202L
# define __cpp_lib_ranges_contains 202207L
# define __cpp_lib_ranges_find_last 202207L
-// # 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
>From 82e5428cd45a288d32f6430af7fc0392a56663ef Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 21 Sep 2024 22:50:06 +0200
Subject: [PATCH 13/21] numeric synopsis: add iota_result, iota
---
libcxx/include/numeric | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/libcxx/include/numeric b/libcxx/include/numeric
index 6b92ce3a071237..eb192c56fb1b17 100644
--- a/libcxx/include/numeric
+++ b/libcxx/include/numeric
@@ -128,6 +128,18 @@ template <class ForwardIterator, class T>
constexpr void // constexpr since C++20
iota(ForwardIterator first, ForwardIterator last, T value);
+namespace ranges {
+ template<class O, class T>
+ using iota_result = out_value_result<O, T>; // C++23
+
+ template<input_or_output_iterator O, sentinel_for<O> S, weakly_incrementable T>
+ requires indirectly_writable<O, const T&>
+ constexpr iota_result<O, T> iota(O first, S last, T value); // C++23
+
+ template<weakly_incrementable T, output_range<const T&> R>
+ constexpr iota_result<borrowed_iterator_t<R>, T> iota(R&& r, T value); // C++23
+}
+
template <class M, class N>
constexpr common_type_t<M,N> gcd(M m, N n); // C++17
>From 2b962fc04e972734cb7cb8bd636e4c6f29427cb3 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 21 Sep 2024 22:55:07 +0200
Subject: [PATCH 14/21] numeric synopsis: match ISO standard's style
---
libcxx/include/numeric | 47 +++++++++++++++++++++---------------------
1 file changed, 24 insertions(+), 23 deletions(-)
diff --git a/libcxx/include/numeric b/libcxx/include/numeric
index eb192c56fb1b17..bac9e7274fe791 100644
--- a/libcxx/include/numeric
+++ b/libcxx/include/numeric
@@ -124,46 +124,47 @@ template <class InputIterator, class OutputIterator, class BinaryOperation>
constexpr OutputIterator // constexpr since C++20
adjacent_difference(InputIterator first, InputIterator last, OutputIterator result, BinaryOperation binary_op);
-template <class ForwardIterator, class T>
- constexpr void // constexpr since C++20
- iota(ForwardIterator first, ForwardIterator last, T value);
+// [numeric.iota], iota
+template<class ForwardIterator, class T>
+ constexpr void iota(ForwardIterator first, ForwardIterator last, T value); // constexpr since C++20
namespace ranges {
- template<class O, class T>
- using iota_result = out_value_result<O, T>; // C++23
+ template<class O, class T>
+ using iota_result = out_value_result<O, T>; // C++23
- template<input_or_output_iterator O, sentinel_for<O> S, weakly_incrementable T>
- requires indirectly_writable<O, const T&>
- constexpr iota_result<O, T> iota(O first, S last, T value); // C++23
+ template<input_or_output_iterator O, sentinel_for<O> S, weakly_incrementable T>
+ requires indirectly_writable<O, const T&>
+ constexpr iota_result<O, T> iota(O first, S last, T value); // C++23
- template<weakly_incrementable T, output_range<const T&> R>
- constexpr iota_result<borrowed_iterator_t<R>, T> iota(R&& r, T value); // C++23
+ template<weakly_incrementable T, output_range<const T&> R>
+ constexpr iota_result<borrowed_iterator_t<R>, T> iota(R&& r, T value); // C++23
}
-template <class M, class N>
- constexpr common_type_t<M,N> gcd(M m, N n); // C++17
+// [numeric.ops.gcd], greatest common divisor
+template<class M, class N>
+ constexpr common_type_t<M, N> gcd(M m, N n); // C++17
-template <class M, class N>
- constexpr common_type_t<M,N> lcm(M m, N n); // C++17
+// [numeric.ops.lcm], least common multiple
+template<class M, class N>
+ constexpr common_type_t<M, N> lcm(M m, N n); // C++17
+// [numeric.ops.midpoint], midpoint
template<class T>
- constexpr T midpoint(T a, T b) noexcept; // C++20
-
+ constexpr T midpoint(T a, T b) noexcept; // C++20
template<class T>
- constexpr T* midpoint(T* a, T* b); // C++20
+ constexpr T* midpoint(T* a, T* b); // C++20
// [numeric.sat], saturation arithmetic
template<class T>
-constexpr T add_sat(T x, T y) noexcept; // freestanding, Since C++26
+ constexpr T add_sat(T x, T y) noexcept; // freestanding, Since C++26
template<class T>
-constexpr T sub_sat(T x, T y) noexcept; // freestanding, Since C++26
+ constexpr T sub_sat(T x, T y) noexcept; // freestanding, Since C++26
template<class T>
-constexpr T mul_sat(T x, T y) noexcept; // freestanding, Since C++26
+ constexpr T mul_sat(T x, T y) noexcept; // freestanding, Since C++26
template<class T>
-constexpr T div_sat(T x, T y) noexcept; // freestanding, Since C++26
+ constexpr T div_sat(T x, T y) noexcept; // freestanding, Since C++26
template<class T, class U>
-constexpr T saturate_cast(U x) noexcept; // freestanding, Since C++26
-
+ constexpr T saturate_cast(U x) noexcept; // freestanding, Since C++26
} // std
*/
>From 6d7cafe5c9de0fc8748635805c4e25b097fd8505 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 21 Sep 2024 22:59:11 +0200
Subject: [PATCH 15/21] algorithm synopsis: mention out_value_result
---
libcxx/include/algorithm | 3 +++
1 file changed, 3 insertions(+)
diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm
index 36fd035b7e51b3..c0b6c0b77cd0d4 100644
--- a/libcxx/include/algorithm
+++ b/libcxx/include/algorithm
@@ -45,6 +45,9 @@ namespace ranges {
template <class I, class T>
struct in_value_result; // since C++23
+ template<class O, class T>
+ struct out_value_result; // since C++23
+
template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less> // since C++20
constexpr I min_element(I first, S last, Comp comp = {}, Proj proj = {});
>From eac5d45ad0ebdb8f9a09be49967318b5da8aafd1 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 21 Sep 2024 23:15:04 +0200
Subject: [PATCH 16/21] add out_value_result.h to <algorithm> header
---
libcxx/include/algorithm | 1 +
1 file changed, 1 insertion(+)
diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm
index c0b6c0b77cd0d4..9058541824589b 100644
--- a/libcxx/include/algorithm
+++ b/libcxx/include/algorithm
@@ -2028,6 +2028,7 @@ template <class BidirectionalIterator, class Compare>
# include <__algorithm/ranges_ends_with.h>
# include <__algorithm/ranges_find_last.h>
# include <__algorithm/ranges_starts_with.h>
+# include <__algorithm/out_value_result.h>
#endif // _LIBCPP_STD_VER >= 23
#include <version>
>From a9b3ba7385f11bfad3a373a56d18967b794e3e67 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 21 Sep 2024 23:19:47 +0200
Subject: [PATCH 17/21] testing: out_value_result
---
.../out_value_result.pass.cpp | 100 ++++++++++++++++++
1 file changed, 100 insertions(+)
create mode 100644 libcxx/test/std/algorithms/algorithms.results/out_value_result.pass.cpp
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 00000000000000..fa04acf4be17f2
--- /dev/null
+++ b/libcxx/test/std/algorithms/algorithms.results/out_value_result.pass.cpp
@@ -0,0 +1,100 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 <class _O, class _T>
+// struct out_value_result;
+
+#include <algorithm>
+#include <cassert>
+#include <type_traits>
+#include <utility>
+
+#include "MoveOnly.h"
+
+struct A {
+ explicit A(int);
+};
+// no implicit conversion
+static_assert(!std::is_constructible_v<std::ranges::out_value_result<A, A>, std::ranges::out_value_result<int, int>>);
+
+struct B {
+ B(int);
+};
+// implicit conversion
+static_assert(std::is_constructible_v<std::ranges::out_value_result<B, B>, std::ranges::out_value_result<int, int>>);
+static_assert(std::is_constructible_v<std::ranges::out_value_result<B, B>, std::ranges::out_value_result<int, int>&>);
+static_assert(std::is_constructible_v<std::ranges::out_value_result<B, B>, const std::ranges::out_value_result<int, int>>);
+static_assert(std::is_constructible_v<std::ranges::out_value_result<B, B>, const std::ranges::out_value_result<int, int>&>);
+
+struct C {
+ C(int&);
+};
+static_assert(!std::is_constructible_v<std::ranges::out_value_result<C, C>, std::ranges::out_value_result<int, int>&>);
+
+// has to be convertible via const&
+static_assert(std::is_convertible_v<std::ranges::out_value_result<int, int>&, std::ranges::out_value_result<long, long>>);
+static_assert(std::is_convertible_v<const std::ranges::out_value_result<int, int>&, std::ranges::out_value_result<long, long>>);
+static_assert(std::is_convertible_v<std::ranges::out_value_result<int, int>&&, std::ranges::out_value_result<long, long>>);
+static_assert(std::is_convertible_v<const std::ranges::out_value_result<int, int>&&, std::ranges::out_value_result<long, long>>);
+
+// should be move constructible
+static_assert(std::is_move_constructible_v<std::ranges::out_value_result<MoveOnly, int>>);
+static_assert(std::is_move_constructible_v<std::ranges::out_value_result<int, MoveOnly>>);
+
+// should not be copy constructible with move-only type
+static_assert(!std::is_copy_constructible_v<std::ranges::out_value_result<MoveOnly, int>>);
+static_assert(!std::is_copy_constructible_v<std::ranges::out_value_result<int, MoveOnly>>);
+
+struct NotConvertible {};
+// conversions should not work if there is no conversion
+static_assert(!std::is_convertible_v<std::ranges::out_value_result<NotConvertible, int>, std::ranges::out_value_result<int, int>>);
+static_assert(!std::is_convertible_v<std::ranges::out_value_result<int, NotConvertible>, std::ranges::out_value_result<int, int>>);
+
+template <class T>
+struct ConvertibleFrom {
+ constexpr ConvertibleFrom(T c) : content{c} {}
+ T content;
+};
+
+constexpr bool test() {
+ // Checks that conversion operations are correct.
+ {
+ const std::ranges::out_value_result<int, double> res{10, 0.};
+ assert(res.out == 10);
+ assert(res.value == 0.);
+ const std::ranges::out_value_result<ConvertibleFrom<int>, ConvertibleFrom<double>> res2 = res;
+ assert(res2.out.content == 10);
+ assert(res2.value.content == 0.);
+ }
+
+ // Checks that conversions are possible when one of the types is move-only.
+ {
+ std::ranges::out_value_result<MoveOnly, int> res{MoveOnly{}, 2};
+ assert(res.out.get() == 1);
+ assert(res.value == 2);
+ const auto res2 = static_cast<std::ranges::out_value_result<MoveOnly, int>>(std::move(res));
+ assert(res.out.get() == 0);
+ assert(res2.out.get() == 1);
+ assert(res2.value == 2);
+ }
+
+ // Checks that structured bindings get the correct values.
+ {
+ const auto [out, value] = std::ranges::out_value_result<int, int>{1, 2};
+ assert(out == 1);
+ assert(value == 2);
+ }
+ return true;
+}
+
+int main() {
+ test();
+ static_assert(test());
+}
>From 919c863b34783e847c0c0fb3630800bafaa6637f Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 21 Sep 2024 23:22:33 +0200
Subject: [PATCH 18/21] update docs/Status
---
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 6dde153ee8aab5..5f4ff35fd90421 100644
--- a/libcxx/docs/Status/Cxx23Papers.csv
+++ b/libcxx/docs/Status/Cxx23Papers.csv
@@ -46,7 +46,7 @@
"`P2255R2 <https://wg21.link/P2255R2>`__","A type trait to detect reference binding to temporary","2022-02 (Virtual)","","",""
"`P2273R3 <https://wg21.link/P2273R3>`__","Making ``std::unique_ptr`` constexpr","2022-02 (Virtual)","|Complete|","16.0",""
"`P2387R3 <https://wg21.link/P2387R3>`__","Pipe support for user-defined range adaptors","2022-02 (Virtual)","|Complete|","19.0",""
-"`P2440R1 <https://wg21.link/P2440R1>`__","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","2022-02 (Virtual)","","",""
+"`P2440R1 <https://wg21.link/P2440R1>`__","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","2022-02 (Virtual)","|In Progress|","",""
"`P2441R2 <https://wg21.link/P2441R2>`__","``views::join_with``","2022-02 (Virtual)","|In Progress|","",""
"`P2442R1 <https://wg21.link/P2442R1>`__","Windowing range adaptors: ``views::chunk`` and ``views::slide``","2022-02 (Virtual)","","",""
"`P2443R1 <https://wg21.link/P2443R1>`__","``views::chunk_by``","2022-02 (Virtual)","|Complete|","18.0",""
>From 4adab5877e7b214d804268aad5e38046e868a147 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 21 Sep 2024 23:29:08 +0200
Subject: [PATCH 19/21] update modulemap
---
libcxx/include/module.modulemap | 1 +
1 file changed, 1 insertion(+)
diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index c1181a3622513f..a237dd19b2ee21 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -766,6 +766,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" }
>From 648fe1baba53dd6895a2f8cf4519fb86f93217e5 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 21 Sep 2024 23:31:45 +0200
Subject: [PATCH 20/21] feature test macro: update
generate_feature_test_macro_components
---
libcxx/utils/generate_feature_test_macro_components.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 3b8a52362ede68..a03b9b20b2fc52 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -1043,7 +1043,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 40a283071edad4fcfbe1f7d80accf6c48f76061a Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 21 Sep 2024 23:35:47 +0200
Subject: [PATCH 21/21] enable feature test macro checks
---
libcxx/docs/FeatureTestMacroTable.rst | 2 +-
.../numeric.version.compile.pass.cpp | 32 ++++++-------------
.../version.version.compile.pass.cpp | 32 ++++++-------------
3 files changed, 21 insertions(+), 45 deletions(-)
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index c909a4300db1a6..76a6c0f9212001 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -364,7 +364,7 @@ Status
---------------------------------------------------------- -----------------
``__cpp_lib_ranges_find_last`` ``202207L``
---------------------------------------------------------- -----------------
- ``__cpp_lib_ranges_iota`` *unimplemented*
+ ``__cpp_lib_ranges_iota`` ``202202L``
---------------------------------------------------------- -----------------
``__cpp_lib_ranges_join_with`` *unimplemented*
---------------------------------------------------------- -----------------
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 d132b7c7b9c4f5..0743c6c71840c4 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
@@ -197,17 +197,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
# ifdef __cpp_lib_saturation_arithmetic
@@ -250,17 +244,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
# ifndef __cpp_lib_saturation_arithmetic
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 985ffeffab96db..840e88cda7ce4c 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
@@ -5682,17 +5682,11 @@
# error "__cpp_lib_ranges_find_last 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)
@@ -7542,17 +7536,11 @@
# error "__cpp_lib_ranges_find_last should have the value 202207L 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)
More information about the libcxx-commits
mailing list