Skip to content

Conversation

@xiaoyang-sde
Copy link
Member

@xiaoyang-sde xiaoyang-sde commented May 8, 2024

Introduction

This patch implements ranges::elements_of from P2502R2. Specializations of elements_of encapsulate a range and act as a tag in overload sets to disambiguate when a range should be treated as a sequence rather than a single value.

template <bool YieldElements>
std::generator<std::any> f(std::ranges::input_range auto &&r) {
  if constexpr (YieldElements) {
    co_yield std::ranges::elements_of(r);
  } else {
    co_yield r;
  }
}

Reference

Partially addresses #105226

@xiaoyang-sde xiaoyang-sde requested a review from a team as a code owner May 8, 2024 01:14
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label May 8, 2024
@llvmbot
Copy link
Member

llvmbot commented May 8, 2024

@llvm/pr-subscribers-libcxx

Author: Xiaoyang Liu (xiaoyang-sde)

Changes

Introduction

This patch implements ranges::elements_of from P2502R2: Specializations of elements_of encapsulate a range and act as a tag in overload sets to disambiguate when a range should be treated as a sequence rather than a single value.

template &lt;bool YieldElements&gt;
std::generator&lt;std::any&gt; f(std::ranges::input_range auto &amp;&amp;r) {
  if constexpr (YieldElements) {
    co_yield std::ranges::elements_of(r);
  } else {
    co_yield r;
  }
}

Reference


Full diff: https://github.com/llvm/llvm-project/pull/91414.diff

5 Files Affected:

  • (modified) libcxx/include/CMakeLists.txt (+1)
  • (added) libcxx/include/__ranges/elements_of.h (+48)
  • (modified) libcxx/include/ranges (+5)
  • (modified) libcxx/modules/std/ranges.inc (+3-1)
  • (added) libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp (+40)
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..d7cb1937563c6
--- /dev/null
+++ b/libcxx/include/__ranges/elements_of.h
@@ -0,0 +1,48 @@
+// -*- 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..378bcb0a2f13f
--- /dev/null
+++ b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
@@ -0,0 +1,40 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// std::ranges::elements_of;
+
+#include <ranges>
+
+#include <concepts>
+#include <memory>
+#include <vector>
+
+constexpr bool test() {
+  {
+    auto elements_of = std::ranges::elements_of(std::vector<int>());
+    static_assert(
+        std::same_as<decltype(elements_of), std::ranges::elements_of<std::vector<int>&&, std::allocator<std::byte>>>);
+    static_assert(std::same_as<decltype(elements_of.range), std::vector<int>&&>);
+    static_assert(std::same_as<decltype(elements_of.allocator), std::allocator<std::byte>>);
+  }
+  {
+    auto elements_of = std::ranges::elements_of(std::vector<int>(), std::allocator<int>());
+    static_assert(
+        std::same_as<decltype(elements_of), std::ranges::elements_of<std::vector<int>&&, std::allocator<int>>>);
+    static_assert(std::same_as<decltype(elements_of.range), std::vector<int>&&>);
+    static_assert(std::same_as<decltype(elements_of.allocator), std::allocator<int>>);
+  }
+  return true;
+}
+
+int main() {
+  test();
+  static_assert(test());
+}

@xiaoyang-sde xiaoyang-sde marked this pull request as draft May 10, 2024 20:11
@xiaoyang-sde xiaoyang-sde removed the request for review from a team May 10, 2024 20:11
@Zingam
Copy link
Contributor

Zingam commented May 11, 2024

Are you working on <generator>?

@xiaoyang-sde
Copy link
Member Author

xiaoyang-sde commented May 11, 2024

Are you working on <generator>?

I've made some progress with an incomplete implementation, but it's not quite ready for review. (Should be finalized in a day or two though.) If you've already have a finalized implementation, I'm willing to take a look!

@xiaoyang-sde xiaoyang-sde added the ranges Issues related to `<ranges>` label May 14, 2024
@xiaoyang-sde xiaoyang-sde marked this pull request as ready for review May 14, 2024 18:16
@mordante mordante self-assigned this Jul 17, 2024
Copy link
Member

@mordante mordante left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems I missed this patch. Thanks for working on this! It looks quite good, but the tests need some improvements.

@xiaoyang-sde
Copy link
Member Author

It seems I missed this patch. Thanks for working on this! It looks quite good, but the tests need some improvements.

Thank you for the review! I'm currently on a trip but will address the comments in a few days.

Copy link
Member

@ldionne ldionne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, let's merge once the CI is green.

@ldionne ldionne added the pending-ci Merging the PR is only pending completion of CI label Dec 4, 2025
@frederick-vs-ja

This comment was marked as resolved.

@frederick-vs-ja frederick-vs-ja self-assigned this Dec 12, 2025
@frederick-vs-ja
Copy link
Contributor

I'm merging this. Tell me if you think test code should cover prvalue ranges. @ldionne @xiaoyang-sde

@frederick-vs-ja frederick-vs-ja merged commit fa79e0a into llvm:main Dec 13, 2025
80 checks passed
@frederick-vs-ja frederick-vs-ja removed their assignment Dec 13, 2025
anonymouspc pushed a commit to anonymouspc/llvm that referenced this pull request Dec 15, 2025
## Introduction

This patch implements `ranges::elements_of` from
[P2502R2](https://wg21.link/P2502R2). Specializations of `elements_of`
encapsulate a range and act as a tag in overload sets to disambiguate
when a range should be treated as a sequence rather than a single value.

```cpp
template <bool YieldElements>
std::generator<std::any> f(std::ranges::input_range auto &&r) {
  if constexpr (YieldElements) {
    co_yield std::ranges::elements_of(r);
  } else {
    co_yield r;
  }
}
```

## Reference

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

Partially addresses llvm#105226

---------

Co-authored-by: Louis Dionne <[email protected]>
Co-authored-by: A. Jiang <[email protected]>
mahesh-attarde pushed a commit to mahesh-attarde/llvm-project that referenced this pull request Dec 19, 2025
## Introduction

This patch implements `ranges::elements_of` from
[P2502R2](https://wg21.link/P2502R2). Specializations of `elements_of`
encapsulate a range and act as a tag in overload sets to disambiguate
when a range should be treated as a sequence rather than a single value.

```cpp
template <bool YieldElements>
std::generator<std::any> f(std::ranges::input_range auto &&r) {
  if constexpr (YieldElements) {
    co_yield std::ranges::elements_of(r);
  } else {
    co_yield r;
  }
}
```

## Reference

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

Partially addresses llvm#105226

---------

Co-authored-by: Louis Dionne <[email protected]>
Co-authored-by: A. Jiang <[email protected]>
Priyanshu3820 pushed a commit to Priyanshu3820/llvm-project that referenced this pull request Dec 20, 2025
## Introduction

This patch implements `ranges::elements_of` from
[P2502R2](https://wg21.link/P2502R2). Specializations of `elements_of`
encapsulate a range and act as a tag in overload sets to disambiguate
when a range should be treated as a sequence rather than a single value.

```cpp
template <bool YieldElements>
std::generator<std::any> f(std::ranges::input_range auto &&r) {
  if constexpr (YieldElements) {
    co_yield std::ranges::elements_of(r);
  } else {
    co_yield r;
  }
}
```

## Reference

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

Partially addresses llvm#105226

---------

Co-authored-by: Louis Dionne <[email protected]>
Co-authored-by: A. Jiang <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. pending-ci Merging the PR is only pending completion of CI ranges Issues related to `<ranges>`

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants