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 <__cxx03/__algorithm/find_segment_if.h>
14 #include <__cxx03/__algorithm/min.h>
15 #include <__cxx03/__algorithm/unwrap_iter.h>
16 #include <__cxx03/__bit/countr.h>
17 #include <__cxx03/__bit/invert_if.h>
18 #include <__cxx03/__config>
19 #include <__cxx03/__functional/identity.h>
20 #include <__cxx03/__functional/invoke.h>
21 #include <__cxx03/__fwd/bit_reference.h>
22 #include <__cxx03/__iterator/segmented_iterator.h>
23 #include <__cxx03/__string/constexpr_c_functions.h>
24 #include <__cxx03/__type_traits/is_integral.h>
25 #include <__cxx03/__type_traits/is_same.h>
26 #include <__cxx03/__type_traits/is_signed.h>
27 #include <__cxx03/__utility/move.h>
28 #include <__cxx03/limits>
30 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
31 # include <__cxx03/cwchar>
34 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
35 # pragma GCC system_header
39 #include <__cxx03/__undef_macros>
41 _LIBCPP_BEGIN_NAMESPACE_STD
43 // generic implementation
44 template <class _Iter
, class _Sent
, class _Tp
, class _Proj
>
45 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Iter
46 __find(_Iter __first
, _Sent __last
, const _Tp
& __value
, _Proj
& __proj
) {
47 for (; __first
!= __last
; ++__first
)
48 if (std::__invoke(__proj
, *__first
) == __value
)
53 // trivially equality comparable implementations
57 __enable_if_t
<__is_identity
<_Proj
>::value
&& __libcpp_is_trivially_equality_comparable
<_Tp
, _Up
>::value
&&
60 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp
* __find(_Tp
* __first
, _Tp
* __last
, const _Up
& __value
, _Proj
&) {
61 if (auto __ret
= std::__constexpr_memchr(__first
, __value
, __last
- __first
))
66 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
70 __enable_if_t
<__is_identity
<_Proj
>::value
&& __libcpp_is_trivially_equality_comparable
<_Tp
, _Up
>::value
&&
71 sizeof(_Tp
) == sizeof(wchar_t) && _LIBCPP_ALIGNOF(_Tp
) >= _LIBCPP_ALIGNOF(wchar_t),
73 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp
* __find(_Tp
* __first
, _Tp
* __last
, const _Up
& __value
, _Proj
&) {
74 if (auto __ret
= std::__constexpr_wmemchr(__first
, __value
, __last
- __first
))
78 #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
80 // TODO: This should also be possible to get right with different signedness
81 // cast integral types to allow vectorization
85 __enable_if_t
<__is_identity
<_Proj
>::value
&& !__libcpp_is_trivially_equality_comparable
<_Tp
, _Up
>::value
&&
86 is_integral
<_Tp
>::value
&& is_integral
<_Up
>::value
&&
87 is_signed
<_Tp
>::value
== is_signed
<_Up
>::value
,
89 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp
*
90 __find(_Tp
* __first
, _Tp
* __last
, const _Up
& __value
, _Proj
& __proj
) {
91 if (__value
< numeric_limits
<_Tp
>::min() || __value
> numeric_limits
<_Tp
>::max())
93 return std::__find(__first
, __last
, _Tp(__value
), __proj
);
96 // __bit_iterator implementation
97 template <bool _ToFind
, class _Cp
, bool _IsConst
>
98 _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __bit_iterator
<_Cp
, _IsConst
>
99 __find_bool(__bit_iterator
<_Cp
, _IsConst
> __first
, typename
_Cp::size_type __n
) {
100 using _It
= __bit_iterator
<_Cp
, _IsConst
>;
101 using __storage_type
= typename
_It::__storage_type
;
103 const int __bits_per_word
= _It::__bits_per_word
;
104 // do first partial word
105 if (__first
.__ctz_
!= 0) {
106 __storage_type __clz_f
= static_cast<__storage_type
>(__bits_per_word
- __first
.__ctz_
);
107 __storage_type __dn
= std::min(__clz_f
, __n
);
108 __storage_type __m
= (~__storage_type(0) << __first
.__ctz_
) & (~__storage_type(0) >> (__clz_f
- __dn
));
109 __storage_type __b
= std::__invert_if
<!_ToFind
>(*__first
.__seg_
) & __m
;
111 return _It(__first
.__seg_
, static_cast<unsigned>(std::__libcpp_ctz(__b
)));
113 return __first
+ __n
;
117 // do middle whole words
118 for (; __n
>= __bits_per_word
; ++__first
.__seg_
, __n
-= __bits_per_word
) {
119 __storage_type __b
= std::__invert_if
<!_ToFind
>(*__first
.__seg_
);
121 return _It(__first
.__seg_
, static_cast<unsigned>(std::__libcpp_ctz(__b
)));
123 // do last partial word
125 __storage_type __m
= ~__storage_type(0) >> (__bits_per_word
- __n
);
126 __storage_type __b
= std::__invert_if
<!_ToFind
>(*__first
.__seg_
) & __m
;
128 return _It(__first
.__seg_
, static_cast<unsigned>(std::__libcpp_ctz(__b
)));
130 return _It(__first
.__seg_
, static_cast<unsigned>(__n
));
133 template <class _Cp
, bool _IsConst
, class _Tp
, class _Proj
, __enable_if_t
<__is_identity
<_Proj
>::value
, int> = 0>
134 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator
<_Cp
, _IsConst
>
135 __find(__bit_iterator
<_Cp
, _IsConst
> __first
, __bit_iterator
<_Cp
, _IsConst
> __last
, const _Tp
& __value
, _Proj
&) {
136 if (static_cast<bool>(__value
))
137 return std::__find_bool
<true>(__first
, static_cast<typename
_Cp::size_type
>(__last
- __first
));
138 return std::__find_bool
<false>(__first
, static_cast<typename
_Cp::size_type
>(__last
- __first
));
141 // segmented iterator implementation
144 struct __find_segment
;
146 template <class _SegmentedIterator
,
149 __enable_if_t
<__is_segmented_iterator
<_SegmentedIterator
>::value
, int> = 0>
150 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _SegmentedIterator
151 __find(_SegmentedIterator __first
, _SegmentedIterator __last
, const _Tp
& __value
, _Proj
& __proj
) {
152 return std::__find_segment_if(std::move(__first
), std::move(__last
), __find_segment
<_Tp
>(__value
), __proj
);
156 struct __find_segment
{
159 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR
__find_segment(const _Tp
& __value
) : __value_(__value
) {}
161 template <class _InputIterator
, class _Proj
>
162 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _InputIterator
163 operator()(_InputIterator __first
, _InputIterator __last
, _Proj
& __proj
) const {
164 return std::__find(__first
, __last
, __value_
, __proj
);
169 template <class _InputIterator
, class _Tp
>
170 _LIBCPP_NODISCARD
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _InputIterator
171 find(_InputIterator __first
, _InputIterator __last
, const _Tp
& __value
) {
173 return std::__rewrap_iter(
174 __first
, std::__find(std::__unwrap_iter(__first
), std::__unwrap_iter(__last
), __value
, __proj
));
177 _LIBCPP_END_NAMESPACE_STD
181 #endif // _LIBCPP___ALGORITHM_FIND_H