mirror of
https://github.com/gcc-mirror/gcc.git
synced 2024-11-21 13:40:47 +00:00
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:
parent
762ee55d36
commit
ce34fcc572
@ -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,
|
||||
|
@ -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>();
|
||||
|
Loading…
Reference in New Issue
Block a user