[libcxx-commits] [libcxx] [libc++] Backport segmented iterator optimization for std::for_each to C++11 (PR #134960)
Peng Liu via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Apr 10 20:05:17 PDT 2025
https://github.com/winner245 updated https://github.com/llvm/llvm-project/pull/134960
>From 6bb2d23c82eb1789cc3dfe52f9351ee407f012c5 Mon Sep 17 00:00:00 2001
From: Peng Liu <winner245 at hotmail.com>
Date: Tue, 8 Apr 2025 18:47:48 -0400
Subject: [PATCH 1/3] Backport for_each segmented iterator optimization to
C++03
---
libcxx/include/__algorithm/for_each.h | 51 +++++++++++++++++----------
1 file changed, 33 insertions(+), 18 deletions(-)
diff --git a/libcxx/include/__algorithm/for_each.h b/libcxx/include/__algorithm/for_each.h
index e08f583504c01..c5d1576c09d7d 100644
--- a/libcxx/include/__algorithm/for_each.h
+++ b/libcxx/include/__algorithm/for_each.h
@@ -13,7 +13,7 @@
#include <__algorithm/for_each_segment.h>
#include <__config>
#include <__iterator/segmented_iterator.h>
-#include <__ranges/movable_box.h>
+#include <__type_traits/enable_if.h>
#include <__utility/in_place.h>
#include <__utility/move.h>
@@ -26,28 +26,43 @@ _LIBCPP_PUSH_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)));
- });
- return std::move(*__wrapped_func);
+// __segment_processor handles the per-segment processing by applying the function object __func_ to each
+// element within the segment.
+template <class _SegmentedIterator, class _Func>
+struct __segment_processor {
+ using _Traits _LIBCPP_NODEBUG = __segmented_iterator_traits<_SegmentedIterator>;
+
+ _Func& __func_;
+
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __segment_processor(_Func& __f) : __func_(__f) {}
+
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
+ operator()(typename _Traits::__local_iterator __lfirst, typename _Traits::__local_iterator __llast) {
+ std::__for_each(__lfirst, __llast, __func_);
+ }
+};
+
+template <class _SegmentedIterator,
+ class _Function,
+ __enable_if_t<__is_segmented_iterator<_SegmentedIterator>::value, int> = 0>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Function
+__for_each(_SegmentedIterator __first, _SegmentedIterator __last, _Function __func) {
+ std::__for_each_segment(__first, __last, std::__segment_processor<_SegmentedIterator, _Function>(__func));
+ return __func;
+}
+
+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;
}
-#endif // _LIBCPP_STD_VER >= 23
_LIBCPP_END_NAMESPACE_STD
>From a33aee8f5cde8d6d7ee8ebcd15dc80e034569022 Mon Sep 17 00:00:00 2001
From: Peng Liu <winner245 at hotmail.com>
Date: Thu, 10 Apr 2025 15:52:33 -0400
Subject: [PATCH 2/3] Fix reviewer comments
---
libcxx/include/__algorithm/for_each.h | 15 +++++++--------
libcxx/include/__algorithm/for_each_segment.h | 8 ++++----
libcxx/include/algorithm | 1 +
libcxx/include/array | 1 +
libcxx/include/bitset | 1 +
libcxx/include/codecvt | 1 +
libcxx/include/condition_variable | 1 +
libcxx/include/ios | 1 +
libcxx/include/locale | 1 +
libcxx/include/streambuf | 1 +
libcxx/include/string | 1 +
libcxx/include/string_view | 1 +
libcxx/include/system_error | 1 +
libcxx/include/vector | 1 +
...robust_against_copying_comparators.pass.cpp | 18 ++++++++++++++++++
15 files changed, 41 insertions(+), 12 deletions(-)
diff --git a/libcxx/include/__algorithm/for_each.h b/libcxx/include/__algorithm/for_each.h
index c5d1576c09d7d..a52bdaed4ce49 100644
--- a/libcxx/include/__algorithm/for_each.h
+++ b/libcxx/include/__algorithm/for_each.h
@@ -34,16 +34,16 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __for_each(_InputIterat
// __segment_processor handles the per-segment processing by applying the function object __func_ to each
// element within the segment.
-template <class _SegmentedIterator, class _Func>
+template <class _Func>
struct __segment_processor {
- using _Traits _LIBCPP_NODEBUG = __segmented_iterator_traits<_SegmentedIterator>;
-
_Func& __func_;
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __segment_processor(_Func& __f) : __func_(__f) {}
+ template <class _SegmentedIterator>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
- operator()(typename _Traits::__local_iterator __lfirst, typename _Traits::__local_iterator __llast) {
+ operator()(typename __segmented_iterator_traits<_SegmentedIterator>::__local_iterator __lfirst,
+ typename __segmented_iterator_traits<_SegmentedIterator>::__local_iterator __llast) {
std::__for_each(__lfirst, __llast, __func_);
}
};
@@ -51,10 +51,9 @@ struct __segment_processor {
template <class _SegmentedIterator,
class _Function,
__enable_if_t<__is_segmented_iterator<_SegmentedIterator>::value, int> = 0>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Function
-__for_each(_SegmentedIterator __first, _SegmentedIterator __last, _Function __func) {
- std::__for_each_segment(__first, __last, std::__segment_processor<_SegmentedIterator, _Function>(__func));
- return __func;
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
+__for_each(_SegmentedIterator __first, _SegmentedIterator __last, _Function& __func) {
+ std::__for_each_segment(__first, __last, std::__segment_processor<_Function>(__func));
}
template <class _InputIterator, class _Function>
diff --git a/libcxx/include/__algorithm/for_each_segment.h b/libcxx/include/__algorithm/for_each_segment.h
index 93aa8259b2f7f..a96174c70a6bc 100644
--- a/libcxx/include/__algorithm/for_each_segment.h
+++ b/libcxx/include/__algorithm/for_each_segment.h
@@ -32,20 +32,20 @@ __for_each_segment(_SegmentedIterator __first, _SegmentedIterator __last, _Funct
// We are in a single segment, so we might not be at the beginning or end
if (__sfirst == __slast) {
- __func(_Traits::__local(__first), _Traits::__local(__last));
+ __func.template operator()<_SegmentedIterator>(_Traits::__local(__first), _Traits::__local(__last));
return;
}
// We have more than one segment. Iterate over the first segment, since we might not start at the beginning
- __func(_Traits::__local(__first), _Traits::__end(__sfirst));
+ __func.template operator()<_SegmentedIterator>(_Traits::__local(__first), _Traits::__end(__sfirst));
++__sfirst;
// iterate over the segments which are guaranteed to be completely in the range
while (__sfirst != __slast) {
- __func(_Traits::__begin(__sfirst), _Traits::__end(__sfirst));
+ __func.template operator()<_SegmentedIterator>(_Traits::__begin(__sfirst), _Traits::__end(__sfirst));
++__sfirst;
}
// iterate over the last segment
- __func(_Traits::__begin(__sfirst), _Traits::__local(__last));
+ __func.template operator()<_SegmentedIterator>(_Traits::__begin(__sfirst), _Traits::__local(__last));
}
_LIBCPP_END_NAMESPACE_STD
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 8e07b8be9ce0d..40f9dd2608fb6 100644
--- a/libcxx/include/locale
+++ b/libcxx/include/locale
@@ -3666,6 +3666,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..87bbfae949b62 100644
--- a/libcxx/test/libcxx/algorithms/robust_against_copying_comparators.pass.cpp
+++ b/libcxx/test/libcxx/algorithms/robust_against_copying_comparators.pass.cpp
@@ -12,7 +12,10 @@
#include <cassert>
#include <compare>
#include <cstddef>
+#include <deque>
+#include <ranges>
#include <type_traits>
+#include <vector>
#include "test_macros.h"
@@ -207,10 +210,25 @@ TEST_CONSTEXPR_CXX20 bool all_the_algorithms()
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);
+ 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>();
+ test_segmented_iterator();
#if TEST_STD_VER > 17
static_assert(all_the_algorithms<void*>());
static_assert(all_the_algorithms<int>());
>From d8642b24e845f16a000f9a5ca8cbdbe794038eb9 Mon Sep 17 00:00:00 2001
From: Peng Liu <winner245 at hotmail.com>
Date: Thu, 10 Apr 2025 17:02:50 -0400
Subject: [PATCH 3/3] Use lambda instead of function object class template
---
libcxx/include/__algorithm/for_each.h | 29 +-
libcxx/include/__algorithm/for_each_segment.h | 8 +-
...obust_against_copying_comparators.pass.cpp | 379 +++++++++++-------
3 files changed, 243 insertions(+), 173 deletions(-)
diff --git a/libcxx/include/__algorithm/for_each.h b/libcxx/include/__algorithm/for_each.h
index a52bdaed4ce49..74352797de301 100644
--- a/libcxx/include/__algorithm/for_each.h
+++ b/libcxx/include/__algorithm/for_each.h
@@ -21,9 +21,6 @@
# pragma GCC system_header
#endif
-_LIBCPP_PUSH_MACROS
-#include <__undef_macros>
-
_LIBCPP_BEGIN_NAMESPACE_STD
template <class _InputIterator, class _Sent, class _Func>
@@ -32,29 +29,19 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __for_each(_InputIterat
__f(*__first);
}
-// __segment_processor handles the per-segment processing by applying the function object __func_ to each
-// element within the segment.
-template <class _Func>
-struct __segment_processor {
- _Func& __func_;
-
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __segment_processor(_Func& __f) : __func_(__f) {}
-
- template <class _SegmentedIterator>
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
- operator()(typename __segmented_iterator_traits<_SegmentedIterator>::__local_iterator __lfirst,
- typename __segmented_iterator_traits<_SegmentedIterator>::__local_iterator __llast) {
- std::__for_each(__lfirst, __llast, __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) {
- std::__for_each_segment(__first, __last, std::__segment_processor<_Function>(__func));
+ using _Traits = __segmented_iterator_traits<_SegmentedIterator>;
+ std::__for_each_segment(
+ __first, __last, [&](typename _Traits::__local_iterator __lfirst, typename _Traits::__local_iterator __llast) {
+ std::__for_each(__lfirst, __llast, __func);
+ });
}
+#endif
template <class _InputIterator, class _Function>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Function
@@ -65,6 +52,4 @@ for_each(_InputIterator __first, _InputIterator __last, _Function __f) {
_LIBCPP_END_NAMESPACE_STD
-_LIBCPP_POP_MACROS
-
#endif // _LIBCPP___ALGORITHM_FOR_EACH_H
diff --git a/libcxx/include/__algorithm/for_each_segment.h b/libcxx/include/__algorithm/for_each_segment.h
index a96174c70a6bc..93aa8259b2f7f 100644
--- a/libcxx/include/__algorithm/for_each_segment.h
+++ b/libcxx/include/__algorithm/for_each_segment.h
@@ -32,20 +32,20 @@ __for_each_segment(_SegmentedIterator __first, _SegmentedIterator __last, _Funct
// We are in a single segment, so we might not be at the beginning or end
if (__sfirst == __slast) {
- __func.template operator()<_SegmentedIterator>(_Traits::__local(__first), _Traits::__local(__last));
+ __func(_Traits::__local(__first), _Traits::__local(__last));
return;
}
// We have more than one segment. Iterate over the first segment, since we might not start at the beginning
- __func.template operator()<_SegmentedIterator>(_Traits::__local(__first), _Traits::__end(__sfirst));
+ __func(_Traits::__local(__first), _Traits::__end(__sfirst));
++__sfirst;
// iterate over the segments which are guaranteed to be completely in the range
while (__sfirst != __slast) {
- __func.template operator()<_SegmentedIterator>(_Traits::__begin(__sfirst), _Traits::__end(__sfirst));
+ __func(_Traits::__begin(__sfirst), _Traits::__end(__sfirst));
++__sfirst;
}
// iterate over the last segment
- __func.template operator()<_SegmentedIterator>(_Traits::__begin(__sfirst), _Traits::__local(__last));
+ __func(_Traits::__begin(__sfirst), _Traits::__local(__last));
}
_LIBCPP_END_NAMESPACE_STD
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 87bbfae949b62..256251686bb3e 100644
--- a/libcxx/test/libcxx/algorithms/robust_against_copying_comparators.pass.cpp
+++ b/libcxx/test/libcxx/algorithms/robust_against_copying_comparators.pass.cpp
@@ -21,218 +21,303 @@
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_difference(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_difference(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_difference(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_difference(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;
+ 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);
- std::for_each(v.begin(), v.end(), UnaryVoid<int>(&copies)); assert(copies == 1); copies = 0;
+ 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;
+ return true;
}
-int main(int, char**)
-{
- all_the_algorithms<void*>();
- all_the_algorithms<int>();
- test_segmented_iterator();
+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