2 //===----------------------------------------------------------------------===//
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
8 //===----------------------------------------------------------------------===//
10 #ifndef _LIBCPP___ALGORITHM_FIND_H
11 #define _LIBCPP___ALGORITHM_FIND_H
13 #include <__algorithm/find_segment_if.h>
14 #include <__algorithm/min.h>
15 #include <__algorithm/unwrap_iter.h>
16 #include <__bit/countr.h>
17 #include <__bit/invert_if.h>
19 #include <__functional/identity.h>
20 #include <__fwd/bit_reference.h>
21 #include <__iterator/segmented_iterator.h>
22 #include <__string/constexpr_c_functions.h>
23 #include <__type_traits/enable_if.h>
24 #include <__type_traits/invoke.h>
25 #include <__type_traits/is_equality_comparable.h>
26 #include <__type_traits/is_integral.h>
27 #include <__type_traits/is_signed.h>
28 #include <__utility/move.h>
31 #if _LIBCPP_HAS_WIDE_CHARACTERS
35 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
36 # pragma GCC system_header
40 #include <__undef_macros>
42 _LIBCPP_BEGIN_NAMESPACE_STD
44 // generic implementation
45 template <class _Iter
, class _Sent
, class _Tp
, class _Proj
>
46 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Iter
47 __find(_Iter __first
, _Sent __last
, const _Tp
& __value
, _Proj
& __proj
) {
48 for (; __first
!= __last
; ++__first
)
49 if (std::__invoke(__proj
, *__first
) == __value
)
54 // trivially equality comparable implementations
58 __enable_if_t
<__is_identity
<_Proj
>::value
&& __libcpp_is_trivially_equality_comparable
<_Tp
, _Up
>::value
&&
61 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp
* __find(_Tp
* __first
, _Tp
* __last
, const _Up
& __value
, _Proj
&) {
62 if (auto __ret
= std::__constexpr_memchr(__first
, __value
, __last
- __first
))
67 #if _LIBCPP_HAS_WIDE_CHARACTERS
71 __enable_if_t
<__is_identity
<_Proj
>::value
&& __libcpp_is_trivially_equality_comparable
<_Tp
, _Up
>::value
&&
72 sizeof(_Tp
) == sizeof(wchar_t) && _LIBCPP_ALIGNOF(_Tp
) >= _LIBCPP_ALIGNOF(wchar_t),
74 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp
* __find(_Tp
* __first
, _Tp
* __last
, const _Up
& __value
, _Proj
&) {
75 if (auto __ret
= std::__constexpr_wmemchr(__first
, __value
, __last
- __first
))
79 #endif // _LIBCPP_HAS_WIDE_CHARACTERS
81 // TODO: This should also be possible to get right with different signedness
82 // cast integral types to allow vectorization
86 __enable_if_t
<__is_identity
<_Proj
>::value
&& !__libcpp_is_trivially_equality_comparable
<_Tp
, _Up
>::value
&&
87 is_integral
<_Tp
>::value
&& is_integral
<_Up
>::value
&&
88 is_signed
<_Tp
>::value
== is_signed
<_Up
>::value
,
90 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp
*
91 __find(_Tp
* __first
, _Tp
* __last
, const _Up
& __value
, _Proj
& __proj
) {
92 if (__value
< numeric_limits
<_Tp
>::min() || __value
> numeric_limits
<_Tp
>::max())
94 return std::__find(__first
, __last
, _Tp(__value
), __proj
);
97 // __bit_iterator implementation
98 template <bool _ToFind
, class _Cp
, bool _IsConst
>
99 _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __bit_iterator
<_Cp
, _IsConst
>
100 __find_bool(__bit_iterator
<_Cp
, _IsConst
> __first
, typename __size_difference_type_traits
<_Cp
>::size_type __n
) {
101 using _It
= __bit_iterator
<_Cp
, _IsConst
>;
102 using __storage_type
= typename
_It::__storage_type
;
104 const int __bits_per_word
= _It::__bits_per_word
;
105 // do first partial word
106 if (__first
.__ctz_
!= 0) {
107 __storage_type __clz_f
= static_cast<__storage_type
>(__bits_per_word
- __first
.__ctz_
);
108 __storage_type __dn
= std::min(__clz_f
, __n
);
109 __storage_type __m
= (~__storage_type(0) << __first
.__ctz_
) & (~__storage_type(0) >> (__clz_f
- __dn
));
110 __storage_type __b
= std::__invert_if
<!_ToFind
>(*__first
.__seg_
) & __m
;
112 return _It(__first
.__seg_
, static_cast<unsigned>(std::__libcpp_ctz(__b
)));
114 return __first
+ __n
;
118 // do middle whole words
119 for (; __n
>= __bits_per_word
; ++__first
.__seg_
, __n
-= __bits_per_word
) {
120 __storage_type __b
= std::__invert_if
<!_ToFind
>(*__first
.__seg_
);
122 return _It(__first
.__seg_
, static_cast<unsigned>(std::__libcpp_ctz(__b
)));
124 // do last partial word
126 __storage_type __m
= ~__storage_type(0) >> (__bits_per_word
- __n
);
127 __storage_type __b
= std::__invert_if
<!_ToFind
>(*__first
.__seg_
) & __m
;
129 return _It(__first
.__seg_
, static_cast<unsigned>(std::__libcpp_ctz(__b
)));
131 return _It(__first
.__seg_
, static_cast<unsigned>(__n
));
134 template <class _Cp
, bool _IsConst
, class _Tp
, class _Proj
, __enable_if_t
<__is_identity
<_Proj
>::value
, int> = 0>
135 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator
<_Cp
, _IsConst
>
136 __find(__bit_iterator
<_Cp
, _IsConst
> __first
, __bit_iterator
<_Cp
, _IsConst
> __last
, const _Tp
& __value
, _Proj
&) {
137 if (static_cast<bool>(__value
))
138 return std::__find_bool
<true>(
139 __first
, static_cast<typename __size_difference_type_traits
<_Cp
>::size_type
>(__last
- __first
));
140 return std::__find_bool
<false>(
141 __first
, static_cast<typename __size_difference_type_traits
<_Cp
>::size_type
>(__last
- __first
));
144 // segmented iterator implementation
147 struct __find_segment
;
149 template <class _SegmentedIterator
,
152 __enable_if_t
<__is_segmented_iterator
<_SegmentedIterator
>::value
, int> = 0>
153 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _SegmentedIterator
154 __find(_SegmentedIterator __first
, _SegmentedIterator __last
, const _Tp
& __value
, _Proj
& __proj
) {
155 return std::__find_segment_if(std::move(__first
), std::move(__last
), __find_segment
<_Tp
>(__value
), __proj
);
159 struct __find_segment
{
162 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR
__find_segment(const _Tp
& __value
) : __value_(__value
) {}
164 template <class _InputIterator
, class _Proj
>
165 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _InputIterator
166 operator()(_InputIterator __first
, _InputIterator __last
, _Proj
& __proj
) const {
167 return std::__find(__first
, __last
, __value_
, __proj
);
172 template <class _InputIterator
, class _Tp
>
173 [[__nodiscard__
]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _InputIterator
174 find(_InputIterator __first
, _InputIterator __last
, const _Tp
& __value
) {
176 return std::__rewrap_iter(
177 __first
, std::__find(std::__unwrap_iter(__first
), std::__unwrap_iter(__last
), __value
, __proj
));
180 _LIBCPP_END_NAMESPACE_STD
184 #endif // _LIBCPP___ALGORITHM_FIND_H