[libcxx-commits] [libcxx] e9280a1 - [libc++] Backport segmented iterator optimization for std::for_each to C++11 (#134960)

via libcxx-commits libcxx-commits at lists.llvm.org
Sat Apr 19 04:12:46 PDT 2025


Author: Peng Liu
Date: 2025-04-19T07:12:43-04:00
New Revision: e9280a1d39af88468ffea9a14fad5bf96d51d6e6

URL: https://github.com/llvm/llvm-project/commit/e9280a1d39af88468ffea9a14fad5bf96d51d6e6
DIFF: https://github.com/llvm/llvm-project/commit/e9280a1d39af88468ffea9a14fad5bf96d51d6e6.diff

LOG: [libc++] Backport segmented iterator optimization for std::for_each to C++11 (#134960)

Previously, the segmented iterator optimization for `std::for_each` was restricted to C++23 and later due to its dependency on `__movable_box`, which is not available in earlier standards. This patch eliminates that restriction, enabling consistent optimizations starting from C++11. 

By backporting this enhancement, we improve performance across older standards and create opportunities to extend similar optimizations to other algorithms by forwarding their calls to `std::for_each`.

Added: 
    

Modified: 
    libcxx/docs/ReleaseNotes/21.rst
    libcxx/include/__algorithm/for_each.h
    libcxx/include/algorithm
    libcxx/include/array
    libcxx/include/bitset
    libcxx/include/codecvt
    libcxx/include/condition_variable
    libcxx/include/ios
    libcxx/include/locale
    libcxx/include/streambuf
    libcxx/include/string
    libcxx/include/string_view
    libcxx/include/system_error
    libcxx/include/vector
    libcxx/test/libcxx/algorithms/robust_against_copying_comparators.pass.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/ReleaseNotes/21.rst b/libcxx/docs/ReleaseNotes/21.rst
index 2091a713ea200..a7382c5222d08 100644
--- a/libcxx/docs/ReleaseNotes/21.rst
+++ b/libcxx/docs/ReleaseNotes/21.rst
@@ -67,6 +67,9 @@ Improvements and New Features
 - The ``std::stable_sort`` algorithm uses radix sort for floating-point types now, which can improve the performance
   up to 10x, depending on type of sorted elements and the initial state of the sorted array.
 
+- The segmented iterator optimization for ``std::for_each`` has been backported to C++11. Previously it was only available
+  in C++23 and later.
+
 Deprecations and Removals
 -------------------------
 

diff  --git a/libcxx/include/__algorithm/for_each.h b/libcxx/include/__algorithm/for_each.h
index e08f583504c01..b6c2c7c056edd 100644
--- a/libcxx/include/__algorithm/for_each.h
+++ b/libcxx/include/__algorithm/for_each.h
@@ -13,44 +13,40 @@
 #include <__algorithm/for_each_segment.h>
 #include <__config>
 #include <__iterator/segmented_iterator.h>
-#include <__ranges/movable_box.h>
-#include <__utility/in_place.h>
-#include <__utility/move.h>
+#include <__type_traits/enable_if.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
 #endif
 
-_LIBCPP_PUSH_MACROS
-#include <__undef_macros>
-
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-template <class _InputIterator, class _Function>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Function
-for_each(_InputIterator __first, _InputIterator __last, _Function __f) {
+template <class _InputIterator, class _Sent, class _Func>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __for_each(_InputIterator __first, _Sent __last, _Func& __f) {
   for (; __first != __last; ++__first)
     __f(*__first);
-  return __f;
 }
 
-// __movable_box is available in C++20, but is actually a copyable-box, so optimization is only correct in C++23
-#if _LIBCPP_STD_VER >= 23
-template <class _SegmentedIterator, class _Function>
-  requires __is_segmented_iterator<_SegmentedIterator>::value
-_LIBCPP_HIDE_FROM_ABI constexpr _Function
-for_each(_SegmentedIterator __first, _SegmentedIterator __last, _Function __func) {
-  ranges::__movable_box<_Function> __wrapped_func(in_place, std::move(__func));
-  std::__for_each_segment(__first, __last, [&](auto __lfirst, auto __llast) {
-    __wrapped_func =
-        ranges::__movable_box<_Function>(in_place, std::for_each(__lfirst, __llast, std::move(*__wrapped_func)));
+#ifndef _LIBCPP_CXX03_LANG
+template <class _SegmentedIterator,
+          class _Function,
+          __enable_if_t<__is_segmented_iterator<_SegmentedIterator>::value, int> = 0>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
+__for_each(_SegmentedIterator __first, _SegmentedIterator __last, _Function& __func) {
+  using __local_iterator_t = typename __segmented_iterator_traits<_SegmentedIterator>::__local_iterator;
+  std::__for_each_segment(__first, __last, [&](__local_iterator_t __lfirst, __local_iterator_t __llast) {
+    std::__for_each(__lfirst, __llast, __func);
   });
-  return std::move(*__wrapped_func);
 }
-#endif // _LIBCPP_STD_VER >= 23
+#endif // !_LIBCPP_CXX03_LANG
 
-_LIBCPP_END_NAMESPACE_STD
+template <class _InputIterator, class _Function>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Function
+for_each(_InputIterator __first, _InputIterator __last, _Function __f) {
+  std::__for_each(__first, __last, __f);
+  return __f;
+}
 
-_LIBCPP_POP_MACROS
+_LIBCPP_END_NAMESPACE_STD
 
 #endif // _LIBCPP___ALGORITHM_FOR_EACH_H

diff  --git a/libcxx/include/algorithm b/libcxx/include/algorithm
index bf67d3363a595..64e9fa6306145 100644
--- a/libcxx/include/algorithm
+++ b/libcxx/include/algorithm
@@ -2061,6 +2061,7 @@ template <class BidirectionalIterator, class Compare>
 #    include <cstring>
 #    include <iterator>
 #    include <memory>
+#    include <optional>
 #    include <stdexcept>
 #    include <type_traits>
 #    include <utility>

diff  --git a/libcxx/include/array b/libcxx/include/array
index 6e3a1d82abb1b..ff46838e2e8e2 100644
--- a/libcxx/include/array
+++ b/libcxx/include/array
@@ -566,6 +566,7 @@ _LIBCPP_POP_MACROS
 #    include <cstdlib>
 #    include <iterator>
 #    include <new>
+#    include <optional>
 #    include <type_traits>
 #    include <utility>
 #  endif

diff  --git a/libcxx/include/bitset b/libcxx/include/bitset
index c403c533db7e9..9273ccabbb4e3 100644
--- a/libcxx/include/bitset
+++ b/libcxx/include/bitset
@@ -973,6 +973,7 @@ _LIBCPP_POP_MACROS
 #  if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20
 #    include <concepts>
 #    include <cstdlib>
+#    include <optional>
 #    include <type_traits>
 #  endif
 #endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)

diff  --git a/libcxx/include/codecvt b/libcxx/include/codecvt
index 9f241b734d694..33ade1d298a7e 100644
--- a/libcxx/include/codecvt
+++ b/libcxx/include/codecvt
@@ -596,6 +596,7 @@ _LIBCPP_END_NAMESPACE_STD
 #    include <limits>
 #    include <mutex>
 #    include <new>
+#    include <optional>
 #    include <stdexcept>
 #    include <type_traits>
 #    include <typeinfo>

diff  --git a/libcxx/include/condition_variable b/libcxx/include/condition_variable
index 7f44990547f55..99c74b02807ae 100644
--- a/libcxx/include/condition_variable
+++ b/libcxx/include/condition_variable
@@ -357,6 +357,7 @@ _LIBCPP_POP_MACROS
 #    include <initializer_list>
 #    include <iosfwd>
 #    include <new>
+#    include <optional>
 #    include <stdexcept>
 #    include <system_error>
 #    include <type_traits>

diff  --git a/libcxx/include/ios b/libcxx/include/ios
index 9d2968753c507..9e48ec88ce59d 100644
--- a/libcxx/include/ios
+++ b/libcxx/include/ios
@@ -887,6 +887,7 @@ _LIBCPP_POP_MACROS
 #    include <limits>
 #    include <mutex>
 #    include <new>
+#    include <optional>
 #    include <stdexcept>
 #    include <system_error>
 #    include <type_traits>

diff  --git a/libcxx/include/locale b/libcxx/include/locale
index 26495497d660f..fa2620d883598 100644
--- a/libcxx/include/locale
+++ b/libcxx/include/locale
@@ -3692,6 +3692,7 @@ _LIBCPP_POP_MACROS
 #    include <cstdarg>
 #    include <iterator>
 #    include <mutex>
+#    include <optional>
 #    include <stdexcept>
 #    include <type_traits>
 #    include <typeinfo>

diff  --git a/libcxx/include/streambuf b/libcxx/include/streambuf
index eed7eb4d75ecb..85f3af1b88ae7 100644
--- a/libcxx/include/streambuf
+++ b/libcxx/include/streambuf
@@ -386,6 +386,7 @@ _LIBCPP_POP_MACROS
 
 #  if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20
 #    include <cstdint>
+#    include <optional>
 #  endif
 #endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
 

diff  --git a/libcxx/include/string b/libcxx/include/string
index e7e541e31432d..f3f97655d79ea 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -4027,6 +4027,7 @@ _LIBCPP_POP_MACROS
 #    include <cstdlib>
 #    include <iterator>
 #    include <new>
+#    include <optional>
 #    include <type_traits>
 #    include <typeinfo>
 #    include <utility>

diff  --git a/libcxx/include/string_view b/libcxx/include/string_view
index 5054b14efd2d5..861187c0640e1 100644
--- a/libcxx/include/string_view
+++ b/libcxx/include/string_view
@@ -952,6 +952,7 @@ _LIBCPP_POP_MACROS
 #    include <concepts>
 #    include <cstdlib>
 #    include <iterator>
+#    include <optional>
 #    include <type_traits>
 #  endif
 #endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)

diff  --git a/libcxx/include/system_error b/libcxx/include/system_error
index 4dadc0a6ab483..2b668e5f8f1bc 100644
--- a/libcxx/include/system_error
+++ b/libcxx/include/system_error
@@ -168,6 +168,7 @@ template <> struct hash<std::error_condition>;
 #    include <cstdint>
 #    include <cstring>
 #    include <limits>
+#    include <optional>
 #    include <type_traits>
 #  endif
 #endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)

diff  --git a/libcxx/include/vector b/libcxx/include/vector
index 9fa81dcb7e76e..d2d5fcf4a3199 100644
--- a/libcxx/include/vector
+++ b/libcxx/include/vector
@@ -362,6 +362,7 @@ template<class T, class charT> requires is-vector-bool-reference<T> // Since C++
 #    if _LIBCPP_HAS_LOCALIZATION
 #      include <locale>
 #    endif
+#    include <optional>
 #    include <string>
 #    include <string_view>
 #    include <tuple>

diff  --git a/libcxx/test/libcxx/algorithms/robust_against_copying_comparators.pass.cpp b/libcxx/test/libcxx/algorithms/robust_against_copying_comparators.pass.cpp
index df656f296bd05..256251686bb3e 100644
--- a/libcxx/test/libcxx/algorithms/robust_against_copying_comparators.pass.cpp
+++ b/libcxx/test/libcxx/algorithms/robust_against_copying_comparators.pass.cpp
@@ -12,209 +12,312 @@
 #include <cassert>
 #include <compare>
 #include <cstddef>
+#include <deque>
+#include <ranges>
 #include <type_traits>
+#include <vector>
 
 #include "test_macros.h"
 
 template <class T>
 struct Less {
-    int *copies_;
-    TEST_CONSTEXPR explicit Less(int *copies) : copies_(copies) {}
-    TEST_CONSTEXPR_CXX14 Less(const Less& rhs) : copies_(rhs.copies_) { *copies_ += 1; }
-    TEST_CONSTEXPR_CXX14 Less& operator=(const Less&) = default;
-    TEST_CONSTEXPR bool operator()(T, T) const { return false; }
+  int* copies_;
+  TEST_CONSTEXPR explicit Less(int* copies) : copies_(copies) {}
+  TEST_CONSTEXPR_CXX14 Less(const Less& rhs) : copies_(rhs.copies_) { *copies_ += 1; }
+  TEST_CONSTEXPR_CXX14 Less& operator=(const Less&) = default;
+  TEST_CONSTEXPR bool operator()(T, T) const { return false; }
 };
 
 template <class T>
 struct Equal {
-    int *copies_;
-    TEST_CONSTEXPR explicit Equal(int *copies) : copies_(copies) {}
-    TEST_CONSTEXPR_CXX14 Equal(const Equal& rhs) : copies_(rhs.copies_) { *copies_ += 1; }
-    TEST_CONSTEXPR_CXX14 Equal& operator=(const Equal&) = default;
-    TEST_CONSTEXPR bool operator()(T, T) const { return true; }
+  int* copies_;
+  TEST_CONSTEXPR explicit Equal(int* copies) : copies_(copies) {}
+  TEST_CONSTEXPR_CXX14 Equal(const Equal& rhs) : copies_(rhs.copies_) { *copies_ += 1; }
+  TEST_CONSTEXPR_CXX14 Equal& operator=(const Equal&) = default;
+  TEST_CONSTEXPR bool operator()(T, T) const { return true; }
 };
 
 template <class T>
 struct UnaryVoid {
-    int *copies_;
-    TEST_CONSTEXPR explicit UnaryVoid(int *copies) : copies_(copies) {}
-    TEST_CONSTEXPR_CXX14 UnaryVoid(const UnaryVoid& rhs) : copies_(rhs.copies_) { *copies_ += 1; }
-    TEST_CONSTEXPR_CXX14 UnaryVoid& operator=(const UnaryVoid&) = default;
-    TEST_CONSTEXPR_CXX14 void operator()(T) const {}
+  int* copies_;
+  TEST_CONSTEXPR explicit UnaryVoid(int* copies) : copies_(copies) {}
+  TEST_CONSTEXPR_CXX14 UnaryVoid(const UnaryVoid& rhs) : copies_(rhs.copies_) { *copies_ += 1; }
+  TEST_CONSTEXPR_CXX14 UnaryVoid& operator=(const UnaryVoid&) = default;
+  TEST_CONSTEXPR_CXX14 void operator()(T) const {}
 };
 
 template <class T>
 struct UnaryTrue {
-    int *copies_;
-    TEST_CONSTEXPR explicit UnaryTrue(int *copies) : copies_(copies) {}
-    TEST_CONSTEXPR_CXX14 UnaryTrue(const UnaryTrue& rhs) : copies_(rhs.copies_) { *copies_ += 1; }
-    TEST_CONSTEXPR_CXX14 UnaryTrue& operator=(const UnaryTrue&) = default;
-    TEST_CONSTEXPR bool operator()(T) const { return true; }
+  int* copies_;
+  TEST_CONSTEXPR explicit UnaryTrue(int* copies) : copies_(copies) {}
+  TEST_CONSTEXPR_CXX14 UnaryTrue(const UnaryTrue& rhs) : copies_(rhs.copies_) { *copies_ += 1; }
+  TEST_CONSTEXPR_CXX14 UnaryTrue& operator=(const UnaryTrue&) = default;
+  TEST_CONSTEXPR bool operator()(T) const { return true; }
 };
 
 template <class T>
 struct NullaryValue {
-    int *copies_;
-    TEST_CONSTEXPR explicit NullaryValue(int *copies) : copies_(copies) {}
-    TEST_CONSTEXPR_CXX14 NullaryValue(const NullaryValue& rhs) : copies_(rhs.copies_) { *copies_ += 1; }
-    TEST_CONSTEXPR_CXX14 NullaryValue& operator=(const NullaryValue&) = default;
-    TEST_CONSTEXPR T operator()() const { return 0; }
+  int* copies_;
+  TEST_CONSTEXPR explicit NullaryValue(int* copies) : copies_(copies) {}
+  TEST_CONSTEXPR_CXX14 NullaryValue(const NullaryValue& rhs) : copies_(rhs.copies_) { *copies_ += 1; }
+  TEST_CONSTEXPR_CXX14 NullaryValue& operator=(const NullaryValue&) = default;
+  TEST_CONSTEXPR T operator()() const { return 0; }
 };
 
 template <class T>
 struct UnaryTransform {
-    int *copies_;
-    TEST_CONSTEXPR explicit UnaryTransform(int *copies) : copies_(copies) {}
-    TEST_CONSTEXPR_CXX14 UnaryTransform(const UnaryTransform& rhs) : copies_(rhs.copies_) { *copies_ += 1; }
-    TEST_CONSTEXPR_CXX14 UnaryTransform& operator=(const UnaryTransform&) = default;
-    TEST_CONSTEXPR T operator()(T) const { return 0; }
+  int* copies_;
+  TEST_CONSTEXPR explicit UnaryTransform(int* copies) : copies_(copies) {}
+  TEST_CONSTEXPR_CXX14 UnaryTransform(const UnaryTransform& rhs) : copies_(rhs.copies_) { *copies_ += 1; }
+  TEST_CONSTEXPR_CXX14 UnaryTransform& operator=(const UnaryTransform&) = default;
+  TEST_CONSTEXPR T operator()(T) const { return 0; }
 };
 
 template <class T>
 struct BinaryTransform {
-    int *copies_;
-    TEST_CONSTEXPR explicit BinaryTransform(int *copies) : copies_(copies) {}
-    TEST_CONSTEXPR_CXX14 BinaryTransform(const BinaryTransform& rhs) : copies_(rhs.copies_) { *copies_ += 1; }
-    TEST_CONSTEXPR_CXX14 BinaryTransform& operator=(const BinaryTransform&) = default;
-    TEST_CONSTEXPR T operator()(T, T) const { return 0; }
+  int* copies_;
+  TEST_CONSTEXPR explicit BinaryTransform(int* copies) : copies_(copies) {}
+  TEST_CONSTEXPR_CXX14 BinaryTransform(const BinaryTransform& rhs) : copies_(rhs.copies_) { *copies_ += 1; }
+  TEST_CONSTEXPR_CXX14 BinaryTransform& operator=(const BinaryTransform&) = default;
+  TEST_CONSTEXPR T operator()(T, T) const { return 0; }
 };
 
 #if TEST_STD_VER > 17
 template <class T>
 struct ThreeWay {
-    int *copies_;
-    constexpr explicit ThreeWay(int *copies) : copies_(copies) {}
-    constexpr ThreeWay(const ThreeWay& rhs) : copies_(rhs.copies_) { *copies_ += 1; }
-    constexpr ThreeWay& operator=(const ThreeWay&) = default;
-    constexpr std::strong_ordering operator()(T, T) const { return std::strong_ordering::equal; }
+  int* copies_;
+  constexpr explicit ThreeWay(int* copies) : copies_(copies) {}
+  constexpr ThreeWay(const ThreeWay& rhs) : copies_(rhs.copies_) { *copies_ += 1; }
+  constexpr ThreeWay& operator=(const ThreeWay&) = default;
+  constexpr std::strong_ordering operator()(T, T) const { return std::strong_ordering::equal; }
 };
 #endif
 
 template <class T>
-TEST_CONSTEXPR_CXX20 bool all_the_algorithms()
-{
-    T a[10] = {};
-    T b[10] = {};
-    T *first = a;
-    T *mid = a+5;
-    T *last = a+10;
-    T *first2 = b;
-    T *mid2 = b+5;
-    T *last2 = b+10;
-    T value = 0;
-    int count = 1;
-
-    int copies = 0;
-    (void)std::adjacent_find(first, last, Equal<T>(&copies)); assert(copies == 0);
+TEST_CONSTEXPR_CXX20 bool all_the_algorithms() {
+  T a[10]   = {};
+  T b[10]   = {};
+  T* first  = a;
+  T* mid    = a + 5;
+  T* last   = a + 10;
+  T* first2 = b;
+  T* mid2   = b + 5;
+  T* last2  = b + 10;
+  T value   = 0;
+  int count = 1;
+
+  int copies = 0;
+  (void)std::adjacent_find(first, last, Equal<T>(&copies));
+  assert(copies == 0);
 #if TEST_STD_VER >= 11
-    (void)std::all_of(first, last, UnaryTrue<T>(&copies)); assert(copies == 0);
-    (void)std::any_of(first, last, UnaryTrue<T>(&copies)); assert(copies == 0);
+  (void)std::all_of(first, last, UnaryTrue<T>(&copies));
+  assert(copies == 0);
+  (void)std::any_of(first, last, UnaryTrue<T>(&copies));
+  assert(copies == 0);
 #endif
-    (void)std::binary_search(first, last, value, Less<T>(&copies)); assert(copies == 0);
+  (void)std::binary_search(first, last, value, Less<T>(&copies));
+  assert(copies == 0);
 #if TEST_STD_VER > 17
-    (void)std::clamp(value, value, value, Less<T>(&copies)); assert(copies == 0);
+  (void)std::clamp(value, value, value, Less<T>(&copies));
+  assert(copies == 0);
 #endif
-    (void)std::count_if(first, last, UnaryTrue<T>(&copies)); assert(copies == 0);
-    (void)std::copy_if(first, last, first2, UnaryTrue<T>(&copies)); assert(copies == 0);
-    (void)std::equal(first, last, first2, Equal<T>(&copies)); assert(copies == 0);
+  (void)std::count_if(first, last, UnaryTrue<T>(&copies));
+  assert(copies == 0);
+  (void)std::copy_if(first, last, first2, UnaryTrue<T>(&copies));
+  assert(copies == 0);
+  (void)std::equal(first, last, first2, Equal<T>(&copies));
+  assert(copies == 0);
 #if TEST_STD_VER > 11
-    (void)std::equal(first, last, first2, last2, Equal<T>(&copies)); assert(copies == 0);
+  (void)std::equal(first, last, first2, last2, Equal<T>(&copies));
+  assert(copies == 0);
 #endif
-    (void)std::equal_range(first, last, value, Less<T>(&copies)); assert(copies == 0);
-    (void)std::find_end(first, last, first2, mid2, Equal<T>(&copies)); assert(copies == 0);
-    (void)std::find_first_of(first, last, first2, last2, Equal<T>(&copies)); assert(copies == 0);
-    (void)std::find_if(first, last, UnaryTrue<T>(&copies)); assert(copies == 0);
-    (void)std::find_if_not(first, last, UnaryTrue<T>(&copies)); assert(copies == 0);
-    (void)std::for_each(first, last, UnaryVoid<T>(&copies)); assert(copies == 1); copies = 0;
+  (void)std::equal_range(first, last, value, Less<T>(&copies));
+  assert(copies == 0);
+  (void)std::find_end(first, last, first2, mid2, Equal<T>(&copies));
+  assert(copies == 0);
+  (void)std::find_first_of(first, last, first2, last2, Equal<T>(&copies));
+  assert(copies == 0);
+  (void)std::find_if(first, last, UnaryTrue<T>(&copies));
+  assert(copies == 0);
+  (void)std::find_if_not(first, last, UnaryTrue<T>(&copies));
+  assert(copies == 0);
+  (void)std::for_each(first, last, UnaryVoid<T>(&copies));
+  assert(copies == 1);
+  copies = 0;
 #if TEST_STD_VER > 14
-    (void)std::for_each_n(first, count, UnaryVoid<T>(&copies)); assert(copies == 0);
+  (void)std::for_each_n(first, count, UnaryVoid<T>(&copies));
+  assert(copies == 0);
 #endif
-    (void)std::generate(first, last, NullaryValue<T>(&copies)); assert(copies == 0);
-    (void)std::generate_n(first, count, NullaryValue<T>(&copies)); assert(copies == 0);
-    (void)std::includes(first, last, first2, last2, Less<T>(&copies)); assert(copies == 0);
-    (void)std::is_heap(first, last, Less<T>(&copies)); assert(copies == 0);
-    (void)std::is_heap_until(first, last, Less<T>(&copies)); assert(copies == 0);
-    (void)std::is_partitioned(first, last, UnaryTrue<T>(&copies)); assert(copies == 0);
-    (void)std::is_permutation(first, last, first2, Equal<T>(&copies)); assert(copies == 0);
+  (void)std::generate(first, last, NullaryValue<T>(&copies));
+  assert(copies == 0);
+  (void)std::generate_n(first, count, NullaryValue<T>(&copies));
+  assert(copies == 0);
+  (void)std::includes(first, last, first2, last2, Less<T>(&copies));
+  assert(copies == 0);
+  (void)std::is_heap(first, last, Less<T>(&copies));
+  assert(copies == 0);
+  (void)std::is_heap_until(first, last, Less<T>(&copies));
+  assert(copies == 0);
+  (void)std::is_partitioned(first, last, UnaryTrue<T>(&copies));
+  assert(copies == 0);
+  (void)std::is_permutation(first, last, first2, Equal<T>(&copies));
+  assert(copies == 0);
 #if TEST_STD_VER > 11
-    (void)std::is_permutation(first, last, first2, last2, Equal<T>(&copies)); assert(copies == 0);
+  (void)std::is_permutation(first, last, first2, last2, Equal<T>(&copies));
+  assert(copies == 0);
 #endif
-    (void)std::is_sorted(first, last, Less<T>(&copies)); assert(copies == 0);
-    (void)std::is_sorted_until(first, last, Less<T>(&copies)); assert(copies == 0);
-    if (!TEST_IS_CONSTANT_EVALUATED) { (void)std::inplace_merge(first, mid, last, Less<T>(&copies)); assert(copies == 0); }
-    (void)std::lexicographical_compare(first, last, first2, last2, Less<T>(&copies)); assert(copies == 0);
+  (void)std::is_sorted(first, last, Less<T>(&copies));
+  assert(copies == 0);
+  (void)std::is_sorted_until(first, last, Less<T>(&copies));
+  assert(copies == 0);
+  if (!TEST_IS_CONSTANT_EVALUATED) {
+    (void)std::inplace_merge(first, mid, last, Less<T>(&copies));
+    assert(copies == 0);
+  }
+  (void)std::lexicographical_compare(first, last, first2, last2, Less<T>(&copies));
+  assert(copies == 0);
 #if TEST_STD_VER > 17
-    (void)std::lexicographical_compare_three_way(first, last, first2, last2, ThreeWay<T>(&copies)); assert(copies == 0);
+  (void)std::lexicographical_compare_three_way(first, last, first2, last2, ThreeWay<T>(&copies));
+  assert(copies == 0);
 #endif
-    (void)std::lower_bound(first, last, value, Less<T>(&copies)); assert(copies == 0);
-    (void)std::make_heap(first, last, Less<T>(&copies)); assert(copies == 0);
-    (void)std::max(value, value, Less<T>(&copies)); assert(copies == 0);
+  (void)std::lower_bound(first, last, value, Less<T>(&copies));
+  assert(copies == 0);
+  (void)std::make_heap(first, last, Less<T>(&copies));
+  assert(copies == 0);
+  (void)std::max(value, value, Less<T>(&copies));
+  assert(copies == 0);
 #if TEST_STD_VER >= 11
-    (void)std::max({ value, value }, Less<T>(&copies)); assert(copies == 0);
+  (void)std::max({value, value}, Less<T>(&copies));
+  assert(copies == 0);
 #endif
-    (void)std::max_element(first, last, Less<T>(&copies)); assert(copies == 0);
-    (void)std::merge(first, mid, mid, last, first2, Less<T>(&copies)); assert(copies == 0);
-    (void)std::min(value, value, Less<T>(&copies)); assert(copies == 0);
+  (void)std::max_element(first, last, Less<T>(&copies));
+  assert(copies == 0);
+  (void)std::merge(first, mid, mid, last, first2, Less<T>(&copies));
+  assert(copies == 0);
+  (void)std::min(value, value, Less<T>(&copies));
+  assert(copies == 0);
 #if TEST_STD_VER >= 11
-    (void)std::min({ value, value }, Less<T>(&copies)); assert(copies == 0);
+  (void)std::min({value, value}, Less<T>(&copies));
+  assert(copies == 0);
 #endif
-    (void)std::min_element(first, last, Less<T>(&copies)); assert(copies == 0);
-    (void)std::minmax(value, value, Less<T>(&copies)); assert(copies == 0);
+  (void)std::min_element(first, last, Less<T>(&copies));
+  assert(copies == 0);
+  (void)std::minmax(value, value, Less<T>(&copies));
+  assert(copies == 0);
 #if TEST_STD_VER >= 11
-    (void)std::minmax({ value, value }, Less<T>(&copies)); assert(copies == 0);
+  (void)std::minmax({value, value}, Less<T>(&copies));
+  assert(copies == 0);
 #endif
-    (void)std::minmax_element(first, last, Less<T>(&copies)); assert(copies == 0);
-    (void)std::mismatch(first, last, first2, Equal<T>(&copies)); assert(copies == 0);
+  (void)std::minmax_element(first, last, Less<T>(&copies));
+  assert(copies == 0);
+  (void)std::mismatch(first, last, first2, Equal<T>(&copies));
+  assert(copies == 0);
 #if TEST_STD_VER > 11
-    (void)std::mismatch(first, last, first2, last2, Equal<T>(&copies)); assert(copies == 0);
+  (void)std::mismatch(first, last, first2, last2, Equal<T>(&copies));
+  assert(copies == 0);
 #endif
-    (void)std::next_permutation(first, last, Less<T>(&copies)); assert(copies == 0);
+  (void)std::next_permutation(first, last, Less<T>(&copies));
+  assert(copies == 0);
 #if TEST_STD_VER >= 11
-    (void)std::none_of(first, last, UnaryTrue<T>(&copies)); assert(copies == 0);
+  (void)std::none_of(first, last, UnaryTrue<T>(&copies));
+  assert(copies == 0);
 #endif
-    (void)std::nth_element(first, mid, last, Less<T>(&copies)); assert(copies == 0);
-    (void)std::partial_sort(first, mid, last, Less<T>(&copies)); assert(copies == 0);
-    (void)std::partial_sort_copy(first, last, first2, mid2, Less<T>(&copies)); assert(copies == 0);
-    (void)std::partition(first, last, UnaryTrue<T>(&copies)); assert(copies == 0);
-    (void)std::partition_copy(first, last, first2, last2, UnaryTrue<T>(&copies)); assert(copies == 0);
-    (void)std::partition_point(first, last, UnaryTrue<T>(&copies)); assert(copies == 0);
-    (void)std::pop_heap(first, last, Less<T>(&copies)); assert(copies == 0);
-    (void)std::prev_permutation(first, last, Less<T>(&copies)); assert(copies == 0);
-    (void)std::push_heap(first, last, Less<T>(&copies)); assert(copies == 0);
-    (void)std::remove_copy_if(first, last, first2, UnaryTrue<T>(&copies)); assert(copies == 0);
-    (void)std::remove_if(first, last, UnaryTrue<T>(&copies)); assert(copies == 0);
-    (void)std::replace_copy_if(first, last, first2, UnaryTrue<T>(&copies), value); assert(copies == 0);
-    (void)std::replace_if(first, last, UnaryTrue<T>(&copies), value); assert(copies == 0);
-    (void)std::search(first, last, first2, mid2, Equal<T>(&copies)); assert(copies == 0);
-    (void)std::search_n(first, last, count, value, Equal<T>(&copies)); assert(copies == 0);
-    (void)std::set_
diff erence(first, mid, mid, last, first2, Less<T>(&copies)); assert(copies == 0);
-    (void)std::set_intersection(first, mid, mid, last, first2, Less<T>(&copies)); assert(copies == 0);
-    (void)std::set_symmetric_
diff erence(first, mid, mid, last, first2, Less<T>(&copies)); assert(copies == 0);
-    (void)std::set_union(first, mid, mid, last, first2, Less<T>(&copies)); assert(copies == 0);
-    (void)std::sort(first, first+3, Less<T>(&copies)); assert(copies == 0);
-    (void)std::sort(first, first+4, Less<T>(&copies)); assert(copies == 0);
-    (void)std::sort(first, first+5, Less<T>(&copies)); assert(copies == 0);
-    (void)std::sort(first, last, Less<T>(&copies)); assert(copies == 0);
-    (void)std::sort_heap(first, last, Less<T>(&copies)); assert(copies == 0);
-    if (!TEST_IS_CONSTANT_EVALUATED) { (void)std::stable_partition(first, last, UnaryTrue<T>(&copies)); assert(copies == 0); }
-    if (!TEST_IS_CONSTANT_EVALUATED) { (void)std::stable_sort(first, last, Less<T>(&copies)); assert(copies == 0); }
-    (void)std::transform(first, last, first2, UnaryTransform<T>(&copies)); assert(copies == 0);
-    (void)std::transform(first, mid, mid, first2, BinaryTransform<T>(&copies)); assert(copies == 0);
-    (void)std::unique(first, last, Equal<T>(&copies)); assert(copies == 0);
-    (void)std::unique_copy(first, last, first2, Equal<T>(&copies)); assert(copies == 0);
-    (void)std::upper_bound(first, last, value, Less<T>(&copies)); assert(copies == 0);
-
-    return true;
+  (void)std::nth_element(first, mid, last, Less<T>(&copies));
+  assert(copies == 0);
+  (void)std::partial_sort(first, mid, last, Less<T>(&copies));
+  assert(copies == 0);
+  (void)std::partial_sort_copy(first, last, first2, mid2, Less<T>(&copies));
+  assert(copies == 0);
+  (void)std::partition(first, last, UnaryTrue<T>(&copies));
+  assert(copies == 0);
+  (void)std::partition_copy(first, last, first2, last2, UnaryTrue<T>(&copies));
+  assert(copies == 0);
+  (void)std::partition_point(first, last, UnaryTrue<T>(&copies));
+  assert(copies == 0);
+  (void)std::pop_heap(first, last, Less<T>(&copies));
+  assert(copies == 0);
+  (void)std::prev_permutation(first, last, Less<T>(&copies));
+  assert(copies == 0);
+  (void)std::push_heap(first, last, Less<T>(&copies));
+  assert(copies == 0);
+  (void)std::remove_copy_if(first, last, first2, UnaryTrue<T>(&copies));
+  assert(copies == 0);
+  (void)std::remove_if(first, last, UnaryTrue<T>(&copies));
+  assert(copies == 0);
+  (void)std::replace_copy_if(first, last, first2, UnaryTrue<T>(&copies), value);
+  assert(copies == 0);
+  (void)std::replace_if(first, last, UnaryTrue<T>(&copies), value);
+  assert(copies == 0);
+  (void)std::search(first, last, first2, mid2, Equal<T>(&copies));
+  assert(copies == 0);
+  (void)std::search_n(first, last, count, value, Equal<T>(&copies));
+  assert(copies == 0);
+  (void)std::set_
diff erence(first, mid, mid, last, first2, Less<T>(&copies));
+  assert(copies == 0);
+  (void)std::set_intersection(first, mid, mid, last, first2, Less<T>(&copies));
+  assert(copies == 0);
+  (void)std::set_symmetric_
diff erence(first, mid, mid, last, first2, Less<T>(&copies));
+  assert(copies == 0);
+  (void)std::set_union(first, mid, mid, last, first2, Less<T>(&copies));
+  assert(copies == 0);
+  (void)std::sort(first, first + 3, Less<T>(&copies));
+  assert(copies == 0);
+  (void)std::sort(first, first + 4, Less<T>(&copies));
+  assert(copies == 0);
+  (void)std::sort(first, first + 5, Less<T>(&copies));
+  assert(copies == 0);
+  (void)std::sort(first, last, Less<T>(&copies));
+  assert(copies == 0);
+  (void)std::sort_heap(first, last, Less<T>(&copies));
+  assert(copies == 0);
+  if (!TEST_IS_CONSTANT_EVALUATED) {
+    (void)std::stable_partition(first, last, UnaryTrue<T>(&copies));
+    assert(copies == 0);
+  }
+  if (!TEST_IS_CONSTANT_EVALUATED) {
+    (void)std::stable_sort(first, last, Less<T>(&copies));
+    assert(copies == 0);
+  }
+  (void)std::transform(first, last, first2, UnaryTransform<T>(&copies));
+  assert(copies == 0);
+  (void)std::transform(first, mid, mid, first2, BinaryTransform<T>(&copies));
+  assert(copies == 0);
+  (void)std::unique(first, last, Equal<T>(&copies));
+  assert(copies == 0);
+  (void)std::unique_copy(first, last, first2, Equal<T>(&copies));
+  assert(copies == 0);
+  (void)std::upper_bound(first, last, value, Less<T>(&copies));
+  assert(copies == 0);
+
+  return true;
+}
+
+bool test_segmented_iterator() {
+  int copies = 0;
+  std::deque<int> dq(10);
+  (void)std::for_each(dq.begin(), dq.end(), UnaryVoid<int>(&copies));
+  assert(copies == 1);
+  copies = 0;
+
+#if TEST_STD_VER >= 20
+  std::vector<std::vector<int>> vecs(3, std::vector<int>(10));
+  auto v = std::views::join(vecs);
+  (void)std::for_each(v.begin(), v.end(), UnaryVoid<int>(&copies));
+  assert(copies == 1);
+  copies = 0;
+#endif
+
+  return true;
 }
 
-int main(int, char**)
-{
-    all_the_algorithms<void*>();
-    all_the_algorithms<int>();
+int main(int, char**) {
+  all_the_algorithms<void*>();
+  all_the_algorithms<int>();
+  assert(test_segmented_iterator());
 #if TEST_STD_VER > 17
-    static_assert(all_the_algorithms<void*>());
-    static_assert(all_the_algorithms<int>());
+  static_assert(all_the_algorithms<void*>());
+  static_assert(all_the_algorithms<int>());
 #endif
 
-    return 0;
+  return 0;
 }


        


More information about the libcxx-commits mailing list