1 //===----------------------------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #ifndef _LIBCPP___CXX03___FUNCTIONAL_BOYER_MOORE_SEARCHER_H
10 #define _LIBCPP___CXX03___FUNCTIONAL_BOYER_MOORE_SEARCHER_H
12 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
13 # pragma GCC system_header
16 #include <__cxx03/__algorithm/fill_n.h>
17 #include <__cxx03/__config>
18 #include <__cxx03/__functional/hash.h>
19 #include <__cxx03/__functional/operations.h>
20 #include <__cxx03/__iterator/distance.h>
21 #include <__cxx03/__iterator/iterator_traits.h>
22 #include <__cxx03/__memory/shared_ptr.h>
23 #include <__cxx03/__type_traits/make_unsigned.h>
24 #include <__cxx03/__utility/pair.h>
25 #include <__cxx03/array>
26 #include <__cxx03/unordered_map>
27 #include <__cxx03/vector>
29 #if _LIBCPP_STD_VER >= 17
32 # include <__cxx03/__undef_macros>
34 _LIBCPP_BEGIN_NAMESPACE_STD
36 template <class _Key
, class _Value
, class _Hash
, class _BinaryPredicate
, bool /*useArray*/>
39 // General case for BM data searching; use a map
40 template <class _Key
, class _Value
, class _Hash
, class _BinaryPredicate
>
41 class _BMSkipTable
<_Key
, _Value
, _Hash
, _BinaryPredicate
, false> {
43 using value_type
= _Value
;
44 using key_type
= _Key
;
46 const value_type __default_value_
;
47 unordered_map
<_Key
, _Value
, _Hash
, _BinaryPredicate
> __table_
;
50 _LIBCPP_HIDE_FROM_ABI
explicit _BMSkipTable(
51 size_t __sz
, value_type __default_value
, _Hash __hash
, _BinaryPredicate __pred
)
52 : __default_value_(__default_value
), __table_(__sz
, __hash
, __pred
) {}
54 _LIBCPP_HIDE_FROM_ABI
void insert(const key_type
& __key
, value_type __val
) { __table_
[__key
] = __val
; }
56 _LIBCPP_HIDE_FROM_ABI value_type
operator[](const key_type
& __key
) const {
57 auto __it
= __table_
.find(__key
);
58 return __it
== __table_
.end() ? __default_value_
: __it
->second
;
62 // Special case small numeric values; use an array
63 template <class _Key
, class _Value
, class _Hash
, class _BinaryPredicate
>
64 class _BMSkipTable
<_Key
, _Value
, _Hash
, _BinaryPredicate
, true> {
66 using value_type
= _Value
;
67 using key_type
= _Key
;
69 using unsigned_key_type
= make_unsigned_t
<key_type
>;
70 std::array
<value_type
, 256> __table_
;
71 static_assert(numeric_limits
<unsigned_key_type
>::max() < 256);
74 _LIBCPP_HIDE_FROM_ABI
explicit _BMSkipTable(size_t, value_type __default_value
, _Hash
, _BinaryPredicate
) {
75 std::fill_n(__table_
.data(), __table_
.size(), __default_value
);
78 _LIBCPP_HIDE_FROM_ABI
void insert(key_type __key
, value_type __val
) {
79 __table_
[static_cast<unsigned_key_type
>(__key
)] = __val
;
82 _LIBCPP_HIDE_FROM_ABI value_type
operator[](key_type __key
) const {
83 return __table_
[static_cast<unsigned_key_type
>(__key
)];
87 template <class _RandomAccessIterator1
,
88 class _Hash
= hash
<typename iterator_traits
<_RandomAccessIterator1
>::value_type
>,
89 class _BinaryPredicate
= equal_to
<>>
90 class _LIBCPP_TEMPLATE_VIS boyer_moore_searcher
{
92 using difference_type
= typename
std::iterator_traits
<_RandomAccessIterator1
>::difference_type
;
93 using value_type
= typename
std::iterator_traits
<_RandomAccessIterator1
>::value_type
;
94 using __skip_table_type
=
95 _BMSkipTable
<value_type
,
99 is_integral_v
<value_type
> && sizeof(value_type
) == 1 && is_same_v
<_Hash
, hash
<value_type
>> &&
100 is_same_v
<_BinaryPredicate
, equal_to
<>>>;
103 _LIBCPP_HIDE_FROM_ABI
boyer_moore_searcher(
104 _RandomAccessIterator1 __first
,
105 _RandomAccessIterator1 __last
,
106 _Hash __hash
= _Hash(),
107 _BinaryPredicate __pred
= _BinaryPredicate())
111 __pattern_length_(__last
- __first
),
112 __skip_table_(std::make_shared
<__skip_table_type
>(__pattern_length_
, -1, __hash
, __pred_
)),
113 __suffix_(std::__allocate_shared_unbounded_array
<difference_type
[]>(
114 allocator
<difference_type
>(), __pattern_length_
+ 1)) {
115 difference_type __i
= 0;
116 while (__first
!= __last
) {
117 __skip_table_
->insert(*__first
, __i
);
121 __build_suffix_table(__first_
, __last_
, __pred_
);
124 template <class _RandomAccessIterator2
>
125 _LIBCPP_HIDE_FROM_ABI pair
<_RandomAccessIterator2
, _RandomAccessIterator2
>
126 operator()(_RandomAccessIterator2 __first
, _RandomAccessIterator2 __last
) const {
127 static_assert(__is_same_uncvref
<typename iterator_traits
<_RandomAccessIterator1
>::value_type
,
128 typename iterator_traits
<_RandomAccessIterator2
>::value_type
>::value
,
129 "Corpus and Pattern iterators must point to the same type");
130 if (__first
== __last
)
131 return std::make_pair(__last
, __last
);
132 if (__first_
== __last_
)
133 return std::make_pair(__first
, __first
);
135 if (__pattern_length_
> (__last
- __first
))
136 return std::make_pair(__last
, __last
);
137 return __search(__first
, __last
);
141 _RandomAccessIterator1 __first_
;
142 _RandomAccessIterator1 __last_
;
143 _BinaryPredicate __pred_
;
144 difference_type __pattern_length_
;
145 shared_ptr
<__skip_table_type
> __skip_table_
;
146 shared_ptr
<difference_type
[]> __suffix_
;
148 template <class _RandomAccessIterator2
>
149 _LIBCPP_HIDE_FROM_ABI pair
<_RandomAccessIterator2
, _RandomAccessIterator2
>
150 __search(_RandomAccessIterator2 __f
, _RandomAccessIterator2 __l
) const {
151 _RandomAccessIterator2 __current
= __f
;
152 const _RandomAccessIterator2 __last
= __l
- __pattern_length_
;
153 const __skip_table_type
& __skip_table
= *__skip_table_
;
155 while (__current
<= __last
) {
156 difference_type __j
= __pattern_length_
;
157 while (__pred_(__first_
[__j
- 1], __current
[__j
- 1])) {
160 return std::make_pair(__current
, __current
+ __pattern_length_
);
163 difference_type __k
= __skip_table
[__current
[__j
- 1]];
164 difference_type __m
= __j
- __k
- 1;
165 if (__k
< __j
&& __m
> __suffix_
[__j
])
168 __current
+= __suffix_
[__j
];
170 return std::make_pair(__l
, __l
);
173 template <class _Iterator
, class _Container
>
174 _LIBCPP_HIDE_FROM_ABI
void
175 __compute_bm_prefix(_Iterator __first
, _Iterator __last
, _BinaryPredicate __pred
, _Container
& __prefix
) {
176 const size_t __count
= __last
- __first
;
181 for (size_t __i
= 1; __i
!= __count
; ++__i
) {
182 while (__k
> 0 && !__pred(__first
[__k
], __first
[__i
]))
183 __k
= __prefix
[__k
- 1];
185 if (__pred(__first
[__k
], __first
[__i
]))
191 _LIBCPP_HIDE_FROM_ABI
void
192 __build_suffix_table(_RandomAccessIterator1 __first
, _RandomAccessIterator1 __last
, _BinaryPredicate __pred
) {
193 const size_t __count
= __last
- __first
;
198 vector
<difference_type
> __scratch(__count
);
200 __compute_bm_prefix(__first
, __last
, __pred
, __scratch
);
201 for (size_t __i
= 0; __i
<= __count
; ++__i
)
202 __suffix_
[__i
] = __count
- __scratch
[__count
- 1];
204 using _ReverseIter
= reverse_iterator
<_RandomAccessIterator1
>;
205 __compute_bm_prefix(_ReverseIter(__last
), _ReverseIter(__first
), __pred
, __scratch
);
207 for (size_t __i
= 0; __i
!= __count
; ++__i
) {
208 const size_t __j
= __count
- __scratch
[__i
];
209 const difference_type __k
= __i
- __scratch
[__i
] + 1;
211 if (__suffix_
[__j
] > __k
)
212 __suffix_
[__j
] = __k
;
216 _LIBCPP_CTAD_SUPPORTED_FOR_TYPE(boyer_moore_searcher
);
218 template <class _RandomAccessIterator1
,
219 class _Hash
= hash
<typename iterator_traits
<_RandomAccessIterator1
>::value_type
>,
220 class _BinaryPredicate
= equal_to
<>>
221 class _LIBCPP_TEMPLATE_VIS boyer_moore_horspool_searcher
{
223 using difference_type
= typename iterator_traits
<_RandomAccessIterator1
>::difference_type
;
224 using value_type
= typename iterator_traits
<_RandomAccessIterator1
>::value_type
;
225 using __skip_table_type
=
226 _BMSkipTable
<value_type
,
230 is_integral_v
<value_type
> && sizeof(value_type
) == 1 && is_same_v
<_Hash
, hash
<value_type
>> &&
231 is_same_v
<_BinaryPredicate
, equal_to
<>>>;
234 _LIBCPP_HIDE_FROM_ABI
boyer_moore_horspool_searcher(
235 _RandomAccessIterator1 __first
,
236 _RandomAccessIterator1 __last
,
237 _Hash __hash
= _Hash(),
238 _BinaryPredicate __pred
= _BinaryPredicate())
242 __pattern_length_(__last
- __first
),
243 __skip_table_(std::make_shared
<__skip_table_type
>(__pattern_length_
, __pattern_length_
, __hash
, __pred_
)) {
244 if (__first
== __last
)
247 difference_type __i
= 0;
248 while (__first
!= __last
) {
249 __skip_table_
->insert(*__first
, __pattern_length_
- 1 - __i
);
255 template <class _RandomAccessIterator2
>
256 _LIBCPP_HIDE_FROM_ABI pair
<_RandomAccessIterator2
, _RandomAccessIterator2
>
257 operator()(_RandomAccessIterator2 __first
, _RandomAccessIterator2 __last
) const {
258 static_assert(__is_same_uncvref
<typename
std::iterator_traits
<_RandomAccessIterator1
>::value_type
,
259 typename
std::iterator_traits
<_RandomAccessIterator2
>::value_type
>::value
,
260 "Corpus and Pattern iterators must point to the same type");
261 if (__first
== __last
)
262 return std::make_pair(__last
, __last
);
263 if (__first_
== __last_
)
264 return std::make_pair(__first
, __first
);
266 if (__pattern_length_
> __last
- __first
)
267 return std::make_pair(__last
, __last
);
269 return __search(__first
, __last
);
273 _RandomAccessIterator1 __first_
;
274 _RandomAccessIterator1 __last_
;
275 _BinaryPredicate __pred_
;
276 difference_type __pattern_length_
;
277 shared_ptr
<__skip_table_type
> __skip_table_
;
279 template <class _RandomAccessIterator2
>
280 _LIBCPP_HIDE_FROM_ABI pair
<_RandomAccessIterator2
, _RandomAccessIterator2
>
281 __search(_RandomAccessIterator2 __f
, _RandomAccessIterator2 __l
) const {
282 _RandomAccessIterator2 __current
= __f
;
283 const _RandomAccessIterator2 __last
= __l
- __pattern_length_
;
284 const __skip_table_type
& __skip_table
= *__skip_table_
;
286 while (__current
<= __last
) {
287 difference_type __j
= __pattern_length_
;
288 while (__pred_(__first_
[__j
- 1], __current
[__j
- 1])) {
291 return std::make_pair(__current
, __current
+ __pattern_length_
);
293 __current
+= __skip_table
[__current
[__pattern_length_
- 1]];
295 return std::make_pair(__l
, __l
);
298 _LIBCPP_CTAD_SUPPORTED_FOR_TYPE(boyer_moore_horspool_searcher
);
300 _LIBCPP_END_NAMESPACE_STD
304 #endif // _LIBCPP_STD_VER >= 17
306 #endif // _LIBCPP___CXX03___FUNCTIONAL_BOYER_MOORE_SEARCHER_H