[libcxx-commits] [libcxx] [libc++][ranges] implement `ranges::elements_of` (PR #91414)

Xiaoyang Liu via libcxx-commits libcxx-commits at lists.llvm.org
Sun Nov 10 09:51:16 PST 2024


https://github.com/xiaoyang-sde updated https://github.com/llvm/llvm-project/pull/91414

>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/25] [libc++][ranges] implement 'ranges::elements_of'

---
 libcxx/include/CMakeLists.txt                 |  1 +
 libcxx/include/__ranges/elements_of.h         | 47 +++++++++++++++++++
 libcxx/include/ranges                         |  5 ++
 libcxx/modules/std/ranges.inc                 |  4 +-
 .../range.elementsof/elements_of.pass.cpp     | 39 +++++++++++++++
 5 files changed, 95 insertions(+), 1 deletion(-)
 create mode 100644 libcxx/include/__ranges/elements_of.h
 create mode 100644 libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp

diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index fd7eb125e007b6..b1f9be1dc3d7da 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -646,6 +646,7 @@ set(files
   __ranges/data.h
   __ranges/drop_view.h
   __ranges/drop_while_view.h
+  __ranges/elements_of.h
   __ranges/elements_view.h
   __ranges/empty.h
   __ranges/empty_view.h
diff --git a/libcxx/include/__ranges/elements_of.h b/libcxx/include/__ranges/elements_of.h
new file mode 100644
index 00000000000000..727ba92666eb36
--- /dev/null
+++ b/libcxx/include/__ranges/elements_of.h
@@ -0,0 +1,47 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___RANGES_ELEMENTS_OF_H
+#define _LIBCPP___RANGES_ELEMENTS_OF_H
+
+#include <__config>
+#include <__memory/allocator.h>
+#include <__ranges/concepts.h>
+#include <cstddef>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER >= 23
+
+namespace ranges {
+
+template <range _Range, class _Allocator = allocator<byte>>
+struct elements_of {
+  _LIBCPP_NO_UNIQUE_ADDRESS _Range range;
+  _LIBCPP_NO_UNIQUE_ADDRESS _Allocator allocator = _Allocator();
+};
+
+template <class _Range, class _Allocator = allocator<byte>>
+elements_of(_Range&&, _Allocator = _Allocator()) -> elements_of<_Range&&, _Allocator>;
+
+} // namespace ranges
+
+#endif // _LIBCPP_STD_VER >= 23
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+#endif // _LIBCPP___RANGES_ELEMENTS_OF_H
diff --git a/libcxx/include/ranges b/libcxx/include/ranges
index 07a525ed8641fd..a8fbfc462bf0db 100644
--- a/libcxx/include/ranges
+++ b/libcxx/include/ranges
@@ -116,6 +116,10 @@ namespace std::ranges {
   // [range.dangling], dangling iterator handling
   struct dangling;
 
+  // [range.elementsof], class template elements_of
+  template<range R, class Allocator = allocator<byte>>
+    struct elements_of;
+
   template<range R>
     using borrowed_iterator_t = see below;
 
@@ -392,6 +396,7 @@ namespace std {
 #include <__ranges/data.h>
 #include <__ranges/drop_view.h>
 #include <__ranges/drop_while_view.h>
+#include <__ranges/elements_of.h>
 #include <__ranges/elements_view.h>
 #include <__ranges/empty.h>
 #include <__ranges/empty_view.h>
diff --git a/libcxx/modules/std/ranges.inc b/libcxx/modules/std/ranges.inc
index 80f31c79a1a405..94f3defdcbc356 100644
--- a/libcxx/modules/std/ranges.inc
+++ b/libcxx/modules/std/ranges.inc
@@ -83,8 +83,10 @@ export namespace std {
     // [range.dangling], dangling iterator handling
     using std::ranges::dangling;
 
+#if _LIBCPP_STD_VER >= 23
     // [range.elementsof], class template elements_­of
-    // using std::ranges::elements_of;
+    using std::ranges::elements_of;
+#endif
 
     using std::ranges::borrowed_iterator_t;
 
diff --git a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
new file mode 100644
index 00000000000000..e1c2f91b960796
--- /dev/null
+++ b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
@@ -0,0 +1,39 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// std::ranges::elements_of;
+
+#include <ranges>
+
+#include <vector>
+#include <concepts>
+
+constexpr bool test() {
+  {
+    auto elements_of = std::ranges::elements_of(std::vector<int>());
+    static_assert(
+        std::same_as<decltype(elements_of), std::ranges::elements_of<std::vector<int>&&, std::allocator<std::byte>>>);
+    static_assert(std::same_as<decltype(elements_of.range), std::vector<int>&&>);
+    static_assert(std::same_as<decltype(elements_of.allocator), std::allocator<std::byte>>);
+  }
+  {
+    auto elements_of = std::ranges::elements_of(std::vector<int>(), std::allocator<int>());
+    static_assert(
+        std::same_as<decltype(elements_of), std::ranges::elements_of<std::vector<int>&&, std::allocator<int>>>);
+    static_assert(std::same_as<decltype(elements_of.range), std::vector<int>&&>);
+    static_assert(std::same_as<decltype(elements_of.allocator), std::allocator<int>>);
+  }
+  return true;
+}
+
+int main() {
+  test();
+  static_assert(test());
+}

>From e14469bc4b829a7d40e8a445920d396ef08c5dda Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Tue, 7 May 2024 18:03:43 -0700
Subject: [PATCH 02/25] [libc++][ranges] implement 'ranges::elements_of'

---
 libcxx/include/__ranges/elements_of.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libcxx/include/__ranges/elements_of.h b/libcxx/include/__ranges/elements_of.h
index 727ba92666eb36..d7cb1937563c60 100644
--- a/libcxx/include/__ranges/elements_of.h
+++ b/libcxx/include/__ranges/elements_of.h
@@ -44,4 +44,5 @@ elements_of(_Range&&, _Allocator = _Allocator()) -> elements_of<_Range&&, _Alloc
 _LIBCPP_END_NAMESPACE_STD
 
 _LIBCPP_POP_MACROS
+
 #endif // _LIBCPP___RANGES_ELEMENTS_OF_H

>From 85ca069a211767c13059a315803fb71c442540a5 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Tue, 7 May 2024 18:04:53 -0700
Subject: [PATCH 03/25] [libc++][ranges] implement 'ranges::elements_of'

---
 .../ranges/range.utility/range.elementsof/elements_of.pass.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
index e1c2f91b960796..378bcb0a2f13f3 100644
--- a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
+++ b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
@@ -12,8 +12,9 @@
 
 #include <ranges>
 
-#include <vector>
 #include <concepts>
+#include <memory>
+#include <vector>
 
 constexpr bool test() {
   {

>From b031c387baf12789a0da5268da2c92710087aac8 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Tue, 7 May 2024 19:45:10 -0700
Subject: [PATCH 04/25] [libc++][ranges] implement 'ranges::elements_of'

---
 libcxx/include/module.modulemap | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index 2974d12500c4cb..ee952c48c11d5b 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -1699,6 +1699,7 @@ module std_private_ranges_dangling                   [system] { header "__ranges
 module std_private_ranges_data                       [system] { header "__ranges/data.h" }
 module std_private_ranges_drop_view                  [system] { header "__ranges/drop_view.h" }
 module std_private_ranges_drop_while_view            [system] { header "__ranges/drop_while_view.h" }
+module std_private_ranges_elements_of                [system] { header "__ranges/elements_of.h" }
 module std_private_ranges_elements_view              [system] { header "__ranges/elements_view.h" }
 module std_private_ranges_empty                      [system] { header "__ranges/empty.h" }
 module std_private_ranges_empty_view                 [system] { header "__ranges/empty_view.h" }

>From 32b68f274244cc866d7edf5a83fffcb4ba0bec19 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Wed, 8 May 2024 13:22:10 -0400
Subject: [PATCH 05/25] [libc++][ranges] implement 'ranges::elements_of'

---
 libcxx/include/__ranges/elements_of.h | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/libcxx/include/__ranges/elements_of.h b/libcxx/include/__ranges/elements_of.h
index d7cb1937563c60..6219446a742a85 100644
--- a/libcxx/include/__ranges/elements_of.h
+++ b/libcxx/include/__ranges/elements_of.h
@@ -31,7 +31,11 @@ namespace ranges {
 template <range _Range, class _Allocator = allocator<byte>>
 struct elements_of {
   _LIBCPP_NO_UNIQUE_ADDRESS _Range range;
-  _LIBCPP_NO_UNIQUE_ADDRESS _Allocator allocator = _Allocator();
+  _LIBCPP_NO_UNIQUE_ADDRESS _Allocator allocator;
+
+  // This explicit constructor is required because AppleClang 15 hasn't implement P0960R3
+  explicit elements_of(_Range&& __range, _Allocator __allocator = _Allocator())
+      : range(std::move(__range)), allocator(std::move(__allocator)) {}
 };
 
 template <class _Range, class _Allocator = allocator<byte>>

>From 8e3560904d1cc79d014acba31eb2586edd71869d Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Wed, 8 May 2024 13:36:27 -0400
Subject: [PATCH 06/25] [libc++][ranges] implement 'ranges::elements_of'

---
 libcxx/include/__ranges/elements_of.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libcxx/include/__ranges/elements_of.h b/libcxx/include/__ranges/elements_of.h
index 6219446a742a85..043bcb918a692d 100644
--- a/libcxx/include/__ranges/elements_of.h
+++ b/libcxx/include/__ranges/elements_of.h
@@ -13,6 +13,7 @@
 #include <__config>
 #include <__memory/allocator.h>
 #include <__ranges/concepts.h>
+#include <__utility/move.h>
 #include <cstddef>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)

>From 162ce8ab091420ff39031aad4260843ac8df6391 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Wed, 8 May 2024 16:36:47 -0400
Subject: [PATCH 07/25] [libc++][ranges] implement 'ranges::elements_of'

---
 libcxx/include/__ranges/elements_of.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/include/__ranges/elements_of.h b/libcxx/include/__ranges/elements_of.h
index 043bcb918a692d..93020c93d5f7b8 100644
--- a/libcxx/include/__ranges/elements_of.h
+++ b/libcxx/include/__ranges/elements_of.h
@@ -35,7 +35,7 @@ struct elements_of {
   _LIBCPP_NO_UNIQUE_ADDRESS _Allocator allocator;
 
   // This explicit constructor is required because AppleClang 15 hasn't implement P0960R3
-  explicit elements_of(_Range&& __range, _Allocator __allocator = _Allocator())
+  _LIBCPP_HIDE_FROM_ABI explicit constexpr elements_of(_Range __range, _Allocator __allocator = _Allocator())
       : range(std::move(__range)), allocator(std::move(__allocator)) {}
 };
 

>From 9dd983d4ccd1ac0e1b5a74340212d6013309cf2d Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Wed, 8 May 2024 16:51:32 -0400
Subject: [PATCH 08/25] [libc++][ranges] implement 'ranges::elements_of'

---
 libcxx/include/__ranges/elements_of.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/__ranges/elements_of.h b/libcxx/include/__ranges/elements_of.h
index 93020c93d5f7b8..edce0af345f378 100644
--- a/libcxx/include/__ranges/elements_of.h
+++ b/libcxx/include/__ranges/elements_of.h
@@ -35,8 +35,8 @@ struct elements_of {
   _LIBCPP_NO_UNIQUE_ADDRESS _Allocator allocator;
 
   // This explicit constructor is required because AppleClang 15 hasn't implement P0960R3
-  _LIBCPP_HIDE_FROM_ABI explicit constexpr elements_of(_Range __range, _Allocator __allocator = _Allocator())
-      : range(std::move(__range)), allocator(std::move(__allocator)) {}
+  _LIBCPP_HIDE_FROM_ABI explicit constexpr elements_of(_Range __range, _Allocator __alloc = _Allocator())
+      : range(std::move(__range)), allocator(std::move(__alloc)) {}
 };
 
 template <class _Range, class _Allocator = allocator<byte>>

>From 8291917ab08f32b609b7c2711ce63de9b649051b Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Tue, 14 May 2024 12:49:39 -0400
Subject: [PATCH 09/25] [libc++][ranges] implement 'ranges::elements_of'

---
 libcxx/include/__ranges/elements_of.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/libcxx/include/__ranges/elements_of.h b/libcxx/include/__ranges/elements_of.h
index edce0af345f378..f446d3c12d67e7 100644
--- a/libcxx/include/__ranges/elements_of.h
+++ b/libcxx/include/__ranges/elements_of.h
@@ -40,6 +40,8 @@ struct elements_of {
 };
 
 template <class _Range, class _Allocator = allocator<byte>>
+// This explicit constraint is required because AppleClang 15 might not deduce the correct type for `_Range` without it
+  requires range<_Range&&>
 elements_of(_Range&&, _Allocator = _Allocator()) -> elements_of<_Range&&, _Allocator>;
 
 } // namespace ranges

>From b741665949ed7fc8b58b757ae22499b7bff0aba7 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Sun, 28 Jul 2024 22:10:33 +0800
Subject: [PATCH 10/25] [libc++][ranges] implement 'ranges::elements_of'

---
 libcxx/include/__ranges/elements_of.h         |  6 ++-
 .../range.elementsof/elements_of.pass.cpp     | 48 +++++++++++++------
 2 files changed, 38 insertions(+), 16 deletions(-)

diff --git a/libcxx/include/__ranges/elements_of.h b/libcxx/include/__ranges/elements_of.h
index f446d3c12d67e7..1b8f916589505c 100644
--- a/libcxx/include/__ranges/elements_of.h
+++ b/libcxx/include/__ranges/elements_of.h
@@ -32,16 +32,20 @@ namespace ranges {
 template <range _Range, class _Allocator = allocator<byte>>
 struct elements_of {
   _LIBCPP_NO_UNIQUE_ADDRESS _Range range;
-  _LIBCPP_NO_UNIQUE_ADDRESS _Allocator allocator;
+  _LIBCPP_NO_UNIQUE_ADDRESS _Allocator allocator = _Allocator();
 
+#  if defined(_LIBCPP_COMPILER_CLANG_BASED) && _LIBCPP_CLANG_VER < 1600
   // This explicit constructor is required because AppleClang 15 hasn't implement P0960R3
   _LIBCPP_HIDE_FROM_ABI explicit constexpr elements_of(_Range __range, _Allocator __alloc = _Allocator())
       : range(std::move(__range)), allocator(std::move(__alloc)) {}
+#  endif
 };
 
 template <class _Range, class _Allocator = allocator<byte>>
+#  if defined(_LIBCPP_COMPILER_CLANG_BASED) && _LIBCPP_CLANG_VER < 1600
 // This explicit constraint is required because AppleClang 15 might not deduce the correct type for `_Range` without it
   requires range<_Range&&>
+#  endif
 elements_of(_Range&&, _Allocator = _Allocator()) -> elements_of<_Range&&, _Allocator>;
 
 } // namespace ranges
diff --git a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
index 378bcb0a2f13f3..8bdb4f7992ae23 100644
--- a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
+++ b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
@@ -16,25 +16,43 @@
 #include <memory>
 #include <vector>
 
+#include "min_allocator.h"
+#include "test_allocator.h"
+#include "test_iterators.h"
+
+template <typename Range>
+constexpr bool test_range() {
+  std::same_as<std::ranges::elements_of<Range&&, std::allocator<std::byte>>> decltype(auto) elements_of =
+      std::ranges::elements_of(Range());
+  [[maybe_unused]] std::same_as<Range&&> decltype(auto) elements_of_range = std::move(elements_of.range);
+  [[maybe_unused]] std::same_as<std::allocator<std::byte>> decltype(auto) elements_of_allocator = elements_of.allocator;
+  return true;
+}
+
+template <typename Range, typename Allocator>
+constexpr bool test_range_with_allocator() {
+  std::same_as< std::ranges::elements_of< Range&&, Allocator >> decltype(auto) elements_of =
+      std::ranges::elements_of(Range(), Allocator());
+  [[maybe_unused]] std::same_as<Range&&> decltype(auto) elements_of_range       = std::move(elements_of.range);
+  [[maybe_unused]] std::same_as<Allocator> decltype(auto) elements_of_allocator = elements_of.allocator;
+  return true;
+}
+
 constexpr bool test() {
-  {
-    auto elements_of = std::ranges::elements_of(std::vector<int>());
-    static_assert(
-        std::same_as<decltype(elements_of), std::ranges::elements_of<std::vector<int>&&, std::allocator<std::byte>>>);
-    static_assert(std::same_as<decltype(elements_of.range), std::vector<int>&&>);
-    static_assert(std::same_as<decltype(elements_of.allocator), std::allocator<std::byte>>);
-  }
-  {
-    auto elements_of = std::ranges::elements_of(std::vector<int>(), std::allocator<int>());
-    static_assert(
-        std::same_as<decltype(elements_of), std::ranges::elements_of<std::vector<int>&&, std::allocator<int>>>);
-    static_assert(std::same_as<decltype(elements_of.range), std::vector<int>&&>);
-    static_assert(std::same_as<decltype(elements_of.allocator), std::allocator<int>>);
-  }
+  types::for_each(types::type_list<std::allocator<std::byte>, min_allocator<std::byte>, test_allocator<std::byte>>{},
+                  []<class Allocator> {
+                    types::for_each(types::type_list<std::vector<int>>{}, []<class Range> {
+                      test_range<Range>();
+                      test_range_with_allocator<Range, Allocator>();
+                    });
+                  });
+
   return true;
 }
 
-int main() {
+int main(int, char**) {
   test();
   static_assert(test());
+
+  return 0;
 }

>From 07a62fe1e65a3c5c147acc9088f26a36faffa57e Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Thu, 8 Aug 2024 12:50:36 -0400
Subject: [PATCH 11/25] [libc++][ranges] implement 'ranges::elements_of'

---
 libcxx/include/__ranges/elements_of.h            | 4 ++--
 libcxx/test/libcxx/transitive_includes/cxx03.csv | 1 +
 libcxx/test/libcxx/transitive_includes/cxx11.csv | 1 +
 libcxx/test/libcxx/transitive_includes/cxx14.csv | 1 +
 libcxx/test/libcxx/transitive_includes/cxx17.csv | 1 +
 libcxx/test/libcxx/transitive_includes/cxx20.csv | 1 +
 libcxx/test/libcxx/transitive_includes/cxx23.csv | 1 +
 libcxx/test/libcxx/transitive_includes/cxx26.csv | 1 +
 8 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/__ranges/elements_of.h b/libcxx/include/__ranges/elements_of.h
index 1b8f916589505c..b2a93e9d553409 100644
--- a/libcxx/include/__ranges/elements_of.h
+++ b/libcxx/include/__ranges/elements_of.h
@@ -35,7 +35,7 @@ struct elements_of {
   _LIBCPP_NO_UNIQUE_ADDRESS _Allocator allocator = _Allocator();
 
 #  if defined(_LIBCPP_COMPILER_CLANG_BASED) && _LIBCPP_CLANG_VER < 1600
-  // This explicit constructor is required because AppleClang 15 hasn't implement P0960R3
+  // This explicit constructor is required because AppleClang 15 hasn't implemented P0960R3.
   _LIBCPP_HIDE_FROM_ABI explicit constexpr elements_of(_Range __range, _Allocator __alloc = _Allocator())
       : range(std::move(__range)), allocator(std::move(__alloc)) {}
 #  endif
@@ -43,7 +43,7 @@ struct elements_of {
 
 template <class _Range, class _Allocator = allocator<byte>>
 #  if defined(_LIBCPP_COMPILER_CLANG_BASED) && _LIBCPP_CLANG_VER < 1600
-// This explicit constraint is required because AppleClang 15 might not deduce the correct type for `_Range` without it
+// This explicit constraint is required because AppleClang 15 might not deduce the correct type for `_Range` without it.
   requires range<_Range&&>
 #  endif
 elements_of(_Range&&, _Allocator = _Allocator()) -> elements_of<_Range&&, _Allocator>;
diff --git a/libcxx/test/libcxx/transitive_includes/cxx03.csv b/libcxx/test/libcxx/transitive_includes/cxx03.csv
index fd2cd7f1c2d961..f0efe06a01cd18 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx03.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx03.csv
@@ -671,6 +671,7 @@ ranges initializer_list
 ranges iosfwd
 ranges iterator
 ranges limits
+ranges new
 ranges optional
 ranges span
 ranges tuple
diff --git a/libcxx/test/libcxx/transitive_includes/cxx11.csv b/libcxx/test/libcxx/transitive_includes/cxx11.csv
index 04122fd0f4571a..64a4954730d979 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx11.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx11.csv
@@ -676,6 +676,7 @@ ranges initializer_list
 ranges iosfwd
 ranges iterator
 ranges limits
+ranges new
 ranges optional
 ranges span
 ranges tuple
diff --git a/libcxx/test/libcxx/transitive_includes/cxx14.csv b/libcxx/test/libcxx/transitive_includes/cxx14.csv
index 42c742bead0c1f..bc56918cb638b7 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx14.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx14.csv
@@ -679,6 +679,7 @@ ranges initializer_list
 ranges iosfwd
 ranges iterator
 ranges limits
+ranges new
 ranges optional
 ranges span
 ranges tuple
diff --git a/libcxx/test/libcxx/transitive_includes/cxx17.csv b/libcxx/test/libcxx/transitive_includes/cxx17.csv
index bc0659127d4bf5..29791eb0b56e32 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx17.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv
@@ -680,6 +680,7 @@ ranges initializer_list
 ranges iosfwd
 ranges iterator
 ranges limits
+ranges new
 ranges optional
 ranges span
 ranges tuple
diff --git a/libcxx/test/libcxx/transitive_includes/cxx20.csv b/libcxx/test/libcxx/transitive_includes/cxx20.csv
index fed0944f0219c4..70470de2106e77 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx20.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv
@@ -687,6 +687,7 @@ ranges initializer_list
 ranges iosfwd
 ranges iterator
 ranges limits
+ranges new
 ranges optional
 ranges span
 ranges tuple
diff --git a/libcxx/test/libcxx/transitive_includes/cxx23.csv b/libcxx/test/libcxx/transitive_includes/cxx23.csv
index 53f99384a7f573..117a87b66a2cdb 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx23.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx23.csv
@@ -464,6 +464,7 @@ ranges cwchar
 ranges initializer_list
 ranges iterator
 ranges limits
+ranges new
 ranges optional
 ranges span
 ranges tuple
diff --git a/libcxx/test/libcxx/transitive_includes/cxx26.csv b/libcxx/test/libcxx/transitive_includes/cxx26.csv
index 53f99384a7f573..117a87b66a2cdb 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx26.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv
@@ -464,6 +464,7 @@ ranges cwchar
 ranges initializer_list
 ranges iterator
 ranges limits
+ranges new
 ranges optional
 ranges span
 ranges tuple

>From 74bd1855a16977ffd2e93619fa0e0cdfe83762d3 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Thu, 8 Aug 2024 12:55:24 -0400
Subject: [PATCH 12/25] [libc++][ranges] implement 'ranges::elements_of'

---
 libcxx/include/__ranges/elements_of.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/__ranges/elements_of.h b/libcxx/include/__ranges/elements_of.h
index b2a93e9d553409..f23e8dd4a15e5d 100644
--- a/libcxx/include/__ranges/elements_of.h
+++ b/libcxx/include/__ranges/elements_of.h
@@ -34,7 +34,7 @@ struct elements_of {
   _LIBCPP_NO_UNIQUE_ADDRESS _Range range;
   _LIBCPP_NO_UNIQUE_ADDRESS _Allocator allocator = _Allocator();
 
-#  if defined(_LIBCPP_COMPILER_CLANG_BASED) && _LIBCPP_CLANG_VER < 1600
+#  if defined(_LIBCPP_COMPILER_CLANG_BASED) && defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER < 1600
   // This explicit constructor is required because AppleClang 15 hasn't implemented P0960R3.
   _LIBCPP_HIDE_FROM_ABI explicit constexpr elements_of(_Range __range, _Allocator __alloc = _Allocator())
       : range(std::move(__range)), allocator(std::move(__alloc)) {}
@@ -42,7 +42,7 @@ struct elements_of {
 };
 
 template <class _Range, class _Allocator = allocator<byte>>
-#  if defined(_LIBCPP_COMPILER_CLANG_BASED) && _LIBCPP_CLANG_VER < 1600
+#  if defined(_LIBCPP_COMPILER_CLANG_BASED) && defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER < 1600
 // This explicit constraint is required because AppleClang 15 might not deduce the correct type for `_Range` without it.
   requires range<_Range&&>
 #  endif

>From 5e37e03d58d03a739942a0354646f057312be35f Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Thu, 8 Aug 2024 14:04:15 -0400
Subject: [PATCH 13/25] [libc++][ranges] implement 'ranges::elements_of'

---
 .../range.elementsof/ctad.compile.pass.cpp    | 49 ++++++++++++++
 .../range.elementsof/elements_of.pass.cpp     | 66 ++++++++++++++-----
 2 files changed, 98 insertions(+), 17 deletions(-)
 create mode 100644 libcxx/test/std/ranges/range.utility/range.elementsof/ctad.compile.pass.cpp

diff --git a/libcxx/test/std/ranges/range.utility/range.elementsof/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.utility/range.elementsof/ctad.compile.pass.cpp
new file mode 100644
index 00000000000000..3a679b521f75e5
--- /dev/null
+++ b/libcxx/test/std/ranges/range.utility/range.elementsof/ctad.compile.pass.cpp
@@ -0,0 +1,49 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// std::ranges::elements_of;
+
+#include <ranges>
+
+#include <memory>
+
+#include "min_allocator.h"
+#include "test_allocator.h"
+#include "test_iterators.h"
+
+template <class Iterator>
+struct Range {
+  Iterator begin() const;
+  sentinel_wrapper<Iterator> end() const;
+};
+
+constexpr bool test() {
+  types::for_each(
+      types::type_list<std::allocator<std::byte>, min_allocator<std::byte>, test_allocator<std::byte>>{},
+      []<class Allocator> {
+        types::for_each(types::cpp20_input_iterator_list<int*>{}, []<class Iterator> {
+          Range<Iterator> r;
+          static_assert(std::same_as<decltype(std::ranges::elements_of(r)),
+                                     std::ranges::elements_of<Range<Iterator>&, std::allocator<std::byte>>>);
+          static_assert(std::same_as<decltype(std::ranges::elements_of(Range<Iterator>())),
+                                     std::ranges::elements_of<Range<Iterator>&&, std::allocator<std::byte>>>);
+
+          Allocator a;
+          static_assert(std::same_as<decltype(std::ranges::elements_of(r, a)),
+                                     std::ranges::elements_of<Range<Iterator>&, Allocator>>);
+          static_assert(std::same_as<decltype(std::ranges::elements_of(Range<Iterator>(), Allocator())),
+                                     std::ranges::elements_of<Range<Iterator>&&, Allocator>>);
+        });
+      });
+
+  return true;
+}
+
+static_assert(test());
diff --git a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
index 8bdb4f7992ae23..8c6a8f98058c85 100644
--- a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
+++ b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
@@ -12,7 +12,6 @@
 
 #include <ranges>
 
-#include <concepts>
 #include <memory>
 #include <vector>
 
@@ -20,30 +19,63 @@
 #include "test_allocator.h"
 #include "test_iterators.h"
 
-template <typename Range>
+template <class Iterator>
+struct Range {
+  using Sentinel = sentinel_wrapper<Iterator>;
+
+  Iterator begin() { return Iterator(data.data()); }
+
+  sentinel_wrapper<Iterator> end() { return Sentinel(Iterator(data.data() + data.size())); }
+
+  std::vector<int> data = {0, 1, 2, 3};
+};
+
+template <class Range, class Allocator>
 constexpr bool test_range() {
-  std::same_as<std::ranges::elements_of<Range&&, std::allocator<std::byte>>> decltype(auto) elements_of =
-      std::ranges::elements_of(Range());
-  [[maybe_unused]] std::same_as<Range&&> decltype(auto) elements_of_range = std::move(elements_of.range);
-  [[maybe_unused]] std::same_as<std::allocator<std::byte>> decltype(auto) elements_of_allocator = elements_of.allocator;
-  return true;
-}
+  Range r;
+
+  using elements_of_t = std::ranges::elements_of<Range&, Allocator>;
+  {
+    // constructor
+    std::same_as<elements_of_t> decltype(auto) elements_of                 = std::ranges::elements_of(r, Allocator());
+    [[maybe_unused]] std::same_as<Range&> decltype(auto) elements_of_range = elements_of.range;
+    [[maybe_unused]] std::same_as<Allocator> decltype(auto) elements_of_allocator = elements_of.allocator;
+  }
+  {
+    // designated initializer
+    std::same_as<elements_of_t> decltype(auto) elements_of = std::ranges::elements_of{
+        .range     = r,
+        .allocator = Allocator(),
+    };
+    [[maybe_unused]] std::same_as<Range&> decltype(auto) elements_of_range        = elements_of.range;
+    [[maybe_unused]] std::same_as<Allocator> decltype(auto) elements_of_allocator = elements_of.allocator;
+  }
+  {
+    // copy constructor
+    std::same_as<elements_of_t> decltype(auto) elements_of_1                 = std::ranges::elements_of(r, Allocator());
+    std::same_as<elements_of_t> auto elements_of_2                           = elements_of_1;
+    [[maybe_unused]] std::same_as<Range&> decltype(auto) elements_of_1_range = elements_of_1.range;
+    [[maybe_unused]] std::same_as<Range&> decltype(auto) elements_of_2_range = elements_of_2.range;
+    [[maybe_unused]] std::same_as<Allocator> decltype(auto) elements_of_2_allocator = elements_of_2.allocator;
+  }
 
-template <typename Range, typename Allocator>
-constexpr bool test_range_with_allocator() {
-  std::same_as< std::ranges::elements_of< Range&&, Allocator >> decltype(auto) elements_of =
-      std::ranges::elements_of(Range(), Allocator());
-  [[maybe_unused]] std::same_as<Range&&> decltype(auto) elements_of_range       = std::move(elements_of.range);
-  [[maybe_unused]] std::same_as<Allocator> decltype(auto) elements_of_allocator = elements_of.allocator;
+  using elements_of_r_t = std::ranges::elements_of<Range&&, Allocator>;
+  {
+    // move constructor
+    std::same_as<elements_of_r_t> decltype(auto) elements_of_1 = std::ranges::elements_of(std::move(r), Allocator());
+    std::same_as<elements_of_r_t> auto elements_of_2           = std::move(elements_of_1);
+    [[maybe_unused]] std::same_as<Range&&> decltype(auto) elements_of_1_range       = std::move(elements_of_1.range);
+    [[maybe_unused]] std::same_as<Range&&> decltype(auto) elements_of_2_range       = std::move(elements_of_2.range);
+    [[maybe_unused]] std::same_as<Allocator> decltype(auto) elements_of_2_allocator = elements_of_2.allocator;
+  }
   return true;
 }
 
 constexpr bool test() {
   types::for_each(types::type_list<std::allocator<std::byte>, min_allocator<std::byte>, test_allocator<std::byte>>{},
                   []<class Allocator> {
-                    types::for_each(types::type_list<std::vector<int>>{}, []<class Range> {
-                      test_range<Range>();
-                      test_range_with_allocator<Range, Allocator>();
+                    types::for_each(types::cpp20_input_iterator_list<int*>{}, []<class Iterator> {
+                      test_range<Range<Iterator>, Allocator>();
                     });
                   });
 

>From cd3b4cd40ee16c41e7c3f5070e7fde13c1373c84 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Thu, 8 Aug 2024 14:09:12 -0400
Subject: [PATCH 14/25] [libc++][ranges] implement 'ranges::elements_of'

---
 .../range.elementsof/elements_of.pass.cpp     | 28 +++++++++++++++----
 1 file changed, 22 insertions(+), 6 deletions(-)

diff --git a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
index 8c6a8f98058c85..945d9dd67a34ab 100644
--- a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
+++ b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
@@ -13,6 +13,7 @@
 #include <ranges>
 
 #include <memory>
+#include <type_traits>
 #include <vector>
 
 #include "min_allocator.h"
@@ -23,11 +24,12 @@ template <class Iterator>
 struct Range {
   using Sentinel = sentinel_wrapper<Iterator>;
 
-  Iterator begin() { return Iterator(data.data()); }
+  Iterator begin() { return Iterator(data_.data()); }
 
-  sentinel_wrapper<Iterator> end() { return Sentinel(Iterator(data.data() + data.size())); }
+  sentinel_wrapper<Iterator> end() { return Sentinel(Iterator(data_.data() + data_.size())); }
 
-  std::vector<int> data = {0, 1, 2, 3};
+private:
+  std::vector<int> data_ = {0, 1, 2, 3};
 };
 
 template <class Range, class Allocator>
@@ -39,6 +41,9 @@ constexpr bool test_range() {
     // constructor
     std::same_as<elements_of_t> decltype(auto) elements_of                 = std::ranges::elements_of(r, Allocator());
     [[maybe_unused]] std::same_as<Range&> decltype(auto) elements_of_range = elements_of.range;
+    if (!std::is_constant_evaluated()) {
+      assert(std::ranges::distance(elements_of_range) == 4);
+    }
     [[maybe_unused]] std::same_as<Allocator> decltype(auto) elements_of_allocator = elements_of.allocator;
   }
   {
@@ -47,7 +52,10 @@ constexpr bool test_range() {
         .range     = r,
         .allocator = Allocator(),
     };
-    [[maybe_unused]] std::same_as<Range&> decltype(auto) elements_of_range        = elements_of.range;
+    [[maybe_unused]] std::same_as<Range&> decltype(auto) elements_of_range = elements_of.range;
+    if (!std::is_constant_evaluated()) {
+      assert(std::ranges::distance(elements_of_range) == 4);
+    }
     [[maybe_unused]] std::same_as<Allocator> decltype(auto) elements_of_allocator = elements_of.allocator;
   }
   {
@@ -56,6 +64,10 @@ constexpr bool test_range() {
     std::same_as<elements_of_t> auto elements_of_2                           = elements_of_1;
     [[maybe_unused]] std::same_as<Range&> decltype(auto) elements_of_1_range = elements_of_1.range;
     [[maybe_unused]] std::same_as<Range&> decltype(auto) elements_of_2_range = elements_of_2.range;
+    if (!std::is_constant_evaluated()) {
+      assert(std::ranges::distance(elements_of_1_range) == 4);
+      assert(std::ranges::distance(elements_of_2_range) == 4);
+    }
     [[maybe_unused]] std::same_as<Allocator> decltype(auto) elements_of_2_allocator = elements_of_2.allocator;
   }
 
@@ -64,8 +76,12 @@ constexpr bool test_range() {
     // move constructor
     std::same_as<elements_of_r_t> decltype(auto) elements_of_1 = std::ranges::elements_of(std::move(r), Allocator());
     std::same_as<elements_of_r_t> auto elements_of_2           = std::move(elements_of_1);
-    [[maybe_unused]] std::same_as<Range&&> decltype(auto) elements_of_1_range       = std::move(elements_of_1.range);
-    [[maybe_unused]] std::same_as<Range&&> decltype(auto) elements_of_2_range       = std::move(elements_of_2.range);
+    [[maybe_unused]] std::same_as<Range&&> decltype(auto) elements_of_1_range = std::move(elements_of_1.range);
+    [[maybe_unused]] std::same_as<Range&&> decltype(auto) elements_of_2_range = std::move(elements_of_2.range);
+    if (!std::is_constant_evaluated()) {
+      assert(std::ranges::distance(elements_of_1_range) == 4);
+      assert(std::ranges::distance(elements_of_2_range) == 4);
+    }
     [[maybe_unused]] std::same_as<Allocator> decltype(auto) elements_of_2_allocator = elements_of_2.allocator;
   }
   return true;

>From bfb0e2511fb6d0d83178fb9f90a4a00f9b1dd0df Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Thu, 8 Aug 2024 14:18:39 -0400
Subject: [PATCH 15/25] [libc++][ranges] implement 'ranges::elements_of'

---
 libcxx/test/libcxx/transitive_includes/cxx03.csv | 1 -
 1 file changed, 1 deletion(-)

diff --git a/libcxx/test/libcxx/transitive_includes/cxx03.csv b/libcxx/test/libcxx/transitive_includes/cxx03.csv
index f0efe06a01cd18..fd2cd7f1c2d961 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx03.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx03.csv
@@ -671,7 +671,6 @@ ranges initializer_list
 ranges iosfwd
 ranges iterator
 ranges limits
-ranges new
 ranges optional
 ranges span
 ranges tuple

>From aacbc6b65346b18b1e2cd065387d42aebb800868 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Thu, 8 Aug 2024 15:42:24 -0400
Subject: [PATCH 16/25] [libc++][ranges] implement 'ranges::elements_of'

---
 libcxx/test/libcxx/transitive_includes/cxx11.csv | 2 +-
 libcxx/test/libcxx/transitive_includes/cxx14.csv | 2 +-
 libcxx/test/libcxx/transitive_includes/cxx17.csv | 2 +-
 libcxx/test/libcxx/transitive_includes/cxx20.csv | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/libcxx/test/libcxx/transitive_includes/cxx11.csv b/libcxx/test/libcxx/transitive_includes/cxx11.csv
index 64a4954730d979..1d4dea0b18ba6b 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx11.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx11.csv
@@ -676,7 +676,7 @@ ranges initializer_list
 ranges iosfwd
 ranges iterator
 ranges limits
-ranges new
+
 ranges optional
 ranges span
 ranges tuple
diff --git a/libcxx/test/libcxx/transitive_includes/cxx14.csv b/libcxx/test/libcxx/transitive_includes/cxx14.csv
index bc56918cb638b7..72f55701ee1b33 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx14.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx14.csv
@@ -679,7 +679,7 @@ ranges initializer_list
 ranges iosfwd
 ranges iterator
 ranges limits
-ranges new
+
 ranges optional
 ranges span
 ranges tuple
diff --git a/libcxx/test/libcxx/transitive_includes/cxx17.csv b/libcxx/test/libcxx/transitive_includes/cxx17.csv
index 29791eb0b56e32..2591484084da51 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx17.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv
@@ -680,7 +680,7 @@ ranges initializer_list
 ranges iosfwd
 ranges iterator
 ranges limits
-ranges new
+
 ranges optional
 ranges span
 ranges tuple
diff --git a/libcxx/test/libcxx/transitive_includes/cxx20.csv b/libcxx/test/libcxx/transitive_includes/cxx20.csv
index 70470de2106e77..8d832cdacf993b 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx20.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv
@@ -687,7 +687,7 @@ ranges initializer_list
 ranges iosfwd
 ranges iterator
 ranges limits
-ranges new
+
 ranges optional
 ranges span
 ranges tuple

>From ffc970083fa5b3e4950dfb2479d9d625ddfd29db Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Thu, 8 Aug 2024 15:43:08 -0400
Subject: [PATCH 17/25] [libc++][ranges] implement 'ranges::elements_of'

---
 libcxx/test/libcxx/transitive_includes/cxx11.csv | 1 -
 libcxx/test/libcxx/transitive_includes/cxx14.csv | 1 -
 libcxx/test/libcxx/transitive_includes/cxx17.csv | 1 -
 libcxx/test/libcxx/transitive_includes/cxx20.csv | 1 -
 4 files changed, 4 deletions(-)

diff --git a/libcxx/test/libcxx/transitive_includes/cxx11.csv b/libcxx/test/libcxx/transitive_includes/cxx11.csv
index 1d4dea0b18ba6b..04122fd0f4571a 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx11.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx11.csv
@@ -676,7 +676,6 @@ ranges initializer_list
 ranges iosfwd
 ranges iterator
 ranges limits
-
 ranges optional
 ranges span
 ranges tuple
diff --git a/libcxx/test/libcxx/transitive_includes/cxx14.csv b/libcxx/test/libcxx/transitive_includes/cxx14.csv
index 72f55701ee1b33..42c742bead0c1f 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx14.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx14.csv
@@ -679,7 +679,6 @@ ranges initializer_list
 ranges iosfwd
 ranges iterator
 ranges limits
-
 ranges optional
 ranges span
 ranges tuple
diff --git a/libcxx/test/libcxx/transitive_includes/cxx17.csv b/libcxx/test/libcxx/transitive_includes/cxx17.csv
index 2591484084da51..bc0659127d4bf5 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx17.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv
@@ -680,7 +680,6 @@ ranges initializer_list
 ranges iosfwd
 ranges iterator
 ranges limits
-
 ranges optional
 ranges span
 ranges tuple
diff --git a/libcxx/test/libcxx/transitive_includes/cxx20.csv b/libcxx/test/libcxx/transitive_includes/cxx20.csv
index 8d832cdacf993b..fed0944f0219c4 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx20.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv
@@ -687,7 +687,6 @@ ranges initializer_list
 ranges iosfwd
 ranges iterator
 ranges limits
-
 ranges optional
 ranges span
 ranges tuple

>From 4c72a3a27463672b1eac3582836851778634ce02 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Thu, 8 Aug 2024 23:46:16 -0400
Subject: [PATCH 18/25] [libc++][ranges] implement 'ranges::elements_of'

---
 .../range.elementsof/elements_of.pass.cpp     | 22 ++++++++++++-------
 1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
index 945d9dd67a34ab..13ce4cbea964da 100644
--- a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
+++ b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
@@ -48,15 +48,21 @@ constexpr bool test_range() {
   }
   {
     // designated initializer
-    std::same_as<elements_of_t> decltype(auto) elements_of = std::ranges::elements_of{
-        .range     = r,
-        .allocator = Allocator(),
-    };
-    [[maybe_unused]] std::same_as<Range&> decltype(auto) elements_of_range = elements_of.range;
-    if (!std::is_constant_evaluated()) {
-      assert(std::ranges::distance(elements_of_range) == 4);
+  
+    // AppleClang 15 hasn't implemented P0960R3, so `std::ranges::elements_of` requires a
+    // user-defined constructor, making it non-aggregate and therefore incompatible with designated
+    // initializers.
+    if constexpr (std::is_aggregate_v<elements_of_t>) {
+      std::same_as<elements_of_t> decltype(auto) elements_of = std::ranges::elements_of{
+          .range     = r,
+          .allocator = Allocator(),
+      };
+      [[maybe_unused]] std::same_as<Range&> decltype(auto) elements_of_range = elements_of.range;
+      if (!std::is_constant_evaluated()) {
+        assert(std::ranges::distance(elements_of_range) == 4);
+      }
+      [[maybe_unused]] std::same_as<Allocator> decltype(auto) elements_of_allocator = elements_of.allocator;
     }
-    [[maybe_unused]] std::same_as<Allocator> decltype(auto) elements_of_allocator = elements_of.allocator;
   }
   {
     // copy constructor

>From c2df436f696ba4494ce676436d7022c2cf222604 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Thu, 8 Aug 2024 23:52:09 -0400
Subject: [PATCH 19/25] [libc++][ranges] implement 'ranges::elements_of'

---
 .../ranges/range.utility/range.elementsof/elements_of.pass.cpp  | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
index 13ce4cbea964da..38392383029d0d 100644
--- a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
+++ b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
@@ -48,7 +48,7 @@ constexpr bool test_range() {
   }
   {
     // designated initializer
-  
+
     // AppleClang 15 hasn't implemented P0960R3, so `std::ranges::elements_of` requires a
     // user-defined constructor, making it non-aggregate and therefore incompatible with designated
     // initializers.

>From 5884764de738c8cc30de3d967b662033c6e8f476 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Fri, 9 Aug 2024 00:31:52 -0400
Subject: [PATCH 20/25] [libc++][ranges] implement 'ranges::elements_of'

---
 libcxx/include/__ranges/elements_of.h | 34 +++++++++++++++++----------
 1 file changed, 21 insertions(+), 13 deletions(-)

diff --git a/libcxx/include/__ranges/elements_of.h b/libcxx/include/__ranges/elements_of.h
index f23e8dd4a15e5d..f6e1218cd998a3 100644
--- a/libcxx/include/__ranges/elements_of.h
+++ b/libcxx/include/__ranges/elements_of.h
@@ -17,7 +17,7 @@
 #include <cstddef>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
-#  pragma GCC system_header
+#pragma GCC system_header
 #endif
 
 _LIBCPP_PUSH_MACROS
@@ -29,24 +29,32 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 namespace ranges {
 
-template <range _Range, class _Allocator = allocator<byte>>
-struct elements_of {
+template <range _Range, class _Allocator = allocator<byte>> struct elements_of {
   _LIBCPP_NO_UNIQUE_ADDRESS _Range range;
   _LIBCPP_NO_UNIQUE_ADDRESS _Allocator allocator = _Allocator();
 
-#  if defined(_LIBCPP_COMPILER_CLANG_BASED) && defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER < 1600
-  // This explicit constructor is required because AppleClang 15 hasn't implemented P0960R3.
-  _LIBCPP_HIDE_FROM_ABI explicit constexpr elements_of(_Range __range, _Allocator __alloc = _Allocator())
-      : range(std::move(__range)), allocator(std::move(__alloc)) {}
-#  endif
+#if defined(_LIBCPP_COMPILER_CLANG_BASED) &&                                   \
+    defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER < 1600
+  // This explicit constructor is required because AppleClang 15 hasn't
+  // implemented P0960R3.
+  template <std::ranges::range _Range2,
+            class _Allocator2 = std::allocator<std::byte>>
+  _LIBCPP_HIDE_FROM_ABI explicit constexpr elements_of(
+      _Range2 &&Range, _Allocator2 &&Alloc = _Allocator())
+      : range(std::forward<_Range2>(Range)),
+        allocator(std::forward<_Allocator2>(Alloc)) {}
+#endif
 };
 
 template <class _Range, class _Allocator = allocator<byte>>
-#  if defined(_LIBCPP_COMPILER_CLANG_BASED) && defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER < 1600
-// This explicit constraint is required because AppleClang 15 might not deduce the correct type for `_Range` without it.
-  requires range<_Range&&>
-#  endif
-elements_of(_Range&&, _Allocator = _Allocator()) -> elements_of<_Range&&, _Allocator>;
+#if defined(_LIBCPP_COMPILER_CLANG_BASED) &&                                   \
+    defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER < 1600
+// This explicit constraint is required because AppleClang 15 might not deduce
+// the correct type for `_Range` without it.
+  requires range<_Range &&>
+#endif
+elements_of(_Range &&,
+            _Allocator = _Allocator()) -> elements_of<_Range &&, _Allocator>;
 
 } // namespace ranges
 

>From 752d590e4f8dd8ab28ba30129dfbd614654121a1 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Fri, 9 Aug 2024 02:37:21 -0400
Subject: [PATCH 21/25] [libc++][ranges] implement 'ranges::elements_of'

---
 libcxx/include/__ranges/elements_of.h | 31 +++++++++++----------------
 1 file changed, 13 insertions(+), 18 deletions(-)

diff --git a/libcxx/include/__ranges/elements_of.h b/libcxx/include/__ranges/elements_of.h
index f6e1218cd998a3..bb79adeed538ca 100644
--- a/libcxx/include/__ranges/elements_of.h
+++ b/libcxx/include/__ranges/elements_of.h
@@ -13,11 +13,11 @@
 #include <__config>
 #include <__memory/allocator.h>
 #include <__ranges/concepts.h>
-#include <__utility/move.h>
+#include <__utility/forward.h>
 #include <cstddef>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
-#pragma GCC system_header
+#  pragma GCC system_header
 #endif
 
 _LIBCPP_PUSH_MACROS
@@ -29,32 +29,27 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 namespace ranges {
 
-template <range _Range, class _Allocator = allocator<byte>> struct elements_of {
+template <range _Range, class _Allocator = allocator<byte>>
+struct elements_of {
   _LIBCPP_NO_UNIQUE_ADDRESS _Range range;
   _LIBCPP_NO_UNIQUE_ADDRESS _Allocator allocator = _Allocator();
 
-#if defined(_LIBCPP_COMPILER_CLANG_BASED) &&                                   \
-    defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER < 1600
+#  if defined(_LIBCPP_COMPILER_CLANG_BASED) && defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER < 1600
   // This explicit constructor is required because AppleClang 15 hasn't
   // implemented P0960R3.
-  template <std::ranges::range _Range2,
-            class _Allocator2 = std::allocator<std::byte>>
-  _LIBCPP_HIDE_FROM_ABI explicit constexpr elements_of(
-      _Range2 &&Range, _Allocator2 &&Alloc = _Allocator())
-      : range(std::forward<_Range2>(Range)),
-        allocator(std::forward<_Allocator2>(Alloc)) {}
-#endif
+  template <std::ranges::range _Range2, class _Allocator2 = std::allocator<std::byte>>
+  _LIBCPP_HIDE_FROM_ABI explicit constexpr elements_of(_Range2&& Range, _Allocator2&& Alloc = _Allocator())
+      : range(std::forward<_Range2>(Range)), allocator(std::forward<_Allocator2>(Alloc)) {}
+#  endif
 };
 
 template <class _Range, class _Allocator = allocator<byte>>
-#if defined(_LIBCPP_COMPILER_CLANG_BASED) &&                                   \
-    defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER < 1600
+#  if defined(_LIBCPP_COMPILER_CLANG_BASED) && defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER < 1600
 // This explicit constraint is required because AppleClang 15 might not deduce
 // the correct type for `_Range` without it.
-  requires range<_Range &&>
-#endif
-elements_of(_Range &&,
-            _Allocator = _Allocator()) -> elements_of<_Range &&, _Allocator>;
+  requires range<_Range&&>
+#  endif
+elements_of(_Range&&, _Allocator = _Allocator()) -> elements_of<_Range&&, _Allocator>;
 
 } // namespace ranges
 

>From 93c65aa6c7fc7117fb153ca32c3e84c62e2a0051 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Mon, 12 Aug 2024 21:37:53 -0400
Subject: [PATCH 22/25] [libc++][ranges] implement 'ranges::elements_of'

---
 .../ranges/range.utility/range.elementsof/elements_of.pass.cpp   | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
index 38392383029d0d..090a0dd50c778f 100644
--- a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
+++ b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
@@ -12,6 +12,7 @@
 
 #include <ranges>
 
+#include <concepts>
 #include <memory>
 #include <type_traits>
 #include <vector>

>From 94b9c2c31884c5ed15bcf7044f2979d0eb6cce7a Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Sun, 18 Aug 2024 15:52:22 -0400
Subject: [PATCH 23/25] [libc++][ranges] implement 'ranges::elements_of'

---
 libcxx/include/__ranges/elements_of.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/include/__ranges/elements_of.h b/libcxx/include/__ranges/elements_of.h
index bb79adeed538ca..fd918c3df0233d 100644
--- a/libcxx/include/__ranges/elements_of.h
+++ b/libcxx/include/__ranges/elements_of.h
@@ -34,7 +34,7 @@ struct elements_of {
   _LIBCPP_NO_UNIQUE_ADDRESS _Range range;
   _LIBCPP_NO_UNIQUE_ADDRESS _Allocator allocator = _Allocator();
 
-#  if defined(_LIBCPP_COMPILER_CLANG_BASED) && defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER < 1600
+#  if !defined(__cpp_aggregate_paren_init)
   // This explicit constructor is required because AppleClang 15 hasn't
   // implemented P0960R3.
   template <std::ranges::range _Range2, class _Allocator2 = std::allocator<std::byte>>

>From 06f28a1a0f3a60fcb2ead8f700bd2d3bb4c3296b Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Tue, 27 Aug 2024 21:31:36 -0400
Subject: [PATCH 24/25] [libc++][ranges] implement 'ranges::elements_of'

---
 libcxx/include/__ranges/elements_of.h         |  2 +-
 .../range.elementsof/ctad.compile.pass.cpp    | 10 +++++++
 .../range.elementsof/elements_of.pass.cpp     | 28 +++++++++----------
 3 files changed, 24 insertions(+), 16 deletions(-)

diff --git a/libcxx/include/__ranges/elements_of.h b/libcxx/include/__ranges/elements_of.h
index fd918c3df0233d..f414a662907a9e 100644
--- a/libcxx/include/__ranges/elements_of.h
+++ b/libcxx/include/__ranges/elements_of.h
@@ -37,7 +37,7 @@ struct elements_of {
 #  if !defined(__cpp_aggregate_paren_init)
   // This explicit constructor is required because AppleClang 15 hasn't
   // implemented P0960R3.
-  template <std::ranges::range _Range2, class _Allocator2 = std::allocator<std::byte>>
+  template <std::ranges::range _Range2, class _Allocator2 = std::allocator<byte>>
   _LIBCPP_HIDE_FROM_ABI explicit constexpr elements_of(_Range2&& Range, _Allocator2&& Alloc = _Allocator())
       : range(std::forward<_Range2>(Range)), allocator(std::forward<_Allocator2>(Alloc)) {}
 #  endif
diff --git a/libcxx/test/std/ranges/range.utility/range.elementsof/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.utility/range.elementsof/ctad.compile.pass.cpp
index 3a679b521f75e5..0f9204a07118ee 100644
--- a/libcxx/test/std/ranges/range.utility/range.elementsof/ctad.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.utility/range.elementsof/ctad.compile.pass.cpp
@@ -40,6 +40,16 @@ constexpr bool test() {
                                      std::ranges::elements_of<Range<Iterator>&, Allocator>>);
           static_assert(std::same_as<decltype(std::ranges::elements_of(Range<Iterator>(), Allocator())),
                                      std::ranges::elements_of<Range<Iterator>&&, Allocator>>);
+
+// AppleClang 15 hasn't implemented P0960R3 and P1816R0
+#if defined(__cpp_aggregate_paren_init) && __cpp_aggregate_paren_init >= 201902L && defined(__cpp_deduction_guides) && \
+    __cpp_deduction_guides >= 201907L
+          static_assert(std::same_as<decltype(std::ranges::elements_of{.range = r, .allocator = a}),
+                                     std::ranges::elements_of<Range<Iterator>&, Allocator>>);
+          static_assert(
+              std::same_as<decltype(std::ranges::elements_of{.range = Range<Iterator>(), .allocator = Allocator()}),
+                           std::ranges::elements_of<Range<Iterator>&&, Allocator>>);
+#endif
         });
       });
 
diff --git a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
index 090a0dd50c778f..f18a3bc8c61bc0 100644
--- a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
+++ b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
@@ -48,22 +48,20 @@ constexpr bool test_range() {
     [[maybe_unused]] std::same_as<Allocator> decltype(auto) elements_of_allocator = elements_of.allocator;
   }
   {
-    // designated initializer
-
-    // AppleClang 15 hasn't implemented P0960R3, so `std::ranges::elements_of` requires a
-    // user-defined constructor, making it non-aggregate and therefore incompatible with designated
-    // initializers.
-    if constexpr (std::is_aggregate_v<elements_of_t>) {
-      std::same_as<elements_of_t> decltype(auto) elements_of = std::ranges::elements_of{
-          .range     = r,
-          .allocator = Allocator(),
-      };
-      [[maybe_unused]] std::same_as<Range&> decltype(auto) elements_of_range = elements_of.range;
-      if (!std::is_constant_evaluated()) {
-        assert(std::ranges::distance(elements_of_range) == 4);
-      }
-      [[maybe_unused]] std::same_as<Allocator> decltype(auto) elements_of_allocator = elements_of.allocator;
+// designated initializer
+// AppleClang 15 hasn't implemented P0960R3 and P1816R0
+#if defined(__cpp_aggregate_paren_init) && __cpp_aggregate_paren_init >= 201902L && defined(__cpp_deduction_guides) && \
+    __cpp_deduction_guides >= 201907L
+    std::same_as<elements_of_t> decltype(auto) elements_of = std::ranges::elements_of{
+        .range     = r,
+        .allocator = Allocator(),
+    };
+    [[maybe_unused]] std::same_as<Range&> decltype(auto) elements_of_range = elements_of.range;
+    if (!std::is_constant_evaluated()) {
+      assert(std::ranges::distance(elements_of_range) == 4);
     }
+    [[maybe_unused]] std::same_as<Allocator> decltype(auto) elements_of_allocator = elements_of.allocator;
+#endif
   }
   {
     // copy constructor

>From ea82cce5f0702b2138b17901d716ff88525aad0d Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Thu, 17 Oct 2024 00:30:54 -0400
Subject: [PATCH 25/25] [libc++][ranges] implement 'ranges::elements_of'

---
 libcxx/include/__ranges/elements_of.h                         | 4 ++--
 .../range.utility/range.elementsof/elements_of.pass.cpp       | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/libcxx/include/__ranges/elements_of.h b/libcxx/include/__ranges/elements_of.h
index f414a662907a9e..415565e813f397 100644
--- a/libcxx/include/__ranges/elements_of.h
+++ b/libcxx/include/__ranges/elements_of.h
@@ -38,8 +38,8 @@ struct elements_of {
   // This explicit constructor is required because AppleClang 15 hasn't
   // implemented P0960R3.
   template <std::ranges::range _Range2, class _Allocator2 = std::allocator<byte>>
-  _LIBCPP_HIDE_FROM_ABI explicit constexpr elements_of(_Range2&& Range, _Allocator2&& Alloc = _Allocator())
-      : range(std::forward<_Range2>(Range)), allocator(std::forward<_Allocator2>(Alloc)) {}
+  _LIBCPP_HIDE_FROM_ABI explicit constexpr elements_of(_Range2&& __range, _Allocator2&& __alloc = _Allocator())
+      : range(std::forward<_Range2>(__range)), allocator(std::forward<_Allocator2>(__alloc)) {}
 #  endif
 };
 
diff --git a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
index f18a3bc8c61bc0..5f63f090f45ff6 100644
--- a/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
+++ b/libcxx/test/std/ranges/range.utility/range.elementsof/elements_of.pass.cpp
@@ -27,7 +27,7 @@ struct Range {
 
   Iterator begin() { return Iterator(data_.data()); }
 
-  sentinel_wrapper<Iterator> end() { return Sentinel(Iterator(data_.data() + data_.size())); }
+  Sentinel end() { return Sentinel(Iterator(data_.data() + data_.size())); }
 
 private:
   std::vector<int> data_ = {0, 1, 2, 3};



More information about the libcxx-commits mailing list