libstdc++: Fix std::find for non-contiguous iterators [PR115799]

The r15-1857 change didn't correctly restrict the new optimization to
contiguous iterators.

libstdc++-v3/ChangeLog:

	PR libstdc++/115799
	* include/bits/stl_algo.h (find): Use 'if constexpr' so that
	memchr optimization is a discarded statement for non-contiguous
	iterators.
	* testsuite/25_algorithms/find/bytes.cc: Check with input
	iterators.
This commit is contained in:
Jonathan Wakely 2024-07-06 21:34:29 +01:00 committed by Jonathan Wakely
parent 762ee55d36
commit ce34fcc572
No known key found for this signature in database
2 changed files with 27 additions and 24 deletions

View File

@ -3849,32 +3849,28 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO
#if __cpp_if_constexpr && __glibcxx_type_trait_variable_templates
using _ValT = typename iterator_traits<_InputIterator>::value_type;
if constexpr (__can_use_memchr_for_find<_ValT, _Tp>)
{
// If converting the value to the 1-byte value_type alters its value,
// then it would not be found by std::find using equality comparison.
// We need to check this here, because otherwise something like
// memchr("a", 'a'+256, 1) would give a false positive match.
if (!(static_cast<_ValT>(__val) == __val))
return __last;
else if (!__is_constant_evaluated())
{
const void* __p0 = nullptr;
if constexpr (is_pointer_v<decltype(std::__niter_base(__first))>)
__p0 = std::__niter_base(__first);
if constexpr (is_pointer_v<decltype(std::__niter_base(__first))>
#if __cpp_lib_concepts
else if constexpr (contiguous_iterator<_InputIterator>)
__p0 = std::to_address(__first);
|| contiguous_iterator<_InputIterator>
#endif
if (__p0)
{
const int __ival = static_cast<int>(__val);
if (auto __n = std::distance(__first, __last); __n > 0)
if (auto __p1 = __builtin_memchr(__p0, __ival, __n))
return __first + ((const char*)__p1 - (const char*)__p0);
return __last;
}
}
}
)
{
// If conversion to the 1-byte value_type alters the value,
// it would not be found by std::find using equality comparison.
// We need to check this here, because otherwise something like
// memchr("a", 'a'+256, 1) would give a false positive match.
if (!(static_cast<_ValT>(__val) == __val))
return __last;
else if (!__is_constant_evaluated())
{
const void* __p0 = std::__to_address(__first);
const int __ival = static_cast<int>(__val);
if (auto __n = std::distance(__first, __last); __n > 0)
if (auto __p1 = __builtin_memchr(__p0, __ival, __n))
return __first + ((const char*)__p1 - (const char*)__p0);
return __last;
}
}
#endif
return std::__find_if(__first, __last,

View File

@ -3,6 +3,7 @@
#include <algorithm>
#include <cstddef> // std::byte
#include <testsuite_hooks.h>
#include <testsuite_iterators.h>
// PR libstdc++/88545 made std::find use memchr as an optimization.
// This test verifies that it didn't change any semantics.
@ -113,6 +114,12 @@ test_non_characters()
#endif
}
void
test_pr115799c2(__gnu_test::input_iterator_wrapper<char> i)
{
(void) std::find(i, i, 'a');
}
int main()
{
test_char<char>();