[libcxx-commits] [libcxx] [libc++] P2502R2: `std::generator` (PR #92213)
Xiaoyang Liu via libcxx-commits
libcxx-commits at lists.llvm.org
Sun Dec 1 12:56:26 PST 2024
https://github.com/xiaoyang-sde updated https://github.com/llvm/llvm-project/pull/92213
>From 1807a424108f29e2cf73f8ac8b086a2f28f52939 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Tue, 7 May 2024 17:58:02 -0700
Subject: [PATCH 01/38] [libc++][ranges] implement 'ranges::elements_of'
---
libcxx/include/CMakeLists.txt | 1 +
libcxx/include/__ranges/elements_of.h | 47 +++++++++++++++++++
libcxx/include/ranges | 5 ++
libcxx/modules/std/ranges.inc | 4 +-
.../range.elementsof/elements_of.pass.cpp | 39 +++++++++++++++
5 files changed, 95 insertions(+), 1 deletion(-)
create mode 100644 libcxx/include/__ranges/elements_of.h
create mode 100644 libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index fd7eb125e007b6..b1f9be1dc3d7da 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -646,6 +646,7 @@ set(files
__ranges/data.h
__ranges/drop_view.h
__ranges/drop_while_view.h
+ __ranges/elements_of.h
__ranges/elements_view.h
__ranges/empty.h
__ranges/empty_view.h
diff --git a/libcxx/include/__ranges/elements_of.h b/libcxx/include/__ranges/elements_of.h
new file mode 100644
index 00000000000000..727ba92666eb36
--- /dev/null
+++ b/libcxx/include/__ranges/elements_of.h
@@ -0,0 +1,47 @@
+// -*- 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___RANGES_ELEMENTS_OF_H
+#define _LIBCPP___RANGES_ELEMENTS_OF_H
+
+#include <__config>
+#include <__memory/allocator.h>
+#include <__ranges/concepts.h>
+#include <cstddef>
+
+#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 <range _Range, class _Allocator = allocator<byte>>
+struct elements_of {
+ _LIBCPP_NO_UNIQUE_ADDRESS _Range range;
+ _LIBCPP_NO_UNIQUE_ADDRESS _Allocator allocator = _Allocator();
+};
+
+template <class _Range, class _Allocator = allocator<byte>>
+elements_of(_Range&&, _Allocator = _Allocator()) -> elements_of<_Range&&, _Allocator>;
+
+} // namespace ranges
+
+#endif // _LIBCPP_STD_VER >= 23
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+#endif // _LIBCPP___RANGES_ELEMENTS_OF_H
diff --git a/libcxx/include/ranges b/libcxx/include/ranges
index 07a525ed8641fd..a8fbfc462bf0db 100644
--- a/libcxx/include/ranges
+++ b/libcxx/include/ranges
@@ -116,6 +116,10 @@ namespace std::ranges {
// [range.dangling], dangling iterator handling
struct dangling;
+ // [range.elementsof], class template elements_of
+ template<range R, class Allocator = allocator<byte>>
+ struct elements_of;
+
template<range R>
using borrowed_iterator_t = see below;
@@ -392,6 +396,7 @@ namespace std {
#include <__ranges/data.h>
#include <__ranges/drop_view.h>
#include <__ranges/drop_while_view.h>
+#include <__ranges/elements_of.h>
#include <__ranges/elements_view.h>
#include <__ranges/empty.h>
#include <__ranges/empty_view.h>
diff --git a/libcxx/modules/std/ranges.inc b/libcxx/modules/std/ranges.inc
index 80f31c79a1a405..94f3defdcbc356 100644
--- a/libcxx/modules/std/ranges.inc
+++ b/libcxx/modules/std/ranges.inc
@@ -83,8 +83,10 @@ export namespace std {
// [range.dangling], dangling iterator handling
using std::ranges::dangling;
+#if _LIBCPP_STD_VER >= 23
// [range.elementsof], class template elements_of
- // using std::ranges::elements_of;
+ using std::ranges::elements_of;
+#endif
using std::ranges::borrowed_iterator_t;
diff --git a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
new file mode 100644
index 00000000000000..e1c2f91b960796
--- /dev/null
+++ b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
@@ -0,0 +1,39 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// std::ranges::elements_of;
+
+#include <ranges>
+
+#include <vector>
+#include <concepts>
+
+constexpr bool test() {
+ {
+ auto elements_of = std::ranges::elements_of(std::vector<int>());
+ static_assert(
+ std::same_as<decltype(elements_of), std::ranges::elements_of<std::vector<int>&&, std::allocator<std::byte>>>);
+ static_assert(std::same_as<decltype(elements_of.range), std::vector<int>&&>);
+ static_assert(std::same_as<decltype(elements_of.allocator), std::allocator<std::byte>>);
+ }
+ {
+ auto elements_of = std::ranges::elements_of(std::vector<int>(), std::allocator<int>());
+ static_assert(
+ std::same_as<decltype(elements_of), std::ranges::elements_of<std::vector<int>&&, std::allocator<int>>>);
+ static_assert(std::same_as<decltype(elements_of.range), std::vector<int>&&>);
+ static_assert(std::same_as<decltype(elements_of.allocator), std::allocator<int>>);
+ }
+ return true;
+}
+
+int main() {
+ test();
+ static_assert(test());
+}
>From e14469bc4b829a7d40e8a445920d396ef08c5dda Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Tue, 7 May 2024 18:03:43 -0700
Subject: [PATCH 02/38] [libc++][ranges] implement 'ranges::elements_of'
---
libcxx/include/__ranges/elements_of.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/libcxx/include/__ranges/elements_of.h b/libcxx/include/__ranges/elements_of.h
index 727ba92666eb36..d7cb1937563c60 100644
--- a/libcxx/include/__ranges/elements_of.h
+++ b/libcxx/include/__ranges/elements_of.h
@@ -44,4 +44,5 @@ elements_of(_Range&&, _Allocator = _Allocator()) -> elements_of<_Range&&, _Alloc
_LIBCPP_END_NAMESPACE_STD
_LIBCPP_POP_MACROS
+
#endif // _LIBCPP___RANGES_ELEMENTS_OF_H
>From 85ca069a211767c13059a315803fb71c442540a5 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Tue, 7 May 2024 18:04:53 -0700
Subject: [PATCH 03/38] [libc++][ranges] implement 'ranges::elements_of'
---
.../ranges/range.utility/range.elementsof/elements_of.pass.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
index e1c2f91b960796..378bcb0a2f13f3 100644
--- a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
+++ b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
@@ -12,8 +12,9 @@
#include <ranges>
-#include <vector>
#include <concepts>
+#include <memory>
+#include <vector>
constexpr bool test() {
{
>From b031c387baf12789a0da5268da2c92710087aac8 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Tue, 7 May 2024 19:45:10 -0700
Subject: [PATCH 04/38] [libc++][ranges] implement 'ranges::elements_of'
---
libcxx/include/module.modulemap | 1 +
1 file changed, 1 insertion(+)
diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index 2974d12500c4cb..ee952c48c11d5b 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -1699,6 +1699,7 @@ module std_private_ranges_dangling [system] { header "__ranges
module std_private_ranges_data [system] { header "__ranges/data.h" }
module std_private_ranges_drop_view [system] { header "__ranges/drop_view.h" }
module std_private_ranges_drop_while_view [system] { header "__ranges/drop_while_view.h" }
+module std_private_ranges_elements_of [system] { header "__ranges/elements_of.h" }
module std_private_ranges_elements_view [system] { header "__ranges/elements_view.h" }
module std_private_ranges_empty [system] { header "__ranges/empty.h" }
module std_private_ranges_empty_view [system] { header "__ranges/empty_view.h" }
>From 32b68f274244cc866d7edf5a83fffcb4ba0bec19 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Wed, 8 May 2024 13:22:10 -0400
Subject: [PATCH 05/38] [libc++][ranges] implement 'ranges::elements_of'
---
libcxx/include/__ranges/elements_of.h | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/libcxx/include/__ranges/elements_of.h b/libcxx/include/__ranges/elements_of.h
index d7cb1937563c60..6219446a742a85 100644
--- a/libcxx/include/__ranges/elements_of.h
+++ b/libcxx/include/__ranges/elements_of.h
@@ -31,7 +31,11 @@ namespace ranges {
template <range _Range, class _Allocator = allocator<byte>>
struct elements_of {
_LIBCPP_NO_UNIQUE_ADDRESS _Range range;
- _LIBCPP_NO_UNIQUE_ADDRESS _Allocator allocator = _Allocator();
+ _LIBCPP_NO_UNIQUE_ADDRESS _Allocator allocator;
+
+ // This explicit constructor is required because AppleClang 15 hasn't implement P0960R3
+ explicit elements_of(_Range&& __range, _Allocator __allocator = _Allocator())
+ : range(std::move(__range)), allocator(std::move(__allocator)) {}
};
template <class _Range, class _Allocator = allocator<byte>>
>From 8e3560904d1cc79d014acba31eb2586edd71869d Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Wed, 8 May 2024 13:36:27 -0400
Subject: [PATCH 06/38] [libc++][ranges] implement 'ranges::elements_of'
---
libcxx/include/__ranges/elements_of.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/libcxx/include/__ranges/elements_of.h b/libcxx/include/__ranges/elements_of.h
index 6219446a742a85..043bcb918a692d 100644
--- a/libcxx/include/__ranges/elements_of.h
+++ b/libcxx/include/__ranges/elements_of.h
@@ -13,6 +13,7 @@
#include <__config>
#include <__memory/allocator.h>
#include <__ranges/concepts.h>
+#include <__utility/move.h>
#include <cstddef>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
>From 162ce8ab091420ff39031aad4260843ac8df6391 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Wed, 8 May 2024 16:36:47 -0400
Subject: [PATCH 07/38] [libc++][ranges] implement 'ranges::elements_of'
---
libcxx/include/__ranges/elements_of.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/include/__ranges/elements_of.h b/libcxx/include/__ranges/elements_of.h
index 043bcb918a692d..93020c93d5f7b8 100644
--- a/libcxx/include/__ranges/elements_of.h
+++ b/libcxx/include/__ranges/elements_of.h
@@ -35,7 +35,7 @@ struct elements_of {
_LIBCPP_NO_UNIQUE_ADDRESS _Allocator allocator;
// This explicit constructor is required because AppleClang 15 hasn't implement P0960R3
- explicit elements_of(_Range&& __range, _Allocator __allocator = _Allocator())
+ _LIBCPP_HIDE_FROM_ABI explicit constexpr elements_of(_Range __range, _Allocator __allocator = _Allocator())
: range(std::move(__range)), allocator(std::move(__allocator)) {}
};
>From 9dd983d4ccd1ac0e1b5a74340212d6013309cf2d Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Wed, 8 May 2024 16:51:32 -0400
Subject: [PATCH 08/38] [libc++][ranges] implement 'ranges::elements_of'
---
libcxx/include/__ranges/elements_of.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libcxx/include/__ranges/elements_of.h b/libcxx/include/__ranges/elements_of.h
index 93020c93d5f7b8..edce0af345f378 100644
--- a/libcxx/include/__ranges/elements_of.h
+++ b/libcxx/include/__ranges/elements_of.h
@@ -35,8 +35,8 @@ struct elements_of {
_LIBCPP_NO_UNIQUE_ADDRESS _Allocator allocator;
// This explicit constructor is required because AppleClang 15 hasn't implement P0960R3
- _LIBCPP_HIDE_FROM_ABI explicit constexpr elements_of(_Range __range, _Allocator __allocator = _Allocator())
- : range(std::move(__range)), allocator(std::move(__allocator)) {}
+ _LIBCPP_HIDE_FROM_ABI explicit constexpr elements_of(_Range __range, _Allocator __alloc = _Allocator())
+ : range(std::move(__range)), allocator(std::move(__alloc)) {}
};
template <class _Range, class _Allocator = allocator<byte>>
>From 8291917ab08f32b609b7c2711ce63de9b649051b Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Tue, 14 May 2024 12:49:39 -0400
Subject: [PATCH 09/38] [libc++][ranges] implement 'ranges::elements_of'
---
libcxx/include/__ranges/elements_of.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/libcxx/include/__ranges/elements_of.h b/libcxx/include/__ranges/elements_of.h
index edce0af345f378..f446d3c12d67e7 100644
--- a/libcxx/include/__ranges/elements_of.h
+++ b/libcxx/include/__ranges/elements_of.h
@@ -40,6 +40,8 @@ struct elements_of {
};
template <class _Range, class _Allocator = allocator<byte>>
+// This explicit constraint is required because AppleClang 15 might not deduce the correct type for `_Range` without it
+ requires range<_Range&&>
elements_of(_Range&&, _Allocator = _Allocator()) -> elements_of<_Range&&, _Allocator>;
} // namespace ranges
>From c1fc9cb0b75b81d0a91364f4bbffb64bf2c6de86 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Wed, 15 May 2024 00:36:58 -0400
Subject: [PATCH 10/38] [libc++][ranges] implement 'ranges::elements_of'
---
libcxx/include/CMakeLists.txt | 1 +
libcxx/include/__ranges/elements_of.h | 55 +++++++++++++++++++
libcxx/include/module.modulemap | 1 +
libcxx/include/ranges | 5 ++
libcxx/modules/std/ranges.inc | 4 +-
.../range.elementsof/elements_of.pass.cpp | 40 ++++++++++++++
6 files changed, 105 insertions(+), 1 deletion(-)
create mode 100644 libcxx/include/__ranges/elements_of.h
create mode 100644 libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 01e9c247560ca0..2be32fee2a9fd6 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -647,6 +647,7 @@ set(files
__ranges/data.h
__ranges/drop_view.h
__ranges/drop_while_view.h
+ __ranges/elements_of.h
__ranges/elements_view.h
__ranges/empty.h
__ranges/empty_view.h
diff --git a/libcxx/include/__ranges/elements_of.h b/libcxx/include/__ranges/elements_of.h
new file mode 100644
index 00000000000000..f446d3c12d67e7
--- /dev/null
+++ b/libcxx/include/__ranges/elements_of.h
@@ -0,0 +1,55 @@
+// -*- 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___RANGES_ELEMENTS_OF_H
+#define _LIBCPP___RANGES_ELEMENTS_OF_H
+
+#include <__config>
+#include <__memory/allocator.h>
+#include <__ranges/concepts.h>
+#include <__utility/move.h>
+#include <cstddef>
+
+#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 <range _Range, class _Allocator = allocator<byte>>
+struct elements_of {
+ _LIBCPP_NO_UNIQUE_ADDRESS _Range range;
+ _LIBCPP_NO_UNIQUE_ADDRESS _Allocator allocator;
+
+ // This explicit constructor is required because AppleClang 15 hasn't implement P0960R3
+ _LIBCPP_HIDE_FROM_ABI explicit constexpr elements_of(_Range __range, _Allocator __alloc = _Allocator())
+ : range(std::move(__range)), allocator(std::move(__alloc)) {}
+};
+
+template <class _Range, class _Allocator = allocator<byte>>
+// This explicit constraint is required because AppleClang 15 might not deduce the correct type for `_Range` without it
+ requires range<_Range&&>
+elements_of(_Range&&, _Allocator = _Allocator()) -> elements_of<_Range&&, _Allocator>;
+
+} // namespace ranges
+
+#endif // _LIBCPP_STD_VER >= 23
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___RANGES_ELEMENTS_OF_H
diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index 70dac2f19846b0..6bc9403db2b59f 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -1701,6 +1701,7 @@ module std_private_ranges_dangling [system] { header "__ranges
module std_private_ranges_data [system] { header "__ranges/data.h" }
module std_private_ranges_drop_view [system] { header "__ranges/drop_view.h" }
module std_private_ranges_drop_while_view [system] { header "__ranges/drop_while_view.h" }
+module std_private_ranges_elements_of [system] { header "__ranges/elements_of.h" }
module std_private_ranges_elements_view [system] { header "__ranges/elements_view.h" }
module std_private_ranges_empty [system] { header "__ranges/empty.h" }
module std_private_ranges_empty_view [system] { header "__ranges/empty_view.h" }
diff --git a/libcxx/include/ranges b/libcxx/include/ranges
index 07a525ed8641fd..a8fbfc462bf0db 100644
--- a/libcxx/include/ranges
+++ b/libcxx/include/ranges
@@ -116,6 +116,10 @@ namespace std::ranges {
// [range.dangling], dangling iterator handling
struct dangling;
+ // [range.elementsof], class template elements_of
+ template<range R, class Allocator = allocator<byte>>
+ struct elements_of;
+
template<range R>
using borrowed_iterator_t = see below;
@@ -392,6 +396,7 @@ namespace std {
#include <__ranges/data.h>
#include <__ranges/drop_view.h>
#include <__ranges/drop_while_view.h>
+#include <__ranges/elements_of.h>
#include <__ranges/elements_view.h>
#include <__ranges/empty.h>
#include <__ranges/empty_view.h>
diff --git a/libcxx/modules/std/ranges.inc b/libcxx/modules/std/ranges.inc
index f71efe948ede10..82055c2ddbfbb5 100644
--- a/libcxx/modules/std/ranges.inc
+++ b/libcxx/modules/std/ranges.inc
@@ -83,8 +83,10 @@ export namespace std {
// [range.dangling], dangling iterator handling
using std::ranges::dangling;
+#if _LIBCPP_STD_VER >= 23
// [range.elementsof], class template elements_of
- // using std::ranges::elements_of;
+ using std::ranges::elements_of;
+#endif
using std::ranges::borrowed_iterator_t;
diff --git a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
new file mode 100644
index 00000000000000..378bcb0a2f13f3
--- /dev/null
+++ b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
@@ -0,0 +1,40 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// std::ranges::elements_of;
+
+#include <ranges>
+
+#include <concepts>
+#include <memory>
+#include <vector>
+
+constexpr bool test() {
+ {
+ auto elements_of = std::ranges::elements_of(std::vector<int>());
+ static_assert(
+ std::same_as<decltype(elements_of), std::ranges::elements_of<std::vector<int>&&, std::allocator<std::byte>>>);
+ static_assert(std::same_as<decltype(elements_of.range), std::vector<int>&&>);
+ static_assert(std::same_as<decltype(elements_of.allocator), std::allocator<std::byte>>);
+ }
+ {
+ auto elements_of = std::ranges::elements_of(std::vector<int>(), std::allocator<int>());
+ static_assert(
+ std::same_as<decltype(elements_of), std::ranges::elements_of<std::vector<int>&&, std::allocator<int>>>);
+ static_assert(std::same_as<decltype(elements_of.range), std::vector<int>&&>);
+ static_assert(std::same_as<decltype(elements_of.allocator), std::allocator<int>>);
+ }
+ return true;
+}
+
+int main() {
+ test();
+ static_assert(test());
+}
>From 176b313133ecdc07a774de28551c4d91fe7c4d7e Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Wed, 15 May 2024 00:39:07 -0400
Subject: [PATCH 11/38] [libc++] implement 'std::generator'
---
libcxx/include/CMakeLists.txt | 1 +
libcxx/include/generator | 377 ++++++++++++++++++
.../ranges/coro.generator/generator.pass.cpp | 40 ++
.../ranges/coro.generator/recursive.pass.cpp | 92 +++++
4 files changed, 510 insertions(+)
create mode 100644 libcxx/include/generator
create mode 100644 libcxx/test/std/ranges/coro.generator/generator.pass.cpp
create mode 100644 libcxx/test/std/ranges/coro.generator/recursive.pass.cpp
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 2be32fee2a9fd6..5344dc06decfb0 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -951,6 +951,7 @@ set(files
fstream
functional
future
+ generator
initializer_list
inttypes.h
iomanip
diff --git a/libcxx/include/generator b/libcxx/include/generator
new file mode 100644
index 00000000000000..6542e4c02499dc
--- /dev/null
+++ b/libcxx/include/generator
@@ -0,0 +1,377 @@
+// -*- 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_GENERATOR
+#define _LIBCPP_GENERATOR
+
+#include <__assert>
+#include <__concepts/constructible.h>
+#include <__concepts/convertible_to.h>
+#include <__config>
+#include <__coroutine/coroutine_handle.h>
+#include <__coroutine/coroutine_traits.h>
+#include <__coroutine/noop_coroutine_handle.h>
+#include <__coroutine/trivial_awaitables.h>
+#include <__exception/exception_ptr.h>
+#include <__iterator/default_sentinel.h>
+#include <__memory/addressof.h>
+#include <__memory/allocator_arg_t.h>
+#include <__memory/allocator_traits.h>
+#include <__ranges/concepts.h>
+#include <__ranges/elements_of.h>
+#include <__ranges/view_interface.h>
+#include <__type_traits/add_pointer.h>
+#include <__type_traits/common_reference.h>
+#include <__type_traits/conditional.h>
+#include <__type_traits/is_nothrow_constructible.h>
+#include <__type_traits/is_object.h>
+#include <__type_traits/is_reference.h>
+#include <__type_traits/is_void.h>
+#include <__type_traits/remove_cvref.h>
+#include <__utility/exchange.h>
+#include <__utility/swap.h>
+
+#if _LIBCPP_STD_VER >= 23
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <class _Ref, class _Val>
+using __gen_val = conditional_t<is_void_v<_Val>, remove_cvref_t<_Ref>, _Val>;
+
+template <class _Ref, class _Val>
+using __gen_ref = conditional_t<is_void_v<_Val>, _Ref&&, _Ref>;
+
+template <class _Ref, class _Val>
+using __gen_yielded =
+ conditional_t<is_reference_v<__gen_ref<_Ref, _Val>>, __gen_ref<_Ref, _Val>, const __gen_ref<_Ref, _Val>&>;
+
+template <class, class, class>
+class generator;
+
+template <class _Yielded>
+class __gen_promise_base {
+private:
+ template <class, class, class>
+ friend class generator;
+
+ template <class, class>
+ friend class __gen_iter;
+
+ // Each promise object stores either a `__root_data` when associated with a root generator, or a `__recursive_data`
+ // when associated with a generator that is yielded recursively.
+ struct __root_data {
+ // The client code has access only to the iterator of the root generator. Thus, the root generator must store the
+ // yielded values of recursively-yielded generators, which will then be returned when the client code dereferences
+ // the iterator.
+ add_pointer_t<_Yielded> __value_ptr;
+ // The client code has access only to the iterator of the root generator. Thus, the root generator needs to identify
+ // which generator is currently active. This active generator will then be resumed when the client code increments
+ // the iterator.
+ std::coroutine_handle<__gen_promise_base> __active;
+ };
+
+ struct __recursive_data {
+ std::exception_ptr __exception;
+ std::coroutine_handle<__gen_promise_base> __parent;
+ std::coroutine_handle<__gen_promise_base> __root;
+ };
+
+ union __union {
+ __root_data __root;
+ __recursive_data __recursive;
+
+ ~__union() noexcept {}
+ } __data_;
+
+ // The `__tag_` stores the active member of the `__data_` union:
+ // - `false` indicates that the active member is `__root`.
+ // - `true` indicates that the active member is `__recursive`.
+ // This field can be omitted because `__recursive_data.__root` can store the active member.
+ bool __tag_;
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool __is_root() noexcept { return !__tag_; }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __root_data& __get_root_data() noexcept {
+ _LIBCPP_ASSERT_INTERNAL(__is_root(), "the active member of `__data_` is not `__root`");
+ return __data_.__root;
+ }
+ _LIBCPP_HIDE_FROM_ABI void __set_root_tag() noexcept { __tag_ = false; }
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool __is_recursive() noexcept { return __tag_; }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __recursive_data& __get_recursive_data() noexcept {
+ _LIBCPP_ASSERT_INTERNAL(__is_recursive(), "the active member of `__data_` is not `__recursive`");
+ return __data_.__recursive;
+ }
+ _LIBCPP_HIDE_FROM_ABI void __set_recursive_tag() noexcept { __tag_ = true; }
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI std::coroutine_handle<__gen_promise_base>& __active() noexcept {
+ _LIBCPP_ASSERT_INTERNAL(__is_root(), "the active member of `__data_` is not `__root`");
+ return __get_root_data().__active;
+ }
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI add_pointer_t<_Yielded>& __value_ptr() noexcept {
+ _LIBCPP_ASSERT_INTERNAL(__is_root(), "the active member of `__data_` is not `__root`");
+ return __get_root_data().__value_ptr;
+ }
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI add_pointer_t<_Yielded>& __root_value_ptr() noexcept {
+ if (__is_root()) {
+ return __value_ptr();
+ }
+ return __get_recursive_data().__root.promise().__value_ptr();
+ }
+
+ struct __element_awaiter {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool await_ready() noexcept { return false; }
+
+ template <class _Promise>
+ _LIBCPP_HIDE_FROM_ABI void await_suspend(coroutine_handle<_Promise> __current) noexcept {
+ __current.promise().__root_value_ptr() = std::addressof(__value);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI void await_resume() noexcept {}
+
+ remove_cvref_t<_Yielded> __value;
+ };
+
+ struct __final_awaiter {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool await_ready() noexcept { return false; }
+
+ template <class _Promise>
+ _LIBCPP_HIDE_FROM_ABI coroutine_handle<> await_suspend(coroutine_handle<_Promise> __current) noexcept {
+ // Checks if the current generator is recursively-yielded
+ if (__current.promise().__is_recursive()) {
+ auto&& __recursive_data = __current.promise().__get_recursive_data();
+ auto __parent = __recursive_data.__parent;
+ // Updates the active generator to its parent, allowing the client code to resume it later
+ __recursive_data.__root.promise().__active() = __parent;
+ // Transfers execution to its parent, which is the generator that yields it
+ return __parent;
+ }
+ return std::noop_coroutine();
+ }
+
+ _LIBCPP_HIDE_FROM_ABI void await_resume() noexcept {}
+ };
+
+ template <class _Ref, class _Val, class _Allocator>
+ struct __recursive_awaiter {
+ generator<_Ref, _Val, _Allocator> __gen;
+
+ _LIBCPP_HIDE_FROM_ABI explicit __recursive_awaiter(generator<_Ref, _Val, _Allocator>&& __gen) noexcept
+ : __gen{std::move(__gen)} {}
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool await_ready() noexcept { return !__gen.__coroutine_; }
+
+ template <class _Promise>
+ _LIBCPP_HIDE_FROM_ABI coroutine_handle<__gen_promise_base>
+ await_suspend(coroutine_handle<_Promise> __current) noexcept {
+ // Stores a `__recursive_data` in the promise object associated with `__gen`
+ auto __recursive = coroutine_handle<__gen_promise_base>::from_address(__gen.__coroutine_.address());
+ __recursive.promise().__set_recursive_tag();
+ auto&& __recursive_data = __recursive.promise().__get_recursive_data();
+
+ // Sets `__recursive_data.__parent` to the current generator
+ auto __parent = coroutine_handle<__gen_promise_base>::from_address(__current.address());
+ __recursive_data.__parent = __parent;
+
+ // Sets `__recursive_data.__root` to the current generator if it's a root generator, or to the root generator of
+ // the current generator otherwise
+ if (__parent.promise().__is_recursive()) {
+ __recursive_data.__root = __parent.promise().__get_recursive_data().__root;
+ } else {
+ __recursive_data.__root = __parent;
+ }
+
+ // Updates the active generator to `__gen`, allowing the client code to resume it later
+ __recursive_data.__root.promise().__active() = __recursive;
+
+ // Transfers execution to `__gen`
+ return __recursive;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI void await_resume() {
+ auto __recursive = coroutine_handle<__gen_promise_base>::from_address(__gen.__coroutine_.address());
+ auto&& __recursive_data = __recursive.promise().__get_recursive_data();
+ if (__recursive_data.__exception) {
+ std::rethrow_exception(std::move(__recursive_data.__exception));
+ }
+ }
+ };
+
+public:
+ _LIBCPP_HIDE_FROM_ABI __gen_promise_base() noexcept
+ : __data_{.__root =
+ {
+ .__value_ptr = nullptr,
+ .__active = coroutine_handle<__gen_promise_base>::from_promise(*this),
+ }},
+ __tag_{false} {}
+
+ _LIBCPP_HIDE_FROM_ABI ~__gen_promise_base() noexcept {
+ if (__is_root()) {
+ __data_.__root.~__root_data();
+ } else {
+ __data_.__recursive.~__recursive_data();
+ }
+ }
+
+ _LIBCPP_HIDE_FROM_ABI suspend_always initial_suspend() const noexcept { return {}; }
+
+ _LIBCPP_HIDE_FROM_ABI __final_awaiter final_suspend() noexcept { return {}; }
+
+ _LIBCPP_HIDE_FROM_ABI suspend_always yield_value(_Yielded __value) noexcept {
+ __root_value_ptr() = std::addressof(__value);
+ return {};
+ }
+
+ _LIBCPP_HIDE_FROM_ABI auto yield_value(const remove_reference_t<_Yielded>& __value)
+ requires is_rvalue_reference_v<_Yielded> &&
+ constructible_from<remove_cvref_t<_Yielded>, const remove_reference_t<_Yielded>&>
+ {
+ return __element_awaiter{.__value = __value};
+ }
+
+ template <class _Ref2, class _Val2, class _Allocator2, class _Unused>
+ requires same_as<__gen_yielded<_Ref2, _Val2>, _Yielded>
+ _LIBCPP_HIDE_FROM_ABI auto
+ yield_value(ranges::elements_of<generator<_Ref2, _Val2, _Allocator2>&&, _Unused> __elements) noexcept {
+ return __recursive_awaiter<_Ref2, _Val2, _Allocator2>{std::move(__elements.range)};
+ }
+
+ template <ranges::input_range _Range, class _Allocator>
+ requires convertible_to<ranges::range_reference_t<_Range>, _Yielded>
+ _LIBCPP_HIDE_FROM_ABI auto yield_value(ranges::elements_of<_Range, _Allocator> __range) {
+ auto __lambda =
+ [](allocator_arg_t, _Allocator, ranges::iterator_t<_Range> __i, ranges::sentinel_t<_Range> __s) static
+ -> generator<_Yielded, ranges::range_value_t<_Range>, _Allocator> {
+ for (; __i != __s; ++__i) {
+ co_yield static_cast<_Yielded>(*__i);
+ }
+ };
+ return yield_value(ranges::elements_of(
+ __lambda(allocator_arg, __range.allocator, ranges::begin(__range.range), ranges::end(__range.range))));
+ }
+
+ _LIBCPP_HIDE_FROM_ABI void await_transform() = delete;
+
+ _LIBCPP_HIDE_FROM_ABI void return_void() const noexcept {}
+
+ _LIBCPP_HIDE_FROM_ABI void unhandled_exception() {
+ if (__is_root()) {
+ throw;
+ } else {
+ __get_recursive_data().__exception = std::current_exception();
+ }
+ }
+};
+
+template <class _Ref, class _Val>
+class __gen_iter {
+private:
+ using __val = __gen_val<_Ref, _Val>;
+ using __ref = __gen_ref<_Ref, _Val>;
+
+public:
+ using value_type = __val;
+ using difference_type = ptrdiff_t;
+
+ _LIBCPP_HIDE_FROM_ABI explicit __gen_iter(
+ coroutine_handle<__gen_promise_base<__gen_yielded<_Ref, _Val>>> __coroutine) noexcept
+ : __coroutine_{__coroutine} {}
+
+ _LIBCPP_HIDE_FROM_ABI __gen_iter(__gen_iter&& __other) noexcept
+ : __coroutine_{std::exchange(__other.__coroutine_, {})} {}
+
+ _LIBCPP_HIDE_FROM_ABI __gen_iter& operator=(__gen_iter&& __other) noexcept {
+ __coroutine_ = std::exchange(__other.__coroutine_, {});
+ return *this;
+ }
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __ref operator*() const noexcept(is_nothrow_copy_constructible_v<__ref>) {
+ return static_cast<__ref>(*__coroutine_.promise().__value_ptr());
+ }
+
+ _LIBCPP_HIDE_FROM_ABI __gen_iter& operator++() {
+ __coroutine_.promise().__active().resume();
+ return *this;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI void operator++(int) { ++*this; }
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool operator==(default_sentinel_t) const noexcept { return __coroutine_.done(); }
+
+private:
+ coroutine_handle<__gen_promise_base<__gen_yielded<_Ref, _Val>>> __coroutine_;
+};
+
+template <class _Ref, class _Val = void, class _Allocator = void>
+class generator : public ranges::view_interface<generator<_Ref, _Val, _Allocator>> {
+private:
+ using __val = __gen_val<_Ref, _Val>;
+ static_assert(same_as<remove_cvref_t<__val>, __val> && is_object_v<__val>);
+
+ using __ref = __gen_ref<_Ref, _Val>;
+ static_assert(is_reference_v<__ref> ||
+ (same_as<remove_cvref_t<__ref>, __ref> && is_object_v<__ref> && copy_constructible<__ref>));
+
+ using __rref = conditional_t<is_lvalue_reference_v<_Ref>, remove_reference_t<_Ref>&&, _Ref>;
+ static_assert(common_reference_with<__ref&&, __val&> && common_reference_with<__ref&&, __rref&&> &&
+ common_reference_with<__rref&&, const __val&>);
+
+ template <class>
+ friend class __gen_promise_base;
+
+public:
+ using yielded = __gen_yielded<_Ref, _Val>;
+
+ struct promise_type : __gen_promise_base<yielded> {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI generator get_return_object() noexcept {
+ return generator{coroutine_handle<promise_type>::from_promise(*this)};
+ }
+ };
+
+ _LIBCPP_HIDE_FROM_ABI generator(const generator&) = delete;
+ _LIBCPP_HIDE_FROM_ABI generator(generator&& __other) noexcept
+ : __coroutine_{std::exchange(__other.__coroutine_, {})} {}
+
+ _LIBCPP_HIDE_FROM_ABI ~generator() {
+ if (__coroutine_) {
+ __coroutine_.destroy();
+ }
+ }
+
+ _LIBCPP_HIDE_FROM_ABI generator& operator=(generator __other) noexcept {
+ std::swap(__coroutine_, __other.__coroutine_);
+ return *this;
+ }
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __gen_iter<_Ref, _Val> begin() {
+ auto __coroutine = std::coroutine_handle<__gen_promise_base<yielded>>::from_promise(__coroutine_.promise());
+ __coroutine.resume();
+ return __gen_iter<_Ref, _Val>{__coroutine};
+ }
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI default_sentinel_t end() const noexcept { return {}; }
+
+private:
+ _LIBCPP_HIDE_FROM_ABI explicit generator(coroutine_handle<promise_type> __coroutine) noexcept
+ : __coroutine_{__coroutine} {}
+
+ coroutine_handle<promise_type> __coroutine_ = nullptr;
+};
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+#endif
diff --git a/libcxx/test/std/ranges/coro.generator/generator.pass.cpp b/libcxx/test/std/ranges/coro.generator/generator.pass.cpp
new file mode 100644
index 00000000000000..c7e280f74b70a5
--- /dev/null
+++ b/libcxx/test/std/ranges/coro.generator/generator.pass.cpp
@@ -0,0 +1,40 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// std::generator
+
+#include <generator>
+
+#include <cassert>
+#include <ranges>
+#include <utility>
+#include <vector>
+
+std::generator<int> fib() {
+ int a = 0;
+ int b = 1;
+ while (true) {
+ co_yield std::exchange(a, std::exchange(b, a + b));
+ }
+}
+
+bool test() {
+ {
+ std::vector<int> expected_fib_vec = {0, 1, 1, 2, 3};
+ auto fib_vec = fib() | std::views::take(5) | std::ranges::to<std::vector<int>>();
+ assert(fib_vec == expected_fib_vec);
+ }
+ return true;
+}
+
+int main() {
+ test();
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/coro.generator/recursive.pass.cpp b/libcxx/test/std/ranges/coro.generator/recursive.pass.cpp
new file mode 100644
index 00000000000000..f02f5439a77a2d
--- /dev/null
+++ b/libcxx/test/std/ranges/coro.generator/recursive.pass.cpp
@@ -0,0 +1,92 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// std::generator
+
+#include <generator>
+
+#include <cassert>
+#include <ranges>
+#include <utility>
+#include <vector>
+
+std::generator<int> fib() {
+ int a = 0;
+ int b = 1;
+ while (true) {
+ co_yield std::exchange(a, std::exchange(b, a + b));
+ }
+}
+
+std::generator<int> recursive_fib(int depth) {
+ if (depth == 0) {
+ co_yield std::ranges::elements_of(fib());
+ } else {
+ co_yield std::ranges::elements_of(recursive_fib(depth - 1));
+ }
+};
+
+struct tree_node {
+ tree_node* left;
+ tree_node* right;
+ int element;
+
+ ~tree_node() {
+ delete left;
+ delete right;
+ }
+};
+
+tree_node* build_tree(int depth) {
+ if (depth == 0) {
+ return nullptr;
+ }
+
+ tree_node* root = new tree_node();
+ root->element = depth;
+ root->left = build_tree(depth - 1);
+ root->right = build_tree(depth - 1);
+ return root;
+}
+
+std::generator<int> traversal(tree_node* node) {
+ if (node == nullptr) {
+ co_return;
+ }
+ co_yield std::ranges::elements_of(traversal(node->left));
+ co_yield node->element;
+ co_yield std::ranges::elements_of(traversal(node->right));
+}
+
+bool test() {
+ {
+ std::vector<int> expected_fib_vec = {0, 1, 1, 2, 3};
+ {
+ auto fib_vec = recursive_fib(1) | std::views::take(5) | std::ranges::to<std::vector<int>>();
+ assert(fib_vec == expected_fib_vec);
+ }
+ {
+ auto fib_vec = recursive_fib(42) | std::views::take(5) | std::ranges::to<std::vector<int>>();
+ assert(fib_vec == expected_fib_vec);
+ }
+ }
+ {
+ tree_node* tree_root = build_tree(10);
+ auto node_vec = traversal(tree_root) | std::ranges::to<std::vector<int>>();
+ assert(node_vec.size() == 1023);
+ delete tree_root;
+ }
+ return true;
+}
+
+int main() {
+ test();
+ return 0;
+}
>From 652f44fdf37e1124200f66d590f0be75e55366e5 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Wed, 15 May 2024 12:23:53 -0400
Subject: [PATCH 12/38] [libc++] implement 'std::generator'
---
libcxx/include/generator | 20 ++++----
.../test/libcxx/transitive_includes/cxx03.csv | 9 ++++
.../test/libcxx/transitive_includes/cxx11.csv | 9 ++++
.../test/libcxx/transitive_includes/cxx14.csv | 9 ++++
.../test/libcxx/transitive_includes/cxx17.csv | 9 ++++
.../test/libcxx/transitive_includes/cxx20.csv | 9 ++++
.../test/libcxx/transitive_includes/cxx23.csv | 9 ++++
.../test/libcxx/transitive_includes/cxx26.csv | 9 ++++
.../coro.generator/generator.compile.pass.cpp | 49 +++++++++++++++++++
.../ranges/coro.generator/generator.pass.cpp | 22 +++++++--
.../ranges/coro.generator/recursive.pass.cpp | 7 ++-
11 files changed, 148 insertions(+), 13 deletions(-)
create mode 100644 libcxx/test/std/ranges/coro.generator/generator.compile.pass.cpp
diff --git a/libcxx/include/generator b/libcxx/include/generator
index 6542e4c02499dc..c7637d70a70d6e 100644
--- a/libcxx/include/generator
+++ b/libcxx/include/generator
@@ -206,11 +206,10 @@ private:
public:
_LIBCPP_HIDE_FROM_ABI __gen_promise_base() noexcept
- : __data_{.__root =
- {
- .__value_ptr = nullptr,
- .__active = coroutine_handle<__gen_promise_base>::from_promise(*this),
- }},
+ : __data_{.__root{
+ .__value_ptr{nullptr},
+ .__active{coroutine_handle<__gen_promise_base>::from_promise(*this)},
+ }},
__tag_{false} {}
_LIBCPP_HIDE_FROM_ABI ~__gen_promise_base() noexcept {
@@ -230,11 +229,12 @@ public:
return {};
}
- _LIBCPP_HIDE_FROM_ABI auto yield_value(const remove_reference_t<_Yielded>& __value)
+ _LIBCPP_HIDE_FROM_ABI auto yield_value(const remove_reference_t<_Yielded>& __value) noexcept(
+ is_nothrow_constructible_v<remove_cvref_t<_Yielded>, const remove_reference_t<_Yielded>&>)
requires is_rvalue_reference_v<_Yielded> &&
constructible_from<remove_cvref_t<_Yielded>, const remove_reference_t<_Yielded>&>
{
- return __element_awaiter{.__value = __value};
+ return __element_awaiter{.__value{__value}};
}
template <class _Ref2, class _Val2, class _Allocator2, class _Unused>
@@ -304,7 +304,9 @@ public:
_LIBCPP_HIDE_FROM_ABI void operator++(int) { ++*this; }
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool operator==(default_sentinel_t) const noexcept { return __coroutine_.done(); }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend bool operator==(const __gen_iter& __iter, default_sentinel_t) noexcept {
+ return __iter.__coroutine_.done();
+ }
private:
coroutine_handle<__gen_promise_base<__gen_yielded<_Ref, _Val>>> __coroutine_;
@@ -363,7 +365,7 @@ private:
_LIBCPP_HIDE_FROM_ABI explicit generator(coroutine_handle<promise_type> __coroutine) noexcept
: __coroutine_{__coroutine} {}
- coroutine_handle<promise_type> __coroutine_ = nullptr;
+ coroutine_handle<promise_type> __coroutine_;
};
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/test/libcxx/transitive_includes/cxx03.csv b/libcxx/test/libcxx/transitive_includes/cxx03.csv
index 92601fab5b7730..913eebb64f2697 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx03.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx03.csv
@@ -370,6 +370,15 @@ future thread
future type_traits
future typeinfo
future version
+generator compare
+generator cstddef
+generator cstdint
+generator cstdlib
+generator cstring
+generator initializer_list
+generator limits
+generator new
+generator typeinfo
initializer_list cstddef
iomanip istream
iomanip version
diff --git a/libcxx/test/libcxx/transitive_includes/cxx11.csv b/libcxx/test/libcxx/transitive_includes/cxx11.csv
index c05eb42deb9a1f..f205bdc232479e 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx11.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx11.csv
@@ -372,6 +372,15 @@ future thread
future type_traits
future typeinfo
future version
+generator compare
+generator cstddef
+generator cstdint
+generator cstdlib
+generator cstring
+generator initializer_list
+generator limits
+generator new
+generator typeinfo
initializer_list cstddef
iomanip istream
iomanip version
diff --git a/libcxx/test/libcxx/transitive_includes/cxx14.csv b/libcxx/test/libcxx/transitive_includes/cxx14.csv
index 09252b7b7d2dba..85237f65959d07 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx14.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx14.csv
@@ -375,6 +375,15 @@ future thread
future type_traits
future typeinfo
future version
+generator compare
+generator cstddef
+generator cstdint
+generator cstdlib
+generator cstring
+generator initializer_list
+generator limits
+generator new
+generator typeinfo
initializer_list cstddef
iomanip istream
iomanip version
diff --git a/libcxx/test/libcxx/transitive_includes/cxx17.csv b/libcxx/test/libcxx/transitive_includes/cxx17.csv
index 09252b7b7d2dba..85237f65959d07 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx17.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv
@@ -375,6 +375,15 @@ future thread
future type_traits
future typeinfo
future version
+generator compare
+generator cstddef
+generator cstdint
+generator cstdlib
+generator cstring
+generator initializer_list
+generator limits
+generator new
+generator typeinfo
initializer_list cstddef
iomanip istream
iomanip version
diff --git a/libcxx/test/libcxx/transitive_includes/cxx20.csv b/libcxx/test/libcxx/transitive_includes/cxx20.csv
index ce4ccc3d116153..505e1363d3f532 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx20.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv
@@ -386,6 +386,15 @@ future thread
future type_traits
future typeinfo
future version
+generator compare
+generator cstddef
+generator cstdint
+generator cstdlib
+generator cstring
+generator initializer_list
+generator limits
+generator new
+generator typeinfo
initializer_list cstddef
iomanip istream
iomanip version
diff --git a/libcxx/test/libcxx/transitive_includes/cxx23.csv b/libcxx/test/libcxx/transitive_includes/cxx23.csv
index 62d931c0eebade..5af8dc20b70eb9 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx23.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx23.csv
@@ -259,6 +259,15 @@ future string
future thread
future typeinfo
future version
+generator compare
+generator cstddef
+generator cstdint
+generator cstdlib
+generator cstring
+generator initializer_list
+generator limits
+generator new
+generator typeinfo
initializer_list cstddef
iomanip istream
iomanip version
diff --git a/libcxx/test/libcxx/transitive_includes/cxx26.csv b/libcxx/test/libcxx/transitive_includes/cxx26.csv
index f68249aeec78c9..103e9487ec0c2c 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx26.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv
@@ -282,6 +282,15 @@ future string
future thread
future typeinfo
future version
+generator compare
+generator cstddef
+generator cstdint
+generator cstdlib
+generator cstring
+generator initializer_list
+generator limits
+generator new
+generator typeinfo
initializer_list cstddef
iomanip istream
iomanip version
diff --git a/libcxx/test/std/ranges/coro.generator/generator.compile.pass.cpp b/libcxx/test/std/ranges/coro.generator/generator.compile.pass.cpp
new file mode 100644
index 00000000000000..e1725b87e8cd24
--- /dev/null
+++ b/libcxx/test/std/ranges/coro.generator/generator.compile.pass.cpp
@@ -0,0 +1,49 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// <generator>
+
+// template<class Ref, class V = void, class Allocator = void>
+// class generator;
+
+#include <generator>
+
+#include <cassert>
+#include <concepts>
+#include <ranges>
+#include <type_traits>
+
+template <class G, class V, class R, class RR>
+constexpr bool conformance() {
+ static_assert(std::ranges::range<G>);
+ static_assert(std::ranges::view<G>);
+ static_assert(std::ranges::input_range<G>);
+ static_assert(!std::ranges::forward_range<G>);
+ static_assert(!std::ranges::borrowed_range<G>);
+
+ static_assert(std::same_as<std::ranges::range_value_t<G>, V>);
+ static_assert(std::same_as<std::ranges::range_reference_t<G>, R>);
+ static_assert(std::same_as<std::ranges::range_rvalue_reference_t<G>, RR>);
+
+ return true;
+}
+
+static_assert(conformance<std::generator<int>, int, int&&, int&&>());
+static_assert(conformance<std::generator<int, int>, int, int, int>());
+
+static_assert(conformance<std::generator<int&>, int, int&, int&&>());
+static_assert(conformance<std::generator<int&, int>, int, int&, int&&>());
+static_assert(conformance<std::generator<const int&>, int, const int&, const int&&>());
+static_assert(conformance<std::generator<const int&, int>, int, const int&, const int&&>());
+
+static_assert(conformance<std::generator<int&&>, int, int&&, int&&>());
+static_assert(conformance<std::generator<int&&, int>, int, int&&, int&&>());
+static_assert(conformance<std::generator<const int&&>, int, const int&&, const int&&>());
+static_assert(conformance<std::generator<const int&&, int>, int, const int&&, const int&&>());
diff --git a/libcxx/test/std/ranges/coro.generator/generator.pass.cpp b/libcxx/test/std/ranges/coro.generator/generator.pass.cpp
index c7e280f74b70a5..e01d79618b56d3 100644
--- a/libcxx/test/std/ranges/coro.generator/generator.pass.cpp
+++ b/libcxx/test/std/ranges/coro.generator/generator.pass.cpp
@@ -8,7 +8,10 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
-// std::generator
+// <generator>
+
+// template<class Ref, class V = void, class Allocator = void>
+// class generator;
#include <generator>
@@ -25,11 +28,24 @@ std::generator<int> fib() {
}
}
+std::generator<const int&> range_fib() {
+ co_yield std::ranges::elements_of(std::vector<int>{0, 1});
+ co_yield std::ranges::elements_of(std::vector<int>{1, 2});
+ co_yield std::ranges::elements_of(std::vector<int>{3, 5});
+ co_yield std::ranges::elements_of(std::vector<int>{5, 8});
+}
+
bool test() {
{
std::vector<int> expected_fib_vec = {0, 1, 1, 2, 3};
- auto fib_vec = fib() | std::views::take(5) | std::ranges::to<std::vector<int>>();
- assert(fib_vec == expected_fib_vec);
+ {
+ auto fib_vec = fib() | std::views::take(5) | std::ranges::to<std::vector<int>>();
+ assert(fib_vec == expected_fib_vec);
+ }
+ {
+ auto fib_vec = range_fib() | std::views::take(5) | std::ranges::to<std::vector<int>>();
+ assert(fib_vec == expected_fib_vec);
+ }
}
return true;
}
diff --git a/libcxx/test/std/ranges/coro.generator/recursive.pass.cpp b/libcxx/test/std/ranges/coro.generator/recursive.pass.cpp
index f02f5439a77a2d..51365eabec9009 100644
--- a/libcxx/test/std/ranges/coro.generator/recursive.pass.cpp
+++ b/libcxx/test/std/ranges/coro.generator/recursive.pass.cpp
@@ -8,11 +8,15 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
-// std::generator
+// <generator>
+
+// template<class Ref, class V = void, class Allocator = void>
+// class generator;
#include <generator>
#include <cassert>
+#include <numeric>
#include <ranges>
#include <utility>
#include <vector>
@@ -81,6 +85,7 @@ bool test() {
tree_node* tree_root = build_tree(10);
auto node_vec = traversal(tree_root) | std::ranges::to<std::vector<int>>();
assert(node_vec.size() == 1023);
+ assert(std::reduce(node_vec.cbegin(), node_vec.cend()) == 2036);
delete tree_root;
}
return true;
>From 9748a32b918fa1500822388a3f84acbb58aa211f Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Wed, 15 May 2024 12:53:18 -0400
Subject: [PATCH 13/38] [libc++] implement 'std::generator'
---
libcxx/include/__std_clang_module | 1 +
libcxx/include/generator | 22 ++++++++++++++++------
libcxx/include/module.modulemap | 4 ++++
libcxx/modules/std.compat.cppm.in | 3 ---
libcxx/modules/std.cppm.in | 4 +---
libcxx/modules/std/generator.inc | 3 ++-
libcxx/utils/libcxx/header_information.py | 1 -
7 files changed, 24 insertions(+), 14 deletions(-)
diff --git a/libcxx/include/__std_clang_module b/libcxx/include/__std_clang_module
index 18d6ce6b46c1f6..e18947350adc2c 100644
--- a/libcxx/include/__std_clang_module
+++ b/libcxx/include/__std_clang_module
@@ -104,6 +104,7 @@
#if !defined(_LIBCPP_HAS_NO_THREADS)
# include <future>
#endif
+#include <generator>
#include <initializer_list>
#include <inttypes.h>
#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
diff --git a/libcxx/include/generator b/libcxx/include/generator
index c7637d70a70d6e..ebdc264fcb071b 100644
--- a/libcxx/include/generator
+++ b/libcxx/include/generator
@@ -11,8 +11,10 @@
#define _LIBCPP_GENERATOR
#include <__assert>
+#include <__concepts/common_reference_with.h>
#include <__concepts/constructible.h>
#include <__concepts/convertible_to.h>
+#include <__concepts/same_as.h>
#include <__config>
#include <__coroutine/coroutine_handle.h>
#include <__coroutine/coroutine_traits.h>
@@ -23,6 +25,7 @@
#include <__memory/addressof.h>
#include <__memory/allocator_arg_t.h>
#include <__memory/allocator_traits.h>
+#include <__ranges/access.h>
#include <__ranges/concepts.h>
#include <__ranges/elements_of.h>
#include <__ranges/view_interface.h>
@@ -34,9 +37,18 @@
#include <__type_traits/is_reference.h>
#include <__type_traits/is_void.h>
#include <__type_traits/remove_cvref.h>
+#include <__type_traits/remove_reference.h>
#include <__utility/exchange.h>
+#include <__utility/move.h>
#include <__utility/swap.h>
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
#if _LIBCPP_STD_VER >= 23
_LIBCPP_BEGIN_NAMESPACE_STD
@@ -86,7 +98,7 @@ private:
__root_data __root;
__recursive_data __recursive;
- ~__union() noexcept {}
+ _LIBCPP_HIDE_FROM_ABI ~__union() noexcept {}
} __data_;
// The `__tag_` stores the active member of the `__data_` union:
@@ -370,10 +382,8 @@ private:
_LIBCPP_END_NAMESPACE_STD
-#endif
+#endif // _LIBCPP_STD_VER >= 23
-#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
-# pragma GCC system_header
-#endif
+_LIBCPP_POP_MACROS
-#endif
+#endif // _LIBCPP_GENERATOR
diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index 6bc9403db2b59f..a46d283e6d2735 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -99,6 +99,10 @@ module std_future [system] {
header "future"
export *
}
+module std_generator [system] {
+ header "generator"
+ export *
+}
module std_initializer_list [system] {
header "initializer_list"
export *
diff --git a/libcxx/modules/std.compat.cppm.in b/libcxx/modules/std.compat.cppm.in
index b44dbab25c74b4..b1ce8fa37820fe 100644
--- a/libcxx/modules/std.compat.cppm.in
+++ b/libcxx/modules/std.compat.cppm.in
@@ -63,9 +63,6 @@ module;
# if __has_include(<flat_set>)
# error "please update the header information for <flat_set> in headers_not_available in utils/libcxx/header_information.py"
# endif // __has_include(<flat_set>)
-# if __has_include(<generator>)
-# error "please update the header information for <generator> in headers_not_available in utils/libcxx/header_information.py"
-# endif // __has_include(<generator>)
# if __has_include(<hazard_pointer>)
# error "please update the header information for <hazard_pointer> in headers_not_available in utils/libcxx/header_information.py"
# endif // __has_include(<hazard_pointer>)
diff --git a/libcxx/modules/std.cppm.in b/libcxx/modules/std.cppm.in
index b8d89130aae989..0111c739d0cda7 100644
--- a/libcxx/modules/std.cppm.in
+++ b/libcxx/modules/std.cppm.in
@@ -79,6 +79,7 @@ module;
#if !defined(_LIBCPP_HAS_NO_THREADS)
# include <future>
#endif
+#include <generator>
#include <initializer_list>
#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
# include <iomanip>
@@ -185,9 +186,6 @@ module;
# if __has_include(<flat_set>)
# error "please update the header information for <flat_set> in headers_not_available in utils/libcxx/header_information.py"
# endif // __has_include(<flat_set>)
-# if __has_include(<generator>)
-# error "please update the header information for <generator> in headers_not_available in utils/libcxx/header_information.py"
-# endif // __has_include(<generator>)
# if __has_include(<hazard_pointer>)
# error "please update the header information for <hazard_pointer> in headers_not_available in utils/libcxx/header_information.py"
# endif // __has_include(<hazard_pointer>)
diff --git a/libcxx/modules/std/generator.inc b/libcxx/modules/std/generator.inc
index 43fb0daf5c6593..f7102b138b078e 100644
--- a/libcxx/modules/std/generator.inc
+++ b/libcxx/modules/std/generator.inc
@@ -8,7 +8,8 @@
//===----------------------------------------------------------------------===//
export namespace std {
-#if 0
+#if _LIBCPP_STD_VER >= 23
+ // [coro.generator], class template generator
using std::generator;
#endif
} // namespace std
diff --git a/libcxx/utils/libcxx/header_information.py b/libcxx/utils/libcxx/header_information.py
index e2165d6ab80b01..bdfe17f5c9a03e 100644
--- a/libcxx/utils/libcxx/header_information.py
+++ b/libcxx/utils/libcxx/header_information.py
@@ -141,7 +141,6 @@
"debugging",
"flat_map",
"flat_set",
- "generator",
"hazard_pointer",
"linalg",
"rcu",
>From 457f78cebe47bb3d32f499369fa571371e30f40b Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Thu, 16 May 2024 00:14:11 -0400
Subject: [PATCH 14/38] [libc++] implement 'std::generator'
---
libcxx/include/generator | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/libcxx/include/generator b/libcxx/include/generator
index ebdc264fcb071b..c61e43fd7ff321 100644
--- a/libcxx/include/generator
+++ b/libcxx/include/generator
@@ -173,18 +173,16 @@ private:
template <class _Ref, class _Val, class _Allocator>
struct __recursive_awaiter {
- generator<_Ref, _Val, _Allocator> __gen;
-
_LIBCPP_HIDE_FROM_ABI explicit __recursive_awaiter(generator<_Ref, _Val, _Allocator>&& __gen) noexcept
- : __gen{std::move(__gen)} {}
+ : __gen_{std::move(__gen)} {}
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool await_ready() noexcept { return !__gen.__coroutine_; }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool await_ready() noexcept { return !__gen_.__coroutine_; }
template <class _Promise>
_LIBCPP_HIDE_FROM_ABI coroutine_handle<__gen_promise_base>
await_suspend(coroutine_handle<_Promise> __current) noexcept {
// Stores a `__recursive_data` in the promise object associated with `__gen`
- auto __recursive = coroutine_handle<__gen_promise_base>::from_address(__gen.__coroutine_.address());
+ auto __recursive = coroutine_handle<__gen_promise_base>::from_address(__gen_.__coroutine_.address());
__recursive.promise().__set_recursive_tag();
auto&& __recursive_data = __recursive.promise().__get_recursive_data();
@@ -208,12 +206,15 @@ private:
}
_LIBCPP_HIDE_FROM_ABI void await_resume() {
- auto __recursive = coroutine_handle<__gen_promise_base>::from_address(__gen.__coroutine_.address());
+ auto __recursive = coroutine_handle<__gen_promise_base>::from_address(__gen_.__coroutine_.address());
auto&& __recursive_data = __recursive.promise().__get_recursive_data();
if (__recursive_data.__exception) {
std::rethrow_exception(std::move(__recursive_data.__exception));
}
}
+
+ private:
+ generator<_Ref, _Val, _Allocator> __gen_;
};
public:
@@ -275,11 +276,13 @@ public:
_LIBCPP_HIDE_FROM_ABI void return_void() const noexcept {}
_LIBCPP_HIDE_FROM_ABI void unhandled_exception() {
+# ifndef _LIBCPP_HAS_NO_EXCEPTIONS
if (__is_root()) {
throw;
} else {
__get_recursive_data().__exception = std::current_exception();
}
+# endif
}
};
>From c72c94dfa5894fab046126a1a59e4d03681b72ce Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Fri, 17 May 2024 22:48:14 -0400
Subject: [PATCH 15/38] [libc++] implement 'std::generator'
---
libcxx/include/generator | 204 +++++++++++++++++-
.../ranges/coro.generator/allocator.pass.cpp | 123 +++++++++++
2 files changed, 326 insertions(+), 1 deletion(-)
create mode 100644 libcxx/test/std/ranges/coro.generator/allocator.pass.cpp
diff --git a/libcxx/include/generator b/libcxx/include/generator
index c61e43fd7ff321..1931a4c9bdf856 100644
--- a/libcxx/include/generator
+++ b/libcxx/include/generator
@@ -10,6 +10,22 @@
#ifndef _LIBCPP_GENERATOR
#define _LIBCPP_GENERATOR
+/*
+
+namespace std {
+ // [coro.generator.class], class template generator
+ template<class Ref, class V = void, class Allocator = void>
+ class generator;
+
+ namespace pmr {
+ template<class R, class V = void>
+ using generator = std::generator<R, V, polymorphic_allocator<>>;
+ }
+}
+
+*/
+
+#include <__algorithm/max.h>
#include <__assert>
#include <__concepts/common_reference_with.h>
#include <__concepts/constructible.h>
@@ -25,6 +41,8 @@
#include <__memory/addressof.h>
#include <__memory/allocator_arg_t.h>
#include <__memory/allocator_traits.h>
+#include <__memory/construct_at.h>
+#include <__memory_resource/polymorphic_allocator.h>
#include <__ranges/access.h>
#include <__ranges/concepts.h>
#include <__ranges/elements_of.h>
@@ -286,6 +304,183 @@ public:
}
};
+struct alignas(__STDCPP_DEFAULT_NEW_ALIGNMENT__) __gen_aligned_block {
+ char __data[__STDCPP_DEFAULT_NEW_ALIGNMENT__];
+
+ _LIBCPP_HIDE_FROM_ABI static size_t __count(const size_t __size) noexcept {
+ return (__size + sizeof(__gen_aligned_block) - 1) / sizeof(__gen_aligned_block);
+ };
+};
+
+template <class _Allocator>
+concept __gen_stateless_allocator =
+ default_initializable<_Allocator> && allocator_traits<_Allocator>::is_always_equal::value;
+
+template <class _Allocator>
+class __gen_promise_allocator {
+private:
+ using __rebind = allocator_traits<_Allocator>::template rebind_alloc<__gen_aligned_block>;
+ using __rebind_size_type = allocator_traits<__rebind>::size_type;
+
+ using __rebind_pointer = allocator_traits<__rebind>::pointer;
+ static_assert(is_pointer_v<__rebind_pointer>);
+
+ _LIBCPP_HIDE_FROM_ABI static void* __allocate(__rebind __al, const size_t __size) {
+ if constexpr (__gen_stateless_allocator<__rebind>) {
+ const size_t __block_count = __gen_aligned_block::__count(__size);
+ return __al.allocate(static_cast<__rebind_size_type>(__block_count));
+ } else {
+ // Allocates enough blocks for the coroutine frame, the size of the stateful allocator, and the alignment of the
+ // stateful allocator
+ const size_t __block_count = __gen_aligned_block::__count(__size + sizeof(__rebind) + alignof(__rebind));
+ void* const __ptr = __al.allocate(static_cast<__rebind_size_type>(__block_count));
+
+ // Stores the stateful allocator in the allocated block
+ __rebind* const __al_ptr = reinterpret_cast<__rebind*>(
+ (reinterpret_cast<uintptr_t>(__ptr) + __size + alignof(__rebind) - 1) & ~(alignof(__rebind) - 1));
+ std::construct_at(__al_ptr, std::move(__al));
+ return __ptr;
+ }
+ }
+
+public:
+ _LIBCPP_HIDE_FROM_ABI void* operator new(size_t __size)
+ requires default_initializable<_Allocator>
+ {
+ return __allocate({}, __size);
+ }
+
+ template <class _Allocator2, class... _Args>
+ requires convertible_to<const _Allocator2&, _Allocator>
+ _LIBCPP_HIDE_FROM_ABI void*
+ operator new(const size_t __size, allocator_arg_t, const _Allocator2& __alloc, const _Args&...) {
+ return __allocate(static_cast<__rebind>(static_cast<_Allocator>(__alloc)), __size);
+ }
+
+ template <class _This, class _Allocator2, class... _Args>
+ requires convertible_to<const _Allocator2&, _Allocator>
+ _LIBCPP_HIDE_FROM_ABI void*
+ operator new(const size_t __size, const _This&, allocator_arg_t, const _Allocator2& __alloc, const _Args&...) {
+ return __allocate(static_cast<__rebind>(static_cast<_Allocator>(__alloc)), __size);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI static void operator delete(void* const __ptr, const size_t __size) noexcept {
+ if constexpr (__gen_stateless_allocator<__rebind>) {
+ __rebind __al;
+ const size_t __block_count = __gen_aligned_block::__count(__size);
+ __al.deallocate(static_cast<__gen_aligned_block*>(__ptr), static_cast<__rebind_size_type>(__block_count));
+ } else {
+ // Retrieves the stateful allocator stored in the allocated block
+ __rebind* const __al_ptr = reinterpret_cast<__rebind*>(
+ (reinterpret_cast<uintptr_t>(__ptr) + __size + alignof(__rebind) - 1) & ~(alignof(__rebind) - 1));
+ __rebind __al = std::move(*__al_ptr);
+ std::destroy_at(__al_ptr);
+
+ const size_t __block_count = __gen_aligned_block::__count(__size + sizeof(__rebind) + alignof(__rebind));
+ __al.deallocate(static_cast<__gen_aligned_block*>(__ptr), static_cast<__rebind_size_type>(__block_count));
+ }
+ }
+};
+
+template <>
+class __gen_promise_allocator<void> {
+private:
+ using __deallocate_fn = void (*)(void*, size_t) noexcept;
+
+ template <class _Rebind>
+ _LIBCPP_HIDE_FROM_ABI static void __deallocate(void* const __ptr, const size_t __size) noexcept {
+ using __rebind_size_type = allocator_traits<_Rebind>::size_type;
+
+ if constexpr (__gen_stateless_allocator<_Rebind>) {
+ _Rebind __al;
+ const size_t __block_count = __gen_aligned_block::__count(__size + sizeof(__deallocate_fn));
+ __al.deallocate(static_cast<__gen_aligned_block*>(__ptr), static_cast<__rebind_size_type>(__block_count));
+ } else {
+ // Retrieves the stateful allocator stored in the allocated block
+ _Rebind* const __al_ptr = reinterpret_cast<_Rebind*>(
+ (reinterpret_cast<uintptr_t>(__ptr) + __size + sizeof(__deallocate_fn) + alignof(_Rebind) - 1) &
+ ~(alignof(_Rebind) - 1));
+ _Rebind __al = std::move(*__al_ptr);
+ std::destroy_at(__al_ptr);
+
+ const size_t __block_count =
+ __gen_aligned_block::__count(__size + sizeof(__deallocate_fn) + sizeof(_Rebind) + alignof(_Rebind));
+ __al.deallocate(static_cast<__gen_aligned_block*>(__ptr), static_cast<__rebind_size_type>(__block_count));
+ }
+ }
+
+ template <class _Allocator>
+ _LIBCPP_HIDE_FROM_ABI static void* __allocate(const _Allocator& __al, const size_t __size) {
+ using __rebind = allocator_traits<_Allocator>::template rebind_alloc<__gen_aligned_block>;
+ using __rebind_size_type = allocator_traits<__rebind>::size_type;
+
+ using __rebind_pointer = allocator_traits<__rebind>::pointer;
+ static_assert(is_pointer_v<__rebind_pointer>);
+
+ __rebind __rebind_al = static_cast<__rebind>(__al);
+ if constexpr (__gen_stateless_allocator<__rebind>) {
+ const size_t __block_count = __gen_aligned_block::__count(__size + sizeof(__deallocate_fn));
+ void* const __ptr = __rebind_al.allocate(static_cast<__rebind_size_type>(__block_count));
+
+ // Stores the deallocation function in the allocated block
+ __deallocate_fn* const __dealloc_ptr =
+ reinterpret_cast<__deallocate_fn*>(reinterpret_cast<uintptr_t>(__ptr) + __size);
+ *__dealloc_ptr = __deallocate<__rebind>;
+ return __ptr;
+ } else {
+ // Allocates enough blocks for the coroutine frame, the size of the stateful allocator, the alignment of the
+ // stateful allocator, and the deallocation function
+ const size_t __block_count =
+ __gen_aligned_block::__count(__size + sizeof(__deallocate_fn) + sizeof(__rebind) + alignof(__rebind));
+ void* const __ptr = __rebind_al.allocate(static_cast<__rebind_size_type>(__block_count));
+
+ // Stores the deallocation function in the allocated block
+ __deallocate_fn* const __dealloc_ptr =
+ reinterpret_cast<__deallocate_fn*>(reinterpret_cast<uintptr_t>(__ptr) + __size);
+ *__dealloc_ptr = __deallocate<__rebind>;
+
+ // Stores the stateful allocator in the allocated block
+ __rebind* const __al_ptr = reinterpret_cast<__rebind*>(
+ (reinterpret_cast<uintptr_t>(__ptr) + sizeof(__deallocate_fn) + __size + alignof(__rebind) - 1) &
+ ~(alignof(__rebind) - 1));
+ std::construct_at(__al_ptr, std::move(__rebind_al));
+ return __ptr;
+ }
+ }
+
+public:
+ _LIBCPP_HIDE_FROM_ABI void* operator new(const size_t __size) {
+ void* const __ptr = ::operator new(__size + sizeof(__deallocate_fn));
+ __deallocate_fn __dealloc = [](void* const __ptr, const size_t __size) static noexcept -> void {
+ ::operator delete(__ptr, __size + sizeof(__deallocate_fn));
+ };
+
+ __deallocate_fn* const __dealloc_ptr =
+ reinterpret_cast<__deallocate_fn*>(reinterpret_cast<uintptr_t>(__ptr) + __size);
+ *__dealloc_ptr = __dealloc;
+ return __ptr;
+ }
+
+ template <class _Allocator, class... _Args>
+ _LIBCPP_HIDE_FROM_ABI void*
+ operator new(const size_t __size, allocator_arg_t, const _Allocator& __alloc, const _Args&...) {
+ return __allocate(__alloc, __size);
+ }
+
+ template <class _This, class _Allocator, class... _Args>
+ _LIBCPP_HIDE_FROM_ABI void*
+ operator new(const size_t __size, const _This&, allocator_arg_t, const _Allocator& __alloc, const _Args&...) {
+ return __allocate(__alloc, __size);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI static void operator delete(void* const __ptr, const size_t __size) noexcept {
+ __deallocate_fn* const __dealloc_ptr =
+ reinterpret_cast<__deallocate_fn*>(reinterpret_cast<uintptr_t>(__ptr) + __size);
+ const __deallocate_fn __dealloc = *__dealloc_ptr;
+ __dealloc(__ptr, __size);
+ }
+};
+
template <class _Ref, class _Val>
class __gen_iter {
private:
@@ -347,7 +542,7 @@ private:
public:
using yielded = __gen_yielded<_Ref, _Val>;
- struct promise_type : __gen_promise_base<yielded> {
+ struct promise_type : __gen_promise_base<yielded>, __gen_promise_allocator<_Allocator> {
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI generator get_return_object() noexcept {
return generator{coroutine_handle<promise_type>::from_promise(*this)};
}
@@ -383,6 +578,13 @@ private:
coroutine_handle<promise_type> __coroutine_;
};
+namespace pmr {
+
+template <class _Ref, class _Val = void>
+using generator = std::generator<_Ref, _Val, polymorphic_allocator<>>;
+
+} // namespace pmr
+
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP_STD_VER >= 23
diff --git a/libcxx/test/std/ranges/coro.generator/allocator.pass.cpp b/libcxx/test/std/ranges/coro.generator/allocator.pass.cpp
new file mode 100644
index 00000000000000..56f60f60f6dfe8
--- /dev/null
+++ b/libcxx/test/std/ranges/coro.generator/allocator.pass.cpp
@@ -0,0 +1,123 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// <generator>
+
+// template<class Ref, class V = void, class Allocator = void>
+// class generator;
+
+#include <generator>
+
+#include <cassert>
+#include <cstddef>
+#include <memory>
+#include <memory_resource>
+#include <ranges>
+#include <utility>
+#include <vector>
+
+template <class T>
+class stateless_allocator {
+public:
+ using value_type = T;
+
+ stateless_allocator() noexcept = default;
+
+ template <typename U>
+ constexpr stateless_allocator(const stateless_allocator<U>&) noexcept {}
+
+ [[nodiscard]] T* allocate(size_t n) { return static_cast<T*>(::operator new(n * sizeof(T))); }
+
+ void deallocate(void* p, size_t) noexcept { ::operator delete(p); }
+
+ template <class U>
+ constexpr bool operator==(const stateless_allocator<U>&) const noexcept {
+ return true;
+ }
+};
+
+template <class T>
+class stateful_allocator {
+public:
+ using value_type = T;
+
+ stateful_allocator() noexcept = default;
+
+ template <typename U>
+ constexpr stateful_allocator(const stateful_allocator<U>&) noexcept {}
+
+ [[nodiscard]] T* allocate(size_t n) { return static_cast<T*>(::operator new(n * sizeof(T))); }
+
+ void deallocate(void* p, size_t) noexcept { ::operator delete(p); }
+
+ template <class U>
+ constexpr bool operator==(const stateful_allocator<U>& other) const noexcept {
+ return state_ == other.state_;
+ }
+
+private:
+ int state_ = 0;
+};
+
+template <class Allocator>
+bool test_with_allocator() {
+ std::vector<int> expected_fib_vec = {0, 1, 1, 2, 3};
+ {
+ auto fib = []() -> std::generator<int, int, Allocator> {
+ int a = 0;
+ int b = 1;
+ while (true) {
+ co_yield std::exchange(a, std::exchange(b, a + b));
+ }
+ };
+ assert((fib() | std::views::take(5) | std::ranges::to<std::vector>()) == expected_fib_vec);
+ }
+
+ {
+ auto fib = [](std::allocator_arg_t, Allocator) -> std::generator<int, int, Allocator> {
+ int a = 0;
+ int b = 1;
+ while (true) {
+ co_yield std::exchange(a, std::exchange(b, a + b));
+ }
+ };
+ assert((fib(std::allocator_arg, {}) | std::views::take(5) | std::ranges::to<std::vector>()) == expected_fib_vec);
+ }
+
+ {
+ auto fib = [](std::allocator_arg_t, Allocator) -> std::generator<int> {
+ int a = 0;
+ int b = 1;
+ while (true) {
+ co_yield std::exchange(a, std::exchange(b, a + b));
+ }
+ };
+ assert((fib(std::allocator_arg, {}) | std::views::take(5) | std::ranges::to<std::vector>()) == expected_fib_vec);
+ }
+ return true;
+}
+
+bool test() {
+ test_with_allocator<std::allocator<std::byte>>();
+ test_with_allocator<stateless_allocator<std::byte>>();
+ test_with_allocator<stateful_allocator<std::byte>>();
+ test_with_allocator<std::pmr::polymorphic_allocator<std::byte>>();
+
+ test_with_allocator<std::allocator<float>>();
+ test_with_allocator<stateless_allocator<float>>();
+ test_with_allocator<stateful_allocator<float>>();
+ test_with_allocator<std::pmr::polymorphic_allocator<float>>();
+ return true;
+};
+
+int main() {
+ test();
+ return 0;
+}
>From cba0548fde3828de252106f75dd6f1018f30ce90 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Fri, 17 May 2024 22:59:21 -0400
Subject: [PATCH 16/38] [libc++] implement 'std::generator'
---
libcxx/include/generator | 3 +++
libcxx/modules/std/generator.inc | 4 ++++
2 files changed, 7 insertions(+)
diff --git a/libcxx/include/generator b/libcxx/include/generator
index 1931a4c9bdf856..6e1253d9b2e25c 100644
--- a/libcxx/include/generator
+++ b/libcxx/include/generator
@@ -52,6 +52,7 @@ namespace std {
#include <__type_traits/conditional.h>
#include <__type_traits/is_nothrow_constructible.h>
#include <__type_traits/is_object.h>
+#include <__type_traits/is_pointer.h>
#include <__type_traits/is_reference.h>
#include <__type_traits/is_void.h>
#include <__type_traits/remove_cvref.h>
@@ -59,6 +60,8 @@ namespace std {
#include <__utility/exchange.h>
#include <__utility/move.h>
#include <__utility/swap.h>
+#include <cstdint>
+#include <new>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
diff --git a/libcxx/modules/std/generator.inc b/libcxx/modules/std/generator.inc
index f7102b138b078e..8681f4b26dc467 100644
--- a/libcxx/modules/std/generator.inc
+++ b/libcxx/modules/std/generator.inc
@@ -11,5 +11,9 @@ export namespace std {
#if _LIBCPP_STD_VER >= 23
// [coro.generator], class template generator
using std::generator;
+
+ namespace pmr {
+ using std::pmr::generator;
+ }
#endif
} // namespace std
>From 66280fbaee5501ca779e4f6a0e9c6995b33cafe7 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Fri, 17 May 2024 23:49:29 -0400
Subject: [PATCH 17/38] [libc++] implement 'std::generator'
---
libcxx/include/generator | 66 +++++++++----------
.../test/libcxx/transitive_includes/cxx03.csv | 1 +
.../test/libcxx/transitive_includes/cxx11.csv | 1 +
.../test/libcxx/transitive_includes/cxx14.csv | 1 +
.../test/libcxx/transitive_includes/cxx17.csv | 1 +
.../test/libcxx/transitive_includes/cxx20.csv | 1 +
.../test/libcxx/transitive_includes/cxx23.csv | 1 +
.../test/libcxx/transitive_includes/cxx26.csv | 1 +
8 files changed, 40 insertions(+), 33 deletions(-)
diff --git a/libcxx/include/generator b/libcxx/include/generator
index 6e1253d9b2e25c..601998a90b8877 100644
--- a/libcxx/include/generator
+++ b/libcxx/include/generator
@@ -328,7 +328,7 @@ private:
using __rebind_pointer = allocator_traits<__rebind>::pointer;
static_assert(is_pointer_v<__rebind_pointer>);
- _LIBCPP_HIDE_FROM_ABI static void* __allocate(__rebind __al, const size_t __size) {
+ _LIBCPP_HIDE_FROM_ABI static void* __alloc(__rebind __al, const size_t __size) {
if constexpr (__gen_stateless_allocator<__rebind>) {
const size_t __block_count = __gen_aligned_block::__count(__size);
return __al.allocate(static_cast<__rebind_size_type>(__block_count));
@@ -350,21 +350,21 @@ public:
_LIBCPP_HIDE_FROM_ABI void* operator new(size_t __size)
requires default_initializable<_Allocator>
{
- return __allocate({}, __size);
+ return __alloc({}, __size);
}
template <class _Allocator2, class... _Args>
requires convertible_to<const _Allocator2&, _Allocator>
_LIBCPP_HIDE_FROM_ABI void*
- operator new(const size_t __size, allocator_arg_t, const _Allocator2& __alloc, const _Args&...) {
- return __allocate(static_cast<__rebind>(static_cast<_Allocator>(__alloc)), __size);
+ operator new(const size_t __size, allocator_arg_t, const _Allocator2& __al, const _Args&...) {
+ return __alloc(static_cast<__rebind>(static_cast<_Allocator>(__al)), __size);
}
template <class _This, class _Allocator2, class... _Args>
requires convertible_to<const _Allocator2&, _Allocator>
_LIBCPP_HIDE_FROM_ABI void*
- operator new(const size_t __size, const _This&, allocator_arg_t, const _Allocator2& __alloc, const _Args&...) {
- return __allocate(static_cast<__rebind>(static_cast<_Allocator>(__alloc)), __size);
+ operator new(const size_t __size, const _This&, allocator_arg_t, const _Allocator2& __al, const _Args&...) {
+ return __alloc(static_cast<__rebind>(static_cast<_Allocator>(__al)), __size);
}
_LIBCPP_HIDE_FROM_ABI static void operator delete(void* const __ptr, const size_t __size) noexcept {
@@ -388,32 +388,32 @@ public:
template <>
class __gen_promise_allocator<void> {
private:
- using __deallocate_fn = void (*)(void*, size_t) noexcept;
+ using __dealloc_fn = void (*)(void*, size_t) noexcept;
template <class _Rebind>
- _LIBCPP_HIDE_FROM_ABI static void __deallocate(void* const __ptr, const size_t __size) noexcept {
+ _LIBCPP_HIDE_FROM_ABI static void __dealloc(void* const __ptr, const size_t __size) noexcept {
using __rebind_size_type = allocator_traits<_Rebind>::size_type;
if constexpr (__gen_stateless_allocator<_Rebind>) {
_Rebind __al;
- const size_t __block_count = __gen_aligned_block::__count(__size + sizeof(__deallocate_fn));
+ const size_t __block_count = __gen_aligned_block::__count(__size + sizeof(__dealloc_fn));
__al.deallocate(static_cast<__gen_aligned_block*>(__ptr), static_cast<__rebind_size_type>(__block_count));
} else {
// Retrieves the stateful allocator stored in the allocated block
_Rebind* const __al_ptr = reinterpret_cast<_Rebind*>(
- (reinterpret_cast<uintptr_t>(__ptr) + __size + sizeof(__deallocate_fn) + alignof(_Rebind) - 1) &
+ (reinterpret_cast<uintptr_t>(__ptr) + __size + sizeof(__dealloc_fn) + alignof(_Rebind) - 1) &
~(alignof(_Rebind) - 1));
_Rebind __al = std::move(*__al_ptr);
std::destroy_at(__al_ptr);
const size_t __block_count =
- __gen_aligned_block::__count(__size + sizeof(__deallocate_fn) + sizeof(_Rebind) + alignof(_Rebind));
+ __gen_aligned_block::__count(__size + sizeof(__dealloc_fn) + sizeof(_Rebind) + alignof(_Rebind));
__al.deallocate(static_cast<__gen_aligned_block*>(__ptr), static_cast<__rebind_size_type>(__block_count));
}
}
template <class _Allocator>
- _LIBCPP_HIDE_FROM_ABI static void* __allocate(const _Allocator& __al, const size_t __size) {
+ _LIBCPP_HIDE_FROM_ABI static void* __alloc(const _Allocator& __al, const size_t __size) {
using __rebind = allocator_traits<_Allocator>::template rebind_alloc<__gen_aligned_block>;
using __rebind_size_type = allocator_traits<__rebind>::size_type;
@@ -422,29 +422,29 @@ private:
__rebind __rebind_al = static_cast<__rebind>(__al);
if constexpr (__gen_stateless_allocator<__rebind>) {
- const size_t __block_count = __gen_aligned_block::__count(__size + sizeof(__deallocate_fn));
+ const size_t __block_count = __gen_aligned_block::__count(__size + sizeof(__dealloc_fn));
void* const __ptr = __rebind_al.allocate(static_cast<__rebind_size_type>(__block_count));
// Stores the deallocation function in the allocated block
- __deallocate_fn* const __dealloc_ptr =
- reinterpret_cast<__deallocate_fn*>(reinterpret_cast<uintptr_t>(__ptr) + __size);
- *__dealloc_ptr = __deallocate<__rebind>;
+ __dealloc_fn* const __dealloc_ptr =
+ reinterpret_cast<__dealloc_fn*>(reinterpret_cast<uintptr_t>(__ptr) + __size);
+ *__dealloc_ptr = __dealloc<__rebind>;
return __ptr;
} else {
// Allocates enough blocks for the coroutine frame, the size of the stateful allocator, the alignment of the
// stateful allocator, and the deallocation function
const size_t __block_count =
- __gen_aligned_block::__count(__size + sizeof(__deallocate_fn) + sizeof(__rebind) + alignof(__rebind));
+ __gen_aligned_block::__count(__size + sizeof(__dealloc_fn) + sizeof(__rebind) + alignof(__rebind));
void* const __ptr = __rebind_al.allocate(static_cast<__rebind_size_type>(__block_count));
// Stores the deallocation function in the allocated block
- __deallocate_fn* const __dealloc_ptr =
- reinterpret_cast<__deallocate_fn*>(reinterpret_cast<uintptr_t>(__ptr) + __size);
- *__dealloc_ptr = __deallocate<__rebind>;
+ __dealloc_fn* const __dealloc_ptr =
+ reinterpret_cast<__dealloc_fn*>(reinterpret_cast<uintptr_t>(__ptr) + __size);
+ *__dealloc_ptr = __dealloc<__rebind>;
// Stores the stateful allocator in the allocated block
__rebind* const __al_ptr = reinterpret_cast<__rebind*>(
- (reinterpret_cast<uintptr_t>(__ptr) + sizeof(__deallocate_fn) + __size + alignof(__rebind) - 1) &
+ (reinterpret_cast<uintptr_t>(__ptr) + sizeof(__dealloc_fn) + __size + alignof(__rebind) - 1) &
~(alignof(__rebind) - 1));
std::construct_at(__al_ptr, std::move(__rebind_al));
return __ptr;
@@ -453,33 +453,33 @@ private:
public:
_LIBCPP_HIDE_FROM_ABI void* operator new(const size_t __size) {
- void* const __ptr = ::operator new(__size + sizeof(__deallocate_fn));
- __deallocate_fn __dealloc = [](void* const __ptr, const size_t __size) static noexcept -> void {
- ::operator delete(__ptr, __size + sizeof(__deallocate_fn));
+ void* const __ptr = ::operator new(__size + sizeof(__dealloc_fn));
+ __dealloc_fn __dealloc = [](void* const __ptr, const size_t __size) static noexcept -> void {
+ ::operator delete(__ptr, __size + sizeof(__dealloc_fn));
};
- __deallocate_fn* const __dealloc_ptr =
- reinterpret_cast<__deallocate_fn*>(reinterpret_cast<uintptr_t>(__ptr) + __size);
+ __dealloc_fn* const __dealloc_ptr =
+ reinterpret_cast<__dealloc_fn*>(reinterpret_cast<uintptr_t>(__ptr) + __size);
*__dealloc_ptr = __dealloc;
return __ptr;
}
template <class _Allocator, class... _Args>
_LIBCPP_HIDE_FROM_ABI void*
- operator new(const size_t __size, allocator_arg_t, const _Allocator& __alloc, const _Args&...) {
- return __allocate(__alloc, __size);
+ operator new(const size_t __size, allocator_arg_t, const _Allocator& __al, const _Args&...) {
+ return __alloc(__al, __size);
}
template <class _This, class _Allocator, class... _Args>
_LIBCPP_HIDE_FROM_ABI void*
- operator new(const size_t __size, const _This&, allocator_arg_t, const _Allocator& __alloc, const _Args&...) {
- return __allocate(__alloc, __size);
+ operator new(const size_t __size, const _This&, allocator_arg_t, const _Allocator& __al, const _Args&...) {
+ return __alloc(__al, __size);
}
_LIBCPP_HIDE_FROM_ABI static void operator delete(void* const __ptr, const size_t __size) noexcept {
- __deallocate_fn* const __dealloc_ptr =
- reinterpret_cast<__deallocate_fn*>(reinterpret_cast<uintptr_t>(__ptr) + __size);
- const __deallocate_fn __dealloc = *__dealloc_ptr;
+ __dealloc_fn* const __dealloc_ptr =
+ reinterpret_cast<__dealloc_fn*>(reinterpret_cast<uintptr_t>(__ptr) + __size);
+ const __dealloc_fn __dealloc = *__dealloc_ptr;
__dealloc(__ptr, __size);
}
};
diff --git a/libcxx/test/libcxx/transitive_includes/cxx03.csv b/libcxx/test/libcxx/transitive_includes/cxx03.csv
index 913eebb64f2697..047867e9279d6e 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx03.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx03.csv
@@ -378,6 +378,7 @@ generator cstring
generator initializer_list
generator limits
generator new
+generator tuple
generator typeinfo
initializer_list cstddef
iomanip istream
diff --git a/libcxx/test/libcxx/transitive_includes/cxx11.csv b/libcxx/test/libcxx/transitive_includes/cxx11.csv
index f205bdc232479e..dc581f3daec0c4 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx11.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx11.csv
@@ -380,6 +380,7 @@ generator cstring
generator initializer_list
generator limits
generator new
+generator tuple
generator typeinfo
initializer_list cstddef
iomanip istream
diff --git a/libcxx/test/libcxx/transitive_includes/cxx14.csv b/libcxx/test/libcxx/transitive_includes/cxx14.csv
index 85237f65959d07..58924b85ebd2ea 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx14.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx14.csv
@@ -383,6 +383,7 @@ generator cstring
generator initializer_list
generator limits
generator new
+generator tuple
generator typeinfo
initializer_list cstddef
iomanip istream
diff --git a/libcxx/test/libcxx/transitive_includes/cxx17.csv b/libcxx/test/libcxx/transitive_includes/cxx17.csv
index 85237f65959d07..58924b85ebd2ea 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx17.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv
@@ -383,6 +383,7 @@ generator cstring
generator initializer_list
generator limits
generator new
+generator tuple
generator typeinfo
initializer_list cstddef
iomanip istream
diff --git a/libcxx/test/libcxx/transitive_includes/cxx20.csv b/libcxx/test/libcxx/transitive_includes/cxx20.csv
index 505e1363d3f532..90d8de646d2b07 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx20.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv
@@ -394,6 +394,7 @@ generator cstring
generator initializer_list
generator limits
generator new
+generator tuple
generator typeinfo
initializer_list cstddef
iomanip istream
diff --git a/libcxx/test/libcxx/transitive_includes/cxx23.csv b/libcxx/test/libcxx/transitive_includes/cxx23.csv
index 5af8dc20b70eb9..1ad25220635972 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx23.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx23.csv
@@ -267,6 +267,7 @@ generator cstring
generator initializer_list
generator limits
generator new
+generator tuple
generator typeinfo
initializer_list cstddef
iomanip istream
diff --git a/libcxx/test/libcxx/transitive_includes/cxx26.csv b/libcxx/test/libcxx/transitive_includes/cxx26.csv
index 103e9487ec0c2c..53053a12c9bd53 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx26.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv
@@ -290,6 +290,7 @@ generator cstring
generator initializer_list
generator limits
generator new
+generator tuple
generator typeinfo
initializer_list cstddef
iomanip istream
>From 0bb72da775df280008fd227e0e78adfc5e093fdc Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Sat, 18 May 2024 00:16:40 -0400
Subject: [PATCH 18/38] [libc++] implement 'std::generator'
---
libcxx/include/generator | 26 +++++++++++---------------
1 file changed, 11 insertions(+), 15 deletions(-)
diff --git a/libcxx/include/generator b/libcxx/include/generator
index 601998a90b8877..d731ac31ed769b 100644
--- a/libcxx/include/generator
+++ b/libcxx/include/generator
@@ -426,9 +426,8 @@ private:
void* const __ptr = __rebind_al.allocate(static_cast<__rebind_size_type>(__block_count));
// Stores the deallocation function in the allocated block
- __dealloc_fn* const __dealloc_ptr =
- reinterpret_cast<__dealloc_fn*>(reinterpret_cast<uintptr_t>(__ptr) + __size);
- *__dealloc_ptr = __dealloc<__rebind>;
+ __dealloc_fn* const __dealloc_ptr = reinterpret_cast<__dealloc_fn*>(reinterpret_cast<uintptr_t>(__ptr) + __size);
+ *__dealloc_ptr = __dealloc<__rebind>;
return __ptr;
} else {
// Allocates enough blocks for the coroutine frame, the size of the stateful allocator, the alignment of the
@@ -438,9 +437,8 @@ private:
void* const __ptr = __rebind_al.allocate(static_cast<__rebind_size_type>(__block_count));
// Stores the deallocation function in the allocated block
- __dealloc_fn* const __dealloc_ptr =
- reinterpret_cast<__dealloc_fn*>(reinterpret_cast<uintptr_t>(__ptr) + __size);
- *__dealloc_ptr = __dealloc<__rebind>;
+ __dealloc_fn* const __dealloc_ptr = reinterpret_cast<__dealloc_fn*>(reinterpret_cast<uintptr_t>(__ptr) + __size);
+ *__dealloc_ptr = __dealloc<__rebind>;
// Stores the stateful allocator in the allocated block
__rebind* const __al_ptr = reinterpret_cast<__rebind*>(
@@ -453,14 +451,13 @@ private:
public:
_LIBCPP_HIDE_FROM_ABI void* operator new(const size_t __size) {
- void* const __ptr = ::operator new(__size + sizeof(__dealloc_fn));
- __dealloc_fn __dealloc = [](void* const __ptr, const size_t __size) static noexcept -> void {
- ::operator delete(__ptr, __size + sizeof(__dealloc_fn));
+ void* const __ptr = ::operator new(__size + sizeof(__dealloc_fn));
+ __dealloc_fn __dealloc = [](void* const __dealloc_ptr, const size_t __dealloc_size) static noexcept -> void {
+ ::operator delete(__dealloc_ptr, __dealloc_size + sizeof(__dealloc_fn));
};
- __dealloc_fn* const __dealloc_ptr =
- reinterpret_cast<__dealloc_fn*>(reinterpret_cast<uintptr_t>(__ptr) + __size);
- *__dealloc_ptr = __dealloc;
+ __dealloc_fn* const __dealloc_ptr = reinterpret_cast<__dealloc_fn*>(reinterpret_cast<uintptr_t>(__ptr) + __size);
+ *__dealloc_ptr = __dealloc;
return __ptr;
}
@@ -477,9 +474,8 @@ public:
}
_LIBCPP_HIDE_FROM_ABI static void operator delete(void* const __ptr, const size_t __size) noexcept {
- __dealloc_fn* const __dealloc_ptr =
- reinterpret_cast<__dealloc_fn*>(reinterpret_cast<uintptr_t>(__ptr) + __size);
- const __dealloc_fn __dealloc = *__dealloc_ptr;
+ __dealloc_fn* const __dealloc_ptr = reinterpret_cast<__dealloc_fn*>(reinterpret_cast<uintptr_t>(__ptr) + __size);
+ const __dealloc_fn __dealloc = *__dealloc_ptr;
__dealloc(__ptr, __size);
}
};
>From 07a7db6236b87ff770ce48dbeff3c9c0c530c722 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Mon, 20 May 2024 11:19:08 -0400
Subject: [PATCH 19/38] [libc++] implement 'std::generator'
---
libcxx/include/generator | 94 ++++++++++++++++++++--------------------
1 file changed, 47 insertions(+), 47 deletions(-)
diff --git a/libcxx/include/generator b/libcxx/include/generator
index d731ac31ed769b..87f5c99bae8f3e 100644
--- a/libcxx/include/generator
+++ b/libcxx/include/generator
@@ -328,20 +328,22 @@ private:
using __rebind_pointer = allocator_traits<__rebind>::pointer;
static_assert(is_pointer_v<__rebind_pointer>);
- _LIBCPP_HIDE_FROM_ABI static void* __alloc(__rebind __al, const size_t __size) {
+ _LIBCPP_HIDE_FROM_ABI static void* __alloc(const _Allocator& __al, size_t __size) {
+ __rebind __rebind_al = static_cast<__rebind>(__al);
+
if constexpr (__gen_stateless_allocator<__rebind>) {
const size_t __block_count = __gen_aligned_block::__count(__size);
- return __al.allocate(static_cast<__rebind_size_type>(__block_count));
+ return __rebind_al.allocate(static_cast<__rebind_size_type>(__block_count));
} else {
// Allocates enough blocks for the coroutine frame, the size of the stateful allocator, and the alignment of the
// stateful allocator
const size_t __block_count = __gen_aligned_block::__count(__size + sizeof(__rebind) + alignof(__rebind));
- void* const __ptr = __al.allocate(static_cast<__rebind_size_type>(__block_count));
+ void* const __ptr = __rebind_al.allocate(static_cast<__rebind_size_type>(__block_count));
// Stores the stateful allocator in the allocated block
- __rebind* const __al_ptr = reinterpret_cast<__rebind*>(
+ __rebind* const __rebind_al_ptr = reinterpret_cast<__rebind*>(
(reinterpret_cast<uintptr_t>(__ptr) + __size + alignof(__rebind) - 1) & ~(alignof(__rebind) - 1));
- std::construct_at(__al_ptr, std::move(__al));
+ std::construct_at(__rebind_al_ptr, std::move(__rebind_al));
return __ptr;
}
}
@@ -355,32 +357,31 @@ public:
template <class _Allocator2, class... _Args>
requires convertible_to<const _Allocator2&, _Allocator>
- _LIBCPP_HIDE_FROM_ABI void*
- operator new(const size_t __size, allocator_arg_t, const _Allocator2& __al, const _Args&...) {
- return __alloc(static_cast<__rebind>(static_cast<_Allocator>(__al)), __size);
+ _LIBCPP_HIDE_FROM_ABI void* operator new(size_t __size, allocator_arg_t, const _Allocator2& __al, const _Args&...) {
+ return __alloc(static_cast<_Allocator>(__al), __size);
}
template <class _This, class _Allocator2, class... _Args>
requires convertible_to<const _Allocator2&, _Allocator>
_LIBCPP_HIDE_FROM_ABI void*
- operator new(const size_t __size, const _This&, allocator_arg_t, const _Allocator2& __al, const _Args&...) {
- return __alloc(static_cast<__rebind>(static_cast<_Allocator>(__al)), __size);
+ operator new(size_t __size, const _This&, allocator_arg_t, const _Allocator2& __al, const _Args&...) {
+ return __alloc(static_cast<_Allocator>(__al), __size);
}
- _LIBCPP_HIDE_FROM_ABI static void operator delete(void* const __ptr, const size_t __size) noexcept {
+ _LIBCPP_HIDE_FROM_ABI static void operator delete(void* const __ptr, size_t __size) noexcept {
if constexpr (__gen_stateless_allocator<__rebind>) {
- __rebind __al;
+ __rebind __rebind_al;
const size_t __block_count = __gen_aligned_block::__count(__size);
- __al.deallocate(static_cast<__gen_aligned_block*>(__ptr), static_cast<__rebind_size_type>(__block_count));
+ __rebind_al.deallocate(static_cast<__gen_aligned_block*>(__ptr), static_cast<__rebind_size_type>(__block_count));
} else {
// Retrieves the stateful allocator stored in the allocated block
- __rebind* const __al_ptr = reinterpret_cast<__rebind*>(
+ __rebind* const __rebind_al_ptr = reinterpret_cast<__rebind*>(
(reinterpret_cast<uintptr_t>(__ptr) + __size + alignof(__rebind) - 1) & ~(alignof(__rebind) - 1));
- __rebind __al = std::move(*__al_ptr);
- std::destroy_at(__al_ptr);
+ __rebind __rebind_al = std::move(*__rebind_al_ptr);
+ std::destroy_at(__rebind_al_ptr);
const size_t __block_count = __gen_aligned_block::__count(__size + sizeof(__rebind) + alignof(__rebind));
- __al.deallocate(static_cast<__gen_aligned_block*>(__ptr), static_cast<__rebind_size_type>(__block_count));
+ __rebind_al.deallocate(static_cast<__gen_aligned_block*>(__ptr), static_cast<__rebind_size_type>(__block_count));
}
}
};
@@ -390,30 +391,8 @@ class __gen_promise_allocator<void> {
private:
using __dealloc_fn = void (*)(void*, size_t) noexcept;
- template <class _Rebind>
- _LIBCPP_HIDE_FROM_ABI static void __dealloc(void* const __ptr, const size_t __size) noexcept {
- using __rebind_size_type = allocator_traits<_Rebind>::size_type;
-
- if constexpr (__gen_stateless_allocator<_Rebind>) {
- _Rebind __al;
- const size_t __block_count = __gen_aligned_block::__count(__size + sizeof(__dealloc_fn));
- __al.deallocate(static_cast<__gen_aligned_block*>(__ptr), static_cast<__rebind_size_type>(__block_count));
- } else {
- // Retrieves the stateful allocator stored in the allocated block
- _Rebind* const __al_ptr = reinterpret_cast<_Rebind*>(
- (reinterpret_cast<uintptr_t>(__ptr) + __size + sizeof(__dealloc_fn) + alignof(_Rebind) - 1) &
- ~(alignof(_Rebind) - 1));
- _Rebind __al = std::move(*__al_ptr);
- std::destroy_at(__al_ptr);
-
- const size_t __block_count =
- __gen_aligned_block::__count(__size + sizeof(__dealloc_fn) + sizeof(_Rebind) + alignof(_Rebind));
- __al.deallocate(static_cast<__gen_aligned_block*>(__ptr), static_cast<__rebind_size_type>(__block_count));
- }
- }
-
template <class _Allocator>
- _LIBCPP_HIDE_FROM_ABI static void* __alloc(const _Allocator& __al, const size_t __size) {
+ _LIBCPP_HIDE_FROM_ABI static void* __alloc(const _Allocator& __al, size_t __size) {
using __rebind = allocator_traits<_Allocator>::template rebind_alloc<__gen_aligned_block>;
using __rebind_size_type = allocator_traits<__rebind>::size_type;
@@ -441,16 +420,38 @@ private:
*__dealloc_ptr = __dealloc<__rebind>;
// Stores the stateful allocator in the allocated block
- __rebind* const __al_ptr = reinterpret_cast<__rebind*>(
+ __rebind* const __rebind_al_ptr = reinterpret_cast<__rebind*>(
(reinterpret_cast<uintptr_t>(__ptr) + sizeof(__dealloc_fn) + __size + alignof(__rebind) - 1) &
~(alignof(__rebind) - 1));
- std::construct_at(__al_ptr, std::move(__rebind_al));
+ std::construct_at(__rebind_al_ptr, std::move(__rebind_al));
return __ptr;
}
}
+ template <class _Rebind>
+ _LIBCPP_HIDE_FROM_ABI static void __dealloc(void* const __ptr, size_t __size) noexcept {
+ using __rebind_size_type = allocator_traits<_Rebind>::size_type;
+
+ if constexpr (__gen_stateless_allocator<_Rebind>) {
+ _Rebind __rebind_al;
+ const size_t __block_count = __gen_aligned_block::__count(__size + sizeof(__dealloc_fn));
+ __rebind_al.deallocate(static_cast<__gen_aligned_block*>(__ptr), static_cast<__rebind_size_type>(__block_count));
+ } else {
+ // Retrieves the stateful allocator stored in the allocated block
+ _Rebind* const __rebind_al_ptr = reinterpret_cast<_Rebind*>(
+ (reinterpret_cast<uintptr_t>(__ptr) + __size + sizeof(__dealloc_fn) + alignof(_Rebind) - 1) &
+ ~(alignof(_Rebind) - 1));
+ _Rebind __rebind_al = std::move(*__rebind_al_ptr);
+ std::destroy_at(__rebind_al_ptr);
+
+ const size_t __block_count =
+ __gen_aligned_block::__count(__size + sizeof(__dealloc_fn) + sizeof(_Rebind) + alignof(_Rebind));
+ __rebind_al.deallocate(static_cast<__gen_aligned_block*>(__ptr), static_cast<__rebind_size_type>(__block_count));
+ }
+ }
+
public:
- _LIBCPP_HIDE_FROM_ABI void* operator new(const size_t __size) {
+ _LIBCPP_HIDE_FROM_ABI void* operator new(size_t __size) {
void* const __ptr = ::operator new(__size + sizeof(__dealloc_fn));
__dealloc_fn __dealloc = [](void* const __dealloc_ptr, const size_t __dealloc_size) static noexcept -> void {
::operator delete(__dealloc_ptr, __dealloc_size + sizeof(__dealloc_fn));
@@ -462,18 +463,17 @@ public:
}
template <class _Allocator, class... _Args>
- _LIBCPP_HIDE_FROM_ABI void*
- operator new(const size_t __size, allocator_arg_t, const _Allocator& __al, const _Args&...) {
+ _LIBCPP_HIDE_FROM_ABI void* operator new(size_t __size, allocator_arg_t, const _Allocator& __al, const _Args&...) {
return __alloc(__al, __size);
}
template <class _This, class _Allocator, class... _Args>
_LIBCPP_HIDE_FROM_ABI void*
- operator new(const size_t __size, const _This&, allocator_arg_t, const _Allocator& __al, const _Args&...) {
+ operator new(size_t __size, const _This&, allocator_arg_t, const _Allocator& __al, const _Args&...) {
return __alloc(__al, __size);
}
- _LIBCPP_HIDE_FROM_ABI static void operator delete(void* const __ptr, const size_t __size) noexcept {
+ _LIBCPP_HIDE_FROM_ABI static void operator delete(void* const __ptr, size_t __size) noexcept {
__dealloc_fn* const __dealloc_ptr = reinterpret_cast<__dealloc_fn*>(reinterpret_cast<uintptr_t>(__ptr) + __size);
const __dealloc_fn __dealloc = *__dealloc_ptr;
__dealloc(__ptr, __size);
>From b741665949ed7fc8b58b757ae22499b7bff0aba7 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Sun, 28 Jul 2024 22:10:33 +0800
Subject: [PATCH 20/38] [libc++][ranges] implement 'ranges::elements_of'
---
libcxx/include/__ranges/elements_of.h | 6 ++-
.../range.elementsof/elements_of.pass.cpp | 48 +++++++++++++------
2 files changed, 38 insertions(+), 16 deletions(-)
diff --git a/libcxx/include/__ranges/elements_of.h b/libcxx/include/__ranges/elements_of.h
index f446d3c12d67e7..1b8f916589505c 100644
--- a/libcxx/include/__ranges/elements_of.h
+++ b/libcxx/include/__ranges/elements_of.h
@@ -32,16 +32,20 @@ namespace ranges {
template <range _Range, class _Allocator = allocator<byte>>
struct elements_of {
_LIBCPP_NO_UNIQUE_ADDRESS _Range range;
- _LIBCPP_NO_UNIQUE_ADDRESS _Allocator allocator;
+ _LIBCPP_NO_UNIQUE_ADDRESS _Allocator allocator = _Allocator();
+# if defined(_LIBCPP_COMPILER_CLANG_BASED) && _LIBCPP_CLANG_VER < 1600
// This explicit constructor is required because AppleClang 15 hasn't implement P0960R3
_LIBCPP_HIDE_FROM_ABI explicit constexpr elements_of(_Range __range, _Allocator __alloc = _Allocator())
: range(std::move(__range)), allocator(std::move(__alloc)) {}
+# endif
};
template <class _Range, class _Allocator = allocator<byte>>
+# if defined(_LIBCPP_COMPILER_CLANG_BASED) && _LIBCPP_CLANG_VER < 1600
// This explicit constraint is required because AppleClang 15 might not deduce the correct type for `_Range` without it
requires range<_Range&&>
+# endif
elements_of(_Range&&, _Allocator = _Allocator()) -> elements_of<_Range&&, _Allocator>;
} // namespace ranges
diff --git a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
index 378bcb0a2f13f3..8bdb4f7992ae23 100644
--- a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
+++ b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
@@ -16,25 +16,43 @@
#include <memory>
#include <vector>
+#include "min_allocator.h"
+#include "test_allocator.h"
+#include "test_iterators.h"
+
+template <typename Range>
+constexpr bool test_range() {
+ std::same_as<std::ranges::elements_of<Range&&, std::allocator<std::byte>>> decltype(auto) elements_of =
+ std::ranges::elements_of(Range());
+ [[maybe_unused]] std::same_as<Range&&> decltype(auto) elements_of_range = std::move(elements_of.range);
+ [[maybe_unused]] std::same_as<std::allocator<std::byte>> decltype(auto) elements_of_allocator = elements_of.allocator;
+ return true;
+}
+
+template <typename Range, typename Allocator>
+constexpr bool test_range_with_allocator() {
+ std::same_as< std::ranges::elements_of< Range&&, Allocator >> decltype(auto) elements_of =
+ std::ranges::elements_of(Range(), Allocator());
+ [[maybe_unused]] std::same_as<Range&&> decltype(auto) elements_of_range = std::move(elements_of.range);
+ [[maybe_unused]] std::same_as<Allocator> decltype(auto) elements_of_allocator = elements_of.allocator;
+ return true;
+}
+
constexpr bool test() {
- {
- auto elements_of = std::ranges::elements_of(std::vector<int>());
- static_assert(
- std::same_as<decltype(elements_of), std::ranges::elements_of<std::vector<int>&&, std::allocator<std::byte>>>);
- static_assert(std::same_as<decltype(elements_of.range), std::vector<int>&&>);
- static_assert(std::same_as<decltype(elements_of.allocator), std::allocator<std::byte>>);
- }
- {
- auto elements_of = std::ranges::elements_of(std::vector<int>(), std::allocator<int>());
- static_assert(
- std::same_as<decltype(elements_of), std::ranges::elements_of<std::vector<int>&&, std::allocator<int>>>);
- static_assert(std::same_as<decltype(elements_of.range), std::vector<int>&&>);
- static_assert(std::same_as<decltype(elements_of.allocator), std::allocator<int>>);
- }
+ types::for_each(types::type_list<std::allocator<std::byte>, min_allocator<std::byte>, test_allocator<std::byte>>{},
+ []<class Allocator> {
+ types::for_each(types::type_list<std::vector<int>>{}, []<class Range> {
+ test_range<Range>();
+ test_range_with_allocator<Range, Allocator>();
+ });
+ });
+
return true;
}
-int main() {
+int main(int, char**) {
test();
static_assert(test());
+
+ return 0;
}
>From 07a62fe1e65a3c5c147acc9088f26a36faffa57e Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Thu, 8 Aug 2024 12:50:36 -0400
Subject: [PATCH 21/38] [libc++][ranges] implement 'ranges::elements_of'
---
libcxx/include/__ranges/elements_of.h | 4 ++--
libcxx/test/libcxx/transitive_includes/cxx03.csv | 1 +
libcxx/test/libcxx/transitive_includes/cxx11.csv | 1 +
libcxx/test/libcxx/transitive_includes/cxx14.csv | 1 +
libcxx/test/libcxx/transitive_includes/cxx17.csv | 1 +
libcxx/test/libcxx/transitive_includes/cxx20.csv | 1 +
libcxx/test/libcxx/transitive_includes/cxx23.csv | 1 +
libcxx/test/libcxx/transitive_includes/cxx26.csv | 1 +
8 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/libcxx/include/__ranges/elements_of.h b/libcxx/include/__ranges/elements_of.h
index 1b8f916589505c..b2a93e9d553409 100644
--- a/libcxx/include/__ranges/elements_of.h
+++ b/libcxx/include/__ranges/elements_of.h
@@ -35,7 +35,7 @@ struct elements_of {
_LIBCPP_NO_UNIQUE_ADDRESS _Allocator allocator = _Allocator();
# if defined(_LIBCPP_COMPILER_CLANG_BASED) && _LIBCPP_CLANG_VER < 1600
- // This explicit constructor is required because AppleClang 15 hasn't implement P0960R3
+ // This explicit constructor is required because AppleClang 15 hasn't implemented P0960R3.
_LIBCPP_HIDE_FROM_ABI explicit constexpr elements_of(_Range __range, _Allocator __alloc = _Allocator())
: range(std::move(__range)), allocator(std::move(__alloc)) {}
# endif
@@ -43,7 +43,7 @@ struct elements_of {
template <class _Range, class _Allocator = allocator<byte>>
# if defined(_LIBCPP_COMPILER_CLANG_BASED) && _LIBCPP_CLANG_VER < 1600
-// This explicit constraint is required because AppleClang 15 might not deduce the correct type for `_Range` without it
+// This explicit constraint is required because AppleClang 15 might not deduce the correct type for `_Range` without it.
requires range<_Range&&>
# endif
elements_of(_Range&&, _Allocator = _Allocator()) -> elements_of<_Range&&, _Allocator>;
diff --git a/libcxx/test/libcxx/transitive_includes/cxx03.csv b/libcxx/test/libcxx/transitive_includes/cxx03.csv
index fd2cd7f1c2d961..f0efe06a01cd18 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx03.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx03.csv
@@ -671,6 +671,7 @@ ranges initializer_list
ranges iosfwd
ranges iterator
ranges limits
+ranges new
ranges optional
ranges span
ranges tuple
diff --git a/libcxx/test/libcxx/transitive_includes/cxx11.csv b/libcxx/test/libcxx/transitive_includes/cxx11.csv
index 04122fd0f4571a..64a4954730d979 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx11.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx11.csv
@@ -676,6 +676,7 @@ ranges initializer_list
ranges iosfwd
ranges iterator
ranges limits
+ranges new
ranges optional
ranges span
ranges tuple
diff --git a/libcxx/test/libcxx/transitive_includes/cxx14.csv b/libcxx/test/libcxx/transitive_includes/cxx14.csv
index 42c742bead0c1f..bc56918cb638b7 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx14.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx14.csv
@@ -679,6 +679,7 @@ ranges initializer_list
ranges iosfwd
ranges iterator
ranges limits
+ranges new
ranges optional
ranges span
ranges tuple
diff --git a/libcxx/test/libcxx/transitive_includes/cxx17.csv b/libcxx/test/libcxx/transitive_includes/cxx17.csv
index bc0659127d4bf5..29791eb0b56e32 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx17.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv
@@ -680,6 +680,7 @@ ranges initializer_list
ranges iosfwd
ranges iterator
ranges limits
+ranges new
ranges optional
ranges span
ranges tuple
diff --git a/libcxx/test/libcxx/transitive_includes/cxx20.csv b/libcxx/test/libcxx/transitive_includes/cxx20.csv
index fed0944f0219c4..70470de2106e77 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx20.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv
@@ -687,6 +687,7 @@ ranges initializer_list
ranges iosfwd
ranges iterator
ranges limits
+ranges new
ranges optional
ranges span
ranges tuple
diff --git a/libcxx/test/libcxx/transitive_includes/cxx23.csv b/libcxx/test/libcxx/transitive_includes/cxx23.csv
index 53f99384a7f573..117a87b66a2cdb 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx23.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx23.csv
@@ -464,6 +464,7 @@ ranges cwchar
ranges initializer_list
ranges iterator
ranges limits
+ranges new
ranges optional
ranges span
ranges tuple
diff --git a/libcxx/test/libcxx/transitive_includes/cxx26.csv b/libcxx/test/libcxx/transitive_includes/cxx26.csv
index 53f99384a7f573..117a87b66a2cdb 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx26.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv
@@ -464,6 +464,7 @@ ranges cwchar
ranges initializer_list
ranges iterator
ranges limits
+ranges new
ranges optional
ranges span
ranges tuple
>From 74bd1855a16977ffd2e93619fa0e0cdfe83762d3 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Thu, 8 Aug 2024 12:55:24 -0400
Subject: [PATCH 22/38] [libc++][ranges] implement 'ranges::elements_of'
---
libcxx/include/__ranges/elements_of.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libcxx/include/__ranges/elements_of.h b/libcxx/include/__ranges/elements_of.h
index b2a93e9d553409..f23e8dd4a15e5d 100644
--- a/libcxx/include/__ranges/elements_of.h
+++ b/libcxx/include/__ranges/elements_of.h
@@ -34,7 +34,7 @@ struct elements_of {
_LIBCPP_NO_UNIQUE_ADDRESS _Range range;
_LIBCPP_NO_UNIQUE_ADDRESS _Allocator allocator = _Allocator();
-# if defined(_LIBCPP_COMPILER_CLANG_BASED) && _LIBCPP_CLANG_VER < 1600
+# if defined(_LIBCPP_COMPILER_CLANG_BASED) && defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER < 1600
// This explicit constructor is required because AppleClang 15 hasn't implemented P0960R3.
_LIBCPP_HIDE_FROM_ABI explicit constexpr elements_of(_Range __range, _Allocator __alloc = _Allocator())
: range(std::move(__range)), allocator(std::move(__alloc)) {}
@@ -42,7 +42,7 @@ struct elements_of {
};
template <class _Range, class _Allocator = allocator<byte>>
-# if defined(_LIBCPP_COMPILER_CLANG_BASED) && _LIBCPP_CLANG_VER < 1600
+# if defined(_LIBCPP_COMPILER_CLANG_BASED) && defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER < 1600
// This explicit constraint is required because AppleClang 15 might not deduce the correct type for `_Range` without it.
requires range<_Range&&>
# endif
>From 5e37e03d58d03a739942a0354646f057312be35f Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Thu, 8 Aug 2024 14:04:15 -0400
Subject: [PATCH 23/38] [libc++][ranges] implement 'ranges::elements_of'
---
.../range.elementsof/ctad.compile.pass.cpp | 49 ++++++++++++++
.../range.elementsof/elements_of.pass.cpp | 66 ++++++++++++++-----
2 files changed, 98 insertions(+), 17 deletions(-)
create mode 100644 libcxx/test/std/ranges/range.utility/range.elementsof/ctad.compile.pass.cpp
diff --git a/libcxx/test/std/ranges/range.utility/range.elementsof/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.utility/range.elementsof/ctad.compile.pass.cpp
new file mode 100644
index 00000000000000..3a679b521f75e5
--- /dev/null
+++ b/libcxx/test/std/ranges/range.utility/range.elementsof/ctad.compile.pass.cpp
@@ -0,0 +1,49 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// std::ranges::elements_of;
+
+#include <ranges>
+
+#include <memory>
+
+#include "min_allocator.h"
+#include "test_allocator.h"
+#include "test_iterators.h"
+
+template <class Iterator>
+struct Range {
+ Iterator begin() const;
+ sentinel_wrapper<Iterator> end() const;
+};
+
+constexpr bool test() {
+ types::for_each(
+ types::type_list<std::allocator<std::byte>, min_allocator<std::byte>, test_allocator<std::byte>>{},
+ []<class Allocator> {
+ types::for_each(types::cpp20_input_iterator_list<int*>{}, []<class Iterator> {
+ Range<Iterator> r;
+ static_assert(std::same_as<decltype(std::ranges::elements_of(r)),
+ std::ranges::elements_of<Range<Iterator>&, std::allocator<std::byte>>>);
+ static_assert(std::same_as<decltype(std::ranges::elements_of(Range<Iterator>())),
+ std::ranges::elements_of<Range<Iterator>&&, std::allocator<std::byte>>>);
+
+ Allocator a;
+ static_assert(std::same_as<decltype(std::ranges::elements_of(r, a)),
+ std::ranges::elements_of<Range<Iterator>&, Allocator>>);
+ static_assert(std::same_as<decltype(std::ranges::elements_of(Range<Iterator>(), Allocator())),
+ std::ranges::elements_of<Range<Iterator>&&, Allocator>>);
+ });
+ });
+
+ return true;
+}
+
+static_assert(test());
diff --git a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
index 8bdb4f7992ae23..8c6a8f98058c85 100644
--- a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
+++ b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
@@ -12,7 +12,6 @@
#include <ranges>
-#include <concepts>
#include <memory>
#include <vector>
@@ -20,30 +19,63 @@
#include "test_allocator.h"
#include "test_iterators.h"
-template <typename Range>
+template <class Iterator>
+struct Range {
+ using Sentinel = sentinel_wrapper<Iterator>;
+
+ Iterator begin() { return Iterator(data.data()); }
+
+ sentinel_wrapper<Iterator> end() { return Sentinel(Iterator(data.data() + data.size())); }
+
+ std::vector<int> data = {0, 1, 2, 3};
+};
+
+template <class Range, class Allocator>
constexpr bool test_range() {
- std::same_as<std::ranges::elements_of<Range&&, std::allocator<std::byte>>> decltype(auto) elements_of =
- std::ranges::elements_of(Range());
- [[maybe_unused]] std::same_as<Range&&> decltype(auto) elements_of_range = std::move(elements_of.range);
- [[maybe_unused]] std::same_as<std::allocator<std::byte>> decltype(auto) elements_of_allocator = elements_of.allocator;
- return true;
-}
+ Range r;
+
+ using elements_of_t = std::ranges::elements_of<Range&, Allocator>;
+ {
+ // constructor
+ std::same_as<elements_of_t> decltype(auto) elements_of = std::ranges::elements_of(r, Allocator());
+ [[maybe_unused]] std::same_as<Range&> decltype(auto) elements_of_range = elements_of.range;
+ [[maybe_unused]] std::same_as<Allocator> decltype(auto) elements_of_allocator = elements_of.allocator;
+ }
+ {
+ // designated initializer
+ std::same_as<elements_of_t> decltype(auto) elements_of = std::ranges::elements_of{
+ .range = r,
+ .allocator = Allocator(),
+ };
+ [[maybe_unused]] std::same_as<Range&> decltype(auto) elements_of_range = elements_of.range;
+ [[maybe_unused]] std::same_as<Allocator> decltype(auto) elements_of_allocator = elements_of.allocator;
+ }
+ {
+ // copy constructor
+ std::same_as<elements_of_t> decltype(auto) elements_of_1 = std::ranges::elements_of(r, Allocator());
+ std::same_as<elements_of_t> auto elements_of_2 = elements_of_1;
+ [[maybe_unused]] std::same_as<Range&> decltype(auto) elements_of_1_range = elements_of_1.range;
+ [[maybe_unused]] std::same_as<Range&> decltype(auto) elements_of_2_range = elements_of_2.range;
+ [[maybe_unused]] std::same_as<Allocator> decltype(auto) elements_of_2_allocator = elements_of_2.allocator;
+ }
-template <typename Range, typename Allocator>
-constexpr bool test_range_with_allocator() {
- std::same_as< std::ranges::elements_of< Range&&, Allocator >> decltype(auto) elements_of =
- std::ranges::elements_of(Range(), Allocator());
- [[maybe_unused]] std::same_as<Range&&> decltype(auto) elements_of_range = std::move(elements_of.range);
- [[maybe_unused]] std::same_as<Allocator> decltype(auto) elements_of_allocator = elements_of.allocator;
+ using elements_of_r_t = std::ranges::elements_of<Range&&, Allocator>;
+ {
+ // move constructor
+ std::same_as<elements_of_r_t> decltype(auto) elements_of_1 = std::ranges::elements_of(std::move(r), Allocator());
+ std::same_as<elements_of_r_t> auto elements_of_2 = std::move(elements_of_1);
+ [[maybe_unused]] std::same_as<Range&&> decltype(auto) elements_of_1_range = std::move(elements_of_1.range);
+ [[maybe_unused]] std::same_as<Range&&> decltype(auto) elements_of_2_range = std::move(elements_of_2.range);
+ [[maybe_unused]] std::same_as<Allocator> decltype(auto) elements_of_2_allocator = elements_of_2.allocator;
+ }
return true;
}
constexpr bool test() {
types::for_each(types::type_list<std::allocator<std::byte>, min_allocator<std::byte>, test_allocator<std::byte>>{},
[]<class Allocator> {
- types::for_each(types::type_list<std::vector<int>>{}, []<class Range> {
- test_range<Range>();
- test_range_with_allocator<Range, Allocator>();
+ types::for_each(types::cpp20_input_iterator_list<int*>{}, []<class Iterator> {
+ test_range<Range<Iterator>, Allocator>();
});
});
>From cd3b4cd40ee16c41e7c3f5070e7fde13c1373c84 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Thu, 8 Aug 2024 14:09:12 -0400
Subject: [PATCH 24/38] [libc++][ranges] implement 'ranges::elements_of'
---
.../range.elementsof/elements_of.pass.cpp | 28 +++++++++++++++----
1 file changed, 22 insertions(+), 6 deletions(-)
diff --git a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
index 8c6a8f98058c85..945d9dd67a34ab 100644
--- a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
+++ b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
@@ -13,6 +13,7 @@
#include <ranges>
#include <memory>
+#include <type_traits>
#include <vector>
#include "min_allocator.h"
@@ -23,11 +24,12 @@ template <class Iterator>
struct Range {
using Sentinel = sentinel_wrapper<Iterator>;
- Iterator begin() { return Iterator(data.data()); }
+ Iterator begin() { return Iterator(data_.data()); }
- sentinel_wrapper<Iterator> end() { return Sentinel(Iterator(data.data() + data.size())); }
+ sentinel_wrapper<Iterator> end() { return Sentinel(Iterator(data_.data() + data_.size())); }
- std::vector<int> data = {0, 1, 2, 3};
+private:
+ std::vector<int> data_ = {0, 1, 2, 3};
};
template <class Range, class Allocator>
@@ -39,6 +41,9 @@ constexpr bool test_range() {
// constructor
std::same_as<elements_of_t> decltype(auto) elements_of = std::ranges::elements_of(r, Allocator());
[[maybe_unused]] std::same_as<Range&> decltype(auto) elements_of_range = elements_of.range;
+ if (!std::is_constant_evaluated()) {
+ assert(std::ranges::distance(elements_of_range) == 4);
+ }
[[maybe_unused]] std::same_as<Allocator> decltype(auto) elements_of_allocator = elements_of.allocator;
}
{
@@ -47,7 +52,10 @@ constexpr bool test_range() {
.range = r,
.allocator = Allocator(),
};
- [[maybe_unused]] std::same_as<Range&> decltype(auto) elements_of_range = elements_of.range;
+ [[maybe_unused]] std::same_as<Range&> decltype(auto) elements_of_range = elements_of.range;
+ if (!std::is_constant_evaluated()) {
+ assert(std::ranges::distance(elements_of_range) == 4);
+ }
[[maybe_unused]] std::same_as<Allocator> decltype(auto) elements_of_allocator = elements_of.allocator;
}
{
@@ -56,6 +64,10 @@ constexpr bool test_range() {
std::same_as<elements_of_t> auto elements_of_2 = elements_of_1;
[[maybe_unused]] std::same_as<Range&> decltype(auto) elements_of_1_range = elements_of_1.range;
[[maybe_unused]] std::same_as<Range&> decltype(auto) elements_of_2_range = elements_of_2.range;
+ if (!std::is_constant_evaluated()) {
+ assert(std::ranges::distance(elements_of_1_range) == 4);
+ assert(std::ranges::distance(elements_of_2_range) == 4);
+ }
[[maybe_unused]] std::same_as<Allocator> decltype(auto) elements_of_2_allocator = elements_of_2.allocator;
}
@@ -64,8 +76,12 @@ constexpr bool test_range() {
// move constructor
std::same_as<elements_of_r_t> decltype(auto) elements_of_1 = std::ranges::elements_of(std::move(r), Allocator());
std::same_as<elements_of_r_t> auto elements_of_2 = std::move(elements_of_1);
- [[maybe_unused]] std::same_as<Range&&> decltype(auto) elements_of_1_range = std::move(elements_of_1.range);
- [[maybe_unused]] std::same_as<Range&&> decltype(auto) elements_of_2_range = std::move(elements_of_2.range);
+ [[maybe_unused]] std::same_as<Range&&> decltype(auto) elements_of_1_range = std::move(elements_of_1.range);
+ [[maybe_unused]] std::same_as<Range&&> decltype(auto) elements_of_2_range = std::move(elements_of_2.range);
+ if (!std::is_constant_evaluated()) {
+ assert(std::ranges::distance(elements_of_1_range) == 4);
+ assert(std::ranges::distance(elements_of_2_range) == 4);
+ }
[[maybe_unused]] std::same_as<Allocator> decltype(auto) elements_of_2_allocator = elements_of_2.allocator;
}
return true;
>From bfb0e2511fb6d0d83178fb9f90a4a00f9b1dd0df Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Thu, 8 Aug 2024 14:18:39 -0400
Subject: [PATCH 25/38] [libc++][ranges] implement 'ranges::elements_of'
---
libcxx/test/libcxx/transitive_includes/cxx03.csv | 1 -
1 file changed, 1 deletion(-)
diff --git a/libcxx/test/libcxx/transitive_includes/cxx03.csv b/libcxx/test/libcxx/transitive_includes/cxx03.csv
index f0efe06a01cd18..fd2cd7f1c2d961 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx03.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx03.csv
@@ -671,7 +671,6 @@ ranges initializer_list
ranges iosfwd
ranges iterator
ranges limits
-ranges new
ranges optional
ranges span
ranges tuple
>From aacbc6b65346b18b1e2cd065387d42aebb800868 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Thu, 8 Aug 2024 15:42:24 -0400
Subject: [PATCH 26/38] [libc++][ranges] implement 'ranges::elements_of'
---
libcxx/test/libcxx/transitive_includes/cxx11.csv | 2 +-
libcxx/test/libcxx/transitive_includes/cxx14.csv | 2 +-
libcxx/test/libcxx/transitive_includes/cxx17.csv | 2 +-
libcxx/test/libcxx/transitive_includes/cxx20.csv | 2 +-
4 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/libcxx/test/libcxx/transitive_includes/cxx11.csv b/libcxx/test/libcxx/transitive_includes/cxx11.csv
index 64a4954730d979..1d4dea0b18ba6b 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx11.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx11.csv
@@ -676,7 +676,7 @@ ranges initializer_list
ranges iosfwd
ranges iterator
ranges limits
-ranges new
+
ranges optional
ranges span
ranges tuple
diff --git a/libcxx/test/libcxx/transitive_includes/cxx14.csv b/libcxx/test/libcxx/transitive_includes/cxx14.csv
index bc56918cb638b7..72f55701ee1b33 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx14.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx14.csv
@@ -679,7 +679,7 @@ ranges initializer_list
ranges iosfwd
ranges iterator
ranges limits
-ranges new
+
ranges optional
ranges span
ranges tuple
diff --git a/libcxx/test/libcxx/transitive_includes/cxx17.csv b/libcxx/test/libcxx/transitive_includes/cxx17.csv
index 29791eb0b56e32..2591484084da51 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx17.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv
@@ -680,7 +680,7 @@ ranges initializer_list
ranges iosfwd
ranges iterator
ranges limits
-ranges new
+
ranges optional
ranges span
ranges tuple
diff --git a/libcxx/test/libcxx/transitive_includes/cxx20.csv b/libcxx/test/libcxx/transitive_includes/cxx20.csv
index 70470de2106e77..8d832cdacf993b 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx20.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv
@@ -687,7 +687,7 @@ ranges initializer_list
ranges iosfwd
ranges iterator
ranges limits
-ranges new
+
ranges optional
ranges span
ranges tuple
>From ffc970083fa5b3e4950dfb2479d9d625ddfd29db Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Thu, 8 Aug 2024 15:43:08 -0400
Subject: [PATCH 27/38] [libc++][ranges] implement 'ranges::elements_of'
---
libcxx/test/libcxx/transitive_includes/cxx11.csv | 1 -
libcxx/test/libcxx/transitive_includes/cxx14.csv | 1 -
libcxx/test/libcxx/transitive_includes/cxx17.csv | 1 -
libcxx/test/libcxx/transitive_includes/cxx20.csv | 1 -
4 files changed, 4 deletions(-)
diff --git a/libcxx/test/libcxx/transitive_includes/cxx11.csv b/libcxx/test/libcxx/transitive_includes/cxx11.csv
index 1d4dea0b18ba6b..04122fd0f4571a 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx11.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx11.csv
@@ -676,7 +676,6 @@ ranges initializer_list
ranges iosfwd
ranges iterator
ranges limits
-
ranges optional
ranges span
ranges tuple
diff --git a/libcxx/test/libcxx/transitive_includes/cxx14.csv b/libcxx/test/libcxx/transitive_includes/cxx14.csv
index 72f55701ee1b33..42c742bead0c1f 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx14.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx14.csv
@@ -679,7 +679,6 @@ ranges initializer_list
ranges iosfwd
ranges iterator
ranges limits
-
ranges optional
ranges span
ranges tuple
diff --git a/libcxx/test/libcxx/transitive_includes/cxx17.csv b/libcxx/test/libcxx/transitive_includes/cxx17.csv
index 2591484084da51..bc0659127d4bf5 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx17.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv
@@ -680,7 +680,6 @@ ranges initializer_list
ranges iosfwd
ranges iterator
ranges limits
-
ranges optional
ranges span
ranges tuple
diff --git a/libcxx/test/libcxx/transitive_includes/cxx20.csv b/libcxx/test/libcxx/transitive_includes/cxx20.csv
index 8d832cdacf993b..fed0944f0219c4 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx20.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv
@@ -687,7 +687,6 @@ ranges initializer_list
ranges iosfwd
ranges iterator
ranges limits
-
ranges optional
ranges span
ranges tuple
>From 4c72a3a27463672b1eac3582836851778634ce02 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Thu, 8 Aug 2024 23:46:16 -0400
Subject: [PATCH 28/38] [libc++][ranges] implement 'ranges::elements_of'
---
.../range.elementsof/elements_of.pass.cpp | 22 ++++++++++++-------
1 file changed, 14 insertions(+), 8 deletions(-)
diff --git a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
index 945d9dd67a34ab..13ce4cbea964da 100644
--- a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
+++ b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
@@ -48,15 +48,21 @@ constexpr bool test_range() {
}
{
// designated initializer
- std::same_as<elements_of_t> decltype(auto) elements_of = std::ranges::elements_of{
- .range = r,
- .allocator = Allocator(),
- };
- [[maybe_unused]] std::same_as<Range&> decltype(auto) elements_of_range = elements_of.range;
- if (!std::is_constant_evaluated()) {
- assert(std::ranges::distance(elements_of_range) == 4);
+
+ // AppleClang 15 hasn't implemented P0960R3, so `std::ranges::elements_of` requires a
+ // user-defined constructor, making it non-aggregate and therefore incompatible with designated
+ // initializers.
+ if constexpr (std::is_aggregate_v<elements_of_t>) {
+ std::same_as<elements_of_t> decltype(auto) elements_of = std::ranges::elements_of{
+ .range = r,
+ .allocator = Allocator(),
+ };
+ [[maybe_unused]] std::same_as<Range&> decltype(auto) elements_of_range = elements_of.range;
+ if (!std::is_constant_evaluated()) {
+ assert(std::ranges::distance(elements_of_range) == 4);
+ }
+ [[maybe_unused]] std::same_as<Allocator> decltype(auto) elements_of_allocator = elements_of.allocator;
}
- [[maybe_unused]] std::same_as<Allocator> decltype(auto) elements_of_allocator = elements_of.allocator;
}
{
// copy constructor
>From c2df436f696ba4494ce676436d7022c2cf222604 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Thu, 8 Aug 2024 23:52:09 -0400
Subject: [PATCH 29/38] [libc++][ranges] implement 'ranges::elements_of'
---
.../ranges/range.utility/range.elementsof/elements_of.pass.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
index 13ce4cbea964da..38392383029d0d 100644
--- a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
+++ b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
@@ -48,7 +48,7 @@ constexpr bool test_range() {
}
{
// designated initializer
-
+
// AppleClang 15 hasn't implemented P0960R3, so `std::ranges::elements_of` requires a
// user-defined constructor, making it non-aggregate and therefore incompatible with designated
// initializers.
>From 5884764de738c8cc30de3d967b662033c6e8f476 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Fri, 9 Aug 2024 00:31:52 -0400
Subject: [PATCH 30/38] [libc++][ranges] implement 'ranges::elements_of'
---
libcxx/include/__ranges/elements_of.h | 34 +++++++++++++++++----------
1 file changed, 21 insertions(+), 13 deletions(-)
diff --git a/libcxx/include/__ranges/elements_of.h b/libcxx/include/__ranges/elements_of.h
index f23e8dd4a15e5d..f6e1218cd998a3 100644
--- a/libcxx/include/__ranges/elements_of.h
+++ b/libcxx/include/__ranges/elements_of.h
@@ -17,7 +17,7 @@
#include <cstddef>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
-# pragma GCC system_header
+#pragma GCC system_header
#endif
_LIBCPP_PUSH_MACROS
@@ -29,24 +29,32 @@ _LIBCPP_BEGIN_NAMESPACE_STD
namespace ranges {
-template <range _Range, class _Allocator = allocator<byte>>
-struct elements_of {
+template <range _Range, class _Allocator = allocator<byte>> struct elements_of {
_LIBCPP_NO_UNIQUE_ADDRESS _Range range;
_LIBCPP_NO_UNIQUE_ADDRESS _Allocator allocator = _Allocator();
-# if defined(_LIBCPP_COMPILER_CLANG_BASED) && defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER < 1600
- // This explicit constructor is required because AppleClang 15 hasn't implemented P0960R3.
- _LIBCPP_HIDE_FROM_ABI explicit constexpr elements_of(_Range __range, _Allocator __alloc = _Allocator())
- : range(std::move(__range)), allocator(std::move(__alloc)) {}
-# endif
+#if defined(_LIBCPP_COMPILER_CLANG_BASED) && \
+ defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER < 1600
+ // This explicit constructor is required because AppleClang 15 hasn't
+ // implemented P0960R3.
+ template <std::ranges::range _Range2,
+ class _Allocator2 = std::allocator<std::byte>>
+ _LIBCPP_HIDE_FROM_ABI explicit constexpr elements_of(
+ _Range2 &&Range, _Allocator2 &&Alloc = _Allocator())
+ : range(std::forward<_Range2>(Range)),
+ allocator(std::forward<_Allocator2>(Alloc)) {}
+#endif
};
template <class _Range, class _Allocator = allocator<byte>>
-# if defined(_LIBCPP_COMPILER_CLANG_BASED) && defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER < 1600
-// This explicit constraint is required because AppleClang 15 might not deduce the correct type for `_Range` without it.
- requires range<_Range&&>
-# endif
-elements_of(_Range&&, _Allocator = _Allocator()) -> elements_of<_Range&&, _Allocator>;
+#if defined(_LIBCPP_COMPILER_CLANG_BASED) && \
+ defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER < 1600
+// This explicit constraint is required because AppleClang 15 might not deduce
+// the correct type for `_Range` without it.
+ requires range<_Range &&>
+#endif
+elements_of(_Range &&,
+ _Allocator = _Allocator()) -> elements_of<_Range &&, _Allocator>;
} // namespace ranges
>From 752d590e4f8dd8ab28ba30129dfbd614654121a1 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Fri, 9 Aug 2024 02:37:21 -0400
Subject: [PATCH 31/38] [libc++][ranges] implement 'ranges::elements_of'
---
libcxx/include/__ranges/elements_of.h | 31 +++++++++++----------------
1 file changed, 13 insertions(+), 18 deletions(-)
diff --git a/libcxx/include/__ranges/elements_of.h b/libcxx/include/__ranges/elements_of.h
index f6e1218cd998a3..bb79adeed538ca 100644
--- a/libcxx/include/__ranges/elements_of.h
+++ b/libcxx/include/__ranges/elements_of.h
@@ -13,11 +13,11 @@
#include <__config>
#include <__memory/allocator.h>
#include <__ranges/concepts.h>
-#include <__utility/move.h>
+#include <__utility/forward.h>
#include <cstddef>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
-#pragma GCC system_header
+# pragma GCC system_header
#endif
_LIBCPP_PUSH_MACROS
@@ -29,32 +29,27 @@ _LIBCPP_BEGIN_NAMESPACE_STD
namespace ranges {
-template <range _Range, class _Allocator = allocator<byte>> struct elements_of {
+template <range _Range, class _Allocator = allocator<byte>>
+struct elements_of {
_LIBCPP_NO_UNIQUE_ADDRESS _Range range;
_LIBCPP_NO_UNIQUE_ADDRESS _Allocator allocator = _Allocator();
-#if defined(_LIBCPP_COMPILER_CLANG_BASED) && \
- defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER < 1600
+# if defined(_LIBCPP_COMPILER_CLANG_BASED) && defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER < 1600
// This explicit constructor is required because AppleClang 15 hasn't
// implemented P0960R3.
- template <std::ranges::range _Range2,
- class _Allocator2 = std::allocator<std::byte>>
- _LIBCPP_HIDE_FROM_ABI explicit constexpr elements_of(
- _Range2 &&Range, _Allocator2 &&Alloc = _Allocator())
- : range(std::forward<_Range2>(Range)),
- allocator(std::forward<_Allocator2>(Alloc)) {}
-#endif
+ template <std::ranges::range _Range2, class _Allocator2 = std::allocator<std::byte>>
+ _LIBCPP_HIDE_FROM_ABI explicit constexpr elements_of(_Range2&& Range, _Allocator2&& Alloc = _Allocator())
+ : range(std::forward<_Range2>(Range)), allocator(std::forward<_Allocator2>(Alloc)) {}
+# endif
};
template <class _Range, class _Allocator = allocator<byte>>
-#if defined(_LIBCPP_COMPILER_CLANG_BASED) && \
- defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER < 1600
+# if defined(_LIBCPP_COMPILER_CLANG_BASED) && defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER < 1600
// This explicit constraint is required because AppleClang 15 might not deduce
// the correct type for `_Range` without it.
- requires range<_Range &&>
-#endif
-elements_of(_Range &&,
- _Allocator = _Allocator()) -> elements_of<_Range &&, _Allocator>;
+ requires range<_Range&&>
+# endif
+elements_of(_Range&&, _Allocator = _Allocator()) -> elements_of<_Range&&, _Allocator>;
} // namespace ranges
>From 93c65aa6c7fc7117fb153ca32c3e84c62e2a0051 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Mon, 12 Aug 2024 21:37:53 -0400
Subject: [PATCH 32/38] [libc++][ranges] implement 'ranges::elements_of'
---
.../ranges/range.utility/range.elementsof/elements_of.pass.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
index 38392383029d0d..090a0dd50c778f 100644
--- a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
+++ b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
@@ -12,6 +12,7 @@
#include <ranges>
+#include <concepts>
#include <memory>
#include <type_traits>
#include <vector>
>From 94b9c2c31884c5ed15bcf7044f2979d0eb6cce7a Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Sun, 18 Aug 2024 15:52:22 -0400
Subject: [PATCH 33/38] [libc++][ranges] implement 'ranges::elements_of'
---
libcxx/include/__ranges/elements_of.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/include/__ranges/elements_of.h b/libcxx/include/__ranges/elements_of.h
index bb79adeed538ca..fd918c3df0233d 100644
--- a/libcxx/include/__ranges/elements_of.h
+++ b/libcxx/include/__ranges/elements_of.h
@@ -34,7 +34,7 @@ struct elements_of {
_LIBCPP_NO_UNIQUE_ADDRESS _Range range;
_LIBCPP_NO_UNIQUE_ADDRESS _Allocator allocator = _Allocator();
-# if defined(_LIBCPP_COMPILER_CLANG_BASED) && defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER < 1600
+# if !defined(__cpp_aggregate_paren_init)
// This explicit constructor is required because AppleClang 15 hasn't
// implemented P0960R3.
template <std::ranges::range _Range2, class _Allocator2 = std::allocator<std::byte>>
>From 06f28a1a0f3a60fcb2ead8f700bd2d3bb4c3296b Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Tue, 27 Aug 2024 21:31:36 -0400
Subject: [PATCH 34/38] [libc++][ranges] implement 'ranges::elements_of'
---
libcxx/include/__ranges/elements_of.h | 2 +-
.../range.elementsof/ctad.compile.pass.cpp | 10 +++++++
.../range.elementsof/elements_of.pass.cpp | 28 +++++++++----------
3 files changed, 24 insertions(+), 16 deletions(-)
diff --git a/libcxx/include/__ranges/elements_of.h b/libcxx/include/__ranges/elements_of.h
index fd918c3df0233d..f414a662907a9e 100644
--- a/libcxx/include/__ranges/elements_of.h
+++ b/libcxx/include/__ranges/elements_of.h
@@ -37,7 +37,7 @@ struct elements_of {
# if !defined(__cpp_aggregate_paren_init)
// This explicit constructor is required because AppleClang 15 hasn't
// implemented P0960R3.
- template <std::ranges::range _Range2, class _Allocator2 = std::allocator<std::byte>>
+ template <std::ranges::range _Range2, class _Allocator2 = std::allocator<byte>>
_LIBCPP_HIDE_FROM_ABI explicit constexpr elements_of(_Range2&& Range, _Allocator2&& Alloc = _Allocator())
: range(std::forward<_Range2>(Range)), allocator(std::forward<_Allocator2>(Alloc)) {}
# endif
diff --git a/libcxx/test/std/ranges/range.utility/range.elementsof/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.utility/range.elementsof/ctad.compile.pass.cpp
index 3a679b521f75e5..0f9204a07118ee 100644
--- a/libcxx/test/std/ranges/range.utility/range.elementsof/ctad.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.utility/range.elementsof/ctad.compile.pass.cpp
@@ -40,6 +40,16 @@ constexpr bool test() {
std::ranges::elements_of<Range<Iterator>&, Allocator>>);
static_assert(std::same_as<decltype(std::ranges::elements_of(Range<Iterator>(), Allocator())),
std::ranges::elements_of<Range<Iterator>&&, Allocator>>);
+
+// AppleClang 15 hasn't implemented P0960R3 and P1816R0
+#if defined(__cpp_aggregate_paren_init) && __cpp_aggregate_paren_init >= 201902L && defined(__cpp_deduction_guides) && \
+ __cpp_deduction_guides >= 201907L
+ static_assert(std::same_as<decltype(std::ranges::elements_of{.range = r, .allocator = a}),
+ std::ranges::elements_of<Range<Iterator>&, Allocator>>);
+ static_assert(
+ std::same_as<decltype(std::ranges::elements_of{.range = Range<Iterator>(), .allocator = Allocator()}),
+ std::ranges::elements_of<Range<Iterator>&&, Allocator>>);
+#endif
});
});
diff --git a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
index 090a0dd50c778f..f18a3bc8c61bc0 100644
--- a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
+++ b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
@@ -48,22 +48,20 @@ constexpr bool test_range() {
[[maybe_unused]] std::same_as<Allocator> decltype(auto) elements_of_allocator = elements_of.allocator;
}
{
- // designated initializer
-
- // AppleClang 15 hasn't implemented P0960R3, so `std::ranges::elements_of` requires a
- // user-defined constructor, making it non-aggregate and therefore incompatible with designated
- // initializers.
- if constexpr (std::is_aggregate_v<elements_of_t>) {
- std::same_as<elements_of_t> decltype(auto) elements_of = std::ranges::elements_of{
- .range = r,
- .allocator = Allocator(),
- };
- [[maybe_unused]] std::same_as<Range&> decltype(auto) elements_of_range = elements_of.range;
- if (!std::is_constant_evaluated()) {
- assert(std::ranges::distance(elements_of_range) == 4);
- }
- [[maybe_unused]] std::same_as<Allocator> decltype(auto) elements_of_allocator = elements_of.allocator;
+// designated initializer
+// AppleClang 15 hasn't implemented P0960R3 and P1816R0
+#if defined(__cpp_aggregate_paren_init) && __cpp_aggregate_paren_init >= 201902L && defined(__cpp_deduction_guides) && \
+ __cpp_deduction_guides >= 201907L
+ std::same_as<elements_of_t> decltype(auto) elements_of = std::ranges::elements_of{
+ .range = r,
+ .allocator = Allocator(),
+ };
+ [[maybe_unused]] std::same_as<Range&> decltype(auto) elements_of_range = elements_of.range;
+ if (!std::is_constant_evaluated()) {
+ assert(std::ranges::distance(elements_of_range) == 4);
}
+ [[maybe_unused]] std::same_as<Allocator> decltype(auto) elements_of_allocator = elements_of.allocator;
+#endif
}
{
// copy constructor
>From ea82cce5f0702b2138b17901d716ff88525aad0d Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Thu, 17 Oct 2024 00:30:54 -0400
Subject: [PATCH 35/38] [libc++][ranges] implement 'ranges::elements_of'
---
libcxx/include/__ranges/elements_of.h | 4 ++--
.../range.utility/range.elementsof/elements_of.pass.cpp | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/libcxx/include/__ranges/elements_of.h b/libcxx/include/__ranges/elements_of.h
index f414a662907a9e..415565e813f397 100644
--- a/libcxx/include/__ranges/elements_of.h
+++ b/libcxx/include/__ranges/elements_of.h
@@ -38,8 +38,8 @@ struct elements_of {
// This explicit constructor is required because AppleClang 15 hasn't
// implemented P0960R3.
template <std::ranges::range _Range2, class _Allocator2 = std::allocator<byte>>
- _LIBCPP_HIDE_FROM_ABI explicit constexpr elements_of(_Range2&& Range, _Allocator2&& Alloc = _Allocator())
- : range(std::forward<_Range2>(Range)), allocator(std::forward<_Allocator2>(Alloc)) {}
+ _LIBCPP_HIDE_FROM_ABI explicit constexpr elements_of(_Range2&& __range, _Allocator2&& __alloc = _Allocator())
+ : range(std::forward<_Range2>(__range)), allocator(std::forward<_Allocator2>(__alloc)) {}
# endif
};
diff --git a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
index f18a3bc8c61bc0..5f63f090f45ff6 100644
--- a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
+++ b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
@@ -27,7 +27,7 @@ struct Range {
Iterator begin() { return Iterator(data_.data()); }
- sentinel_wrapper<Iterator> end() { return Sentinel(Iterator(data_.data() + data_.size())); }
+ Sentinel end() { return Sentinel(Iterator(data_.data() + data_.size())); }
private:
std::vector<int> data_ = {0, 1, 2, 3};
>From 5ca60028e46828fe50715994f58f0b6b23563575 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Sun, 10 Nov 2024 13:03:11 -0500
Subject: [PATCH 36/38] [libc++][ranges] implement 'ranges::elements_of'
---
libcxx/include/__ranges/elements_of.h | 13 -------------
.../range.elementsof/ctad.compile.pass.cpp | 4 ----
.../range.elementsof/elements_of.pass.cpp | 6 +-----
3 files changed, 1 insertion(+), 22 deletions(-)
diff --git a/libcxx/include/__ranges/elements_of.h b/libcxx/include/__ranges/elements_of.h
index 415565e813f397..668bd23d0ff7fb 100644
--- a/libcxx/include/__ranges/elements_of.h
+++ b/libcxx/include/__ranges/elements_of.h
@@ -33,22 +33,9 @@ template <range _Range, class _Allocator = allocator<byte>>
struct elements_of {
_LIBCPP_NO_UNIQUE_ADDRESS _Range range;
_LIBCPP_NO_UNIQUE_ADDRESS _Allocator allocator = _Allocator();
-
-# if !defined(__cpp_aggregate_paren_init)
- // This explicit constructor is required because AppleClang 15 hasn't
- // implemented P0960R3.
- template <std::ranges::range _Range2, class _Allocator2 = std::allocator<byte>>
- _LIBCPP_HIDE_FROM_ABI explicit constexpr elements_of(_Range2&& __range, _Allocator2&& __alloc = _Allocator())
- : range(std::forward<_Range2>(__range)), allocator(std::forward<_Allocator2>(__alloc)) {}
-# endif
};
template <class _Range, class _Allocator = allocator<byte>>
-# if defined(_LIBCPP_COMPILER_CLANG_BASED) && defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER < 1600
-// This explicit constraint is required because AppleClang 15 might not deduce
-// the correct type for `_Range` without it.
- requires range<_Range&&>
-# endif
elements_of(_Range&&, _Allocator = _Allocator()) -> elements_of<_Range&&, _Allocator>;
} // namespace ranges
diff --git a/libcxx/test/std/ranges/range.utility/range.elementsof/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.utility/range.elementsof/ctad.compile.pass.cpp
index 0f9204a07118ee..5e7eeb831ba776 100644
--- a/libcxx/test/std/ranges/range.utility/range.elementsof/ctad.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.utility/range.elementsof/ctad.compile.pass.cpp
@@ -41,15 +41,11 @@ constexpr bool test() {
static_assert(std::same_as<decltype(std::ranges::elements_of(Range<Iterator>(), Allocator())),
std::ranges::elements_of<Range<Iterator>&&, Allocator>>);
-// AppleClang 15 hasn't implemented P0960R3 and P1816R0
-#if defined(__cpp_aggregate_paren_init) && __cpp_aggregate_paren_init >= 201902L && defined(__cpp_deduction_guides) && \
- __cpp_deduction_guides >= 201907L
static_assert(std::same_as<decltype(std::ranges::elements_of{.range = r, .allocator = a}),
std::ranges::elements_of<Range<Iterator>&, Allocator>>);
static_assert(
std::same_as<decltype(std::ranges::elements_of{.range = Range<Iterator>(), .allocator = Allocator()}),
std::ranges::elements_of<Range<Iterator>&&, Allocator>>);
-#endif
});
});
diff --git a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
index 5f63f090f45ff6..e7bf9098881abd 100644
--- a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
+++ b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
@@ -48,10 +48,7 @@ constexpr bool test_range() {
[[maybe_unused]] std::same_as<Allocator> decltype(auto) elements_of_allocator = elements_of.allocator;
}
{
-// designated initializer
-// AppleClang 15 hasn't implemented P0960R3 and P1816R0
-#if defined(__cpp_aggregate_paren_init) && __cpp_aggregate_paren_init >= 201902L && defined(__cpp_deduction_guides) && \
- __cpp_deduction_guides >= 201907L
+ // designated initializer
std::same_as<elements_of_t> decltype(auto) elements_of = std::ranges::elements_of{
.range = r,
.allocator = Allocator(),
@@ -61,7 +58,6 @@ constexpr bool test_range() {
assert(std::ranges::distance(elements_of_range) == 4);
}
[[maybe_unused]] std::same_as<Allocator> decltype(auto) elements_of_allocator = elements_of.allocator;
-#endif
}
{
// copy constructor
>From 2e11e4359bb8606668c37542db5668d134269ffc Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Sun, 10 Nov 2024 15:43:17 -0500
Subject: [PATCH 37/38] [libc++][ranges] implement 'ranges::elements_of'
---
libcxx/test/libcxx/transitive_includes/cxx23.csv | 1 +
libcxx/test/libcxx/transitive_includes/cxx26.csv | 1 +
2 files changed, 2 insertions(+)
diff --git a/libcxx/test/libcxx/transitive_includes/cxx23.csv b/libcxx/test/libcxx/transitive_includes/cxx23.csv
index 854ad1b5df6f1e..143949088a50ad 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx23.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx23.csv
@@ -882,6 +882,7 @@ random version
ranges cctype
ranges compare
ranges concepts
+ranges cstddef
ranges cstdint
ranges cstdio
ranges cstring
diff --git a/libcxx/test/libcxx/transitive_includes/cxx26.csv b/libcxx/test/libcxx/transitive_includes/cxx26.csv
index ba2faaee5e3757..4cd7f6df79e578 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx26.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv
@@ -881,6 +881,7 @@ random version
ranges cctype
ranges compare
ranges concepts
+ranges cstddef
ranges cstdint
ranges cstdio
ranges cstring
>From 0587a50302dbca0fc25b03048d34cc56deb388ae Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Sun, 1 Dec 2024 15:55:54 -0500
Subject: [PATCH 38/38] [libc++] implement 'std::generator'
---
.../range.elementsof/elements_of.pass.cpp | 25 -------------------
1 file changed, 25 deletions(-)
diff --git a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
index 5ea61afc712db0..e7bf9098881abd 100644
--- a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
+++ b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
@@ -14,24 +14,6 @@
#include <concepts>
#include <memory>
-<<<<<<< HEAD
-#include <vector>
-
-constexpr bool test() {
- {
- auto elements_of = std::ranges::elements_of(std::vector<int>());
- static_assert(
- std::same_as<decltype(elements_of), std::ranges::elements_of<std::vector<int>&&, std::allocator<std::byte>>>);
- static_assert(std::same_as<decltype(elements_of.range), std::vector<int>&&>);
- static_assert(std::same_as<decltype(elements_of.allocator), std::allocator<std::byte>>);
- }
- {
- auto elements_of = std::ranges::elements_of(std::vector<int>(), std::allocator<int>());
- static_assert(
- std::same_as<decltype(elements_of), std::ranges::elements_of<std::vector<int>&&, std::allocator<int>>>);
- static_assert(std::same_as<decltype(elements_of.range), std::vector<int>&&>);
- static_assert(std::same_as<decltype(elements_of.allocator), std::allocator<int>>);
-=======
#include <type_traits>
#include <vector>
@@ -102,16 +84,10 @@ constexpr bool test_range() {
assert(std::ranges::distance(elements_of_2_range) == 4);
}
[[maybe_unused]] std::same_as<Allocator> decltype(auto) elements_of_2_allocator = elements_of_2.allocator;
->>>>>>> elements_of
}
return true;
}
-<<<<<<< HEAD
-int main() {
- test();
- static_assert(test());
-=======
constexpr bool test() {
types::for_each(types::type_list<std::allocator<std::byte>, min_allocator<std::byte>, test_allocator<std::byte>>{},
[]<class Allocator> {
@@ -128,5 +104,4 @@ int main(int, char**) {
static_assert(test());
return 0;
->>>>>>> elements_of
}
More information about the libcxx-commits
mailing list