[libcxx-commits] [libcxx] [libc++] P2502R2: `std::generator` (PR #92213)

Xiaoyang Liu via libcxx-commits libcxx-commits at lists.llvm.org
Tue May 14 21:25:57 PDT 2024


https://github.com/xiaoyang-sde created https://github.com/llvm/llvm-project/pull/92213

## Introduction

This patch attempts to implement `std::generator` from [P2502R2](https://wg21.link/P2502R2). `std::generator` is a view that represents a recursive coroutine-based generator.

```cpp
std::generator<int> fib() {
  int a = 0;
  int b = 1;
  while (true) {
    co_yield std::exchange(a, std::exchange(b, a + b));
  }
}

auto fib_vec = fib() | std::views::take(5) | std::ranges::to<std::vector<int>>();
```

As of 05/14/2024, this patch is in its initial phase. During this stage, the `std::generator::<Ref, V, Allocator>::promise_type` does not include the overloads for `void* operator new()`. Therefore, the coroutine frame will be allocated using the default allocator, disregarding the `Allocator` template parameter. This decision was deliberate, as the absent functionalities are independent of the existing code. Therefore, reviewers can review this patch through multiple stages.

## Implementation

In practice, each generator owns a coroutine. The coroutine uses the `co_yield` statement to produce values for its consumer. Its `begin()` method returns an iterator with access to the coroutine handle.

- When the iterator is incremented, the coroutine resumes execution until encountering a `co_yield` statement, at which point it suspends, storing the address of the yielded value within its promise.
- When the iterator is dereferenced, it obtains a reference to the coroutine's promise through the coroutine handle and then returns a reference to the yielded value.

If the generator can't be recursive and doesn't support custom allocators, it can be implemented in fewer than 100 lines. It's recommended to understand how it works before proceeding. The code is available on [Compiler Explorer](https://godbolt.org/z/jY6TTfsKa).

Complexities arise when the generator can be recursive. It should be able to yield another generator, which in turn can yield another generator, and so forth. For example, this capability is useful in implementing a lazily-evaluated tree traversal algorithm:

```cpp
struct tree_node {
  tree_node* left;
  tree_node* right;
  int element;
};

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));
}
```

To illustrate the implementation, consider a scenario where generator `A` yields another generator `B`, which in turn yields a generator `C`. Here, `A` is the root generator because the client code has access to its iterator, while `B` and `C` are recursive generators. Due to the lazily-evaluated nature of generators, `A` cannot consume all elements of `B` at once, store them in a container, and yield them individually. Instead, when the iterator of `A` is incremented, it should directly resume the coroutine of `C` and transfer control back to the client code once `C`'s coroutine has yielded a value.

The client code only has access to `A`'s iterator, which doesn't know the existence of `B` and `C`. Consequently, `B` and `C` are responsible for writing their yielded values to `A`'s promise, which will subsequently be returned to the client code upon dereferencing `A`'s iterator. When incrementing `A`'s iterator, merely resuming `A`'s coroutine is insufficient, as `B`'s or `C`'s coroutine might still be yielding values. Consequently, `A`'s promise must store the coroutine handle of the currently active coroutine, which will be resumed upon incrementing `A`'s iterator.

```cpp
struct __root_data {
  add_pointer_t<_Yielded> __value_ptr;
  std::coroutine_handle<__gen_promise_base> __active;
};
```

The promise type of `B` and `C` needs to store the coroutine handle of its parent, allowing the transfer of control back to the parent upon completion. Additionally, it must store the coroutine handle of its root generator, as it's responsible for writing the address of the yielded value to the root generator's promise, as explained earlier.

```cpp
struct __recursive_data {
  std::coroutine_handle<__gen_promise_base> __parent;
  std::coroutine_handle<__gen_promise_base> __root;
};
```

Given that a generator can be either a root generator (`A`) or a recursive generator (`B` and `C`), the promise type can use a tagged union to store the required data based on the generator's type. (In practice, additional fields are included to enable the propagation of exceptions out of recursive generators.)

```cpp
template <class _Yielded>
class __gen_promise_base {
private:
  /* ... */

  union __union {
    __root_data __root;
    __recursive_data __recursive;
  } __data_;

  bool __tag_;

  /* ... */
}
```

Given the information provided, it would be easier to read the code. Complicated logics, such as transferring control from a recursive generator to its parent, are well-documented in the code.

## Reference

- [P2502R2: `std::generator`: Synchronous Coroutine Generator for Ranges](https://wg21.link/P2502R2)
- [[coro.generator]](https://eel.is/c++draft/coro.generator)

>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/26] [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 fd7eb125e007b..b1f9be1dc3d7d 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 0000000000000..727ba92666eb3
--- /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 07a525ed8641f..a8fbfc462bf0d 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 80f31c79a1a40..94f3defdcbc35 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 0000000000000..e1c2f91b96079
--- /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/26] [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 727ba92666eb3..d7cb1937563c6 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/26] [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 e1c2f91b96079..378bcb0a2f13f 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/26] [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 2974d12500c4c..ee952c48c11d5 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/26] [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 d7cb1937563c6..6219446a742a8 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/26] [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 6219446a742a8..043bcb918a692 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/26] [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 043bcb918a692..93020c93d5f7b 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/26] [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 93020c93d5f7b..edce0af345f37 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 7cec4cac116e3d4745bfa9d7b29c80d051a4b5ec 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 09/26] [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 96d7b4037e106..df30145751f17 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 0000000000000..727ba92666eb3
--- /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 07a525ed8641f..a8fbfc462bf0d 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 f71efe948ede1..82055c2ddbfbb 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 0000000000000..e1c2f91b96079
--- /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 915cd7ada8810c2eca9d506ab7e04ae68029abd3 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 10/26] [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 727ba92666eb3..d7cb1937563c6 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 222d5d78f5a8666b015563caf6ca97d961ce02a1 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 11/26] [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 e1c2f91b96079..378bcb0a2f13f 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 fb3c4f616ffd436a7249e7cd51c6b9403d7d737e 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 12/26] [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 0ee0cdce61bc0..421963e0bc9a8 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 f7d235bc28b925a45ae2d4a517c3d14b75bee8ae 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 13/26] [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 d7cb1937563c6..6219446a742a8 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 3078e338678568e68b5cf5aed5f91ef733b374c7 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 14/26] [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 6219446a742a8..043bcb918a692 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 6ff45ee4f3eb1a00f0ba5055565f621d15934109 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 15/26] [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 043bcb918a692..93020c93d5f7b 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 e3d85f9e1366b06fc88fe620f85fc0024e7a3c9b 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 16/26] [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 93020c93d5f7b..edce0af345f37 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 2ef95185adc17ce4ccce1c175f0c7739e67122cd Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Wed, 8 May 2024 17:00:41 -0400
Subject: [PATCH 17/26] [libc++] implement 'std::generator'

---
 libcxx/include/generator | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)
 create mode 100644 libcxx/include/generator

diff --git a/libcxx/include/generator b/libcxx/include/generator
new file mode 100644
index 0000000000000..dbb001c6be39f
--- /dev/null
+++ b/libcxx/include/generator
@@ -0,0 +1,29 @@
+// -*- 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 <__config>
+
+#if _LIBCPP_STD_VER >= 23
+
+#include <__ranges/elements_of.h>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+#endif

>From 346b58d5838bdcec055851a9ce3e1edfa15bf321 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Thu, 9 May 2024 10:19:16 -0400
Subject: [PATCH 18/26] [libc++] implement 'std::generator'

---
 libcxx/include/generator | 76 ++++++++++++++++++++++++++++++++++++++--
 1 file changed, 74 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/generator b/libcxx/include/generator
index dbb001c6be39f..479e8b19ea678 100644
--- a/libcxx/include/generator
+++ b/libcxx/include/generator
@@ -11,13 +11,85 @@
 #define _LIBCPP_GENERATOR
 
 #include <__config>
+#include <__coroutine/coroutine_handle.h>
+#include <__iterator/default_sentinel.h>
+#include <__ranges/elements_of.h>
+#include <__ranges/view_interface.h>
+#include <__type_traits/conditional.h>
+#include <__type_traits/is_nothrow_constructible.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
 
-#include <__ranges/elements_of.h>
-
 _LIBCPP_BEGIN_NAMESPACE_STD
 
+template <class _Ref, class _Val = void, class _Allocator = void>
+class generator : public ranges::view_interface<generator<_Ref, _Val, _Allocator>> {
+private:
+  using __value_t = conditional_t<is_void_v<_Val>, remove_cvref_t<_Ref>, _Val>;
+
+  using __reference_t = conditional_t<is_void_v<_Val>, _Ref&&, _Ref>;
+
+  class __iterator;
+
+public:
+  using yielded = conditional_t<is_reference_v<__reference_t>, __reference_t, const __reference_t&>;
+
+  class promise_type;
+
+  _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 __iterator begin() { __coroutine_.resume(); }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI default_sentinel_t end() const noexcept { return default_sentinel; }
+
+private:
+  coroutine_handle<promise_type> __coroutine_ = nullptr;
+};
+
+template <class _Ref, class _Val, class _Allocator>
+class generator<_Ref, _Val, _Allocator>::__iterator {
+public:
+  using value_type      = __value_t;
+  using difference_type = ptrdiff_t;
+
+  __iterator(__iterator&& __other) noexcept : __coroutine_(std::exchange(__other.__coroutine_, {})) {}
+
+  __iterator& operator=(__iterator&& __other) noexcept {
+    __coroutine_ = std::exchange(__other.__coroutine_, {});
+    return *this;
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __reference_t operator*() const
+      noexcept(is_nothrow_copy_constructible_v<__reference_t>);
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __iterator& operator++();
+
+  _LIBCPP_HIDE_FROM_ABI void operator++(int) { ++*this; }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool operator==(default_sentinel_t) { return __coroutine_.done(); }
+
+private:
+  coroutine_handle<promise_type> __coroutine_;
+};
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif

>From 1e234cfb034f9c7aff18abf1f3c45c6cefb3b683 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Fri, 10 May 2024 16:15:25 -0400
Subject: [PATCH 19/26] [libc++] implement 'std::generator'

---
 libcxx/include/generator | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/libcxx/include/generator b/libcxx/include/generator
index 479e8b19ea678..01a46139d9f58 100644
--- a/libcxx/include/generator
+++ b/libcxx/include/generator
@@ -10,9 +10,11 @@
 #ifndef _LIBCPP_GENERATOR
 #define _LIBCPP_GENERATOR
 
+#include <__concepts/constructible.h>
 #include <__config>
 #include <__coroutine/coroutine_handle.h>
 #include <__iterator/default_sentinel.h>
+#include <__memory/allocator_traits.h>
 #include <__ranges/elements_of.h>
 #include <__ranges/view_interface.h>
 #include <__type_traits/conditional.h>
@@ -27,6 +29,24 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
+struct alignas(__STDCPP_DEFAULT_NEW_ALIGNMENT__) __aligned_block {
+  unsigned char data[__STDCPP_DEFAULT_NEW_ALIGNMENT__];
+};
+
+template <class _Allocator = void>
+class __coroutine_allocator {
+private:
+  using __alloc_t = __rebind_alloc<_Allocator, __aligned_block>::type;
+
+  static void* __allocate(__alloc_t __allocator, const size_t __size) {
+    if constexpr (default_initializable<__alloc_t> && allocator_traits<__alloc_t>::is_always_equal::value) {
+      
+    }
+  }
+
+public:
+};
+
 template <class _Ref, class _Val = void, class _Allocator = void>
 class generator : public ranges::view_interface<generator<_Ref, _Val, _Allocator>> {
 private:

>From 67ca477791ec9843e57568805f226f78c6cf6de7 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Sun, 12 May 2024 12:48:16 -0400
Subject: [PATCH 20/26] [libc++] implement 'std::generator'

---
 libcxx/include/generator | 273 ++++++++++++++++++++++++++++++++++-----
 1 file changed, 244 insertions(+), 29 deletions(-)

diff --git a/libcxx/include/generator b/libcxx/include/generator
index 01a46139d9f58..726a0a9310ed7 100644
--- a/libcxx/include/generator
+++ b/libcxx/include/generator
@@ -13,10 +13,14 @@
 #include <__concepts/constructible.h>
 #include <__config>
 #include <__coroutine/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_traits.h>
 #include <__ranges/elements_of.h>
 #include <__ranges/view_interface.h>
+#include <__type_traits/add_pointer.h>
 #include <__type_traits/conditional.h>
 #include <__type_traits/is_nothrow_constructible.h>
 #include <__type_traits/is_reference.h>
@@ -24,6 +28,9 @@
 #include <__type_traits/remove_cvref.h>
 #include <__utility/exchange.h>
 #include <__utility/swap.h>
+#include <coroutine>
+#include <exception>
+#include <variant>
 
 #if _LIBCPP_STD_VER >= 23
 
@@ -40,76 +47,284 @@ private:
 
   static void* __allocate(__alloc_t __allocator, const size_t __size) {
     if constexpr (default_initializable<__alloc_t> && allocator_traits<__alloc_t>::is_always_equal::value) {
-      
     }
   }
 
 public:
 };
 
-template <class _Ref, class _Val = void, class _Allocator = void>
-class generator : public ranges::view_interface<generator<_Ref, _Val, _Allocator>> {
+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:
-  using __value_t = conditional_t<is_void_v<_Val>, remove_cvref_t<_Ref>, _Val>;
+  // todo(delete me): root <-> nested <-> nested
+  // outmost gen yield nested gen yield nested gen
+  // outmost gen promise should know inner-most gen, so ++iter can resume the inner-most gen directly
+  // inner-most gen should know parent gen, so it can resume parent gen when it final_await
+  // inner-most gen should know root gen, so it can resume root gen when it yield_value, because *iter access the
+  // inner-most gen
+
+  // root: value, active
+  // nested: parent, bottom, exception
+
+  struct __promise_data;
+
+  class __root_frame {
+    add_pointer_t<_Yielded> __value_ptr_ = nullptr;
+    std::coroutine_handle<__gen_promise_base> __active_coroutine_ =
+        coroutine_handle<__gen_promise_base>::from_promise(*this);
+  };
+
+  class __nested_frame {
+    std::coroutine_handle<__gen_promise_base> __parent_coroutine_;
+    std::coroutine_handle<__gen_promise_base> __root_coroutine_;
+    std::exception_ptr __exception_;
+  };
+
+  std::variant<__root_frame, __nested_frame> __frame_state_;
+
+  __root_frame* __get_root_frame() { return std::get_if<__root_frame>(__frame_state_); }
+
+  __nested_frame* __get_nested_frame() { return std::get_if<__nested_frame>(__frame_state_); }
+  void __set_nested_frame() { __frame_state_ = __nested_frame{}; }
+
+  class __element_awaiter {
+  public:
+    [[nodiscard]] constexpr bool await_ready() const noexcept { return false; }
+
+    template <class _Promise>
+    constexpr void await_suspend(coroutine_handle<_Promise> __handle) noexcept {
+      __handle.promise().__value_ptr_ = std::addressof(__value_);
+    }
+
+    constexpr void await_resume() const noexcept {}
+
+  private:
+    remove_cvref_t<_Yielded> __value_;
+  };
+
+  class __final_awaiter {
+  public:
+    [[nodiscard]] constexpr bool await_ready() const noexcept { return false; }
+
+    template <class _Promise>
+    constexpr coroutine_handle<> await_suspend(coroutine_handle<_Promise> __handle) noexcept {
+      if (auto __nested_frame = __handle.promise().__get_nested_frame()) {
+        auto __parent_coroutine          = __nested_frame.__parent_coroutine_;
+        auto __root_frame                = __nested_frame.__root_coroutine_.promise().__get_root_frame();
+        __root_frame.__active_coroutine_ = __parent_coroutine;
+        return __parent_coroutine;
+      }
+      return std::noop_coroutine();
+    }
+
+    constexpr void await_resume() const noexcept {}
+  };
+
+  template <class _Ref, class _Val, class _Allocator>
+  class __nested_awaiter {
+  private:
+    generator<_Ref, _Val, _Allocator> __gen_;
+
+  public:
+    explicit __nested_awaiter(generator<_Ref, _Val, _Allocator>&& __gen) noexcept : __gen_(std::move(__gen)) {}
 
-  using __reference_t = conditional_t<is_void_v<_Val>, _Ref&&, _Ref>;
+    [[nodiscard]] constexpr bool await_ready() const noexcept { return !__gen_.__coroutine_; }
 
-  class __iterator;
+    template <class _Promise>
+    constexpr coroutine_handle<__gen_promise_base> await_suspend(coroutine_handle<_Promise> __current) noexcept {
+      auto __nested = coroutine_handle<__gen_promise_base>::from_address(__gen_.__coroutine_.address());
+      __nested.__set_nested_frame();
+
+      auto __nested_frame                = __nested.promise().__get_nested_frame();
+      __nested_frame.__parent_coroutine_ = coroutine_handle<__gen_promise_base>::from_address(__current.address());
+      if (auto __parent_nested_frame = __nested_frame.__parent_coroutine_.promise().__get_nested_frame()) {
+        __nested_frame.__root_coroutine_ = __parent_nested_frame.__root_coroutine_;
+      } else {
+        __nested_frame.__root_coroutine_ = __nested_frame.__parent_coroutine_;
+      }
+
+      auto __root_frame                = __nested_frame.__root_coroutine_.promise().__get_root_frame();
+      __root_frame.__active_coroutine_ = __nested;
+
+      return __nested;
+    }
+
+    void await_resume() {
+      auto __nested       = coroutine_handle<__gen_promise_base>::from_address(__gen_.__coroutine_.address());
+      auto __nested_frame = __nested.promise().__get_nested_frame();
+      if (__nested_frame.__exception_) {
+        std::rethrow_exception(std::move(__nested_frame.__exception_));
+      }
+    }
+  };
 
 public:
-  using yielded = conditional_t<is_reference_v<__reference_t>, __reference_t, const __reference_t&>;
+  suspend_always initial_suspend() const noexcept { return {}; }
 
-  class promise_type;
+  auto final_suspend() noexcept { return __final_awaiter{}; }
 
-  _LIBCPP_HIDE_FROM_ABI generator(const generator&) = delete;
-  _LIBCPP_HIDE_FROM_ABI generator(generator&& __other) noexcept
-      : __coroutine_(std::exchange(__other.__coroutine_, {})) {}
+  suspend_always yield_value(_Yielded __val) noexcept {
+    std::get_if<__root_frame>(__frame_state_)->__value_ptr = addressof(__val);
+    return {};
+  }
 
-  _LIBCPP_HIDE_FROM_ABI ~generator() {
-    if (__coroutine_) {
-      __coroutine_.destroy();
+  auto yield_value(const remove_reference_t<_Yielded>& __val)
+    requires is_rvalue_reference_v<_Yielded> &&
+             constructible_from<remove_cvref_t<_Yielded>, const remove_reference_t<_Yielded>&>
+  {
+    return __element_awaiter(__val);
+  }
+
+  void await_transform() = delete;
+
+  void return_void() const noexcept {}
+
+  void unhandled_exception() {
+    if (auto __nested_frame = __get_nested_frame()) {
+      __nested_frame.exception_ptr = std::current_exception();
+    } else {
+      throw;
     }
   }
+};
 
-  _LIBCPP_HIDE_FROM_ABI generator& operator=(generator __other) noexcept {
-    std::swap(__coroutine_, __other.__coroutine_);
-    return *this;
+template <class _Yielded>
+struct __gen_promise_base<_Yielded>::__promise_data {
+  using __value_ptr_t = add_pointer_t<_Yielded>;
+
+  struct __root_data {
+    __value_ptr_t __value_ptr;
+    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 {
+    __root_data __root;
+    __recursive_data __recursive;
+  } __data;
+  bool __tag = false;
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool __is_root() noexcept { return !__tag; }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool __is_recursive() noexcept { return __tag; }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __root_data* __get_root_data() noexcept {
+    // assert(__is_root());
+    return __data.__root;
   }
 
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __iterator begin() { __coroutine_.resume(); }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __root_data* __get_recursive_data() noexcept {
+    // assert(__is_recursive());
+    return __data.__recursive;
+  }
 
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI default_sentinel_t end() const noexcept { return default_sentinel; }
+  // [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __value_ptr_t& __value_ptr() noexcept {
+  //   return __data.__root.__value_ptr;
+  // }
 
-private:
-  coroutine_handle<promise_type> __coroutine_ = nullptr;
+  // [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __value_ptr_t& __root_value_ptr() noexcept {
+  //   if (__is_root()) {
+
+  //   }
+  //   return __data.__recursive.__root.promise().__data.__root.__value_ptr;
+  // }
 };
 
-template <class _Ref, class _Val, class _Allocator>
-class generator<_Ref, _Val, _Allocator>::__iterator {
+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      = __value_t;
+  using value_type      = __val;
   using difference_type = ptrdiff_t;
 
-  __iterator(__iterator&& __other) noexcept : __coroutine_(std::exchange(__other.__coroutine_, {})) {}
+  struct promise_type {};
+
+  __gen_iter(__gen_iter&& __other) noexcept : __coroutine_(std::exchange(__other.__coroutine_, {})) {}
 
-  __iterator& operator=(__iterator&& __other) noexcept {
+  __gen_iter& operator=(__gen_iter&& __other) noexcept {
     __coroutine_ = std::exchange(__other.__coroutine_, {});
     return *this;
   }
 
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __reference_t operator*() const
-      noexcept(is_nothrow_copy_constructible_v<__reference_t>);
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __ref operator*() const noexcept(is_nothrow_copy_constructible_v<__ref>) {
+    // todo: return static_cast<__reference_t>();
+  }
 
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __iterator& operator++();
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __gen_iter& operator++() {
+    // todo
+  }
 
   _LIBCPP_HIDE_FROM_ABI void operator++(int) { ++*this; }
 
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool operator==(default_sentinel_t) { return __coroutine_.done(); }
 
 private:
+  _LIBCPP_HIDE_FROM_ABI explicit __gen_iter(coroutine_handle<promise_type> __coroutine) noexcept
+      : __coroutine_(std::move(__coroutine)) {}
+
   coroutine_handle<promise_type> __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>;
+
+  using __ref = __gen_ref<_Ref, _Val>;
+
+  friend __gen_iter<_Ref, _Val>;
+
+public:
+  using yielded = __gen_yielded<_Ref, _Val>;
+
+  class promise_type;
+
+  _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() {
+    __coroutine_.resume();
+    return __gen_iter(__coroutine_);
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI default_sentinel_t end() const noexcept { return default_sentinel; }
+
+private:
+  coroutine_handle<promise_type> __coroutine_ = nullptr;
+};
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif

>From eccf9f856c1e2f85f0e55578120ee2a5e3dc15f8 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Sun, 12 May 2024 13:36:19 -0400
Subject: [PATCH 21/26] [libc++] implement 'std::generator'

---
 libcxx/include/generator | 169 ++++++++++++++++-----------------------
 1 file changed, 68 insertions(+), 101 deletions(-)

diff --git a/libcxx/include/generator b/libcxx/include/generator
index 726a0a9310ed7..36715fb9e3866 100644
--- a/libcxx/include/generator
+++ b/libcxx/include/generator
@@ -10,9 +10,11 @@
 #ifndef _LIBCPP_GENERATOR
 #define _LIBCPP_GENERATOR
 
+#include <__assert>
 #include <__concepts/constructible.h>
 #include <__config>
 #include <__coroutine/coroutine_handle.h>
+#include <__coroutine/noop_coroutine_handle.h>
 #include <__coroutine/trivial_awaitables.h>
 #include <__exception/exception_ptr.h>
 #include <__iterator/default_sentinel.h>
@@ -28,9 +30,6 @@
 #include <__type_traits/remove_cvref.h>
 #include <__utility/exchange.h>
 #include <__utility/swap.h>
-#include <coroutine>
-#include <exception>
-#include <variant>
 
 #if _LIBCPP_STD_VER >= 23
 
@@ -69,44 +68,56 @@ class generator;
 template <class _Yielded>
 class __gen_promise_base {
 private:
-  // todo(delete me): root <-> nested <-> nested
-  // outmost gen yield nested gen yield nested gen
-  // outmost gen promise should know inner-most gen, so ++iter can resume the inner-most gen directly
-  // inner-most gen should know parent gen, so it can resume parent gen when it final_await
-  // inner-most gen should know root gen, so it can resume root gen when it yield_value, because *iter access the
-  // inner-most gen
-
-  // root: value, active
-  // nested: parent, bottom, exception
-
-  struct __promise_data;
-
-  class __root_frame {
-    add_pointer_t<_Yielded> __value_ptr_ = nullptr;
-    std::coroutine_handle<__gen_promise_base> __active_coroutine_ =
-        coroutine_handle<__gen_promise_base>::from_promise(*this);
+  struct __root_data {
+    add_pointer_t<_Yielded> __value_ptr;
+    std::coroutine_handle<__gen_promise_base> __active;
   };
 
-  class __nested_frame {
-    std::coroutine_handle<__gen_promise_base> __parent_coroutine_;
-    std::coroutine_handle<__gen_promise_base> __root_coroutine_;
-    std::exception_ptr __exception_;
+  struct __recursive_data {
+    std::exception_ptr __exception;
+    std::coroutine_handle<__gen_promise_base> __parent;
+    std::coroutine_handle<__gen_promise_base> __root;
   };
 
-  std::variant<__root_frame, __nested_frame> __frame_state_;
+  union {
+    __root_data __root;
+    __recursive_data __recursive;
+  } __data_;
+  bool __tag_ = false;
+
+  [[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(), "todo");
+    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(), "todo");
+    return &__data_.__recursive;
+  }
+  _LIBCPP_HIDE_FROM_ABI void __set_recursive_tag() noexcept { __tag_ = true; }
 
-  __root_frame* __get_root_frame() { return std::get_if<__root_frame>(__frame_state_); }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI add_pointer_t<_Yielded>& __value_ptr() noexcept {
+    _LIBCPP_ASSERT_INTERNAL(__is_root(), "todo");
+    return __data_.__get_root_data().__value_ptr;
+  }
 
-  __nested_frame* __get_nested_frame() { return std::get_if<__nested_frame>(__frame_state_); }
-  void __set_nested_frame() { __frame_state_ = __nested_frame{}; }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI add_pointer_t<_Yielded>& __root_value_ptr() noexcept {
+    if (__data_.__is_root()) {
+      return __value_ptr();
+    }
+    return __data_.__get_recursive_data().__root.promise().__value_ptr();
+  }
 
   class __element_awaiter {
   public:
     [[nodiscard]] constexpr bool await_ready() const noexcept { return false; }
 
     template <class _Promise>
-    constexpr void await_suspend(coroutine_handle<_Promise> __handle) noexcept {
-      __handle.promise().__value_ptr_ = std::addressof(__value_);
+    constexpr void await_suspend(coroutine_handle<_Promise> __current) noexcept {
+      __current.promise().__root_value_ptr() = std::addressof(__value_);
     }
 
     constexpr void await_resume() const noexcept {}
@@ -120,12 +131,13 @@ private:
     [[nodiscard]] constexpr bool await_ready() const noexcept { return false; }
 
     template <class _Promise>
-    constexpr coroutine_handle<> await_suspend(coroutine_handle<_Promise> __handle) noexcept {
-      if (auto __nested_frame = __handle.promise().__get_nested_frame()) {
-        auto __parent_coroutine          = __nested_frame.__parent_coroutine_;
-        auto __root_frame                = __nested_frame.__root_coroutine_.promise().__get_root_frame();
-        __root_frame.__active_coroutine_ = __parent_coroutine;
-        return __parent_coroutine;
+    constexpr coroutine_handle<> await_suspend(coroutine_handle<_Promise> __current) noexcept {
+      if (__current.promise().__is_recursive()) {
+        auto __recursive_data = __current.promise().__get_recursive_data();
+        auto __parent         = __recursive_data.__parent;
+        auto __root_data      = __recursive_data.__root.promise().__get_root_data();
+        __root_data.__active  = __parent;
+        return __parent;
       }
       return std::noop_coroutine();
     }
@@ -145,28 +157,28 @@ private:
 
     template <class _Promise>
     constexpr coroutine_handle<__gen_promise_base> await_suspend(coroutine_handle<_Promise> __current) noexcept {
-      auto __nested = coroutine_handle<__gen_promise_base>::from_address(__gen_.__coroutine_.address());
-      __nested.__set_nested_frame();
-
-      auto __nested_frame                = __nested.promise().__get_nested_frame();
-      __nested_frame.__parent_coroutine_ = coroutine_handle<__gen_promise_base>::from_address(__current.address());
-      if (auto __parent_nested_frame = __nested_frame.__parent_coroutine_.promise().__get_nested_frame()) {
-        __nested_frame.__root_coroutine_ = __parent_nested_frame.__root_coroutine_;
+      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();
+
+      auto __parent              = coroutine_handle<__gen_promise_base>::from_address(__current.address());
+      __recursive_data.__parent_ = __parent;
+      if (__parent.__is_recursive()) {
+        __recursive_data.__root = __parent.promise().__get_recursive_data().__root;
       } else {
-        __nested_frame.__root_coroutine_ = __nested_frame.__parent_coroutine_;
+        __recursive_data.__root = __parent;
       }
 
-      auto __root_frame                = __nested_frame.__root_coroutine_.promise().__get_root_frame();
-      __root_frame.__active_coroutine_ = __nested;
-
-      return __nested;
+      auto __root_data     = __recursive_data.__root.promise().__get_root_data();
+      __root_data.__active = __recursive;
+      return __recursive;
     }
 
     void await_resume() {
-      auto __nested       = coroutine_handle<__gen_promise_base>::from_address(__gen_.__coroutine_.address());
-      auto __nested_frame = __nested.promise().__get_nested_frame();
-      if (__nested_frame.__exception_) {
-        std::rethrow_exception(std::move(__nested_frame.__exception_));
+      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));
       }
     }
   };
@@ -177,7 +189,7 @@ public:
   auto final_suspend() noexcept { return __final_awaiter{}; }
 
   suspend_always yield_value(_Yielded __val) noexcept {
-    std::get_if<__root_frame>(__frame_state_)->__value_ptr = addressof(__val);
+    __root_value_ptr() = addressof(__val);
     return {};
   }
 
@@ -193,60 +205,15 @@ public:
   void return_void() const noexcept {}
 
   void unhandled_exception() {
-    if (auto __nested_frame = __get_nested_frame()) {
-      __nested_frame.exception_ptr = std::current_exception();
-    } else {
+    if (__is_root()) {
       throw;
+    } else {
+      auto __recursive_data         = __get_recursive_data();
+      __recursive_data->__exception = std::current_exception();
     }
   }
 };
 
-template <class _Yielded>
-struct __gen_promise_base<_Yielded>::__promise_data {
-  using __value_ptr_t = add_pointer_t<_Yielded>;
-
-  struct __root_data {
-    __value_ptr_t __value_ptr;
-    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 {
-    __root_data __root;
-    __recursive_data __recursive;
-  } __data;
-  bool __tag = false;
-
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool __is_root() noexcept { return !__tag; }
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool __is_recursive() noexcept { return __tag; }
-
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __root_data* __get_root_data() noexcept {
-    // assert(__is_root());
-    return __data.__root;
-  }
-
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __root_data* __get_recursive_data() noexcept {
-    // assert(__is_recursive());
-    return __data.__recursive;
-  }
-
-  // [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __value_ptr_t& __value_ptr() noexcept {
-  //   return __data.__root.__value_ptr;
-  // }
-
-  // [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __value_ptr_t& __root_value_ptr() noexcept {
-  //   if (__is_root()) {
-
-  //   }
-  //   return __data.__recursive.__root.promise().__data.__root.__value_ptr;
-  // }
-};
-
 template <class _Ref, class _Val>
 class __gen_iter {
 private:

>From acef7d83c0ee7993db67e516f0a69d72ed754ce4 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Sun, 12 May 2024 17:55:52 -0400
Subject: [PATCH 22/26] [libc++] implement 'std::generator'

---
 libcxx/include/generator | 192 ++++++++++++++++++++++++---------------
 1 file changed, 119 insertions(+), 73 deletions(-)

diff --git a/libcxx/include/generator b/libcxx/include/generator
index 36715fb9e3866..58b01b031a2ac 100644
--- a/libcxx/include/generator
+++ b/libcxx/include/generator
@@ -12,6 +12,7 @@
 
 #include <__assert>
 #include <__concepts/constructible.h>
+#include <__concepts/convertible_to.h>
 #include <__config>
 #include <__coroutine/coroutine_handle.h>
 #include <__coroutine/noop_coroutine_handle.h>
@@ -19,7 +20,9 @@
 #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>
@@ -35,23 +38,6 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-struct alignas(__STDCPP_DEFAULT_NEW_ALIGNMENT__) __aligned_block {
-  unsigned char data[__STDCPP_DEFAULT_NEW_ALIGNMENT__];
-};
-
-template <class _Allocator = void>
-class __coroutine_allocator {
-private:
-  using __alloc_t = __rebind_alloc<_Allocator, __aligned_block>::type;
-
-  static void* __allocate(__alloc_t __allocator, const size_t __size) {
-    if constexpr (default_initializable<__alloc_t> && allocator_traits<__alloc_t>::is_always_equal::value) {
-    }
-  }
-
-public:
-};
-
 template <class _Ref, class _Val>
 using __gen_val = conditional_t<is_void_v<_Val>, remove_cvref_t<_Ref>, _Val>;
 
@@ -68,8 +54,19 @@ class generator;
 template <class _Yielded>
 class __gen_promise_base {
 private:
+  template <class, class, class>
+  friend class generator;
+
+  // 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;
   };
 
@@ -82,25 +79,39 @@ private:
   union {
     __root_data __root;
     __recursive_data __recursive;
-  } __data_;
+  } __data_ = __root_data{
+      .__value_ptr = nullptr,
+      .__active    = coroutine_handle<__gen_promise_base>::from_promise(*this).address(),
+  };
+
+  // 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` could only equal `nullptr` if the active member is
+  // `__root`.
   bool __tag_ = false;
 
   [[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(), "todo");
-    return &__data_.__root;
+    _LIBCPP_ASSERT_INTERNAL(__is_root(), "the active member of `__data_` is not `__root`");
+    return std::addressof(__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(), "todo");
-    return &__data_.__recursive;
+    _LIBCPP_ASSERT_INTERNAL(__is_recursive(), "the active member of `__data_` is not `__recursive`");
+    return std::addressof(__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 __data_.__get_root_data().__active;
+  }
+
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI add_pointer_t<_Yielded>& __value_ptr() noexcept {
-    _LIBCPP_ASSERT_INTERNAL(__is_root(), "todo");
+    _LIBCPP_ASSERT_INTERNAL(__is_root(), "the active member of `__data_` is not `__root`");
     return __data_.__get_root_data().__value_ptr;
   }
 
@@ -111,71 +122,77 @@ private:
     return __data_.__get_recursive_data().__root.promise().__value_ptr();
   }
 
-  class __element_awaiter {
-  public:
-    [[nodiscard]] constexpr bool await_ready() const noexcept { return false; }
+  struct __element_awaiter {
+    [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool await_ready() noexcept { return false; }
 
     template <class _Promise>
-    constexpr void await_suspend(coroutine_handle<_Promise> __current) noexcept {
-      __current.promise().__root_value_ptr() = std::addressof(__value_);
+    _LIBCPP_HIDE_FROM_ABI void await_suspend(coroutine_handle<_Promise> __current) noexcept {
+      __current.promise().__root_value_ptr() = std::addressof(__value);
     }
 
-    constexpr void await_resume() const noexcept {}
+    _LIBCPP_HIDE_FROM_ABI void await_resume() noexcept {}
 
-  private:
-    remove_cvref_t<_Yielded> __value_;
+    remove_cvref_t<_Yielded> __value;
   };
 
-  class __final_awaiter {
-  public:
-    [[nodiscard]] constexpr bool await_ready() const noexcept { return false; }
+  struct __final_awaiter {
+    [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool await_ready() noexcept { return false; }
 
     template <class _Promise>
-    constexpr coroutine_handle<> await_suspend(coroutine_handle<_Promise> __current) noexcept {
+    _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;
-        auto __root_data      = __recursive_data.__root.promise().__get_root_data();
-        __root_data.__active  = __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();
     }
 
-    constexpr void await_resume() const noexcept {}
+    _LIBCPP_HIDE_FROM_ABI void await_resume() noexcept {}
   };
 
   template <class _Ref, class _Val, class _Allocator>
-  class __nested_awaiter {
-  private:
-    generator<_Ref, _Val, _Allocator> __gen_;
+  struct __recursive_awaiter {
+    generator<_Ref, _Val, _Allocator> __gen;
 
-  public:
-    explicit __nested_awaiter(generator<_Ref, _Val, _Allocator>&& __gen) noexcept : __gen_(std::move(__gen)) {}
+    _LIBCPP_HIDE_FROM_ABI explicit __recursive_awaiter(generator<_Ref, _Val, _Allocator>&& __gen) noexcept
+        : __gen(std::move(__gen)) {}
 
-    [[nodiscard]] constexpr bool await_ready() const noexcept { return !__gen_.__coroutine_; }
+    [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool await_ready() noexcept { return !__gen.__coroutine_; }
 
     template <class _Promise>
-    constexpr coroutine_handle<__gen_promise_base> await_suspend(coroutine_handle<_Promise> __current) noexcept {
-      auto __recursive = coroutine_handle<__gen_promise_base>::from_address(__gen_.__coroutine_.address());
+    _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.__is_recursive()) {
         __recursive_data.__root = __parent.promise().__get_recursive_data().__root;
       } else {
         __recursive_data.__root = __parent;
       }
 
-      auto __root_data     = __recursive_data.__root.promise().__get_root_data();
-      __root_data.__active = __recursive;
+      // 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;
     }
 
-    void await_resume() {
-      auto __recursive      = coroutine_handle<__gen_promise_base>::from_address(__gen_.__coroutine_.address());
+    _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));
@@ -184,27 +201,48 @@ private:
   };
 
 public:
-  suspend_always initial_suspend() const noexcept { return {}; }
+  _LIBCPP_HIDE_FROM_ABI suspend_always initial_suspend() const noexcept { return {}; }
 
-  auto final_suspend() noexcept { return __final_awaiter{}; }
+  _LIBCPP_HIDE_FROM_ABI __final_awaiter final_suspend() noexcept { return {}; }
 
-  suspend_always yield_value(_Yielded __val) noexcept {
-    __root_value_ptr() = addressof(__val);
+  _LIBCPP_HIDE_FROM_ABI suspend_always yield_value(_Yielded __value) noexcept {
+    __root_value_ptr() = addressof(__value);
     return {};
   }
 
-  auto yield_value(const remove_reference_t<_Yielded>& __val)
+  _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(__val);
+    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{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))));
   }
 
-  void await_transform() = delete;
+  _LIBCPP_HIDE_FROM_ABI void await_transform() = delete;
 
-  void return_void() const noexcept {}
+  _LIBCPP_HIDE_FROM_ABI void return_void() const noexcept {}
 
-  void unhandled_exception() {
+  _LIBCPP_HIDE_FROM_ABI void unhandled_exception() {
     if (__is_root()) {
       throw;
     } else {
@@ -224,21 +262,21 @@ public:
   using value_type      = __val;
   using difference_type = ptrdiff_t;
 
-  struct promise_type {};
-
-  __gen_iter(__gen_iter&& __other) noexcept : __coroutine_(std::exchange(__other.__coroutine_, {})) {}
+  _LIBCPP_HIDE_FROM_ABI __gen_iter(__gen_iter&& __other) noexcept
+      : __coroutine_(std::exchange(__other.__coroutine_, {})) {}
 
-  __gen_iter& operator=(__gen_iter&& __other) noexcept {
+  _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>) {
-    // todo: return static_cast<__reference_t>();
+    return static_cast<__ref>(__coroutine_.promise().__value_ptr());
   }
 
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __gen_iter& operator++() {
-    // todo
+    __coroutine_.promise().__active().resume();
+    return *this;
   }
 
   _LIBCPP_HIDE_FROM_ABI void operator++(int) { ++*this; }
@@ -246,25 +284,30 @@ public:
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool operator==(default_sentinel_t) { return __coroutine_.done(); }
 
 private:
-  _LIBCPP_HIDE_FROM_ABI explicit __gen_iter(coroutine_handle<promise_type> __coroutine) noexcept
+  template <class, class, class>
+  friend class generator;
+
+  _LIBCPP_HIDE_FROM_ABI explicit __gen_iter(
+      coroutine_handle<__gen_promise_base<__gen_yielded<_Ref, _Val>>> __coroutine) noexcept
       : __coroutine_(std::move(__coroutine)) {}
 
-  coroutine_handle<promise_type> __coroutine_;
+  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>;
-
   using __ref = __gen_ref<_Ref, _Val>;
 
-  friend __gen_iter<_Ref, _Val>;
-
 public:
   using yielded = __gen_yielded<_Ref, _Val>;
 
-  class promise_type;
+  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
@@ -283,12 +326,15 @@ public:
 
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __gen_iter<_Ref, _Val> begin() {
     __coroutine_.resume();
-    return __gen_iter(__coroutine_);
+    return {__coroutine_};
   }
 
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI default_sentinel_t end() const noexcept { return default_sentinel; }
+  [[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;
 };
 

>From baf3820f3a18a56532cb13d03f7afeafbf2a0551 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Sun, 12 May 2024 21:29:11 -0400
Subject: [PATCH 23/26] [libc++] implement 'std::generator'

---
 libcxx/include/CMakeLists.txt |   1 +
 libcxx/include/generator      | 104 ++++++++++++++++++++--------------
 2 files changed, 62 insertions(+), 43 deletions(-)

diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index df30145751f17..73efd343f6ac0 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -950,6 +950,7 @@ set(files
   fstream
   functional
   future
+  generator
   initializer_list
   inttypes.h
   iomanip
diff --git a/libcxx/include/generator b/libcxx/include/generator
index 58b01b031a2ac..b0d5acd38605a 100644
--- a/libcxx/include/generator
+++ b/libcxx/include/generator
@@ -15,6 +15,7 @@
 #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>
@@ -57,6 +58,9 @@ 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 {
@@ -76,50 +80,48 @@ private:
     std::coroutine_handle<__gen_promise_base> __root;
   };
 
-  union {
+  union __union {
     __root_data __root;
     __recursive_data __recursive;
-  } __data_ = __root_data{
-      .__value_ptr = nullptr,
-      .__active    = coroutine_handle<__gen_promise_base>::from_promise(*this).address(),
-  };
+
+    ~__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` could only equal `nullptr` if the active member is
-  // `__root`.
-  bool __tag_ = false;
+  // 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 {
+  [[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 std::addressof(__data_.__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 {
+  [[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 std::addressof(__data_.__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 __data_.__get_root_data().__active;
+    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 __data_.__get_root_data().__value_ptr;
+    return __get_root_data().__value_ptr;
   }
 
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI add_pointer_t<_Yielded>& __root_value_ptr() noexcept {
-    if (__data_.__is_root()) {
+    if (__is_root()) {
       return __value_ptr();
     }
-    return __data_.__get_recursive_data().__root.promise().__value_ptr();
+    return __get_recursive_data().__root.promise().__value_ptr();
   }
 
   struct __element_awaiter {
@@ -142,8 +144,8 @@ private:
     _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;
+        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
@@ -160,7 +162,7 @@ private:
     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_; }
 
@@ -170,15 +172,15 @@ private:
       // 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();
+      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;
+      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.__is_recursive()) {
+      if (__parent.promise().__is_recursive()) {
         __recursive_data.__root = __parent.promise().__get_recursive_data().__root;
       } else {
         __recursive_data.__root = __parent;
@@ -192,8 +194,8 @@ private:
     }
 
     _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();
+      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));
       }
@@ -201,6 +203,22 @@ private:
   };
 
 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 {}; }
@@ -221,7 +239,7 @@ public:
     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{std::move(__elements.range)};
+    return __recursive_awaiter<_Ref2, _Val2, _Allocator2>{std::move(__elements.range)};
   }
 
   template <ranges::input_range _Range, class _Allocator>
@@ -246,8 +264,7 @@ public:
     if (__is_root()) {
       throw;
     } else {
-      auto __recursive_data         = __get_recursive_data();
-      __recursive_data->__exception = std::current_exception();
+      __get_recursive_data().__exception = std::current_exception();
     }
   }
 };
@@ -262,8 +279,12 @@ 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_{std::move(__coroutine)} {}
+
   _LIBCPP_HIDE_FROM_ABI __gen_iter(__gen_iter&& __other) noexcept
-      : __coroutine_(std::exchange(__other.__coroutine_, {})) {}
+      : __coroutine_{std::exchange(__other.__coroutine_, {})} {}
 
   _LIBCPP_HIDE_FROM_ABI __gen_iter& operator=(__gen_iter&& __other) noexcept {
     __coroutine_ = std::exchange(__other.__coroutine_, {});
@@ -271,26 +292,19 @@ public:
   }
 
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __ref operator*() const noexcept(is_nothrow_copy_constructible_v<__ref>) {
-    return static_cast<__ref>(__coroutine_.promise().__value_ptr());
+    return static_cast<__ref>(*__coroutine_.promise().__value_ptr());
   }
 
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __gen_iter& operator++() {
+  _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) { return __coroutine_.done(); }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool operator==(default_sentinel_t) const noexcept { return __coroutine_.done(); }
 
 private:
-  template <class, class, class>
-  friend class generator;
-
-  _LIBCPP_HIDE_FROM_ABI explicit __gen_iter(
-      coroutine_handle<__gen_promise_base<__gen_yielded<_Ref, _Val>>> __coroutine) noexcept
-      : __coroutine_(std::move(__coroutine)) {}
-
   coroutine_handle<__gen_promise_base<__gen_yielded<_Ref, _Val>>> __coroutine_;
 };
 
@@ -300,6 +314,9 @@ private:
   using __val = __gen_val<_Ref, _Val>;
   using __ref = __gen_ref<_Ref, _Val>;
 
+  template <class>
+  friend class __gen_promise_base;
+
 public:
   using yielded = __gen_yielded<_Ref, _Val>;
 
@@ -311,7 +328,7 @@ public:
 
   _LIBCPP_HIDE_FROM_ABI generator(const generator&) = delete;
   _LIBCPP_HIDE_FROM_ABI generator(generator&& __other) noexcept
-      : __coroutine_(std::exchange(__other.__coroutine_, {})) {}
+      : __coroutine_{std::exchange(__other.__coroutine_, {})} {}
 
   _LIBCPP_HIDE_FROM_ABI ~generator() {
     if (__coroutine_) {
@@ -325,15 +342,16 @@ public:
   }
 
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __gen_iter<_Ref, _Val> begin() {
-    __coroutine_.resume();
-    return {__coroutine_};
+    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_{__coroutine} {}
 
   coroutine_handle<promise_type> __coroutine_ = nullptr;
 };

>From b96df9e8402b8380ea81a86f081808d73a0b6a20 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Sun, 12 May 2024 22:25:02 -0400
Subject: [PATCH 24/26] [libc++] implement 'std::generator'

---
 .../ranges/coro.generator/generator.pass.cpp  | 40 ++++++++
 .../ranges/coro.generator/recursive.pass.cpp  | 92 +++++++++++++++++++
 2 files changed, 132 insertions(+)
 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/test/std/ranges/coro.generator/generator.pass.cpp b/libcxx/test/std/ranges/coro.generator/generator.pass.cpp
new file mode 100644
index 0000000000000..c7e280f74b70a
--- /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 0000000000000..f02f5439a77a2
--- /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 eec37135dbbfa5d6daef93305c546cd960598cb5 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Mon, 13 May 2024 16:44:53 -0400
Subject: [PATCH 25/26] [libc++] implement 'std::generator'

---
 libcxx/include/generator | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/libcxx/include/generator b/libcxx/include/generator
index b0d5acd38605a..f4e15fae46023 100644
--- a/libcxx/include/generator
+++ b/libcxx/include/generator
@@ -27,8 +27,10 @@
 #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>
@@ -312,7 +314,15 @@ 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;

>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 26/26] [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 edce0af345f37..f446d3c12d67e 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



More information about the libcxx-commits mailing list