Tested x86_64-linux. -- >8 --
There doesn't seem to be a lot of benefit in reusing __find_if with __gnu_cxx::__ops predicates, since they aren't going to actually instantiate any less code if we use different predicates every time (e.g. __ops::__negate, or __ops::__iter_equals_val, or __ops::__pred_iter). And now that std::find no longer calls __find_if (because it just does a loop directly), we can make the _Iter_equals_val case of __find_if call std::find, to take advantage of its memchr optimization. This benefits other algos like search_n which use __find_if with _Iter_equals_val. libstdc++-v3/ChangeLog: * include/bits/stl_algo.h (__find_if_not): Do loop here instead of using __find_if with __gnu_cxx::__ops predicate. (find_if): Likewise. (find): Move to ... * include/bits/stl_algobase.h (find): ... here. (__find_if): Overload for _Iter_equals_val predicate. --- libstdc++-v3/include/bits/stl_algo.h | 63 +++--------------------- libstdc++-v3/include/bits/stl_algobase.h | 61 +++++++++++++++++++++++ 2 files changed, 68 insertions(+), 56 deletions(-) diff --git a/libstdc++-v3/include/bits/stl_algo.h b/libstdc++-v3/include/bits/stl_algo.h index 489ce7e14d2..05c1dbd07b6 100644 --- a/libstdc++-v3/include/bits/stl_algo.h +++ b/libstdc++-v3/include/bits/stl_algo.h @@ -105,15 +105,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION std::iter_swap(__result, __b); } - /// Provided for stable_partition to use. + // Used by std::find_if_not and __stable_partition. template<typename _InputIterator, typename _Predicate> _GLIBCXX20_CONSTEXPR inline _InputIterator __find_if_not(_InputIterator __first, _InputIterator __last, _Predicate __pred) { - return std::__find_if(__first, __last, - __gnu_cxx::__ops::__negate(__pred)); + while (__first != __last && __pred(__first)) + ++__first; + return __first; } /// Like find_if_not(), but uses and updates a count of the @@ -3810,57 +3811,6 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO } #endif // C++17 - /** - * @brief Find the first occurrence of a value in a sequence. - * @ingroup non_mutating_algorithms - * @param __first An input iterator. - * @param __last An input iterator. - * @param __val The value to find. - * @return The first iterator @c i in the range @p [__first,__last) - * such that @c *i == @p __val, or @p __last if no such iterator exists. - */ - template<typename _InputIterator, typename _Tp> - _GLIBCXX20_CONSTEXPR - inline _InputIterator - find(_InputIterator __first, _InputIterator __last, const _Tp& __val) - { - // concept requirements - __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>) - __glibcxx_function_requires(_EqualOpConcept< - typename iterator_traits<_InputIterator>::value_type, _Tp>) - __glibcxx_requires_valid_range(__first, __last); - -#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 constexpr (is_pointer_v<decltype(std::__niter_base(__first))> -#if __cpp_lib_concepts - || contiguous_iterator<_InputIterator> -#endif - ) - { - // 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, - __gnu_cxx::__ops::__iter_equals_val(__val)); - } - /** * @brief Find the first element in a sequence for which a * predicate is true. @@ -3883,8 +3833,9 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO typename iterator_traits<_InputIterator>::value_type>) __glibcxx_requires_valid_range(__first, __last); - return std::__find_if(__first, __last, - __gnu_cxx::__ops::__pred_iter(__pred)); + while (__first != __last && !__pred(*__first)) + ++__first; + return __first; } /** diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h index 5f77b00be9b..34e1cf7322f 100644 --- a/libstdc++-v3/include/bits/stl_algobase.h +++ b/libstdc++-v3/include/bits/stl_algobase.h @@ -2077,6 +2077,58 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO } #endif + /** + * @brief Find the first occurrence of a value in a sequence. + * @ingroup non_mutating_algorithms + * @param __first An input iterator. + * @param __last An input iterator. + * @param __val The value to find. + * @return The first iterator @c i in the range @p [__first,__last) + * such that @c *i == @p __val, or @p __last if no such iterator exists. + */ + template<typename _InputIterator, typename _Tp> + _GLIBCXX20_CONSTEXPR + inline _InputIterator + find(_InputIterator __first, _InputIterator __last, const _Tp& __val) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>) + __glibcxx_function_requires(_EqualOpConcept< + typename iterator_traits<_InputIterator>::value_type, _Tp>) + __glibcxx_requires_valid_range(__first, __last); + +#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 constexpr (is_pointer_v<decltype(std::__niter_base(__first))> +#if __cpp_lib_concepts + || contiguous_iterator<_InputIterator> +#endif + ) + { + // 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 + + while (__first != __last && !(*__first == __val)) + ++__first; + return __first; + } + _GLIBCXX_END_NAMESPACE_ALGO // Implementation of std::find_if, also used in std::remove_if and others. @@ -2091,6 +2143,15 @@ _GLIBCXX_END_NAMESPACE_ALGO return __first; } + // When the predicate is just comparing to a value we can use std::find, + // which is optimized to memchr for some types. + template<typename _Iterator, typename _Value> + _GLIBCXX20_CONSTEXPR + inline _Iterator + __find_if(_Iterator __first, _Iterator __last, + __gnu_cxx::__ops::_Iter_equals_val<_Value> __pred) + { return _GLIBCXX_STD_A::find(__first, __last, __pred._M_value); } + template<typename _InputIterator, typename _Predicate> _GLIBCXX20_CONSTEXPR typename iterator_traits<_InputIterator>::difference_type -- 2.46.2