Skip to content

Commit b203d53

Browse files
authored
[libc++] Optimize std::find if types are integral and have the same signedness (#70345)
Fixes #70238
1 parent f78a742 commit b203d53

File tree

2 files changed

+61
-0
lines changed

2 files changed

+61
-0
lines changed

libcxx/include/__algorithm/find.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,11 @@
2121
#include <__fwd/bit_reference.h>
2222
#include <__iterator/segmented_iterator.h>
2323
#include <__string/constexpr_c_functions.h>
24+
#include <__type_traits/is_integral.h>
2425
#include <__type_traits/is_same.h>
26+
#include <__type_traits/is_signed.h>
2527
#include <__utility/move.h>
28+
#include <limits>
2629

2730
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2831
# include <cwchar>
@@ -76,6 +79,22 @@ __find_impl(_Tp* __first, _Tp* __last, const _Up& __value, _Proj&) {
7679
}
7780
#endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
7881

82+
// TODO: This should also be possible to get right with different signedness
83+
// cast integral types to allow vectorization
84+
template <class _Tp,
85+
class _Up,
86+
class _Proj,
87+
__enable_if_t<__is_identity<_Proj>::value && !__libcpp_is_trivially_equality_comparable<_Tp, _Up>::value &&
88+
is_integral<_Tp>::value && is_integral<_Up>::value &&
89+
is_signed<_Tp>::value == is_signed<_Up>::value,
90+
int> = 0>
91+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp*
92+
__find_impl(_Tp* __first, _Tp* __last, const _Up& __value, _Proj& __proj) {
93+
if (__value < numeric_limits<_Tp>::min() || __value > numeric_limits<_Tp>::max())
94+
return __last;
95+
return std::__find_impl(__first, __last, _Tp(__value), __proj);
96+
}
97+
7998
// __bit_iterator implementation
8099
template <bool _ToFind, class _Cp, bool _IsConst>
81100
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, _IsConst>

libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9+
// ADDITIONAL_COMPILE_FLAGS(gcc): -Wno-bool-compare
910
// ADDITIONAL_COMPILE_FLAGS(gcc-style-warnings): -Wno-sign-compare
1011
// MSVC warning C4389: '==': signed/unsigned mismatch
1112
// ADDITIONAL_COMPILE_FLAGS(cl-style-warnings): /wd4389
@@ -162,6 +163,45 @@ void test_deque() {
162163
}
163164
}
164165

166+
template <class T>
167+
struct TestIntegerPromotions1 {
168+
template <class U>
169+
TEST_CONSTEXPR_CXX20 void test(T val, U to_find) {
170+
bool expect_match = val == to_find;
171+
assert(std::find(&val, &val + 1, to_find) == (expect_match ? &val : &val + 1));
172+
}
173+
174+
template <class U>
175+
TEST_CONSTEXPR_CXX20 void operator()() {
176+
test<U>(0, 0);
177+
test<U>(0, 1);
178+
test<U>(1, 1);
179+
test<U>(0, -1);
180+
test<U>(-1, -1);
181+
test<U>(0, U(-127));
182+
test<U>(T(-127), U(-127));
183+
test<U>(T(-128), U(-128));
184+
test<U>(T(-129), U(-129));
185+
test<U>(T(255), U(255));
186+
test<U>(T(256), U(256));
187+
test<U>(T(257), U(257));
188+
test<U>(0, std::numeric_limits<U>::min());
189+
test<U>(T(std::numeric_limits<U>::min()), std::numeric_limits<U>::min());
190+
test<U>(0, std::numeric_limits<U>::min() + 1);
191+
test<U>(T(std::numeric_limits<U>::min() + 1), std::numeric_limits<U>::min() + 1);
192+
test<U>(0, std::numeric_limits<U>::max());
193+
test<U>(T(std::numeric_limits<U>::max()), std::numeric_limits<U>::max());
194+
test<U>(T(std::numeric_limits<U>::max() - 1), std::numeric_limits<U>::max() - 1);
195+
}
196+
};
197+
198+
struct TestIntegerPromotions {
199+
template <class T>
200+
TEST_CONSTEXPR_CXX20 void operator()() {
201+
types::for_each(types::integral_types(), TestIntegerPromotions1<T>());
202+
}
203+
};
204+
165205
TEST_CONSTEXPR_CXX20 bool test() {
166206
types::for_each(types::integer_types(), TestTypes<char>());
167207
types::for_each(types::integer_types(), TestTypes<int>());
@@ -181,6 +221,8 @@ TEST_CONSTEXPR_CXX20 bool test() {
181221
}
182222
#endif
183223

224+
types::for_each(types::integral_types(), TestIntegerPromotions());
225+
184226
return true;
185227
}
186228

0 commit comments

Comments
 (0)