[libcxx-commits] [libcxx] [libc++] Optimize lexicographical_compare (PR #65279)
Nikolas Klauser via libcxx-commits
libcxx-commits at lists.llvm.org
Wed Jul 31 10:50:40 PDT 2024
https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/65279
>From 708f75a1429924d1cc175e934d7b699ed184e64b Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Fri, 9 Dec 2022 02:56:05 +0100
Subject: [PATCH] [libc++] Forward to memcmp in lexicographical_compare
---
libcxx/include/__algorithm/comp.h | 3 +-
.../__algorithm/lexicographical_compare.h | 84 ++++++++++++++---
.../ranges_lexicographical_compare.h | 27 +++---
libcxx/include/__algorithm/ranges_minmax.h | 2 +-
libcxx/include/__functional/operations.h | 5 +-
.../include/__functional/ranges_operations.h | 2 +-
.../include/__string/constexpr_c_functions.h | 4 +-
libcxx/include/__type_traits/desugars_to.h | 13 ++-
...s_trivially_lexicographically_comparable.h | 20 +++--
libcxx/test/benchmarks/CMakeLists.txt | 1 +
.../lexicographical_compare.bench.cpp | 44 +++++++++
.../test/libcxx/transitive_includes/cxx03.csv | 8 ++
.../test/libcxx/transitive_includes/cxx26.csv | 6 ++
.../lexicographical_compare.pass.cpp | 90 ++++++++-----------
14 files changed, 219 insertions(+), 90 deletions(-)
create mode 100755 libcxx/test/benchmarks/algorithms/lexicographical_compare.bench.cpp
diff --git a/libcxx/include/__algorithm/comp.h b/libcxx/include/__algorithm/comp.h
index a0fa88d6d2acd..1f38f5d2d99b4 100644
--- a/libcxx/include/__algorithm/comp.h
+++ b/libcxx/include/__algorithm/comp.h
@@ -11,6 +11,7 @@
#include <__config>
#include <__type_traits/desugars_to.h>
+#include <__type_traits/is_integral.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -42,7 +43,7 @@ struct __less<void, void> {
};
template <class _Tp>
-inline const bool __desugars_to_v<__less_tag, __less<>, _Tp, _Tp> = true;
+inline const bool __desugars_to_v<__totally_ordered_less_tag, __less<>, _Tp, _Tp> = is_integral<_Tp>::value;
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__algorithm/lexicographical_compare.h b/libcxx/include/__algorithm/lexicographical_compare.h
index edc29e269c88c..db689e427b91c 100644
--- a/libcxx/include/__algorithm/lexicographical_compare.h
+++ b/libcxx/include/__algorithm/lexicographical_compare.h
@@ -11,31 +11,85 @@
#include <__algorithm/comp.h>
#include <__algorithm/comp_ref_type.h>
+#include <__algorithm/min.h>
+#include <__algorithm/mismatch.h>
+#include <__algorithm/simd_utils.h>
+#include <__algorithm/unwrap_iter.h>
#include <__config>
+#include <__functional/identity.h>
#include <__iterator/iterator_traits.h>
+#include <__string/constexpr_c_functions.h>
+#include <__type_traits/desugars_to.h>
+#include <__type_traits/invoke.h>
+#include <__type_traits/is_equality_comparable.h>
+#include <__type_traits/is_integral.h>
+#include <__type_traits/is_trivially_lexicographically_comparable.h>
+#include <__type_traits/is_volatile.h>
+#include <cwchar>
#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 _Compare, class _InputIterator1, class _InputIterator2>
+template <class _Iter1, class _Sent1, class _Iter2, class _Sent2, class _Proj1, class _Proj2, class _Comp>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __lexicographical_compare(
- _InputIterator1 __first1,
- _InputIterator1 __last1,
- _InputIterator2 __first2,
- _InputIterator2 __last2,
- _Compare __comp) {
- for (; __first2 != __last2; ++__first1, (void)++__first2) {
- if (__first1 == __last1 || __comp(*__first1, *__first2))
+ _Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, _Comp& __comp, _Proj1& __proj1, _Proj2& __proj2) {
+ while (__first2 != __last2) {
+ if (__first1 == __last1 ||
+ std::__invoke(__comp, std::__invoke(__proj1, *__first1), std::__invoke(__proj2, *__first2)))
return true;
- if (__comp(*__first2, *__first1))
+ if (std::__invoke(__comp, std::__invoke(__proj2, *__first2), std::__invoke(__proj1, *__first1)))
return false;
+ ++__first1;
+ ++__first2;
}
return false;
}
+#ifndef _LIBCPP_CXX03_LANG
+
+template <class _Tp,
+ class _Proj1,
+ class _Proj2,
+ class _Comp,
+ __enable_if_t<__desugars_to_v<__totally_ordered_less_tag, _Comp, _Tp, _Tp> && !is_volatile<_Tp>::value &&
+ __libcpp_is_trivially_equality_comparable<_Tp, _Tp>::value &&
+ __is_identity<_Proj1>::value && __is_identity<_Proj2>::value,
+ int> = 0>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool
+__lexicographical_compare(_Tp* __first1, _Tp* __last1, _Tp* __first2, _Tp* __last2, _Comp&, _Proj1&, _Proj2&) {
+ if constexpr (__is_trivially_lexicographically_comparable_v<_Tp, _Tp>) {
+ auto __res =
+ std::__constexpr_memcmp(__first1, __first2, __element_count(std::min(__last1 - __first1, __last2 - __first2)));
+ if (__res == 0)
+ return __last1 - __first1 < __last2 - __first2;
+ return __res < 0;
+ }
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ else if constexpr (is_same<__remove_cv_t<_Tp>, wchar_t>::value) {
+ auto __res = std::__constexpr_wmemcmp(__first1, __first2, std::min(__last1 - __first1, __last2 - __first2));
+ if (__res == 0)
+ return __last1 - __first1 < __last2 - __first2;
+ return __res < 0;
+ }
+#endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ else {
+ auto __res = std::mismatch(__first1, __last1, __first2, __last2);
+ if (__res.second == __last2)
+ return false;
+ if (__res.first == __last1)
+ return true;
+ return *__res.first < *__res.second;
+ }
+}
+
+#endif // _LIBCPP_CXX03_LANG
+
template <class _InputIterator1, class _InputIterator2, class _Compare>
_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool lexicographical_compare(
_InputIterator1 __first1,
@@ -43,7 +97,15 @@ _LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 boo
_InputIterator2 __first2,
_InputIterator2 __last2,
_Compare __comp) {
- return std::__lexicographical_compare<__comp_ref_type<_Compare> >(__first1, __last1, __first2, __last2, __comp);
+ __identity __proj;
+ return std::__lexicographical_compare(
+ std::__unwrap_iter(__first1),
+ std::__unwrap_iter(__last1),
+ std::__unwrap_iter(__first2),
+ std::__unwrap_iter(__last2),
+ __comp,
+ __proj,
+ __proj);
}
template <class _InputIterator1, class _InputIterator2>
@@ -54,4 +116,6 @@ _LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 boo
_LIBCPP_END_NAMESPACE_STD
+_LIBCPP_POP_MACROS
+
#endif // _LIBCPP___ALGORITHM_LEXICOGRAPHICAL_COMPARE_H
diff --git a/libcxx/include/__algorithm/ranges_lexicographical_compare.h b/libcxx/include/__algorithm/ranges_lexicographical_compare.h
index 6d82017e302a7..7cecd9b64c07e 100644
--- a/libcxx/include/__algorithm/ranges_lexicographical_compare.h
+++ b/libcxx/include/__algorithm/ranges_lexicographical_compare.h
@@ -9,6 +9,8 @@
#ifndef _LIBCPP___ALGORITHM_RANGES_LEXICOGRAPHICAL_COMPARE_H
#define _LIBCPP___ALGORITHM_RANGES_LEXICOGRAPHICAL_COMPARE_H
+#include <__algorithm/lexicographical_compare.h>
+#include <__algorithm/unwrap_range.h>
#include <__config>
#include <__functional/identity.h>
#include <__functional/invoke.h>
@@ -34,7 +36,7 @@ namespace ranges {
namespace __lexicographical_compare {
struct __fn {
template <class _Iter1, class _Sent1, class _Iter2, class _Sent2, class _Proj1, class _Proj2, class _Comp>
- _LIBCPP_HIDE_FROM_ABI constexpr static bool __lexicographical_compare_impl(
+ static _LIBCPP_HIDE_FROM_ABI constexpr bool __lexicographical_compare_unwrap(
_Iter1 __first1,
_Sent1 __last1,
_Iter2 __first2,
@@ -42,15 +44,16 @@ struct __fn {
_Comp& __comp,
_Proj1& __proj1,
_Proj2& __proj2) {
- while (__first2 != __last2) {
- if (__first1 == __last1 || std::invoke(__comp, std::invoke(__proj1, *__first1), std::invoke(__proj2, *__first2)))
- return true;
- if (std::invoke(__comp, std::invoke(__proj2, *__first2), std::invoke(__proj1, *__first1)))
- return false;
- ++__first1;
- ++__first2;
- }
- return false;
+ auto [__first1_un, __last1_un] = std::__unwrap_range(std::move(__first1), std::move(__last1));
+ auto [__first2_un, __last2_un] = std::__unwrap_range(std::move(__first2), std::move(__last2));
+ return std::__lexicographical_compare(
+ std::move(__first1_un),
+ std::move(__last1_un),
+ std::move(__first2_un),
+ std::move(__last2_un),
+ __comp,
+ __proj1,
+ __proj2);
}
template <input_iterator _Iter1,
@@ -68,7 +71,7 @@ struct __fn {
_Comp __comp = {},
_Proj1 __proj1 = {},
_Proj2 __proj2 = {}) const {
- return __lexicographical_compare_impl(
+ return __lexicographical_compare_unwrap(
std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), __comp, __proj1, __proj2);
}
@@ -80,7 +83,7 @@ struct __fn {
_Comp = ranges::less>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool operator()(
_Range1&& __range1, _Range2&& __range2, _Comp __comp = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const {
- return __lexicographical_compare_impl(
+ return __lexicographical_compare_unwrap(
ranges::begin(__range1),
ranges::end(__range1),
ranges::begin(__range2),
diff --git a/libcxx/include/__algorithm/ranges_minmax.h b/libcxx/include/__algorithm/ranges_minmax.h
index 09cbefd91a8c7..759ec4fc4676d 100644
--- a/libcxx/include/__algorithm/ranges_minmax.h
+++ b/libcxx/include/__algorithm/ranges_minmax.h
@@ -89,7 +89,7 @@ struct __fn {
// vectorize the code.
if constexpr (contiguous_range<_Range> && is_integral_v<_ValueT> &&
__is_cheap_to_copy<_ValueT> & __is_identity<_Proj>::value &&
- __desugars_to_v<__less_tag, _Comp, _ValueT, _ValueT>) {
+ __desugars_to_v<__totally_ordered_less_tag, _Comp, _ValueT, _ValueT>) {
minmax_result<_ValueT> __result = {__r[0], __r[0]};
for (auto __e : __r) {
if (__e < __result.min)
diff --git a/libcxx/include/__functional/operations.h b/libcxx/include/__functional/operations.h
index 0a6320f19de3f..6022bd679ed3e 100644
--- a/libcxx/include/__functional/operations.h
+++ b/libcxx/include/__functional/operations.h
@@ -14,6 +14,7 @@
#include <__functional/binary_function.h>
#include <__functional/unary_function.h>
#include <__type_traits/desugars_to.h>
+#include <__type_traits/is_integral.h>
#include <__utility/forward.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -362,7 +363,7 @@ struct _LIBCPP_TEMPLATE_VIS less : __binary_function<_Tp, _Tp, bool> {
_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(less);
template <class _Tp>
-inline const bool __desugars_to_v<__less_tag, less<_Tp>, _Tp, _Tp> = true;
+inline const bool __desugars_to_v<__totally_ordered_less_tag, less<_Tp>, _Tp, _Tp> = is_integral<_Tp>::value;
#if _LIBCPP_STD_VER >= 14
template <>
@@ -377,7 +378,7 @@ struct _LIBCPP_TEMPLATE_VIS less<void> {
};
template <class _Tp>
-inline const bool __desugars_to_v<__less_tag, less<>, _Tp, _Tp> = true;
+inline const bool __desugars_to_v<__totally_ordered_less_tag, less<>, _Tp, _Tp> = is_integral<_Tp>::value;
#endif
#if _LIBCPP_STD_VER >= 14
diff --git a/libcxx/include/__functional/ranges_operations.h b/libcxx/include/__functional/ranges_operations.h
index 27f06eadd0eb1..f023d765a6c8a 100644
--- a/libcxx/include/__functional/ranges_operations.h
+++ b/libcxx/include/__functional/ranges_operations.h
@@ -100,7 +100,7 @@ template <class _Tp, class _Up>
inline const bool __desugars_to_v<__equal_tag, ranges::equal_to, _Tp, _Up> = true;
template <class _Tp, class _Up>
-inline const bool __desugars_to_v<__less_tag, ranges::less, _Tp, _Up> = true;
+inline const bool __desugars_to_v<__totally_ordered_less_tag, ranges::less, _Tp, _Up> = true;
#endif // _LIBCPP_STD_VER >= 20
diff --git a/libcxx/include/__string/constexpr_c_functions.h b/libcxx/include/__string/constexpr_c_functions.h
index a978f816f1897..32fc06e121b36 100644
--- a/libcxx/include/__string/constexpr_c_functions.h
+++ b/libcxx/include/__string/constexpr_c_functions.h
@@ -64,13 +64,13 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 size_t __constexpr_st
return __builtin_strlen(reinterpret_cast<const char*>(__str));
}
-// Because of __libcpp_is_trivially_lexicographically_comparable we know that comparing the object representations is
+// Because of __is_trivially_lexicographically_comparable_v we know that comparing the object representations is
// equivalent to a std::memcmp. Since we have multiple objects contiguously in memory, we can call memcmp once instead
// of invoking it on every object individually.
template <class _Tp, class _Up>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int
__constexpr_memcmp(const _Tp* __lhs, const _Up* __rhs, __element_count __n) {
- static_assert(__libcpp_is_trivially_lexicographically_comparable<_Tp, _Up>::value,
+ static_assert(__is_trivially_lexicographically_comparable_v<_Tp, _Up>,
"_Tp and _Up have to be trivially lexicographically comparable");
auto __count = static_cast<size_t>(__n);
diff --git a/libcxx/include/__type_traits/desugars_to.h b/libcxx/include/__type_traits/desugars_to.h
index 97a2ee5448f20..5a7e4794b59c8 100644
--- a/libcxx/include/__type_traits/desugars_to.h
+++ b/libcxx/include/__type_traits/desugars_to.h
@@ -17,10 +17,19 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-// Tags to represent the canonical operations
+// Tags to represent the canonical operations.
+
+// syntactically, the operation is equivalent to calling `a == b`
struct __equal_tag {};
+
+// syntactically, the operation is equivalent to calling `a + b`
struct __plus_tag {};
-struct __less_tag {};
+
+// syntactically, the operation is equivalent to calling `a < b`, and these expressions
+// have to be true for any `a` and `b`:
+// - `(a < b) == (b > a)`
+// - `(!(a < b) && !(b < a)) == (a == b)`
+struct __totally_ordered_less_tag {};
// This class template is used to determine whether an operation "desugars"
// (or boils down) to a given canonical operation.
diff --git a/libcxx/include/__type_traits/is_trivially_lexicographically_comparable.h b/libcxx/include/__type_traits/is_trivially_lexicographically_comparable.h
index a310ea1b87e30..337f878fea5c1 100644
--- a/libcxx/include/__type_traits/is_trivially_lexicographically_comparable.h
+++ b/libcxx/include/__type_traits/is_trivially_lexicographically_comparable.h
@@ -16,6 +16,7 @@
#include <__type_traits/remove_cv.h>
#include <__type_traits/void_t.h>
#include <__utility/declval.h>
+#include <cstddef>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -40,13 +41,22 @@ _LIBCPP_BEGIN_NAMESPACE_STD
// unsigned integer types with sizeof(T) > 1: depending on the endianness, the LSB might be the first byte to be
// compared. This means that when comparing unsigned(129) and unsigned(2)
// using memcmp(), the result would be that 2 > 129.
-// TODO: Do we want to enable this on big-endian systems?
+
+template <class _Tp>
+inline const bool __is_std_byte_v = false;
+
+#if _LIBCPP_STD_VER >= 17
+template <>
+inline const bool __is_std_byte_v<byte> = true;
+#endif
template <class _Tp, class _Up>
-struct __libcpp_is_trivially_lexicographically_comparable
- : integral_constant<bool,
- is_same<__remove_cv_t<_Tp>, __remove_cv_t<_Up> >::value && sizeof(_Tp) == 1 &&
- is_unsigned<_Tp>::value> {};
+inline const bool __is_trivially_lexicographically_comparable_v =
+ is_same<__remove_cv_t<_Tp>, __remove_cv_t<_Up> >::value &&
+#ifdef _LIBCPP_LITTLE_ENDIAN
+ sizeof(_Tp) == 1 &&
+#endif
+ (is_unsigned<_Tp>::value || __is_std_byte_v<_Tp>);
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/test/benchmarks/CMakeLists.txt b/libcxx/test/benchmarks/CMakeLists.txt
index d61367a367738..616cf0ff8d237 100644
--- a/libcxx/test/benchmarks/CMakeLists.txt
+++ b/libcxx/test/benchmarks/CMakeLists.txt
@@ -114,6 +114,7 @@ set(BENCHMARK_TESTS
algorithms/find.bench.cpp
algorithms/fill.bench.cpp
algorithms/for_each.bench.cpp
+ algorithms/lexicographical_compare.bench.cpp
algorithms/lower_bound.bench.cpp
algorithms/make_heap.bench.cpp
algorithms/make_heap_then_sort_heap.bench.cpp
diff --git a/libcxx/test/benchmarks/algorithms/lexicographical_compare.bench.cpp b/libcxx/test/benchmarks/algorithms/lexicographical_compare.bench.cpp
new file mode 100755
index 0000000000000..0c545263109d2
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/lexicographical_compare.bench.cpp
@@ -0,0 +1,44 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include <algorithm>
+#include <benchmark/benchmark.h>
+#include <vector>
+
+// Benchmarks the worst case: check the whole range just to find out that they compare equal
+template <class T>
+static void bm_lexicographical_compare(benchmark::State& state) {
+ std::vector<T> vec1(state.range(), '1');
+ std::vector<T> vec2(state.range(), '1');
+
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(vec1);
+ benchmark::DoNotOptimize(vec2);
+ benchmark::DoNotOptimize(std::lexicographical_compare(vec1.begin(), vec1.end(), vec2.begin(), vec2.end()));
+ }
+}
+BENCHMARK(bm_lexicographical_compare<unsigned char>)->DenseRange(1, 8)->Range(16, 1 << 20);
+BENCHMARK(bm_lexicographical_compare<signed char>)->DenseRange(1, 8)->Range(16, 1 << 20);
+BENCHMARK(bm_lexicographical_compare<int>)->DenseRange(1, 8)->Range(16, 1 << 20);
+
+template <class T>
+static void bm_ranges_lexicographical_compare(benchmark::State& state) {
+ std::vector<T> vec1(state.range(), '1');
+ std::vector<T> vec2(state.range(), '1');
+
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(vec1);
+ benchmark::DoNotOptimize(vec2);
+ benchmark::DoNotOptimize(std::ranges::lexicographical_compare(vec1.begin(), vec1.end(), vec2.begin(), vec2.end()));
+ }
+}
+BENCHMARK(bm_ranges_lexicographical_compare<unsigned char>)->DenseRange(1, 8)->Range(16, 1 << 20);
+BENCHMARK(bm_ranges_lexicographical_compare<signed char>)->DenseRange(1, 8)->Range(16, 1 << 20);
+BENCHMARK(bm_ranges_lexicographical_compare<int>)->DenseRange(1, 8)->Range(16, 1 << 20);
+
+BENCHMARK_MAIN();
diff --git a/libcxx/test/libcxx/transitive_includes/cxx03.csv b/libcxx/test/libcxx/transitive_includes/cxx03.csv
index 51e659f52000b..3bf39ea17c912 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx03.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx03.csv
@@ -40,7 +40,9 @@ array algorithm
array compare
array concepts
array cstddef
+array cstdint
array cstdlib
+array cwchar
array initializer_list
array iterator
array limits
@@ -291,6 +293,7 @@ forward_list cstddef
forward_list cstdint
forward_list cstdlib
forward_list cstring
+forward_list cwchar
forward_list functional
forward_list initializer_list
forward_list iosfwd
@@ -449,6 +452,7 @@ list cstddef
list cstdint
list cstdlib
list cstring
+list cwchar
list functional
list initializer_list
list iosfwd
@@ -489,7 +493,9 @@ locale version
map compare
map concepts
map cstddef
+map cstdint
map cstdlib
+map cwchar
map functional
map initializer_list
map iterator
@@ -723,7 +729,9 @@ semaphore version
set compare
set concepts
set cstddef
+set cstdint
set cstdlib
+set cwchar
set functional
set initializer_list
set iterator
diff --git a/libcxx/test/libcxx/transitive_includes/cxx26.csv b/libcxx/test/libcxx/transitive_includes/cxx26.csv
index 8ffb71d8b566b..f341fb2c29d33 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx26.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv
@@ -23,6 +23,7 @@ any version
array compare
array cstddef
array cstdint
+array cwchar
array initializer_list
array limits
array new
@@ -199,6 +200,8 @@ format typeinfo
format version
forward_list compare
forward_list cstddef
+forward_list cstdint
+forward_list cwchar
forward_list initializer_list
forward_list limits
forward_list new
@@ -312,6 +315,7 @@ list compare
list cstddef
list cstdint
list cstring
+list cwchar
list initializer_list
list limits
list new
@@ -340,6 +344,7 @@ locale version
map compare
map cstddef
map cstdint
+map cwchar
map initializer_list
map limits
map new
@@ -498,6 +503,7 @@ semaphore version
set compare
set cstddef
set cstdint
+set cwchar
set initializer_list
set limits
set new
diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.lex.comparison/lexicographical_compare.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.lex.comparison/lexicographical_compare.pass.cpp
index 10e45df7cf9aa..2cf675476026c 100644
--- a/libcxx/test/std/algorithms/alg.sorting/alg.lex.comparison/lexicographical_compare.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.lex.comparison/lexicographical_compare.pass.cpp
@@ -20,66 +20,48 @@
#include "test_macros.h"
#include "test_iterators.h"
-#if TEST_STD_VER > 17
-TEST_CONSTEXPR bool test_constexpr() {
- int ia[] = {1, 2, 3};
- int ib[] = {1, 3, 5, 2, 4, 6};
+template <class T, class Iter1>
+struct Test {
+ template <class Iter2>
+ TEST_CONSTEXPR_CXX20 void operator()() {
+ T ia[] = {1, 2, 3, 4};
+ const unsigned sa = sizeof(ia) / sizeof(ia[0]);
+ T ib[] = {1, 2, 3};
+ assert(!std::lexicographical_compare(Iter1(ia), Iter1(ia + sa), Iter2(ib), Iter2(ib + 2)));
+ assert(std::lexicographical_compare(Iter1(ib), Iter1(ib + 2), Iter2(ia), Iter2(ia + sa)));
+ assert(!std::lexicographical_compare(Iter1(ia), Iter1(ia + sa), Iter2(ib), Iter2(ib + 3)));
+ assert(std::lexicographical_compare(Iter1(ib), Iter1(ib + 3), Iter2(ia), Iter2(ia + sa)));
+ assert(std::lexicographical_compare(Iter1(ia), Iter1(ia + sa), Iter2(ib + 1), Iter2(ib + 3)));
+ assert(!std::lexicographical_compare(Iter1(ib + 1), Iter1(ib + 3), Iter2(ia), Iter2(ia + sa)));
+ }
+};
- return std::lexicographical_compare(std::begin(ia), std::end(ia), std::begin(ib), std::end(ib))
- && !std::lexicographical_compare(std::begin(ib), std::end(ib), std::begin(ia), std::end(ia))
- ;
- }
-#endif
-
-template <class Iter1, class Iter2>
-void
-test()
-{
- int ia[] = {1, 2, 3, 4};
- const unsigned sa = sizeof(ia)/sizeof(ia[0]);
- int ib[] = {1, 2, 3};
- assert(!std::lexicographical_compare(Iter1(ia), Iter1(ia+sa), Iter2(ib), Iter2(ib+2)));
- assert( std::lexicographical_compare(Iter1(ib), Iter1(ib+2), Iter2(ia), Iter2(ia+sa)));
- assert(!std::lexicographical_compare(Iter1(ia), Iter1(ia+sa), Iter2(ib), Iter2(ib+3)));
- assert( std::lexicographical_compare(Iter1(ib), Iter1(ib+3), Iter2(ia), Iter2(ia+sa)));
- assert( std::lexicographical_compare(Iter1(ia), Iter1(ia+sa), Iter2(ib+1), Iter2(ib+3)));
- assert(!std::lexicographical_compare(Iter1(ib+1), Iter1(ib+3), Iter2(ia), Iter2(ia+sa)));
-}
+template <class T>
+struct TestIter {
+ template <class Iter1>
+ TEST_CONSTEXPR_CXX20 bool operator()() {
+ types::for_each(types::cpp17_input_iterator_list<T*>(), Test<T, Iter1>());
-int main(int, char**)
-{
- test<cpp17_input_iterator<const int*>, cpp17_input_iterator<const int*> >();
- test<cpp17_input_iterator<const int*>, forward_iterator<const int*> >();
- test<cpp17_input_iterator<const int*>, bidirectional_iterator<const int*> >();
- test<cpp17_input_iterator<const int*>, random_access_iterator<const int*> >();
- test<cpp17_input_iterator<const int*>, const int*>();
+ return true;
+ }
+};
- test<forward_iterator<const int*>, cpp17_input_iterator<const int*> >();
- test<forward_iterator<const int*>, forward_iterator<const int*> >();
- test<forward_iterator<const int*>, bidirectional_iterator<const int*> >();
- test<forward_iterator<const int*>, random_access_iterator<const int*> >();
- test<forward_iterator<const int*>, const int*>();
-
- test<bidirectional_iterator<const int*>, cpp17_input_iterator<const int*> >();
- test<bidirectional_iterator<const int*>, forward_iterator<const int*> >();
- test<bidirectional_iterator<const int*>, bidirectional_iterator<const int*> >();
- test<bidirectional_iterator<const int*>, random_access_iterator<const int*> >();
- test<bidirectional_iterator<const int*>, const int*>();
+TEST_CONSTEXPR_CXX20 bool test() {
+ types::for_each(types::cpp17_input_iterator_list<const int*>(), TestIter<const int>());
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+ types::for_each(types::cpp17_input_iterator_list<const wchar_t*>(), TestIter<const wchar_t>());
+#endif
+ types::for_each(types::cpp17_input_iterator_list<const char*>(), TestIter<const char>());
+ types::for_each(types::cpp17_input_iterator_list<unsigned char*>(), TestIter<unsigned char>());
- test<random_access_iterator<const int*>, cpp17_input_iterator<const int*> >();
- test<random_access_iterator<const int*>, forward_iterator<const int*> >();
- test<random_access_iterator<const int*>, bidirectional_iterator<const int*> >();
- test<random_access_iterator<const int*>, random_access_iterator<const int*> >();
- test<random_access_iterator<const int*>, const int*>();
+ return true;
+}
- test<const int*, cpp17_input_iterator<const int*> >();
- test<const int*, forward_iterator<const int*> >();
- test<const int*, bidirectional_iterator<const int*> >();
- test<const int*, random_access_iterator<const int*> >();
- test<const int*, const int*>();
+int main(int, char**) {
+ test();
-#if TEST_STD_VER > 17
- static_assert(test_constexpr());
+#if TEST_STD_VER >= 20
+ static_assert(test());
#endif
return 0;
More information about the libcxx-commits
mailing list