ZOn Tue, 15 Oct 2024, Jonathan Wakely wrote:

> 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.

Makes sense, LGTM

> 
> 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
> 
> 

Reply via email to