1 // -*- C++ -*-
2 //===----------------------------------------------------------------------===//
3 //
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
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #ifndef _PSTL_ALGORITHM_IMPL_H
11 #define _PSTL_ALGORITHM_IMPL_H
12 
13 #include <iterator>
14 #include <type_traits>
15 #include <utility>
16 #include <functional>
17 #include <algorithm>
18 
19 #include "execution_impl.h"
20 #include "memory_impl.h"
21 #include "parallel_backend.h"
22 #include "parallel_backend_utils.h"
23 #include "parallel_impl.h"
24 #include "pstl_config.h"
25 #include "unseq_backend_simd.h"
26 
27 _PSTL_HIDE_FROM_ABI_PUSH
28 
29 namespace __pstl
30 {
31 namespace __internal
32 {
33 
34 //------------------------------------------------------------------------
35 // any_of
36 //------------------------------------------------------------------------
37 
38 template <class _ForwardIterator, class _Pred>
39 bool
__brick_any_of(const _ForwardIterator __first,const _ForwardIterator __last,_Pred __pred,std::false_type)40 __brick_any_of(const _ForwardIterator __first, const _ForwardIterator __last, _Pred __pred,
41                /*__is_vector=*/std::false_type) noexcept
42 {
43     return std::any_of(__first, __last, __pred);
44 };
45 
46 template <class _RandomAccessIterator, class _Pred>
47 bool
__brick_any_of(const _RandomAccessIterator __first,const _RandomAccessIterator __last,_Pred __pred,std::true_type)48 __brick_any_of(const _RandomAccessIterator __first, const _RandomAccessIterator __last, _Pred __pred,
49                /*__is_vector=*/std::true_type) noexcept
50 {
51     return __unseq_backend::__simd_or(__first, __last - __first, __pred);
52 };
53 
54 template <class _ExecutionPolicy, class _ForwardIterator, class _Pred, class _IsVector>
55 bool
__pattern_any_of(_ExecutionPolicy &&,_ForwardIterator __first,_ForwardIterator __last,_Pred __pred,_IsVector __is_vector,std::false_type)56 __pattern_any_of(_ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __last, _Pred __pred,
57                  _IsVector __is_vector, /*parallel=*/std::false_type) noexcept
58 {
59     return __internal::__brick_any_of(__first, __last, __pred, __is_vector);
60 }
61 
62 template <class _ExecutionPolicy, class _RandomAccessIterator, class _Pred, class _IsVector>
63 bool
__pattern_any_of(_ExecutionPolicy && __exec,_RandomAccessIterator __first,_RandomAccessIterator __last,_Pred __pred,_IsVector __is_vector,std::true_type)64 __pattern_any_of(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __last, _Pred __pred,
65                  _IsVector __is_vector, /*parallel=*/std::true_type)
66 {
67     return __internal::__except_handler([&]() {
68         return __internal::__parallel_or(std::forward<_ExecutionPolicy>(__exec), __first, __last,
69                                          [__pred, __is_vector](_RandomAccessIterator __i, _RandomAccessIterator __j) {
70                                              return __internal::__brick_any_of(__i, __j, __pred, __is_vector);
71                                          });
72     });
73 }
74 
75 // [alg.foreach]
76 // for_each_n with no policy
77 
78 template <class _ForwardIterator, class _Size, class _Function>
79 _ForwardIterator
__for_each_n_it_serial(_ForwardIterator __first,_Size __n,_Function __f)80 __for_each_n_it_serial(_ForwardIterator __first, _Size __n, _Function __f)
81 {
82     for (; __n > 0; ++__first, --__n)
83         __f(__first);
84     return __first;
85 }
86 
87 //------------------------------------------------------------------------
88 // walk1 (pseudo)
89 //
90 // walk1 evaluates f(x) for each dereferenced value x drawn from [first,last)
91 //------------------------------------------------------------------------
92 template <class _ForwardIterator, class _Function>
93 void
__brick_walk1(_ForwardIterator __first,_ForwardIterator __last,_Function __f,std::false_type)94 __brick_walk1(_ForwardIterator __first, _ForwardIterator __last, _Function __f, /*vector=*/std::false_type) noexcept
95 {
96     std::for_each(__first, __last, __f);
97 }
98 
99 template <class _RandomAccessIterator, class _Function>
100 void
__brick_walk1(_RandomAccessIterator __first,_RandomAccessIterator __last,_Function __f,std::true_type)101 __brick_walk1(_RandomAccessIterator __first, _RandomAccessIterator __last, _Function __f,
102               /*vector=*/std::true_type) noexcept
103 {
104     __unseq_backend::__simd_walk_1(__first, __last - __first, __f);
105 }
106 
107 template <class _ExecutionPolicy, class _ForwardIterator, class _Function, class _IsVector>
108 void
__pattern_walk1(_ExecutionPolicy &&,_ForwardIterator __first,_ForwardIterator __last,_Function __f,_IsVector __is_vector,std::false_type)109 __pattern_walk1(_ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __last, _Function __f,
110                 _IsVector __is_vector,
111                 /*parallel=*/std::false_type) noexcept
112 {
113     __internal::__brick_walk1(__first, __last, __f, __is_vector);
114 }
115 
116 template <class _ExecutionPolicy, class _RandomAccessIterator, class _Function, class _IsVector>
117 void
__pattern_walk1(_ExecutionPolicy && __exec,_RandomAccessIterator __first,_RandomAccessIterator __last,_Function __f,_IsVector __is_vector,std::true_type)118 __pattern_walk1(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __last, _Function __f,
119                 _IsVector __is_vector,
120                 /*parallel=*/std::true_type)
121 {
122     __internal::__except_handler([&]() {
123         __par_backend::__parallel_for(std::forward<_ExecutionPolicy>(__exec), __first, __last,
124                                       [__f, __is_vector](_RandomAccessIterator __i, _RandomAccessIterator __j) {
125                                           __internal::__brick_walk1(__i, __j, __f, __is_vector);
126                                       });
127     });
128 }
129 
130 template <class _ExecutionPolicy, class _ForwardIterator, class _Brick>
131 void
__pattern_walk_brick(_ExecutionPolicy &&,_ForwardIterator __first,_ForwardIterator __last,_Brick __brick,std::false_type)132 __pattern_walk_brick(_ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __last, _Brick __brick,
133                      /*parallel=*/std::false_type) noexcept
134 {
135     __brick(__first, __last);
136 }
137 
138 template <class _ExecutionPolicy, class _RandomAccessIterator, class _Brick>
139 void
__pattern_walk_brick(_ExecutionPolicy && __exec,_RandomAccessIterator __first,_RandomAccessIterator __last,_Brick __brick,std::true_type)140 __pattern_walk_brick(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __last,
141                      _Brick __brick,
142                      /*parallel=*/std::true_type)
143 {
144     __internal::__except_handler([&]() {
145         __par_backend::__parallel_for(
146             std::forward<_ExecutionPolicy>(__exec), __first, __last,
147             [__brick](_RandomAccessIterator __i, _RandomAccessIterator __j) { __brick(__i, __j); });
148     });
149 }
150 
151 //------------------------------------------------------------------------
152 // walk1_n
153 //------------------------------------------------------------------------
154 template <class _ForwardIterator, class _Size, class _Function>
155 _ForwardIterator
__brick_walk1_n(_ForwardIterator __first,_Size __n,_Function __f,std::false_type)156 __brick_walk1_n(_ForwardIterator __first, _Size __n, _Function __f, /*_IsVectorTag=*/std::false_type)
157 {
158     return __internal::__for_each_n_it_serial(__first, __n,
159                                               [&__f](_ForwardIterator __it) { __f(*__it); }); // calling serial version
160 }
161 
162 template <class _RandomAccessIterator, class _DifferenceType, class _Function>
163 _RandomAccessIterator
__brick_walk1_n(_RandomAccessIterator __first,_DifferenceType __n,_Function __f,std::true_type)164 __brick_walk1_n(_RandomAccessIterator __first, _DifferenceType __n, _Function __f,
165                 /*vectorTag=*/std::true_type) noexcept
166 {
167     return __unseq_backend::__simd_walk_1(__first, __n, __f);
168 }
169 
170 template <class _ExecutionPolicy, class _ForwardIterator, class _Size, class _Function, class _IsVector>
171 _ForwardIterator
__pattern_walk1_n(_ExecutionPolicy &&,_ForwardIterator __first,_Size __n,_Function __f,_IsVector __is_vector,std::false_type)172 __pattern_walk1_n(_ExecutionPolicy&&, _ForwardIterator __first, _Size __n, _Function __f, _IsVector __is_vector,
173                   /*is_parallel=*/std::false_type) noexcept
174 {
175     return __internal::__brick_walk1_n(__first, __n, __f, __is_vector);
176 }
177 
178 template <class _ExecutionPolicy, class _RandomAccessIterator, class _Size, class _Function, class _IsVector>
179 _RandomAccessIterator
__pattern_walk1_n(_ExecutionPolicy && __exec,_RandomAccessIterator __first,_Size __n,_Function __f,_IsVector __is_vector,std::true_type)180 __pattern_walk1_n(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _Size __n, _Function __f,
181                   _IsVector __is_vector,
182                   /*is_parallel=*/std::true_type)
183 {
184     __internal::__pattern_walk1(std::forward<_ExecutionPolicy>(__exec), __first, __first + __n, __f, __is_vector,
185                                 std::true_type());
186     return __first + __n;
187 }
188 
189 template <class _ExecutionPolicy, class _ForwardIterator, class _Size, class _Brick>
190 _ForwardIterator
__pattern_walk_brick_n(_ExecutionPolicy &&,_ForwardIterator __first,_Size __n,_Brick __brick,std::false_type)191 __pattern_walk_brick_n(_ExecutionPolicy&&, _ForwardIterator __first, _Size __n, _Brick __brick,
192                        /*is_parallel=*/std::false_type) noexcept
193 {
194     return __brick(__first, __n);
195 }
196 
197 template <class _ExecutionPolicy, class _RandomAccessIterator, class _Size, class _Brick>
198 _RandomAccessIterator
__pattern_walk_brick_n(_ExecutionPolicy && __exec,_RandomAccessIterator __first,_Size __n,_Brick __brick,std::true_type)199 __pattern_walk_brick_n(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _Size __n, _Brick __brick,
200                        /*is_parallel=*/std::true_type)
201 {
202     return __internal::__except_handler([&]() {
203         __par_backend::__parallel_for(
204             std::forward<_ExecutionPolicy>(__exec), __first, __first + __n,
205             [__brick](_RandomAccessIterator __i, _RandomAccessIterator __j) { __brick(__i, __j - __i); });
206         return __first + __n;
207     });
208 }
209 
210 //------------------------------------------------------------------------
211 // walk2 (pseudo)
212 //
213 // walk2 evaluates f(x,y) for deferenced values (x,y) drawn from [first1,last1) and [first2,...)
214 //------------------------------------------------------------------------
215 template <class _ForwardIterator1, class _ForwardIterator2, class _Function>
216 _ForwardIterator2
__brick_walk2(_ForwardIterator1 __first1,_ForwardIterator1 __last1,_ForwardIterator2 __first2,_Function __f,std::false_type)217 __brick_walk2(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2, _Function __f,
218               /*vector=*/std::false_type) noexcept
219 {
220     for (; __first1 != __last1; ++__first1, ++__first2)
221         __f(*__first1, *__first2);
222     return __first2;
223 }
224 
225 template <class _RandomAccessIterator1, class _RandomAccessIterator2, class _Function>
226 _RandomAccessIterator2
__brick_walk2(_RandomAccessIterator1 __first1,_RandomAccessIterator1 __last1,_RandomAccessIterator2 __first2,_Function __f,std::true_type)227 __brick_walk2(_RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1, _RandomAccessIterator2 __first2,
228               _Function __f,
229               /*vector=*/std::true_type) noexcept
230 {
231     return __unseq_backend::__simd_walk_2(__first1, __last1 - __first1, __first2, __f);
232 }
233 
234 template <class _ForwardIterator1, class _Size, class _ForwardIterator2, class _Function>
235 _ForwardIterator2
__brick_walk2_n(_ForwardIterator1 __first1,_Size __n,_ForwardIterator2 __first2,_Function __f,std::false_type)236 __brick_walk2_n(_ForwardIterator1 __first1, _Size __n, _ForwardIterator2 __first2, _Function __f,
237                 /*vector=*/std::false_type) noexcept
238 {
239     for (; __n > 0; --__n, ++__first1, ++__first2)
240         __f(*__first1, *__first2);
241     return __first2;
242 }
243 
244 template <class _RandomAccessIterator1, class _Size, class _RandomAccessIterator2, class _Function>
245 _RandomAccessIterator2
__brick_walk2_n(_RandomAccessIterator1 __first1,_Size __n,_RandomAccessIterator2 __first2,_Function __f,std::true_type)246 __brick_walk2_n(_RandomAccessIterator1 __first1, _Size __n, _RandomAccessIterator2 __first2, _Function __f,
247                 /*vector=*/std::true_type) noexcept
248 {
249     return __unseq_backend::__simd_walk_2(__first1, __n, __first2, __f);
250 }
251 
252 template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _Function, class _IsVector>
253 _ForwardIterator2
__pattern_walk2(_ExecutionPolicy &&,_ForwardIterator1 __first1,_ForwardIterator1 __last1,_ForwardIterator2 __first2,_Function __f,_IsVector __is_vector,std::false_type)254 __pattern_walk2(_ExecutionPolicy&&, _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
255                 _Function __f, _IsVector __is_vector, /*parallel=*/std::false_type) noexcept
256 {
257     return __internal::__brick_walk2(__first1, __last1, __first2, __f, __is_vector);
258 }
259 
260 template <class _ExecutionPolicy, class _RandomAccessIterator1, class _RandomAccessIterator2, class _Function,
261           class _IsVector>
262 _RandomAccessIterator2
__pattern_walk2(_ExecutionPolicy && __exec,_RandomAccessIterator1 __first1,_RandomAccessIterator1 __last1,_RandomAccessIterator2 __first2,_Function __f,_IsVector __is_vector,std::true_type)263 __pattern_walk2(_ExecutionPolicy&& __exec, _RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1,
264                 _RandomAccessIterator2 __first2, _Function __f, _IsVector __is_vector, /*parallel=*/std::true_type)
265 {
266     return __internal::__except_handler([&]() {
267         __par_backend::__parallel_for(
268             std::forward<_ExecutionPolicy>(__exec), __first1, __last1,
269             [__f, __first1, __first2, __is_vector](_RandomAccessIterator1 __i, _RandomAccessIterator1 __j) {
270                 __internal::__brick_walk2(__i, __j, __first2 + (__i - __first1), __f, __is_vector);
271             });
272         return __first2 + (__last1 - __first1);
273     });
274 }
275 
276 template <class _ExecutionPolicy, class _ForwardIterator1, class _Size, class _ForwardIterator2, class _Function,
277           class _IsVector>
278 _ForwardIterator2
__pattern_walk2_n(_ExecutionPolicy &&,_ForwardIterator1 __first1,_Size __n,_ForwardIterator2 __first2,_Function __f,_IsVector is_vector,std::false_type)279 __pattern_walk2_n(_ExecutionPolicy&&, _ForwardIterator1 __first1, _Size __n, _ForwardIterator2 __first2, _Function __f,
280                   _IsVector is_vector, /*parallel=*/std::false_type) noexcept
281 {
282     return __internal::__brick_walk2_n(__first1, __n, __first2, __f, is_vector);
283 }
284 
285 template <class _ExecutionPolicy, class _RandomAccessIterator1, class _Size, class _RandomAccessIterator2,
286           class _Function, class _IsVector>
287 _RandomAccessIterator2
__pattern_walk2_n(_ExecutionPolicy && __exec,_RandomAccessIterator1 __first1,_Size __n,_RandomAccessIterator2 __first2,_Function __f,_IsVector is_vector,std::true_type)288 __pattern_walk2_n(_ExecutionPolicy&& __exec, _RandomAccessIterator1 __first1, _Size __n,
289                   _RandomAccessIterator2 __first2, _Function __f, _IsVector is_vector, /*parallel=*/std::true_type)
290 {
291     return __internal::__pattern_walk2(std::forward<_ExecutionPolicy>(__exec), __first1, __first1 + __n, __first2, __f,
292                                        is_vector, std::true_type());
293 }
294 
295 template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _Brick>
296 _ForwardIterator2
__pattern_walk2_brick(_ExecutionPolicy &&,_ForwardIterator1 __first1,_ForwardIterator1 __last1,_ForwardIterator2 __first2,_Brick __brick,std::false_type)297 __pattern_walk2_brick(_ExecutionPolicy&&, _ForwardIterator1 __first1, _ForwardIterator1 __last1,
298                       _ForwardIterator2 __first2, _Brick __brick, /*parallel=*/std::false_type) noexcept
299 {
300     return __brick(__first1, __last1, __first2);
301 }
302 
303 template <class _ExecutionPolicy, class _RandomAccessIterator1, class _RandomAccessIterator2, class _Brick>
304 _RandomAccessIterator2
__pattern_walk2_brick(_ExecutionPolicy && __exec,_RandomAccessIterator1 __first1,_RandomAccessIterator1 __last1,_RandomAccessIterator2 __first2,_Brick __brick,std::true_type)305 __pattern_walk2_brick(_ExecutionPolicy&& __exec, _RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1,
306                       _RandomAccessIterator2 __first2, _Brick __brick, /*parallel=*/std::true_type)
307 {
308     return __internal::__except_handler([&]() {
309         __par_backend::__parallel_for(
310             std::forward<_ExecutionPolicy>(__exec), __first1, __last1,
311             [__first1, __first2, __brick](_RandomAccessIterator1 __i, _RandomAccessIterator1 __j) {
312                 __brick(__i, __j, __first2 + (__i - __first1));
313             });
314         return __first2 + (__last1 - __first1);
315     });
316 }
317 
318 template <class _ExecutionPolicy, class _RandomAccessIterator1, class _Size, class _RandomAccessIterator2, class _Brick>
319 _RandomAccessIterator2
__pattern_walk2_brick_n(_ExecutionPolicy && __exec,_RandomAccessIterator1 __first1,_Size __n,_RandomAccessIterator2 __first2,_Brick __brick,std::true_type)320 __pattern_walk2_brick_n(_ExecutionPolicy&& __exec, _RandomAccessIterator1 __first1, _Size __n,
321                         _RandomAccessIterator2 __first2, _Brick __brick, /*parallel=*/std::true_type)
322 {
323     return __internal::__except_handler([&]() {
324         __par_backend::__parallel_for(
325             std::forward<_ExecutionPolicy>(__exec), __first1, __first1 + __n,
326             [__first1, __first2, __brick](_RandomAccessIterator1 __i, _RandomAccessIterator1 __j) {
327                 __brick(__i, __j - __i, __first2 + (__i - __first1));
328             });
329         return __first2 + __n;
330     });
331 }
332 
333 template <class _ExecutionPolicy, class _ForwardIterator1, class _Size, class _ForwardIterator2, class _Brick>
334 _ForwardIterator2
__pattern_walk2_brick_n(_ExecutionPolicy &&,_ForwardIterator1 __first1,_Size __n,_ForwardIterator2 __first2,_Brick __brick,std::false_type)335 __pattern_walk2_brick_n(_ExecutionPolicy&&, _ForwardIterator1 __first1, _Size __n, _ForwardIterator2 __first2,
336                         _Brick __brick, /*parallel=*/std::false_type) noexcept
337 {
338     return __brick(__first1, __n, __first2);
339 }
340 
341 //------------------------------------------------------------------------
342 // walk3 (pseudo)
343 //
344 // walk3 evaluates f(x,y,z) for (x,y,z) drawn from [first1,last1), [first2,...), [first3,...)
345 //------------------------------------------------------------------------
346 template <class _ForwardIterator1, class _ForwardIterator2, class _ForwardIterator3, class _Function>
347 _ForwardIterator3
__brick_walk3(_ForwardIterator1 __first1,_ForwardIterator1 __last1,_ForwardIterator2 __first2,_ForwardIterator3 __first3,_Function __f,std::false_type)348 __brick_walk3(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
349               _ForwardIterator3 __first3, _Function __f, /*vector=*/std::false_type) noexcept
350 {
351     for (; __first1 != __last1; ++__first1, ++__first2, ++__first3)
352         __f(*__first1, *__first2, *__first3);
353     return __first3;
354 }
355 
356 template <class _RandomAccessIterator1, class _RandomAccessIterator2, class _RandomAccessIterator3, class _Function>
357 _RandomAccessIterator3
__brick_walk3(_RandomAccessIterator1 __first1,_RandomAccessIterator1 __last1,_RandomAccessIterator2 __first2,_RandomAccessIterator3 __first3,_Function __f,std::true_type)358 __brick_walk3(_RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1, _RandomAccessIterator2 __first2,
359               _RandomAccessIterator3 __first3, _Function __f, /*vector=*/std::true_type) noexcept
360 {
361     return __unseq_backend::__simd_walk_3(__first1, __last1 - __first1, __first2, __first3, __f);
362 }
363 
364 template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _ForwardIterator3,
365           class _Function, class _IsVector>
366 _ForwardIterator3
__pattern_walk3(_ExecutionPolicy &&,_ForwardIterator1 __first1,_ForwardIterator1 __last1,_ForwardIterator2 __first2,_ForwardIterator3 __first3,_Function __f,_IsVector __is_vector,std::false_type)367 __pattern_walk3(_ExecutionPolicy&&, _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
368                 _ForwardIterator3 __first3, _Function __f, _IsVector __is_vector, /*parallel=*/std::false_type) noexcept
369 {
370     return __internal::__brick_walk3(__first1, __last1, __first2, __first3, __f, __is_vector);
371 }
372 
373 template <class _ExecutionPolicy, class _RandomAccessIterator1, class _RandomAccessIterator2,
374           class _RandomAccessIterator3, class _Function, class _IsVector>
375 _RandomAccessIterator3
__pattern_walk3(_ExecutionPolicy && __exec,_RandomAccessIterator1 __first1,_RandomAccessIterator1 __last1,_RandomAccessIterator2 __first2,_RandomAccessIterator3 __first3,_Function __f,_IsVector __is_vector,std::true_type)376 __pattern_walk3(_ExecutionPolicy&& __exec, _RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1,
377                 _RandomAccessIterator2 __first2, _RandomAccessIterator3 __first3, _Function __f, _IsVector __is_vector,
378                 /*parallel=*/std::true_type)
379 {
380     return __internal::__except_handler([&]() {
381         __par_backend::__parallel_for(
382             std::forward<_ExecutionPolicy>(__exec), __first1, __last1,
383             [__f, __first1, __first2, __first3, __is_vector](_RandomAccessIterator1 __i, _RandomAccessIterator1 __j) {
384                 __internal::__brick_walk3(__i, __j, __first2 + (__i - __first1), __first3 + (__i - __first1), __f,
385                                           __is_vector);
386             });
387         return __first3 + (__last1 - __first1);
388     });
389 }
390 
391 //------------------------------------------------------------------------
392 // equal
393 //------------------------------------------------------------------------
394 
395 template <class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
396 bool
__brick_equal(_ForwardIterator1 __first1,_ForwardIterator1 __last1,_ForwardIterator2 __first2,_ForwardIterator2 __last2,_BinaryPredicate __p,std::false_type)397 __brick_equal(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
398               _ForwardIterator2 __last2, _BinaryPredicate __p, /* IsVector = */ std::false_type) noexcept
399 {
400     return std::equal(__first1, __last1, __first2, __last2, __p);
401 }
402 
403 template <class _RandomAccessIterator1, class _RandomAccessIterator2, class _BinaryPredicate>
404 bool
__brick_equal(_RandomAccessIterator1 __first1,_RandomAccessIterator1 __last1,_RandomAccessIterator2 __first2,_RandomAccessIterator2 __last2,_BinaryPredicate __p,std::true_type)405 __brick_equal(_RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1, _RandomAccessIterator2 __first2,
406               _RandomAccessIterator2 __last2, _BinaryPredicate __p, /* is_vector = */ std::true_type) noexcept
407 {
408     if (__last1 - __first1 != __last2 - __first2)
409         return false;
410 
411     return __unseq_backend::__simd_first(__first1, __last1 - __first1, __first2, std::not_fn(__p)).first == __last1;
412 }
413 
414 template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate,
415           class _IsVector>
416 bool
__pattern_equal(_ExecutionPolicy &&,_ForwardIterator1 __first1,_ForwardIterator1 __last1,_ForwardIterator2 __first2,_ForwardIterator2 __last2,_BinaryPredicate __p,_IsVector __is_vector,std::false_type)417 __pattern_equal(_ExecutionPolicy&&, _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
418                 _ForwardIterator2 __last2, _BinaryPredicate __p, _IsVector __is_vector, /* is_parallel = */
419                 std::false_type) noexcept
420 {
421     return __internal::__brick_equal(__first1, __last1, __first2, __last2, __p, __is_vector);
422 }
423 
424 template <class _ExecutionPolicy, class _RandomAccessIterator1, class _RandomAccessIterator2, class _BinaryPredicate,
425           class _IsVector>
426 bool
__pattern_equal(_ExecutionPolicy && __exec,_RandomAccessIterator1 __first1,_RandomAccessIterator1 __last1,_RandomAccessIterator2 __first2,_RandomAccessIterator2 __last2,_BinaryPredicate __p,_IsVector __is_vector,std::true_type)427 __pattern_equal(_ExecutionPolicy&& __exec, _RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1,
428                 _RandomAccessIterator2 __first2, _RandomAccessIterator2 __last2, _BinaryPredicate __p,
429                 _IsVector __is_vector, /*is_parallel=*/std::true_type)
430 {
431     if (__last1 - __first1 != __last2 - __first2)
432         return false;
433 
434     return __internal::__except_handler([&]() {
435         return !__internal::__parallel_or(
436             std::forward<_ExecutionPolicy>(__exec), __first1, __last1,
437             [__first1, __first2, __p, __is_vector](_RandomAccessIterator1 __i, _RandomAccessIterator1 __j) {
438                 return !__internal::__brick_equal(__i, __j, __first2 + (__i - __first1), __first2 + (__j - __first1),
439                                                   __p, __is_vector);
440             });
441     });
442 }
443 
444 //------------------------------------------------------------------------
445 // equal version for sequences with equal length
446 //------------------------------------------------------------------------
447 
448 template <class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
449 bool
__brick_equal(_ForwardIterator1 __first1,_ForwardIterator1 __last1,_ForwardIterator2 __first2,_BinaryPredicate __p,std::false_type)450 __brick_equal(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2, _BinaryPredicate __p,
451               /* IsVector = */ std::false_type) noexcept
452 {
453     return std::equal(__first1, __last1, __first2, __p);
454 }
455 
456 template <class _RandomAccessIterator1, class _RandomAccessIterator2, class _BinaryPredicate>
457 bool
__brick_equal(_RandomAccessIterator1 __first1,_RandomAccessIterator1 __last1,_RandomAccessIterator2 __first2,_BinaryPredicate __p,std::true_type)458 __brick_equal(_RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1, _RandomAccessIterator2 __first2,
459               _BinaryPredicate __p, /* is_vector = */ std::true_type) noexcept
460 {
461     return __unseq_backend::__simd_first(__first1, __last1 - __first1, __first2, std::not_fn(__p)).first == __last1;
462 }
463 
464 template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate,
465           class _IsVector>
466 bool
__pattern_equal(_ExecutionPolicy &&,_ForwardIterator1 __first1,_ForwardIterator1 __last1,_ForwardIterator2 __first2,_BinaryPredicate __p,_IsVector __is_vector,std::false_type)467 __pattern_equal(_ExecutionPolicy&&, _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
468                 _BinaryPredicate __p, _IsVector __is_vector, /* is_parallel = */ std::false_type) noexcept
469 {
470     return __internal::__brick_equal(__first1, __last1, __first2, __p, __is_vector);
471 }
472 
473 template <class _ExecutionPolicy, class _RandomAccessIterator1, class _RandomAccessIterator2, class _BinaryPredicate,
474           class _IsVector>
475 bool
__pattern_equal(_ExecutionPolicy && __exec,_RandomAccessIterator1 __first1,_RandomAccessIterator1 __last1,_RandomAccessIterator2 __first2,_BinaryPredicate __p,_IsVector __is_vector,std::true_type)476 __pattern_equal(_ExecutionPolicy&& __exec, _RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1,
477                 _RandomAccessIterator2 __first2, _BinaryPredicate __p, _IsVector __is_vector,
478                 /*is_parallel=*/std::true_type)
479 {
480     return __internal::__except_handler([&]() {
481         return !__internal::__parallel_or(
482             std::forward<_ExecutionPolicy>(__exec), __first1, __last1,
483             [__first1, __first2, __p, __is_vector](_RandomAccessIterator1 __i, _RandomAccessIterator1 __j) {
484                 return !__internal::__brick_equal(__i, __j, __first2 + (__i - __first1), __p, __is_vector);
485             });
486     });
487 }
488 
489 //------------------------------------------------------------------------
490 // find_if
491 //------------------------------------------------------------------------
492 template <class _ForwardIterator, class _Predicate>
493 _ForwardIterator
__brick_find_if(_ForwardIterator __first,_ForwardIterator __last,_Predicate __pred,std::false_type)494 __brick_find_if(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred,
495                 /*is_vector=*/std::false_type) noexcept
496 {
497     return std::find_if(__first, __last, __pred);
498 }
499 
500 template <class _RandomAccessIterator, class _Predicate>
501 _RandomAccessIterator
__brick_find_if(_RandomAccessIterator __first,_RandomAccessIterator __last,_Predicate __pred,std::true_type)502 __brick_find_if(_RandomAccessIterator __first, _RandomAccessIterator __last, _Predicate __pred,
503                 /*is_vector=*/std::true_type) noexcept
504 {
505     typedef typename std::iterator_traits<_RandomAccessIterator>::difference_type _SizeType;
506     return __unseq_backend::__simd_first(
507         __first, _SizeType(0), __last - __first,
508         [&__pred](_RandomAccessIterator __it, _SizeType __i) { return __pred(__it[__i]); });
509 }
510 
511 template <class _ExecutionPolicy, class _ForwardIterator, class _Predicate, class _IsVector>
512 _ForwardIterator
__pattern_find_if(_ExecutionPolicy &&,_ForwardIterator __first,_ForwardIterator __last,_Predicate __pred,_IsVector __is_vector,std::false_type)513 __pattern_find_if(_ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred,
514                   _IsVector __is_vector,
515                   /*is_parallel=*/std::false_type) noexcept
516 {
517     return __internal::__brick_find_if(__first, __last, __pred, __is_vector);
518 }
519 
520 template <class _ExecutionPolicy, class _RandomAccessIterator, class _Predicate, class _IsVector>
521 _RandomAccessIterator
__pattern_find_if(_ExecutionPolicy && __exec,_RandomAccessIterator __first,_RandomAccessIterator __last,_Predicate __pred,_IsVector __is_vector,std::true_type)522 __pattern_find_if(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __last,
523                   _Predicate __pred, _IsVector __is_vector,
524                   /*is_parallel=*/std::true_type)
525 {
526     return __internal::__except_handler([&]() {
527         return __internal::__parallel_find(
528             std::forward<_ExecutionPolicy>(__exec), __first, __last,
529             [__pred, __is_vector](_RandomAccessIterator __i, _RandomAccessIterator __j) {
530                 return __internal::__brick_find_if(__i, __j, __pred, __is_vector);
531             },
532             std::less<typename std::iterator_traits<_RandomAccessIterator>::difference_type>(),
533             /*is_first=*/true);
534     });
535 }
536 
537 //------------------------------------------------------------------------
538 // find_end
539 //------------------------------------------------------------------------
540 
541 // find the first occurrence of the subsequence [s_first, s_last)
542 //   or the  last occurrence of the subsequence in the range [first, last)
543 // b_first determines what occurrence we want to find (first or last)
544 template <class _RandomAccessIterator1, class _RandomAccessIterator2, class _BinaryPredicate, class _IsVector>
545 _RandomAccessIterator1
__find_subrange(_RandomAccessIterator1 __first,_RandomAccessIterator1 __last,_RandomAccessIterator1 __global_last,_RandomAccessIterator2 __s_first,_RandomAccessIterator2 __s_last,_BinaryPredicate __pred,bool __b_first,_IsVector __is_vector)546 __find_subrange(_RandomAccessIterator1 __first, _RandomAccessIterator1 __last, _RandomAccessIterator1 __global_last,
547                 _RandomAccessIterator2 __s_first, _RandomAccessIterator2 __s_last, _BinaryPredicate __pred,
548                 bool __b_first, _IsVector __is_vector) noexcept
549 {
550     typedef typename std::iterator_traits<_RandomAccessIterator2>::value_type _ValueType;
551     auto __n2 = __s_last - __s_first;
552     if (__n2 < 1)
553     {
554         return __b_first ? __first : __last;
555     }
556 
557     auto __n1 = __global_last - __first;
558     if (__n1 < __n2)
559     {
560         return __last;
561     }
562 
563     auto __cur = __last;
564     while (__first != __last && (__global_last - __first >= __n2))
565     {
566         // find position of *s_first in [first, last) (it can be start of subsequence)
567         __first = __internal::__brick_find_if(
568             __first, __last, __equal_value_by_pred<_ValueType, _BinaryPredicate>(*__s_first, __pred), __is_vector);
569 
570         // if position that was found previously is the start of subsequence
571         // then we can exit the loop (b_first == true) or keep the position
572         // (b_first == false)
573         if (__first != __last && (__global_last - __first >= __n2) &&
574             __internal::__brick_equal(__s_first + 1, __s_last, __first + 1, __pred, __is_vector))
575         {
576             if (__b_first)
577             {
578                 return __first;
579             }
580             else
581             {
582                 __cur = __first;
583             }
584         }
585         else if (__first == __last)
586         {
587             break;
588         }
589         else
590         {
591         }
592 
593         // in case of b_first == false we try to find new start position
594         // for the next subsequence
595         ++__first;
596     }
597     return __cur;
598 }
599 
600 template <class _RandomAccessIterator, class _Size, class _Tp, class _BinaryPredicate, class _IsVector>
601 _RandomAccessIterator
__find_subrange(_RandomAccessIterator __first,_RandomAccessIterator __last,_RandomAccessIterator __global_last,_Size __count,const _Tp & __value,_BinaryPredicate __pred,_IsVector __is_vector)602 __find_subrange(_RandomAccessIterator __first, _RandomAccessIterator __last, _RandomAccessIterator __global_last,
603                 _Size __count, const _Tp& __value, _BinaryPredicate __pred, _IsVector __is_vector) noexcept
604 {
605     if (static_cast<_Size>(__global_last - __first) < __count || __count < 1)
606     {
607         return __last; // According to the standard last shall be returned when count < 1
608     }
609 
610     auto __unary_pred = __equal_value_by_pred<_Tp, _BinaryPredicate>(__value, __pred);
611     while (__first != __last && (static_cast<_Size>(__global_last - __first) >= __count))
612     {
613         __first = __internal::__brick_find_if(__first, __last, __unary_pred, __is_vector);
614 
615         // check that all of elements in [first+1, first+count) equal to value
616         if (__first != __last && (static_cast<_Size>(__global_last - __first) >= __count) &&
617             !__internal::__brick_any_of(__first + 1, __first + __count, std::not_fn(__unary_pred), __is_vector))
618         {
619             return __first;
620         }
621         else if (__first == __last)
622         {
623             break;
624         }
625         else
626         {
627             ++__first;
628         }
629     }
630     return __last;
631 }
632 
633 template <class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
634 _ForwardIterator1
__brick_find_end(_ForwardIterator1 __first,_ForwardIterator1 __last,_ForwardIterator2 __s_first,_ForwardIterator2 __s_last,_BinaryPredicate __pred,std::false_type)635 __brick_find_end(_ForwardIterator1 __first, _ForwardIterator1 __last, _ForwardIterator2 __s_first,
636                  _ForwardIterator2 __s_last, _BinaryPredicate __pred, /*__is_vector=*/std::false_type) noexcept
637 {
638     return std::find_end(__first, __last, __s_first, __s_last, __pred);
639 }
640 
641 template <class _RandomAccessIterator1, class _RandomAccessIterator2, class _BinaryPredicate>
642 _RandomAccessIterator1
__brick_find_end(_RandomAccessIterator1 __first,_RandomAccessIterator1 __last,_RandomAccessIterator2 __s_first,_RandomAccessIterator2 __s_last,_BinaryPredicate __pred,std::true_type)643 __brick_find_end(_RandomAccessIterator1 __first, _RandomAccessIterator1 __last, _RandomAccessIterator2 __s_first,
644                  _RandomAccessIterator2 __s_last, _BinaryPredicate __pred, /*__is_vector=*/std::true_type) noexcept
645 {
646     return __find_subrange(__first, __last, __last, __s_first, __s_last, __pred, false, std::true_type());
647 }
648 
649 template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate,
650           class _IsVector>
651 _ForwardIterator1
__pattern_find_end(_ExecutionPolicy &&,_ForwardIterator1 __first,_ForwardIterator1 __last,_ForwardIterator2 __s_first,_ForwardIterator2 __s_last,_BinaryPredicate __pred,_IsVector __is_vector,std::false_type)652 __pattern_find_end(_ExecutionPolicy&&, _ForwardIterator1 __first, _ForwardIterator1 __last, _ForwardIterator2 __s_first,
653                    _ForwardIterator2 __s_last, _BinaryPredicate __pred, _IsVector __is_vector,
654                    /*is_parallel=*/std::false_type) noexcept
655 {
656     return __internal::__brick_find_end(__first, __last, __s_first, __s_last, __pred, __is_vector);
657 }
658 
659 template <class _ExecutionPolicy, class _RandomAccessIterator1, class _RandomAccessIterator2, class _BinaryPredicate,
660           class _IsVector>
661 _RandomAccessIterator1
__pattern_find_end(_ExecutionPolicy && __exec,_RandomAccessIterator1 __first,_RandomAccessIterator1 __last,_RandomAccessIterator2 __s_first,_RandomAccessIterator2 __s_last,_BinaryPredicate __pred,_IsVector __is_vector,std::true_type)662 __pattern_find_end(_ExecutionPolicy&& __exec, _RandomAccessIterator1 __first, _RandomAccessIterator1 __last,
663                    _RandomAccessIterator2 __s_first, _RandomAccessIterator2 __s_last, _BinaryPredicate __pred,
664                    _IsVector __is_vector, /*is_parallel=*/std::true_type) noexcept
665 {
666     if (__last - __first == __s_last - __s_first)
667     {
668         const bool __res = __internal::__pattern_equal(std::forward<_ExecutionPolicy>(__exec), __first, __last,
669                                                        __s_first, __pred, __is_vector, std::true_type());
670         return __res ? __first : __last;
671     }
672     else
673     {
674         return __internal::__except_handler([&]() {
675             return __internal::__parallel_find(
676                 std::forward<_ExecutionPolicy>(__exec), __first, __last,
677                 [__last, __s_first, __s_last, __pred, __is_vector](_RandomAccessIterator1 __i,
678                                                                    _RandomAccessIterator1 __j) {
679                     return __internal::__find_subrange(__i, __j, __last, __s_first, __s_last, __pred, false,
680                                                        __is_vector);
681                 },
682                 std::greater<typename std::iterator_traits<_RandomAccessIterator1>::difference_type>(),
683                 /*is_first=*/false);
684         });
685     }
686 }
687 
688 //------------------------------------------------------------------------
689 // find_first_of
690 //------------------------------------------------------------------------
691 template <class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
692 _ForwardIterator1
__brick_find_first_of(_ForwardIterator1 __first,_ForwardIterator1 __last,_ForwardIterator2 __s_first,_ForwardIterator2 __s_last,_BinaryPredicate __pred,std::false_type)693 __brick_find_first_of(_ForwardIterator1 __first, _ForwardIterator1 __last, _ForwardIterator2 __s_first,
694                       _ForwardIterator2 __s_last, _BinaryPredicate __pred, /*__is_vector=*/std::false_type) noexcept
695 {
696     return std::find_first_of(__first, __last, __s_first, __s_last, __pred);
697 }
698 
699 template <class _RandomAccessIterator1, class _RandomAccessIterator2, class _BinaryPredicate>
700 _RandomAccessIterator1
__brick_find_first_of(_RandomAccessIterator1 __first,_RandomAccessIterator1 __last,_RandomAccessIterator2 __s_first,_RandomAccessIterator2 __s_last,_BinaryPredicate __pred,std::true_type)701 __brick_find_first_of(_RandomAccessIterator1 __first, _RandomAccessIterator1 __last, _RandomAccessIterator2 __s_first,
702                       _RandomAccessIterator2 __s_last, _BinaryPredicate __pred, /*__is_vector=*/std::true_type) noexcept
703 {
704     return __unseq_backend::__simd_find_first_of(__first, __last, __s_first, __s_last, __pred);
705 }
706 
707 template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate,
708           class _IsVector>
709 _ForwardIterator1
__pattern_find_first_of(_ExecutionPolicy &&,_ForwardIterator1 __first,_ForwardIterator1 __last,_ForwardIterator2 __s_first,_ForwardIterator2 __s_last,_BinaryPredicate __pred,_IsVector __is_vector,std::false_type)710 __pattern_find_first_of(_ExecutionPolicy&&, _ForwardIterator1 __first, _ForwardIterator1 __last,
711                         _ForwardIterator2 __s_first, _ForwardIterator2 __s_last, _BinaryPredicate __pred,
712                         _IsVector __is_vector, /*is_parallel=*/std::false_type) noexcept
713 {
714     return __internal::__brick_find_first_of(__first, __last, __s_first, __s_last, __pred, __is_vector);
715 }
716 
717 template <class _ExecutionPolicy, class _RandomAccessIterator1, class _RandomAccessIterator2, class _BinaryPredicate,
718           class _IsVector>
719 _RandomAccessIterator1
__pattern_find_first_of(_ExecutionPolicy && __exec,_RandomAccessIterator1 __first,_RandomAccessIterator1 __last,_RandomAccessIterator2 __s_first,_RandomAccessIterator2 __s_last,_BinaryPredicate __pred,_IsVector __is_vector,std::true_type)720 __pattern_find_first_of(_ExecutionPolicy&& __exec, _RandomAccessIterator1 __first, _RandomAccessIterator1 __last,
721                         _RandomAccessIterator2 __s_first, _RandomAccessIterator2 __s_last, _BinaryPredicate __pred,
722                         _IsVector __is_vector, /*is_parallel=*/std::true_type) noexcept
723 {
724     return __internal::__except_handler([&]() {
725         return __internal::__parallel_find(
726             std::forward<_ExecutionPolicy>(__exec), __first, __last,
727             [__s_first, __s_last, __pred, __is_vector](_RandomAccessIterator1 __i, _RandomAccessIterator1 __j) {
728                 return __internal::__brick_find_first_of(__i, __j, __s_first, __s_last, __pred, __is_vector);
729             },
730             std::less<typename std::iterator_traits<_RandomAccessIterator1>::difference_type>(), /*is_first=*/true);
731     });
732 }
733 
734 //------------------------------------------------------------------------
735 // search
736 //------------------------------------------------------------------------
737 template <class _RandomAccessIterator1, class _RandomAccessIterator2, class _BinaryPredicate>
738 _RandomAccessIterator1
__brick_search(_RandomAccessIterator1 __first,_RandomAccessIterator1 __last,_RandomAccessIterator2 __s_first,_RandomAccessIterator2 __s_last,_BinaryPredicate __pred,std::false_type)739 __brick_search(_RandomAccessIterator1 __first, _RandomAccessIterator1 __last, _RandomAccessIterator2 __s_first,
740                _RandomAccessIterator2 __s_last, _BinaryPredicate __pred, /*vector=*/std::false_type) noexcept
741 {
742     return std::search(__first, __last, __s_first, __s_last, __pred);
743 }
744 
745 template <class _RandomAccessIterator1, class _RandomAccessIterator2, class _BinaryPredicate>
746 _RandomAccessIterator1
__brick_search(_RandomAccessIterator1 __first,_RandomAccessIterator1 __last,_RandomAccessIterator2 __s_first,_RandomAccessIterator2 __s_last,_BinaryPredicate __pred,std::true_type)747 __brick_search(_RandomAccessIterator1 __first, _RandomAccessIterator1 __last, _RandomAccessIterator2 __s_first,
748                _RandomAccessIterator2 __s_last, _BinaryPredicate __pred, /*vector=*/std::true_type) noexcept
749 {
750     return __internal::__find_subrange(__first, __last, __last, __s_first, __s_last, __pred, true, std::true_type());
751 }
752 
753 template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate,
754           class _IsVector>
755 _ForwardIterator1
__pattern_search(_ExecutionPolicy &&,_ForwardIterator1 __first,_ForwardIterator1 __last,_ForwardIterator2 __s_first,_ForwardIterator2 __s_last,_BinaryPredicate __pred,_IsVector __is_vector,std::false_type)756 __pattern_search(_ExecutionPolicy&&, _ForwardIterator1 __first, _ForwardIterator1 __last, _ForwardIterator2 __s_first,
757                  _ForwardIterator2 __s_last, _BinaryPredicate __pred, _IsVector __is_vector,
758                  /*is_parallel=*/std::false_type) noexcept
759 {
760     return __internal::__brick_search(__first, __last, __s_first, __s_last, __pred, __is_vector);
761 }
762 
763 template <class _ExecutionPolicy, class _RandomAccessIterator1, class _RandomAccessIterator2, class _BinaryPredicate,
764           class _IsVector>
765 _RandomAccessIterator1
__pattern_search(_ExecutionPolicy && __exec,_RandomAccessIterator1 __first,_RandomAccessIterator1 __last,_RandomAccessIterator2 __s_first,_RandomAccessIterator2 __s_last,_BinaryPredicate __pred,_IsVector __is_vector,std::true_type)766 __pattern_search(_ExecutionPolicy&& __exec, _RandomAccessIterator1 __first, _RandomAccessIterator1 __last,
767                  _RandomAccessIterator2 __s_first, _RandomAccessIterator2 __s_last, _BinaryPredicate __pred,
768                  _IsVector __is_vector,
769                  /*is_parallel=*/std::true_type) noexcept
770 {
771     if (__last - __first == __s_last - __s_first)
772     {
773         const bool __res = __internal::__pattern_equal(std::forward<_ExecutionPolicy>(__exec), __first, __last,
774                                                        __s_first, __pred, __is_vector, std::true_type());
775         return __res ? __first : __last;
776     }
777     else
778     {
779         return __internal::__except_handler([&]() {
780             return __internal::__parallel_find(
781                 std::forward<_ExecutionPolicy>(__exec), __first, __last,
782                 [__last, __s_first, __s_last, __pred, __is_vector](_RandomAccessIterator1 __i,
783                                                                    _RandomAccessIterator1 __j) {
784                     return __internal::__find_subrange(__i, __j, __last, __s_first, __s_last, __pred, true,
785                                                        __is_vector);
786                 },
787                 std::less<typename std::iterator_traits<_RandomAccessIterator1>::difference_type>(), /*is_first=*/true);
788         });
789     }
790 }
791 
792 //------------------------------------------------------------------------
793 // search_n
794 //------------------------------------------------------------------------
795 template <class _ForwardIterator, class _Size, class _Tp, class _BinaryPredicate>
796 _ForwardIterator
__brick_search_n(_ForwardIterator __first,_ForwardIterator __last,_Size __count,const _Tp & __value,_BinaryPredicate __pred,std::false_type)797 __brick_search_n(_ForwardIterator __first, _ForwardIterator __last, _Size __count, const _Tp& __value,
798                  _BinaryPredicate __pred, /*vector=*/std::false_type) noexcept
799 {
800     return std::search_n(__first, __last, __count, __value, __pred);
801 }
802 
803 template <class _RandomAccessIterator, class _Size, class _Tp, class _BinaryPredicate>
804 _RandomAccessIterator
__brick_search_n(_RandomAccessIterator __first,_RandomAccessIterator __last,_Size __count,const _Tp & __value,_BinaryPredicate __pred,std::true_type)805 __brick_search_n(_RandomAccessIterator __first, _RandomAccessIterator __last, _Size __count, const _Tp& __value,
806                  _BinaryPredicate __pred, /*vector=*/std::true_type) noexcept
807 {
808     return __internal::__find_subrange(__first, __last, __last, __count, __value, __pred, std::true_type());
809 }
810 
811 template <class _ExecutionPolicy, class _ForwardIterator, class _Size, class _Tp, class _BinaryPredicate,
812           class _IsVector>
813 _ForwardIterator
__pattern_search_n(_ExecutionPolicy &&,_ForwardIterator __first,_ForwardIterator __last,_Size __count,const _Tp & __value,_BinaryPredicate __pred,_IsVector __is_vector,std::false_type)814 __pattern_search_n(_ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __last, _Size __count,
815                    const _Tp& __value, _BinaryPredicate __pred, _IsVector __is_vector,
816                    /*is_parallel=*/std::false_type) noexcept
817 {
818     return __internal::__brick_search_n(__first, __last, __count, __value, __pred, __is_vector);
819 }
820 
821 template <class _ExecutionPolicy, class _RandomAccessIterator, class _Size, class _Tp, class _BinaryPredicate,
822           class _IsVector>
823 _RandomAccessIterator
__pattern_search_n(_ExecutionPolicy && __exec,_RandomAccessIterator __first,_RandomAccessIterator __last,_Size __count,const _Tp & __value,_BinaryPredicate __pred,_IsVector __is_vector,std::true_type)824 __pattern_search_n(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __last,
825                    _Size __count, const _Tp& __value, _BinaryPredicate __pred, _IsVector __is_vector,
826                    /*is_parallel=*/std::true_type) noexcept
827 {
828     if (static_cast<_Size>(__last - __first) == __count)
829     {
830         const bool __result = !__internal::__pattern_any_of(
831             std::forward<_ExecutionPolicy>(__exec), __first, __last,
832             [&__value, &__pred](const _Tp& __val) { return !__pred(__val, __value); }, __is_vector,
833             /*is_parallel*/ std::true_type());
834         return __result ? __first : __last;
835     }
836     else
837     {
838         return __internal::__except_handler([&__exec, __first, __last, __count, &__value, __pred, __is_vector]() {
839             return __internal::__parallel_find(
840                 std::forward<_ExecutionPolicy>(__exec), __first, __last,
841                 [__last, __count, &__value, __pred, __is_vector](_RandomAccessIterator __i, _RandomAccessIterator __j) {
842                     return __internal::__find_subrange(__i, __j, __last, __count, __value, __pred, __is_vector);
843                 },
844                 std::less<typename std::iterator_traits<_RandomAccessIterator>::difference_type>(), /*is_first=*/true);
845         });
846     }
847 }
848 
849 //------------------------------------------------------------------------
850 // copy_n
851 //------------------------------------------------------------------------
852 
853 template <class _ForwardIterator, class _Size, class _OutputIterator>
854 _OutputIterator
__brick_copy_n(_ForwardIterator __first,_Size __n,_OutputIterator __result,std::false_type)855 __brick_copy_n(_ForwardIterator __first, _Size __n, _OutputIterator __result, /*vector=*/std::false_type) noexcept
856 {
857     return std::copy_n(__first, __n, __result);
858 }
859 
860 template <class _RandomAccessIterator1, class _Size, class _RandomAccessIterator2>
861 _RandomAccessIterator2
__brick_copy_n(_RandomAccessIterator1 __first,_Size __n,_RandomAccessIterator2 __result,std::true_type)862 __brick_copy_n(_RandomAccessIterator1 __first, _Size __n, _RandomAccessIterator2 __result,
863                /*vector=*/std::true_type) noexcept
864 {
865     return __unseq_backend::__simd_assign(
866         __first, __n, __result,
867         [](_RandomAccessIterator1 __first, _RandomAccessIterator2 __result) { *__result = *__first; });
868 }
869 
870 //------------------------------------------------------------------------
871 // copy
872 //------------------------------------------------------------------------
873 template <class _ForwardIterator, class _OutputIterator>
874 _OutputIterator
__brick_copy(_ForwardIterator __first,_ForwardIterator __last,_OutputIterator __result,std::false_type)875 __brick_copy(_ForwardIterator __first, _ForwardIterator __last, _OutputIterator __result,
876              /*vector=*/std::false_type) noexcept
877 {
878     return std::copy(__first, __last, __result);
879 }
880 
881 template <class _RandomAccessIterator1, class _RandomAccessIterator2>
882 _RandomAccessIterator2
__brick_copy(_RandomAccessIterator1 __first,_RandomAccessIterator1 __last,_RandomAccessIterator2 __result,std::true_type)883 __brick_copy(_RandomAccessIterator1 __first, _RandomAccessIterator1 __last, _RandomAccessIterator2 __result,
884              /*vector=*/std::true_type) noexcept
885 {
886     return __unseq_backend::__simd_assign(
887         __first, __last - __first, __result,
888         [](_RandomAccessIterator1 __first, _RandomAccessIterator2 __result) { *__result = *__first; });
889 }
890 
891 //------------------------------------------------------------------------
892 // move
893 //------------------------------------------------------------------------
894 template <class _ForwardIterator, class _OutputIterator>
895 _OutputIterator
__brick_move(_ForwardIterator __first,_ForwardIterator __last,_OutputIterator __result,std::false_type)896 __brick_move(_ForwardIterator __first, _ForwardIterator __last, _OutputIterator __result,
897              /*vector=*/std::false_type) noexcept
898 {
899     return std::move(__first, __last, __result);
900 }
901 
902 template <class _RandomAccessIterator1, class _RandomAccessIterator2>
903 _RandomAccessIterator2
__brick_move(_RandomAccessIterator1 __first,_RandomAccessIterator1 __last,_RandomAccessIterator2 __result,std::true_type)904 __brick_move(_RandomAccessIterator1 __first, _RandomAccessIterator1 __last, _RandomAccessIterator2 __result,
905              /*vector=*/std::true_type) noexcept
906 {
907     return __unseq_backend::__simd_assign(
908         __first, __last - __first, __result,
909         [](_RandomAccessIterator1 __first, _RandomAccessIterator2 __result) { *__result = std::move(*__first); });
910 }
911 
912 struct __brick_move_destroy
913 {
914     template <typename _RandomAccessIterator1, typename _RandomAccessIterator2>
915     _RandomAccessIterator2
operator__brick_move_destroy916     operator()(_RandomAccessIterator1 __first, _RandomAccessIterator1 __last, _RandomAccessIterator2 __result,
917                /*vec*/ std::true_type) const
918     {
919         using _IteratorValueType = typename std::iterator_traits<_RandomAccessIterator1>::value_type;
920 
921         return __unseq_backend::__simd_assign(__first, __last - __first, __result,
922                                               [](_RandomAccessIterator1 __first, _RandomAccessIterator2 __result) {
923                                                   *__result = std::move(*__first);
924                                                   (*__first).~_IteratorValueType();
925                                               });
926     }
927 
928     template <typename _RandomAccessIterator1, typename _RandomAccessIterator2>
929     _RandomAccessIterator2
operator__brick_move_destroy930     operator()(_RandomAccessIterator1 __first, _RandomAccessIterator1 __last, _RandomAccessIterator2 __result,
931                /*vec*/ std::false_type) const
932     {
933         using _IteratorValueType = typename std::iterator_traits<_RandomAccessIterator1>::value_type;
934 
935         for (; __first != __last; ++__first, ++__result)
936         {
937             *__result = std::move(*__first);
938             (*__first).~_IteratorValueType();
939         }
940         return __result;
941     }
942 };
943 
944 //------------------------------------------------------------------------
945 // swap_ranges
946 //------------------------------------------------------------------------
947 template <class _ForwardIterator, class _OutputIterator>
948 _OutputIterator
__brick_swap_ranges(_ForwardIterator __first,_ForwardIterator __last,_OutputIterator __result,std::false_type)949 __brick_swap_ranges(_ForwardIterator __first, _ForwardIterator __last, _OutputIterator __result,
950                     /*vector=*/std::false_type) noexcept
951 {
952     return std::swap_ranges(__first, __last, __result);
953 }
954 
955 template <class _RandomAccessIterator1, class _RandomAccessIterator2>
956 _RandomAccessIterator2
__brick_swap_ranges(_RandomAccessIterator1 __first,_RandomAccessIterator1 __last,_RandomAccessIterator2 __result,std::true_type)957 __brick_swap_ranges(_RandomAccessIterator1 __first, _RandomAccessIterator1 __last, _RandomAccessIterator2 __result,
958                     /*vector=*/std::true_type) noexcept
959 {
960     using std::iter_swap;
961     return __unseq_backend::__simd_assign(__first, __last - __first, __result,
962                                           iter_swap<_RandomAccessIterator1, _RandomAccessIterator2>);
963 }
964 
965 //------------------------------------------------------------------------
966 // copy_if
967 //------------------------------------------------------------------------
968 template <class _ForwardIterator, class _OutputIterator, class _UnaryPredicate>
969 _OutputIterator
__brick_copy_if(_ForwardIterator __first,_ForwardIterator __last,_OutputIterator __result,_UnaryPredicate __pred,std::false_type)970 __brick_copy_if(_ForwardIterator __first, _ForwardIterator __last, _OutputIterator __result, _UnaryPredicate __pred,
971                 /*vector=*/std::false_type) noexcept
972 {
973     return std::copy_if(__first, __last, __result, __pred);
974 }
975 
976 template <class _RandomAccessIterator1, class _RandomAccessIterator2, class _UnaryPredicate>
977 _RandomAccessIterator2
__brick_copy_if(_RandomAccessIterator1 __first,_RandomAccessIterator1 __last,_RandomAccessIterator2 __result,_UnaryPredicate __pred,std::true_type)978 __brick_copy_if(_RandomAccessIterator1 __first, _RandomAccessIterator1 __last, _RandomAccessIterator2 __result,
979                 _UnaryPredicate __pred,
980                 /*vector=*/std::true_type) noexcept
981 {
982 #if defined(_PSTL_MONOTONIC_PRESENT)
983     return __unseq_backend::__simd_copy_if(__first, __last - __first, __result, __pred);
984 #else
985     return std::copy_if(__first, __last, __result, __pred);
986 #endif
987 }
988 
989 // TODO: Try to use transform_reduce for combining __brick_copy_if_phase1 on IsVector.
990 template <class _DifferenceType, class _ForwardIterator, class _UnaryPredicate>
991 std::pair<_DifferenceType, _DifferenceType>
__brick_calc_mask_1(_ForwardIterator __first,_ForwardIterator __last,bool * __restrict __mask,_UnaryPredicate __pred,std::false_type)992 __brick_calc_mask_1(_ForwardIterator __first, _ForwardIterator __last, bool* __restrict __mask, _UnaryPredicate __pred,
993                     /*vector=*/std::false_type) noexcept
994 {
995     auto __count_true = _DifferenceType(0);
996     auto __size = __last - __first;
997 
998     static_assert(__is_random_access_iterator<_ForwardIterator>::value,
999                   "Pattern-brick error. Should be a random access iterator.");
1000 
1001     for (; __first != __last; ++__first, ++__mask)
1002     {
1003         *__mask = __pred(*__first);
1004         if (*__mask)
1005         {
1006             ++__count_true;
1007         }
1008     }
1009     return std::make_pair(__count_true, __size - __count_true);
1010 }
1011 
1012 template <class _DifferenceType, class _RandomAccessIterator, class _UnaryPredicate>
1013 std::pair<_DifferenceType, _DifferenceType>
__brick_calc_mask_1(_RandomAccessIterator __first,_RandomAccessIterator __last,bool * __mask,_UnaryPredicate __pred,std::true_type)1014 __brick_calc_mask_1(_RandomAccessIterator __first, _RandomAccessIterator __last, bool* __mask, _UnaryPredicate __pred,
1015                     /*vector=*/std::true_type) noexcept
1016 {
1017     auto __result = __unseq_backend::__simd_calc_mask_1(__first, __last - __first, __mask, __pred);
1018     return std::make_pair(__result, (__last - __first) - __result);
1019 }
1020 
1021 template <class _ForwardIterator, class _OutputIterator, class _Assigner>
1022 void
__brick_copy_by_mask(_ForwardIterator __first,_ForwardIterator __last,_OutputIterator __result,bool * __mask,_Assigner __assigner,std::false_type)1023 __brick_copy_by_mask(_ForwardIterator __first, _ForwardIterator __last, _OutputIterator __result, bool* __mask,
1024                      _Assigner __assigner, /*vector=*/std::false_type) noexcept
1025 {
1026     for (; __first != __last; ++__first, ++__mask)
1027     {
1028         if (*__mask)
1029         {
1030             __assigner(__first, __result);
1031             ++__result;
1032         }
1033     }
1034 }
1035 
1036 template <class _RandomAccessIterator1, class _RandomAccessIterator2, class _Assigner>
1037 void
__brick_copy_by_mask(_RandomAccessIterator1 __first,_RandomAccessIterator1 __last,_RandomAccessIterator2 __result,bool * __restrict __mask,_Assigner __assigner,std::true_type)1038 __brick_copy_by_mask(_RandomAccessIterator1 __first, _RandomAccessIterator1 __last, _RandomAccessIterator2 __result,
1039                      bool* __restrict __mask, _Assigner __assigner, /*vector=*/std::true_type) noexcept
1040 {
1041 #if defined(_PSTL_MONOTONIC_PRESENT)
1042     __unseq_backend::__simd_copy_by_mask(__first, __last - __first, __result, __mask, __assigner);
1043 #else
1044     __internal::__brick_copy_by_mask(__first, __last, __result, __mask, __assigner, std::false_type());
1045 #endif
1046 }
1047 
1048 template <class _ForwardIterator, class _OutputIterator1, class _OutputIterator2>
1049 void
__brick_partition_by_mask(_ForwardIterator __first,_ForwardIterator __last,_OutputIterator1 __out_true,_OutputIterator2 __out_false,bool * __mask,std::false_type)1050 __brick_partition_by_mask(_ForwardIterator __first, _ForwardIterator __last, _OutputIterator1 __out_true,
1051                           _OutputIterator2 __out_false, bool* __mask, /*vector=*/std::false_type) noexcept
1052 {
1053     for (; __first != __last; ++__first, ++__mask)
1054     {
1055         if (*__mask)
1056         {
1057             *__out_true = *__first;
1058             ++__out_true;
1059         }
1060         else
1061         {
1062             *__out_false = *__first;
1063             ++__out_false;
1064         }
1065     }
1066 }
1067 
1068 template <class _RandomAccessIterator1, class _RandomAccessIterator2, class _RandomAccessIterator3>
1069 void
__brick_partition_by_mask(_RandomAccessIterator1 __first,_RandomAccessIterator1 __last,_RandomAccessIterator2 __out_true,_RandomAccessIterator3 __out_false,bool * __mask,std::true_type)1070 __brick_partition_by_mask(_RandomAccessIterator1 __first, _RandomAccessIterator1 __last,
1071                           _RandomAccessIterator2 __out_true, _RandomAccessIterator3 __out_false, bool* __mask,
1072                           /*vector=*/std::true_type) noexcept
1073 {
1074 #if defined(_PSTL_MONOTONIC_PRESENT)
1075     __unseq_backend::__simd_partition_by_mask(__first, __last - __first, __out_true, __out_false, __mask);
1076 #else
1077     __internal::__brick_partition_by_mask(__first, __last, __out_true, __out_false, __mask, std::false_type());
1078 #endif
1079 }
1080 
1081 template <class _ExecutionPolicy, class _ForwardIterator, class _OutputIterator, class _UnaryPredicate, class _IsVector>
1082 _OutputIterator
__pattern_copy_if(_ExecutionPolicy &&,_ForwardIterator __first,_ForwardIterator __last,_OutputIterator __result,_UnaryPredicate __pred,_IsVector __is_vector,std::false_type)1083 __pattern_copy_if(_ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __last, _OutputIterator __result,
1084                   _UnaryPredicate __pred, _IsVector __is_vector, /*parallel=*/std::false_type) noexcept
1085 {
1086     return __internal::__brick_copy_if(__first, __last, __result, __pred, __is_vector);
1087 }
1088 
1089 template <class _ExecutionPolicy, class _RandomAccessIterator1, class _RandomAccessIterator2, class _UnaryPredicate,
1090           class _IsVector>
1091 _RandomAccessIterator2
__pattern_copy_if(_ExecutionPolicy && __exec,_RandomAccessIterator1 __first,_RandomAccessIterator1 __last,_RandomAccessIterator2 __result,_UnaryPredicate __pred,_IsVector __is_vector,std::true_type)1092 __pattern_copy_if(_ExecutionPolicy&& __exec, _RandomAccessIterator1 __first, _RandomAccessIterator1 __last,
1093                   _RandomAccessIterator2 __result, _UnaryPredicate __pred, _IsVector __is_vector,
1094                   /*parallel=*/std::true_type)
1095 {
1096     typedef typename std::iterator_traits<_RandomAccessIterator1>::difference_type _DifferenceType;
1097     const _DifferenceType __n = __last - __first;
1098     if (_DifferenceType(1) < __n)
1099     {
1100         __par_backend::__buffer<bool> __mask_buf(__n);
1101         return __internal::__except_handler([&__exec, __n, __first, __result, __is_vector, __pred, &__mask_buf]() {
1102             bool* __mask = __mask_buf.get();
1103             _DifferenceType __m{};
1104             __par_backend::__parallel_strict_scan(
1105                 std::forward<_ExecutionPolicy>(__exec), __n, _DifferenceType(0),
1106                 [=](_DifferenceType __i, _DifferenceType __len) { // Reduce
1107                     return __internal::__brick_calc_mask_1<_DifferenceType>(__first + __i, __first + (__i + __len),
1108                                                                             __mask + __i, __pred, __is_vector)
1109                         .first;
1110                 },
1111                 std::plus<_DifferenceType>(),                                                // Combine
1112                 [=](_DifferenceType __i, _DifferenceType __len, _DifferenceType __initial) { // Scan
1113                     __internal::__brick_copy_by_mask(
1114                         __first + __i, __first + (__i + __len), __result + __initial, __mask + __i,
1115                         [](_RandomAccessIterator1 __x, _RandomAccessIterator2 __z) { *__z = *__x; }, __is_vector);
1116                 },
1117                 [&__m](_DifferenceType __total) { __m = __total; });
1118             return __result + __m;
1119         });
1120     }
1121     // trivial sequence - use serial algorithm
1122     return __internal::__brick_copy_if(__first, __last, __result, __pred, __is_vector);
1123 }
1124 
1125 //------------------------------------------------------------------------
1126 // count
1127 //------------------------------------------------------------------------
1128 template <class _RandomAccessIterator, class _Predicate>
1129 typename std::iterator_traits<_RandomAccessIterator>::difference_type
__brick_count(_RandomAccessIterator __first,_RandomAccessIterator __last,_Predicate __pred,std::true_type)1130 __brick_count(_RandomAccessIterator __first, _RandomAccessIterator __last, _Predicate __pred,
1131               /* is_vector = */ std::true_type) noexcept
1132 {
1133     return __unseq_backend::__simd_count(__first, __last - __first, __pred);
1134 }
1135 
1136 template <class _ForwardIterator, class _Predicate>
1137 typename std::iterator_traits<_ForwardIterator>::difference_type
__brick_count(_ForwardIterator __first,_ForwardIterator __last,_Predicate __pred,std::false_type)1138 __brick_count(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred,
1139               /* is_vector = */ std::false_type) noexcept
1140 {
1141     return std::count_if(__first, __last, __pred);
1142 }
1143 
1144 template <class _ExecutionPolicy, class _ForwardIterator, class _Predicate, class _IsVector>
1145 typename std::iterator_traits<_ForwardIterator>::difference_type
__pattern_count(_ExecutionPolicy &&,_ForwardIterator __first,_ForwardIterator __last,_Predicate __pred,std::false_type,_IsVector __is_vector)1146 __pattern_count(_ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred,
1147                 /* is_parallel */ std::false_type, _IsVector __is_vector) noexcept
1148 {
1149     return __internal::__brick_count(__first, __last, __pred, __is_vector);
1150 }
1151 
1152 template <class _ExecutionPolicy, class _RandomAccessIterator, class _Predicate, class _IsVector>
1153 typename std::iterator_traits<_RandomAccessIterator>::difference_type
__pattern_count(_ExecutionPolicy && __exec,_RandomAccessIterator __first,_RandomAccessIterator __last,_Predicate __pred,std::true_type,_IsVector __is_vector)1154 __pattern_count(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __last,
1155                 _Predicate __pred,
1156                 /* is_parallel */ std::true_type, _IsVector __is_vector)
1157 {
1158     typedef typename std::iterator_traits<_RandomAccessIterator>::difference_type _SizeType;
1159     return __internal::__except_handler([&]() {
1160         return __par_backend::__parallel_reduce(
1161             std::forward<_ExecutionPolicy>(__exec), __first, __last, _SizeType(0),
1162             [__pred, __is_vector](_RandomAccessIterator __begin, _RandomAccessIterator __end, _SizeType __value)
1163                 -> _SizeType { return __value + __internal::__brick_count(__begin, __end, __pred, __is_vector); },
1164             std::plus<_SizeType>());
1165     });
1166 }
1167 
1168 //------------------------------------------------------------------------
1169 // unique
1170 //------------------------------------------------------------------------
1171 
1172 template <class _RandomAccessIterator, class _BinaryPredicate>
1173 _RandomAccessIterator
__brick_unique(_RandomAccessIterator __first,_RandomAccessIterator __last,_BinaryPredicate __pred,std::false_type)1174 __brick_unique(_RandomAccessIterator __first, _RandomAccessIterator __last, _BinaryPredicate __pred,
1175                /*is_vector=*/std::false_type) noexcept
1176 {
1177     return std::unique(__first, __last, __pred);
1178 }
1179 
1180 template <class _RandomAccessIterator, class _BinaryPredicate>
1181 _RandomAccessIterator
__brick_unique(_RandomAccessIterator __first,_RandomAccessIterator __last,_BinaryPredicate __pred,std::true_type)1182 __brick_unique(_RandomAccessIterator __first, _RandomAccessIterator __last, _BinaryPredicate __pred,
1183                /*is_vector=*/std::true_type) noexcept
1184 {
1185     _PSTL_PRAGMA_MESSAGE("Vectorized algorithm unimplemented, redirected to serial");
1186     return std::unique(__first, __last, __pred);
1187 }
1188 
1189 template <class _ExecutionPolicy, class _ForwardIterator, class _BinaryPredicate, class _IsVector>
1190 _ForwardIterator
__pattern_unique(_ExecutionPolicy &&,_ForwardIterator __first,_ForwardIterator __last,_BinaryPredicate __pred,_IsVector __is_vector,std::false_type)1191 __pattern_unique(_ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __last, _BinaryPredicate __pred,
1192                  _IsVector __is_vector, /*is_parallel=*/std::false_type) noexcept
1193 {
1194     return __internal::__brick_unique(__first, __last, __pred, __is_vector);
1195 }
1196 
1197 // That function is shared between two algorithms - remove_if (__pattern_remove_if) and unique (pattern unique). But a mask calculation is different.
1198 // So, a caller passes _CalcMask brick into remove_elements.
1199 template <class _ExecutionPolicy, class _ForwardIterator, class _CalcMask, class _IsVector>
1200 _ForwardIterator
__remove_elements(_ExecutionPolicy && __exec,_ForwardIterator __first,_ForwardIterator __last,_CalcMask __calc_mask,_IsVector __is_vector)1201 __remove_elements(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _CalcMask __calc_mask,
1202                   _IsVector __is_vector)
1203 {
1204     typedef typename std::iterator_traits<_ForwardIterator>::difference_type _DifferenceType;
1205     typedef typename std::iterator_traits<_ForwardIterator>::value_type _Tp;
1206     _DifferenceType __n = __last - __first;
1207     __par_backend::__buffer<bool> __mask_buf(__n);
1208     // 1. find a first iterator that should be removed
1209     return __internal::__except_handler([&]() {
1210         bool* __mask = __mask_buf.get();
1211         _DifferenceType __min = __par_backend::__parallel_reduce(
1212             std::forward<_ExecutionPolicy>(__exec), _DifferenceType(0), __n, __n,
1213             [__first, __mask, &__calc_mask, __is_vector](_DifferenceType __i, _DifferenceType __j,
1214                                                          _DifferenceType __local_min) -> _DifferenceType {
1215                 // Create mask
1216                 __calc_mask(__mask + __i, __mask + __j, __first + __i);
1217 
1218                 // if minimum was found in a previous range we shouldn't do anymore
1219                 if (__local_min < __i)
1220                 {
1221                     return __local_min;
1222                 }
1223                 // find first iterator that should be removed
1224                 bool* __result = __internal::__brick_find_if(__mask + __i, __mask + __j,
1225                                                              [](bool __val) { return !__val; }, __is_vector);
1226                 if (__result - __mask == __j)
1227                 {
1228                     return __local_min;
1229                 }
1230                 return std::min(__local_min, _DifferenceType(__result - __mask));
1231             },
1232             [](_DifferenceType __local_min1, _DifferenceType __local_min2) -> _DifferenceType {
1233                 return std::min(__local_min1, __local_min2);
1234             });
1235 
1236         // No elements to remove - exit
1237         if (__min == __n)
1238         {
1239             return __last;
1240         }
1241         __n -= __min;
1242         __first += __min;
1243 
1244         __par_backend::__buffer<_Tp> __buf(__n);
1245         _Tp* __result = __buf.get();
1246         __mask += __min;
1247         _DifferenceType __m{};
1248         // 2. Elements that doesn't satisfy pred are moved to result
1249         __par_backend::__parallel_strict_scan(
1250             std::forward<_ExecutionPolicy>(__exec), __n, _DifferenceType(0),
1251             [__mask, __is_vector](_DifferenceType __i, _DifferenceType __len) {
1252                 return __internal::__brick_count(__mask + __i, __mask + __i + __len, [](bool __val) { return __val; },
1253                                                  __is_vector);
1254             },
1255             std::plus<_DifferenceType>(),
1256             [=](_DifferenceType __i, _DifferenceType __len, _DifferenceType __initial) {
1257                 __internal::__brick_copy_by_mask(
1258                     __first + __i, __first + __i + __len, __result + __initial, __mask + __i,
1259                     [](_ForwardIterator __x, _Tp* __z) {
1260                         __internal::__invoke_if_else(std::is_trivial<_Tp>(), [&]() { *__z = std::move(*__x); },
1261                                                      [&]() { ::new (std::addressof(*__z)) _Tp(std::move(*__x)); });
1262                     },
1263                     __is_vector);
1264             },
1265             [&__m](_DifferenceType __total) { __m = __total; });
1266 
1267         // 3. Elements from result are moved to [first, last)
1268         __par_backend::__parallel_for(
1269             std::forward<_ExecutionPolicy>(__exec), __result, __result + __m,
1270             [__result, __first, __is_vector](_Tp* __i, _Tp* __j) {
1271                 __invoke_if_else(std::is_trivial<_Tp>(),
1272                                  [&]() { __brick_move(__i, __j, __first + (__i - __result), __is_vector); },
1273                                  [&]() { __brick_move_destroy()(__i, __j, __first + (__i - __result), __is_vector); });
1274             });
1275         return __first + __m;
1276     });
1277 }
1278 
1279 template <class _ExecutionPolicy, class _RandomAccessIterator, class _BinaryPredicate, class _IsVector>
1280 _RandomAccessIterator
__pattern_unique(_ExecutionPolicy && __exec,_RandomAccessIterator __first,_RandomAccessIterator __last,_BinaryPredicate __pred,_IsVector __is_vector,std::true_type)1281 __pattern_unique(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __last,
1282                  _BinaryPredicate __pred, _IsVector __is_vector, /*is_parallel=*/std::true_type) noexcept
1283 {
1284     typedef typename std::iterator_traits<_RandomAccessIterator>::reference _ReferenceType;
1285 
1286     if (__first == __last)
1287     {
1288         return __last;
1289     }
1290     if (__first + 1 == __last || __first + 2 == __last)
1291     {
1292         // Trivial sequence - use serial algorithm
1293         return __internal::__brick_unique(__first, __last, __pred, __is_vector);
1294     }
1295     return __internal::__remove_elements(
1296         std::forward<_ExecutionPolicy>(__exec), ++__first, __last,
1297         [&__pred, __is_vector](bool* __b, bool* __e, _RandomAccessIterator __it) {
1298             __internal::__brick_walk3(
1299                 __b, __e, __it - 1, __it,
1300                 [&__pred](bool& __x, _ReferenceType __y, _ReferenceType __z) { __x = !__pred(__y, __z); }, __is_vector);
1301         },
1302         __is_vector);
1303 }
1304 
1305 //------------------------------------------------------------------------
1306 // unique_copy
1307 //------------------------------------------------------------------------
1308 
1309 template <class _ForwardIterator, class OutputIterator, class _BinaryPredicate>
1310 OutputIterator
__brick_unique_copy(_ForwardIterator __first,_ForwardIterator __last,OutputIterator __result,_BinaryPredicate __pred,std::false_type)1311 __brick_unique_copy(_ForwardIterator __first, _ForwardIterator __last, OutputIterator __result, _BinaryPredicate __pred,
1312                     /*vector=*/std::false_type) noexcept
1313 {
1314     return std::unique_copy(__first, __last, __result, __pred);
1315 }
1316 
1317 template <class _RandomAccessIterator1, class _RandomAccessIterator2, class _BinaryPredicate>
1318 _RandomAccessIterator2
__brick_unique_copy(_RandomAccessIterator1 __first,_RandomAccessIterator1 __last,_RandomAccessIterator2 __result,_BinaryPredicate __pred,std::true_type)1319 __brick_unique_copy(_RandomAccessIterator1 __first, _RandomAccessIterator1 __last, _RandomAccessIterator2 __result,
1320                     _BinaryPredicate __pred, /*vector=*/std::true_type) noexcept
1321 {
1322 #if defined(_PSTL_MONOTONIC_PRESENT)
1323     return __unseq_backend::__simd_unique_copy(__first, __last - __first, __result, __pred);
1324 #else
1325     return std::unique_copy(__first, __last, __result, __pred);
1326 #endif
1327 }
1328 
1329 template <class _ExecutionPolicy, class _ForwardIterator, class _OutputIterator, class _BinaryPredicate,
1330           class _IsVector>
1331 _OutputIterator
__pattern_unique_copy(_ExecutionPolicy &&,_ForwardIterator __first,_ForwardIterator __last,_OutputIterator __result,_BinaryPredicate __pred,_IsVector __is_vector,std::false_type)1332 __pattern_unique_copy(_ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __last, _OutputIterator __result,
1333                       _BinaryPredicate __pred, _IsVector __is_vector, /*parallel=*/std::false_type) noexcept
1334 {
1335     return __internal::__brick_unique_copy(__first, __last, __result, __pred, __is_vector);
1336 }
1337 
1338 template <class _DifferenceType, class _RandomAccessIterator, class _BinaryPredicate>
1339 _DifferenceType
__brick_calc_mask_2(_RandomAccessIterator __first,_RandomAccessIterator __last,bool * __restrict __mask,_BinaryPredicate __pred,std::false_type)1340 __brick_calc_mask_2(_RandomAccessIterator __first, _RandomAccessIterator __last, bool* __restrict __mask,
1341                     _BinaryPredicate __pred, /*vector=*/std::false_type) noexcept
1342 {
1343     _DifferenceType __count = 0;
1344     for (; __first != __last; ++__first, ++__mask)
1345     {
1346         *__mask = !__pred(*__first, *(__first - 1));
1347         __count += *__mask;
1348     }
1349     return __count;
1350 }
1351 
1352 template <class _DifferenceType, class _RandomAccessIterator, class _BinaryPredicate>
1353 _DifferenceType
__brick_calc_mask_2(_RandomAccessIterator __first,_RandomAccessIterator __last,bool * __restrict __mask,_BinaryPredicate __pred,std::true_type)1354 __brick_calc_mask_2(_RandomAccessIterator __first, _RandomAccessIterator __last, bool* __restrict __mask,
1355                     _BinaryPredicate __pred, /*vector=*/std::true_type) noexcept
1356 {
1357     return __unseq_backend::__simd_calc_mask_2(__first, __last - __first, __mask, __pred);
1358 }
1359 
1360 template <class _ExecutionPolicy, class _RandomAccessIterator1, class _RandomAccessIterator2, class _BinaryPredicate,
1361           class _IsVector>
1362 _RandomAccessIterator2
__pattern_unique_copy(_ExecutionPolicy && __exec,_RandomAccessIterator1 __first,_RandomAccessIterator1 __last,_RandomAccessIterator2 __result,_BinaryPredicate __pred,_IsVector __is_vector,std::true_type)1363 __pattern_unique_copy(_ExecutionPolicy&& __exec, _RandomAccessIterator1 __first, _RandomAccessIterator1 __last,
1364                       _RandomAccessIterator2 __result, _BinaryPredicate __pred, _IsVector __is_vector,
1365                       /*parallel=*/std::true_type)
1366 {
1367     typedef typename std::iterator_traits<_RandomAccessIterator1>::difference_type _DifferenceType;
1368     const _DifferenceType __n = __last - __first;
1369     if (_DifferenceType(2) < __n)
1370     {
1371         __par_backend::__buffer<bool> __mask_buf(__n);
1372         if (_DifferenceType(2) < __n)
1373         {
1374             return __internal::__except_handler([&__exec, __n, __first, __result, __pred, __is_vector, &__mask_buf]() {
1375                 bool* __mask = __mask_buf.get();
1376                 _DifferenceType __m{};
1377                 __par_backend::__parallel_strict_scan(
1378                     std::forward<_ExecutionPolicy>(__exec), __n, _DifferenceType(0),
1379                     [=](_DifferenceType __i, _DifferenceType __len) -> _DifferenceType { // Reduce
1380                         _DifferenceType __extra = 0;
1381                         if (__i == 0)
1382                         {
1383                             // Special boundary case
1384                             __mask[__i] = true;
1385                             if (--__len == 0)
1386                                 return 1;
1387                             ++__i;
1388                             ++__extra;
1389                         }
1390                         return __internal::__brick_calc_mask_2<_DifferenceType>(__first + __i, __first + (__i + __len),
1391                                                                                 __mask + __i, __pred, __is_vector) +
1392                                __extra;
1393                     },
1394                     std::plus<_DifferenceType>(),                                                // Combine
1395                     [=](_DifferenceType __i, _DifferenceType __len, _DifferenceType __initial) { // Scan
1396                         // Phase 2 is same as for __pattern_copy_if
1397                         __internal::__brick_copy_by_mask(
1398                             __first + __i, __first + (__i + __len), __result + __initial, __mask + __i,
1399                             [](_RandomAccessIterator1 __x, _RandomAccessIterator2 __z) { *__z = *__x; }, __is_vector);
1400                     },
1401                     [&__m](_DifferenceType __total) { __m = __total; });
1402                 return __result + __m;
1403             });
1404         }
1405     }
1406     // trivial sequence - use serial algorithm
1407     return __internal::__brick_unique_copy(__first, __last, __result, __pred, __is_vector);
1408 }
1409 
1410 //------------------------------------------------------------------------
1411 // reverse
1412 //------------------------------------------------------------------------
1413 template <class _BidirectionalIterator>
1414 void
__brick_reverse(_BidirectionalIterator __first,_BidirectionalIterator __last,std::false_type)1415 __brick_reverse(_BidirectionalIterator __first, _BidirectionalIterator __last, /*__is_vector=*/std::false_type) noexcept
1416 {
1417     std::reverse(__first, __last);
1418 }
1419 
1420 template <class _RandomAccessIterator>
1421 void
__brick_reverse(_RandomAccessIterator __first,_RandomAccessIterator __last,std::true_type)1422 __brick_reverse(_RandomAccessIterator __first, _RandomAccessIterator __last, /*__is_vector=*/std::true_type) noexcept
1423 {
1424     typedef typename std::iterator_traits<_RandomAccessIterator>::reference _ReferenceType;
1425 
1426     const auto __n = (__last - __first) / 2;
1427     __unseq_backend::__simd_walk_2(__first, __n, std::reverse_iterator<_RandomAccessIterator>(__last),
1428                                    [](_ReferenceType __x, _ReferenceType __y) {
1429                                        using std::swap;
1430                                        swap(__x, __y);
1431                                    });
1432 }
1433 
1434 // this brick is called in parallel version, so we can use iterator arithmetic
1435 template <class _BidirectionalIterator>
1436 void
__brick_reverse(_BidirectionalIterator __first,_BidirectionalIterator __last,_BidirectionalIterator __d_last,std::false_type)1437 __brick_reverse(_BidirectionalIterator __first, _BidirectionalIterator __last, _BidirectionalIterator __d_last,
1438                 /*is_vector=*/std::false_type) noexcept
1439 {
1440     for (--__d_last; __first != __last; ++__first, --__d_last)
1441     {
1442         using std::iter_swap;
1443         iter_swap(__first, __d_last);
1444     }
1445 }
1446 
1447 // this brick is called in parallel version, so we can use iterator arithmetic
1448 template <class _RandomAccessIterator>
1449 void
__brick_reverse(_RandomAccessIterator __first,_RandomAccessIterator __last,_RandomAccessIterator __d_last,std::true_type)1450 __brick_reverse(_RandomAccessIterator __first, _RandomAccessIterator __last, _RandomAccessIterator __d_last,
1451                 /*is_vector=*/std::true_type) noexcept
1452 {
1453     typedef typename std::iterator_traits<_RandomAccessIterator>::reference _ReferenceType;
1454 
1455     __unseq_backend::__simd_walk_2(__first, __last - __first, std::reverse_iterator<_RandomAccessIterator>(__d_last),
1456                                    [](_ReferenceType __x, _ReferenceType __y) {
1457                                        using std::swap;
1458                                        swap(__x, __y);
1459                                    });
1460 }
1461 
1462 template <class _ExecutionPolicy, class _BidirectionalIterator, class _IsVector>
1463 void
__pattern_reverse(_ExecutionPolicy &&,_BidirectionalIterator __first,_BidirectionalIterator __last,_IsVector _is_vector,std::false_type)1464 __pattern_reverse(_ExecutionPolicy&&, _BidirectionalIterator __first, _BidirectionalIterator __last,
1465                   _IsVector _is_vector,
1466                   /*is_parallel=*/std::false_type) noexcept
1467 {
1468     __internal::__brick_reverse(__first, __last, _is_vector);
1469 }
1470 
1471 template <class _ExecutionPolicy, class _RandomAccessIterator, class _IsVector>
1472 void
__pattern_reverse(_ExecutionPolicy && __exec,_RandomAccessIterator __first,_RandomAccessIterator __last,_IsVector __is_vector,std::true_type)1473 __pattern_reverse(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __last,
1474                   _IsVector __is_vector, /*is_parallel=*/std::true_type)
1475 {
1476     __par_backend::__parallel_for(
1477         std::forward<_ExecutionPolicy>(__exec), __first, __first + (__last - __first) / 2,
1478         [__is_vector, __first, __last](_RandomAccessIterator __inner_first, _RandomAccessIterator __inner_last) {
1479             __internal::__brick_reverse(__inner_first, __inner_last, __last - (__inner_first - __first), __is_vector);
1480         });
1481 }
1482 
1483 //------------------------------------------------------------------------
1484 // reverse_copy
1485 //------------------------------------------------------------------------
1486 
1487 template <class _BidirectionalIterator, class _OutputIterator>
1488 _OutputIterator
__brick_reverse_copy(_BidirectionalIterator __first,_BidirectionalIterator __last,_OutputIterator __d_first,std::false_type)1489 __brick_reverse_copy(_BidirectionalIterator __first, _BidirectionalIterator __last, _OutputIterator __d_first,
1490                      /*is_vector=*/std::false_type) noexcept
1491 {
1492     return std::reverse_copy(__first, __last, __d_first);
1493 }
1494 
1495 template <class _RandomAccessIterator1, class _RandomAccessIterator2>
1496 _RandomAccessIterator2
__brick_reverse_copy(_RandomAccessIterator1 __first,_RandomAccessIterator1 __last,_RandomAccessIterator2 __d_first,std::true_type)1497 __brick_reverse_copy(_RandomAccessIterator1 __first, _RandomAccessIterator1 __last, _RandomAccessIterator2 __d_first,
1498                      /*is_vector=*/std::true_type) noexcept
1499 {
1500     typedef typename std::iterator_traits<_RandomAccessIterator1>::reference _ReferenceType1;
1501     typedef typename std::iterator_traits<_RandomAccessIterator2>::reference _ReferenceType2;
1502 
1503     return __unseq_backend::__simd_walk_2(std::reverse_iterator<_RandomAccessIterator1>(__last), __last - __first,
1504                                           __d_first, [](_ReferenceType1 __x, _ReferenceType2 __y) { __y = __x; });
1505 }
1506 
1507 template <class _ExecutionPolicy, class _BidirectionalIterator, class _OutputIterator, class _IsVector>
1508 _OutputIterator
__pattern_reverse_copy(_ExecutionPolicy &&,_BidirectionalIterator __first,_BidirectionalIterator __last,_OutputIterator __d_first,_IsVector __is_vector,std::false_type)1509 __pattern_reverse_copy(_ExecutionPolicy&&, _BidirectionalIterator __first, _BidirectionalIterator __last,
1510                        _OutputIterator __d_first, _IsVector __is_vector, /*is_parallel=*/std::false_type) noexcept
1511 {
1512     return __internal::__brick_reverse_copy(__first, __last, __d_first, __is_vector);
1513 }
1514 
1515 template <class _ExecutionPolicy, class _RandomAccessIterator1, class _RandomAccessIterator2, class _IsVector>
1516 _RandomAccessIterator2
__pattern_reverse_copy(_ExecutionPolicy && __exec,_RandomAccessIterator1 __first,_RandomAccessIterator1 __last,_RandomAccessIterator2 __d_first,_IsVector __is_vector,std::true_type)1517 __pattern_reverse_copy(_ExecutionPolicy&& __exec, _RandomAccessIterator1 __first, _RandomAccessIterator1 __last,
1518                        _RandomAccessIterator2 __d_first, _IsVector __is_vector, /*is_parallel=*/std::true_type)
1519 {
1520     auto __len = __last - __first;
1521     __par_backend::__parallel_for(std::forward<_ExecutionPolicy>(__exec), __first, __last,
1522                                   [__is_vector, __first, __len, __d_first](_RandomAccessIterator1 __inner_first,
1523                                                                            _RandomAccessIterator1 __inner_last) {
1524                                       __internal::__brick_reverse_copy(__inner_first, __inner_last,
1525                                                                        __d_first + (__len - (__inner_last - __first)),
1526                                                                        __is_vector);
1527                                   });
1528     return __d_first + __len;
1529 }
1530 
1531 //------------------------------------------------------------------------
1532 // rotate
1533 //------------------------------------------------------------------------
1534 template <class _ForwardIterator>
1535 _ForwardIterator
__brick_rotate(_ForwardIterator __first,_ForwardIterator __middle,_ForwardIterator __last,std::false_type)1536 __brick_rotate(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last,
1537                /*is_vector=*/std::false_type) noexcept
1538 {
1539 #if defined(_PSTL_CPP11_STD_ROTATE_BROKEN)
1540     std::rotate(__first, __middle, __last);
1541     return std::next(__first, std::distance(__middle, __last));
1542 #else
1543     return std::rotate(__first, __middle, __last);
1544 #endif
1545 }
1546 
1547 template <class _RandomAccessIterator>
1548 _RandomAccessIterator
__brick_rotate(_RandomAccessIterator __first,_RandomAccessIterator __middle,_RandomAccessIterator __last,std::true_type)1549 __brick_rotate(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last,
1550                /*is_vector=*/std::true_type) noexcept
1551 {
1552     auto __n = __last - __first;
1553     auto __m = __middle - __first;
1554     const _RandomAccessIterator __ret = __first + (__last - __middle);
1555 
1556     bool __is_left = (__m <= __n / 2);
1557     if (!__is_left)
1558         __m = __n - __m;
1559 
1560     while (__n > 1 && __m > 0)
1561     {
1562         using std::iter_swap;
1563         const auto __m_2 = __m * 2;
1564         if (__is_left)
1565         {
1566             for (; __last - __first >= __m_2; __first += __m)
1567             {
1568                 __unseq_backend::__simd_assign(__first, __m, __first + __m,
1569                                                iter_swap<_RandomAccessIterator, _RandomAccessIterator>);
1570             }
1571         }
1572         else
1573         {
1574             for (; __last - __first >= __m_2; __last -= __m)
1575             {
1576                 __unseq_backend::__simd_assign(__last - __m, __m, __last - __m_2,
1577                                                iter_swap<_RandomAccessIterator, _RandomAccessIterator>);
1578             }
1579         }
1580         __is_left = !__is_left;
1581         __m = __n % __m;
1582         __n = __last - __first;
1583     }
1584 
1585     return __ret;
1586 }
1587 
1588 template <class _ExecutionPolicy, class _ForwardIterator, class _IsVector>
1589 _ForwardIterator
__pattern_rotate(_ExecutionPolicy &&,_ForwardIterator __first,_ForwardIterator __middle,_ForwardIterator __last,_IsVector __is_vector,std::false_type)1590 __pattern_rotate(_ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last,
1591                  _IsVector __is_vector, /*is_parallel=*/std::false_type) noexcept
1592 {
1593     return __internal::__brick_rotate(__first, __middle, __last, __is_vector);
1594 }
1595 
1596 template <class _ExecutionPolicy, class _RandomAccessIterator, class _IsVector>
1597 _RandomAccessIterator
__pattern_rotate(_ExecutionPolicy && __exec,_RandomAccessIterator __first,_RandomAccessIterator __middle,_RandomAccessIterator __last,_IsVector __is_vector,std::true_type)1598 __pattern_rotate(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __middle,
1599                  _RandomAccessIterator __last, _IsVector __is_vector, /*is_parallel=*/std::true_type)
1600 {
1601     typedef typename std::iterator_traits<_RandomAccessIterator>::value_type _Tp;
1602     auto __n = __last - __first;
1603     auto __m = __middle - __first;
1604     if (__m <= __n / 2)
1605     {
1606         __par_backend::__buffer<_Tp> __buf(__n - __m);
1607         return __internal::__except_handler([&__exec, __n, __m, __first, __middle, __last, __is_vector, &__buf]() {
1608             _Tp* __result = __buf.get();
1609             __par_backend::__parallel_for(
1610                 std::forward<_ExecutionPolicy>(__exec), __middle, __last,
1611                 [__middle, __result, __is_vector](_RandomAccessIterator __b, _RandomAccessIterator __e) {
1612                     __internal::__brick_uninitialized_move(__b, __e, __result + (__b - __middle), __is_vector);
1613                 });
1614 
1615             __par_backend::__parallel_for(
1616                 std::forward<_ExecutionPolicy>(__exec), __first, __middle,
1617                 [__last, __middle, __is_vector](_RandomAccessIterator __b, _RandomAccessIterator __e) {
1618                     __internal::__brick_move(__b, __e, __b + (__last - __middle), __is_vector);
1619                 });
1620 
1621             __par_backend::__parallel_for(std::forward<_ExecutionPolicy>(__exec), __result, __result + (__n - __m),
1622                                           [__first, __result, __is_vector](_Tp* __b, _Tp* __e) {
1623                                               __brick_move_destroy()(__b, __e, __first + (__b - __result), __is_vector);
1624                                           });
1625 
1626             return __first + (__last - __middle);
1627         });
1628     }
1629     else
1630     {
1631         __par_backend::__buffer<_Tp> __buf(__m);
1632         return __internal::__except_handler([&__exec, __n, __m, __first, __middle, __last, __is_vector, &__buf]() {
1633             _Tp* __result = __buf.get();
1634             __par_backend::__parallel_for(
1635                 std::forward<_ExecutionPolicy>(__exec), __first, __middle,
1636                 [__first, __result, __is_vector](_RandomAccessIterator __b, _RandomAccessIterator __e) {
1637                     __internal::__brick_uninitialized_move(__b, __e, __result + (__b - __first), __is_vector);
1638                 });
1639 
1640             __par_backend::__parallel_for(
1641                 std::forward<_ExecutionPolicy>(__exec), __middle, __last,
1642                 [__first, __middle, __is_vector](_RandomAccessIterator __b, _RandomAccessIterator __e) {
1643                     __internal::__brick_move(__b, __e, __first + (__b - __middle), __is_vector);
1644                 });
1645 
1646             __par_backend::__parallel_for(std::forward<_ExecutionPolicy>(__exec), __result, __result + __m,
1647                                           [__n, __m, __first, __result, __is_vector](_Tp* __b, _Tp* __e) {
1648                                               __brick_move_destroy()(
1649                                                   __b, __e, __first + ((__n - __m) + (__b - __result)), __is_vector);
1650                                           });
1651 
1652             return __first + (__last - __middle);
1653         });
1654     }
1655 }
1656 
1657 //------------------------------------------------------------------------
1658 // rotate_copy
1659 //------------------------------------------------------------------------
1660 
1661 template <class _ForwardIterator, class _OutputIterator>
1662 _OutputIterator
__brick_rotate_copy(_ForwardIterator __first,_ForwardIterator __middle,_ForwardIterator __last,_OutputIterator __result,std::false_type)1663 __brick_rotate_copy(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last,
1664                     _OutputIterator __result, /*__is_vector=*/std::false_type) noexcept
1665 {
1666     return std::rotate_copy(__first, __middle, __last, __result);
1667 }
1668 
1669 template <class _RandomAccessIterator1, class _RandomAccessIterator2>
1670 _RandomAccessIterator2
__brick_rotate_copy(_RandomAccessIterator1 __first,_RandomAccessIterator1 __middle,_RandomAccessIterator1 __last,_RandomAccessIterator2 __result,std::true_type)1671 __brick_rotate_copy(_RandomAccessIterator1 __first, _RandomAccessIterator1 __middle, _RandomAccessIterator1 __last,
1672                     _RandomAccessIterator2 __result, /*__is_vector=*/std::true_type) noexcept
1673 {
1674     _RandomAccessIterator2 __res = __internal::__brick_copy(__middle, __last, __result, std::true_type());
1675     return __internal::__brick_copy(__first, __middle, __res, std::true_type());
1676 }
1677 
1678 template <class _ExecutionPolicy, class _ForwardIterator, class _OutputIterator, class _IsVector>
1679 _OutputIterator
__pattern_rotate_copy(_ExecutionPolicy &&,_ForwardIterator __first,_ForwardIterator __middle,_ForwardIterator __last,_OutputIterator __result,_IsVector __is_vector,std::false_type)1680 __pattern_rotate_copy(_ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last,
1681                       _OutputIterator __result, _IsVector __is_vector, /*is_parallel=*/std::false_type) noexcept
1682 {
1683     return __internal::__brick_rotate_copy(__first, __middle, __last, __result, __is_vector);
1684 }
1685 
1686 template <class _ExecutionPolicy, class _RandomAccessIterator1, class _RandomAccessIterator2, class _IsVector>
1687 _RandomAccessIterator2
__pattern_rotate_copy(_ExecutionPolicy && __exec,_RandomAccessIterator1 __first,_RandomAccessIterator1 __middle,_RandomAccessIterator1 __last,_RandomAccessIterator2 __result,_IsVector __is_vector,std::true_type)1688 __pattern_rotate_copy(_ExecutionPolicy&& __exec, _RandomAccessIterator1 __first, _RandomAccessIterator1 __middle,
1689                       _RandomAccessIterator1 __last, _RandomAccessIterator2 __result, _IsVector __is_vector,
1690                       /*is_parallel=*/std::true_type)
1691 {
1692     __par_backend::__parallel_for(
1693         std::forward<_ExecutionPolicy>(__exec), __first, __last,
1694         [__first, __last, __middle, __result, __is_vector](_RandomAccessIterator1 __b, _RandomAccessIterator1 __e) {
1695             if (__b > __middle)
1696             {
1697                 __internal::__brick_copy(__b, __e, __result + (__b - __middle), __is_vector);
1698             }
1699             else
1700             {
1701                 _RandomAccessIterator2 __new_result = __result + ((__last - __middle) + (__b - __first));
1702                 if (__e < __middle)
1703                 {
1704                     __internal::__brick_copy(__b, __e, __new_result, __is_vector);
1705                 }
1706                 else
1707                 {
1708                     __internal::__brick_copy(__b, __middle, __new_result, __is_vector);
1709                     __internal::__brick_copy(__middle, __e, __result, __is_vector);
1710                 }
1711             }
1712         });
1713     return __result + (__last - __first);
1714 }
1715 
1716 //------------------------------------------------------------------------
1717 // is_partitioned
1718 //------------------------------------------------------------------------
1719 
1720 template <class _ForwardIterator, class _UnaryPredicate>
1721 bool
__brick_is_partitioned(_ForwardIterator __first,_ForwardIterator __last,_UnaryPredicate __pred,std::false_type)1722 __brick_is_partitioned(_ForwardIterator __first, _ForwardIterator __last, _UnaryPredicate __pred,
1723                        /*is_vector=*/std::false_type) noexcept
1724 {
1725     return std::is_partitioned(__first, __last, __pred);
1726 }
1727 
1728 template <class _RandomAccessIterator, class _UnaryPredicate>
1729 bool
__brick_is_partitioned(_RandomAccessIterator __first,_RandomAccessIterator __last,_UnaryPredicate __pred,std::true_type)1730 __brick_is_partitioned(_RandomAccessIterator __first, _RandomAccessIterator __last, _UnaryPredicate __pred,
1731                        /*is_vector=*/std::true_type) noexcept
1732 {
1733     typedef typename std::iterator_traits<_RandomAccessIterator>::difference_type _SizeType;
1734     if (__first == __last)
1735     {
1736         return true;
1737     }
1738     else
1739     {
1740         _RandomAccessIterator __result = __unseq_backend::__simd_first(
1741             __first, _SizeType(0), __last - __first,
1742             [&__pred](_RandomAccessIterator __it, _SizeType __i) { return !__pred(__it[__i]); });
1743         if (__result == __last)
1744         {
1745             return true;
1746         }
1747         else
1748         {
1749             ++__result;
1750             return !__unseq_backend::__simd_or(__result, __last - __result, __pred);
1751         }
1752     }
1753 }
1754 
1755 template <class _ExecutionPolicy, class _ForwardIterator, class _UnaryPredicate, class _IsVector>
1756 bool
__pattern_is_partitioned(_ExecutionPolicy &&,_ForwardIterator __first,_ForwardIterator __last,_UnaryPredicate __pred,_IsVector __is_vector,std::false_type)1757 __pattern_is_partitioned(_ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __last, _UnaryPredicate __pred,
1758                          _IsVector __is_vector, /*is_parallel=*/std::false_type) noexcept
1759 {
1760     return __internal::__brick_is_partitioned(__first, __last, __pred, __is_vector);
1761 }
1762 
1763 template <class _ExecutionPolicy, class _RandomAccessIterator, class _UnaryPredicate, class _IsVector>
1764 bool
__pattern_is_partitioned(_ExecutionPolicy && __exec,_RandomAccessIterator __first,_RandomAccessIterator __last,_UnaryPredicate __pred,_IsVector __is_vector,std::true_type)1765 __pattern_is_partitioned(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __last,
1766                          _UnaryPredicate __pred, _IsVector __is_vector, /*is_parallel=*/std::true_type)
1767 {
1768     if (__first == __last)
1769     {
1770         return true;
1771     }
1772     else
1773     {
1774         return __internal::__except_handler([&]() {
1775             // State of current range:
1776             // broken     - current range is not partitioned by pred
1777             // all_true   - all elements in current range satisfy pred
1778             // all_false  - all elements in current range don't satisfy pred
1779             // true_false - elements satisfy pred are placed before elements that don't satisfy pred
1780             enum _ReduceType
1781             {
1782                 __not_init = -1,
1783                 __broken,
1784                 __all_true,
1785                 __all_false,
1786                 __true_false
1787             };
1788             _ReduceType __init = __not_init;
1789 
1790             // Array with states that we'll have when state from the left branch is merged with state from the right branch.
1791             // State is calculated by formula: new_state = table[left_state * 4 + right_state]
1792             _ReduceType __table[] = {__broken,     __broken,     __broken,     __broken, __broken,    __all_true,
1793                                      __true_false, __true_false, __broken,     __broken, __all_false, __broken,
1794                                      __broken,     __broken,     __true_false, __broken};
1795 
1796             __init = __par_backend::__parallel_reduce(
1797                 std::forward<_ExecutionPolicy>(__exec), __first, __last, __init,
1798                 [&__pred, &__table, __is_vector](_RandomAccessIterator __i, _RandomAccessIterator __j,
1799                                                  _ReduceType __value) -> _ReduceType {
1800                     if (__value == __broken)
1801                     {
1802                         return __broken;
1803                     }
1804                     _ReduceType __res = __not_init;
1805                     // if first element satisfy pred
1806                     if (__pred(*__i))
1807                     {
1808                         // find first element that don't satisfy pred
1809                         _RandomAccessIterator __x =
1810                             __internal::__brick_find_if(__i + 1, __j, std::not_fn(__pred), __is_vector);
1811                         if (__x != __j)
1812                         {
1813                             // find first element after "x" that satisfy pred
1814                             _RandomAccessIterator __y = __internal::__brick_find_if(__x + 1, __j, __pred, __is_vector);
1815                             // if it was found then range isn't partitioned by pred
1816                             if (__y != __j)
1817                             {
1818                                 return __broken;
1819                             }
1820                             else
1821                             {
1822                                 __res = __true_false;
1823                             }
1824                         }
1825                         else
1826                         {
1827                             __res = __all_true;
1828                         }
1829                     }
1830                     else
1831                     { // if first element doesn't satisfy pred
1832                         // then we should find the first element that satisfy pred.
1833                         // If we found it then range isn't partitioned by pred
1834                         if (__internal::__brick_find_if(__i + 1, __j, __pred, __is_vector) != __j)
1835                         {
1836                             return __broken;
1837                         }
1838                         else
1839                         {
1840                             __res = __all_false;
1841                         }
1842                     }
1843                     // if we have value from left range then we should calculate the result
1844                     return (__value == -1) ? __res : __table[__value * 4 + __res];
1845                 },
1846 
1847                 [&__table](_ReduceType __val1, _ReduceType __val2) -> _ReduceType {
1848                     if (__val1 == __broken || __val2 == __broken)
1849                     {
1850                         return __broken;
1851                     }
1852                     // calculate the result for new big range
1853                     return __table[__val1 * 4 + __val2];
1854                 });
1855             return __init != __broken;
1856         });
1857     }
1858 }
1859 
1860 //------------------------------------------------------------------------
1861 // partition
1862 //------------------------------------------------------------------------
1863 
1864 template <class _ForwardIterator, class _UnaryPredicate>
1865 _ForwardIterator
__brick_partition(_ForwardIterator __first,_ForwardIterator __last,_UnaryPredicate __pred,std::false_type)1866 __brick_partition(_ForwardIterator __first, _ForwardIterator __last, _UnaryPredicate __pred,
1867                   /*is_vector=*/std::false_type) noexcept
1868 {
1869     return std::partition(__first, __last, __pred);
1870 }
1871 
1872 template <class _RandomAccessIterator, class _UnaryPredicate>
1873 _RandomAccessIterator
__brick_partition(_RandomAccessIterator __first,_RandomAccessIterator __last,_UnaryPredicate __pred,std::true_type)1874 __brick_partition(_RandomAccessIterator __first, _RandomAccessIterator __last, _UnaryPredicate __pred,
1875                   /*is_vector=*/std::true_type) noexcept
1876 {
1877     _PSTL_PRAGMA_MESSAGE("Vectorized algorithm unimplemented, redirected to serial");
1878     return std::partition(__first, __last, __pred);
1879 }
1880 
1881 template <class _ExecutionPolicy, class _ForwardIterator, class _UnaryPredicate, class _IsVector>
1882 _ForwardIterator
__pattern_partition(_ExecutionPolicy &&,_ForwardIterator __first,_ForwardIterator __last,_UnaryPredicate __pred,_IsVector __is_vector,std::false_type)1883 __pattern_partition(_ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __last, _UnaryPredicate __pred,
1884                     _IsVector __is_vector, /*is_parallel=*/std::false_type) noexcept
1885 {
1886     return __internal::__brick_partition(__first, __last, __pred, __is_vector);
1887 }
1888 
1889 template <class _ExecutionPolicy, class _RandomAccessIterator, class _UnaryPredicate, class _IsVector>
1890 _RandomAccessIterator
__pattern_partition(_ExecutionPolicy && __exec,_RandomAccessIterator __first,_RandomAccessIterator __last,_UnaryPredicate __pred,_IsVector __is_vector,std::true_type)1891 __pattern_partition(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __last,
1892                     _UnaryPredicate __pred, _IsVector __is_vector, /*is_parallel=*/std::true_type)
1893 {
1894 
1895     // partitioned range: elements before pivot satisfy pred (true part),
1896     //                    elements after pivot don't satisfy pred (false part)
1897     struct _PartitionRange
1898     {
1899         _RandomAccessIterator __begin;
1900         _RandomAccessIterator __pivot;
1901         _RandomAccessIterator __end;
1902     };
1903 
1904     return __internal::__except_handler([&]() {
1905         _PartitionRange __init{__last, __last, __last};
1906 
1907         // lambda for merging two partitioned ranges to one partitioned range
1908         auto __reductor = [&__exec, __is_vector](_PartitionRange __val1, _PartitionRange __val2) -> _PartitionRange {
1909             auto __size1 = __val1.__end - __val1.__pivot;
1910             auto __size2 = __val2.__pivot - __val2.__begin;
1911             auto __new_begin = __val2.__begin - (__val1.__end - __val1.__begin);
1912 
1913             // if all elements in left range satisfy pred then we can move new pivot to pivot of right range
1914             if (__val1.__end == __val1.__pivot)
1915             {
1916                 return {__new_begin, __val2.__pivot, __val2.__end};
1917             }
1918             // if true part of right range greater than false part of left range
1919             // then we should swap the false part of left range and last part of true part of right range
1920             else if (__size2 > __size1)
1921             {
1922                 __par_backend::__parallel_for(
1923                     std::forward<_ExecutionPolicy>(__exec), __val1.__pivot, __val1.__pivot + __size1,
1924                     [__val1, __val2, __size1, __is_vector](_RandomAccessIterator __i, _RandomAccessIterator __j) {
1925                         __internal::__brick_swap_ranges(__i, __j, (__val2.__pivot - __size1) + (__i - __val1.__pivot),
1926                                                         __is_vector);
1927                     });
1928                 return {__new_begin, __val2.__pivot - __size1, __val2.__end};
1929             }
1930             // else we should swap the first part of false part of left range and true part of right range
1931             else
1932             {
1933                 __par_backend::__parallel_for(
1934                     std::forward<_ExecutionPolicy>(__exec), __val1.__pivot, __val1.__pivot + __size2,
1935                     [__val1, __val2, __is_vector](_RandomAccessIterator __i, _RandomAccessIterator __j) {
1936                         __internal::__brick_swap_ranges(__i, __j, __val2.__begin + (__i - __val1.__pivot), __is_vector);
1937                     });
1938                 return {__new_begin, __val1.__pivot + __size2, __val2.__end};
1939             }
1940         };
1941 
1942         _PartitionRange __result = __par_backend::__parallel_reduce(
1943             std::forward<_ExecutionPolicy>(__exec), __first, __last, __init,
1944             [__pred, __is_vector, __reductor](_RandomAccessIterator __i, _RandomAccessIterator __j,
1945                                               _PartitionRange __value) -> _PartitionRange {
1946                 //1. serial partition
1947                 _RandomAccessIterator __pivot = __internal::__brick_partition(__i, __j, __pred, __is_vector);
1948 
1949                 // 2. merging of two ranges (left and right respectively)
1950                 return __reductor(__value, {__i, __pivot, __j});
1951             },
1952             __reductor);
1953         return __result.__pivot;
1954     });
1955 }
1956 
1957 //------------------------------------------------------------------------
1958 // stable_partition
1959 //------------------------------------------------------------------------
1960 
1961 template <class _BidirectionalIterator, class _UnaryPredicate>
1962 _BidirectionalIterator
__brick_stable_partition(_BidirectionalIterator __first,_BidirectionalIterator __last,_UnaryPredicate __pred,std::false_type)1963 __brick_stable_partition(_BidirectionalIterator __first, _BidirectionalIterator __last, _UnaryPredicate __pred,
1964                          /*__is_vector=*/std::false_type) noexcept
1965 {
1966     return std::stable_partition(__first, __last, __pred);
1967 }
1968 
1969 template <class _RandomAccessIterator, class _UnaryPredicate>
1970 _RandomAccessIterator
__brick_stable_partition(_RandomAccessIterator __first,_RandomAccessIterator __last,_UnaryPredicate __pred,std::true_type)1971 __brick_stable_partition(_RandomAccessIterator __first, _RandomAccessIterator __last, _UnaryPredicate __pred,
1972                          /*__is_vector=*/std::true_type) noexcept
1973 {
1974     _PSTL_PRAGMA_MESSAGE("Vectorized algorithm unimplemented, redirected to serial");
1975     return std::stable_partition(__first, __last, __pred);
1976 }
1977 
1978 template <class _ExecutionPolicy, class _BidirectionalIterator, class _UnaryPredicate, class _IsVector>
1979 _BidirectionalIterator
__pattern_stable_partition(_ExecutionPolicy &&,_BidirectionalIterator __first,_BidirectionalIterator __last,_UnaryPredicate __pred,_IsVector __is_vector,std::false_type)1980 __pattern_stable_partition(_ExecutionPolicy&&, _BidirectionalIterator __first, _BidirectionalIterator __last,
1981                            _UnaryPredicate __pred, _IsVector __is_vector,
1982                            /*is_parallelization=*/std::false_type) noexcept
1983 {
1984     return __internal::__brick_stable_partition(__first, __last, __pred, __is_vector);
1985 }
1986 
1987 template <class _ExecutionPolicy, class _RandomAccessIterator, class _UnaryPredicate, class _IsVector>
1988 _RandomAccessIterator
__pattern_stable_partition(_ExecutionPolicy && __exec,_RandomAccessIterator __first,_RandomAccessIterator __last,_UnaryPredicate __pred,_IsVector __is_vector,std::true_type)1989 __pattern_stable_partition(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __last,
1990                            _UnaryPredicate __pred, _IsVector __is_vector,
1991                            /*is_parallelization=*/std::true_type) noexcept
1992 {
1993     // partitioned range: elements before pivot satisfy pred (true part),
1994     //                    elements after pivot don't satisfy pred (false part)
1995     struct _PartitionRange
1996     {
1997         _RandomAccessIterator __begin;
1998         _RandomAccessIterator __pivot;
1999         _RandomAccessIterator __end;
2000     };
2001 
2002     return __internal::__except_handler([&]() {
2003         _PartitionRange __init{__last, __last, __last};
2004 
2005         // lambda for merging two partitioned ranges to one partitioned range
2006         auto __reductor = [__is_vector](_PartitionRange __val1, _PartitionRange __val2) -> _PartitionRange {
2007             auto __size1 = __val1.__end - __val1.__pivot;
2008             auto __new_begin = __val2.__begin - (__val1.__end - __val1.__begin);
2009 
2010             // if all elements in left range satisfy pred then we can move new pivot to pivot of right range
2011             if (__val1.__end == __val1.__pivot)
2012             {
2013                 return {__new_begin, __val2.__pivot, __val2.__end};
2014             }
2015             // if true part of right range greater than false part of left range
2016             // then we should swap the false part of left range and last part of true part of right range
2017             else
2018             {
2019                 __internal::__brick_rotate(__val1.__pivot, __val2.__begin, __val2.__pivot, __is_vector);
2020                 return {__new_begin, __val2.__pivot - __size1, __val2.__end};
2021             }
2022         };
2023 
2024         _PartitionRange __result = __par_backend::__parallel_reduce(
2025             std::forward<_ExecutionPolicy>(__exec), __first, __last, __init,
2026             [&__pred, __is_vector, __reductor](_RandomAccessIterator __i, _RandomAccessIterator __j,
2027                                                _PartitionRange __value) -> _PartitionRange {
2028                 //1. serial stable_partition
2029                 _RandomAccessIterator __pivot = __internal::__brick_stable_partition(__i, __j, __pred, __is_vector);
2030 
2031                 // 2. merging of two ranges (left and right respectively)
2032                 return __reductor(__value, {__i, __pivot, __j});
2033             },
2034             __reductor);
2035         return __result.__pivot;
2036     });
2037 }
2038 
2039 //------------------------------------------------------------------------
2040 // partition_copy
2041 //------------------------------------------------------------------------
2042 
2043 template <class _ForwardIterator, class _OutputIterator1, class _OutputIterator2, class _UnaryPredicate>
2044 std::pair<_OutputIterator1, _OutputIterator2>
__brick_partition_copy(_ForwardIterator __first,_ForwardIterator __last,_OutputIterator1 __out_true,_OutputIterator2 __out_false,_UnaryPredicate __pred,std::false_type)2045 __brick_partition_copy(_ForwardIterator __first, _ForwardIterator __last, _OutputIterator1 __out_true,
2046                        _OutputIterator2 __out_false, _UnaryPredicate __pred, /*is_vector=*/std::false_type) noexcept
2047 {
2048     return std::partition_copy(__first, __last, __out_true, __out_false, __pred);
2049 }
2050 
2051 template <class _RandomAccessIterator1, class _RandomAccessIterator2, class _RandomAccessIterator3,
2052           class _UnaryPredicate>
2053 std::pair<_RandomAccessIterator2, _RandomAccessIterator3>
__brick_partition_copy(_RandomAccessIterator1 __first,_RandomAccessIterator1 __last,_RandomAccessIterator2 __out_true,_RandomAccessIterator3 __out_false,_UnaryPredicate __pred,std::true_type)2054 __brick_partition_copy(_RandomAccessIterator1 __first, _RandomAccessIterator1 __last, _RandomAccessIterator2 __out_true,
2055                        _RandomAccessIterator3 __out_false, _UnaryPredicate __pred,
2056                        /*is_vector=*/std::true_type) noexcept
2057 {
2058 #if defined(_PSTL_MONOTONIC_PRESENT)
2059     return __unseq_backend::__simd_partition_copy(__first, __last - __first, __out_true, __out_false, __pred);
2060 #else
2061     return std::partition_copy(__first, __last, __out_true, __out_false, __pred);
2062 #endif
2063 }
2064 
2065 template <class _ExecutionPolicy, class _ForwardIterator, class _OutputIterator1, class _OutputIterator2,
2066           class _UnaryPredicate, class _IsVector>
2067 std::pair<_OutputIterator1, _OutputIterator2>
__pattern_partition_copy(_ExecutionPolicy &&,_ForwardIterator __first,_ForwardIterator __last,_OutputIterator1 __out_true,_OutputIterator2 __out_false,_UnaryPredicate __pred,_IsVector __is_vector,std::false_type)2068 __pattern_partition_copy(_ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __last,
2069                          _OutputIterator1 __out_true, _OutputIterator2 __out_false, _UnaryPredicate __pred,
2070                          _IsVector __is_vector, /*is_parallelization=*/std::false_type) noexcept
2071 {
2072     return __internal::__brick_partition_copy(__first, __last, __out_true, __out_false, __pred, __is_vector);
2073 }
2074 
2075 template <class _ExecutionPolicy, class _RandomAccessIterator1, class _RandomAccessIterator2,
2076           class _RandomAccessIterator3, class _UnaryPredicate, class _IsVector>
2077 std::pair<_RandomAccessIterator2, _RandomAccessIterator3>
__pattern_partition_copy(_ExecutionPolicy && __exec,_RandomAccessIterator1 __first,_RandomAccessIterator1 __last,_RandomAccessIterator2 __out_true,_RandomAccessIterator3 __out_false,_UnaryPredicate __pred,_IsVector __is_vector,std::true_type)2078 __pattern_partition_copy(_ExecutionPolicy&& __exec, _RandomAccessIterator1 __first, _RandomAccessIterator1 __last,
2079                          _RandomAccessIterator2 __out_true, _RandomAccessIterator3 __out_false, _UnaryPredicate __pred,
2080                          _IsVector __is_vector, /*is_parallelization=*/std::true_type)
2081 {
2082     typedef typename std::iterator_traits<_RandomAccessIterator1>::difference_type _DifferenceType;
2083     typedef std::pair<_DifferenceType, _DifferenceType> _ReturnType;
2084     const _DifferenceType __n = __last - __first;
2085     if (_DifferenceType(1) < __n)
2086     {
2087         __par_backend::__buffer<bool> __mask_buf(__n);
2088         return __internal::__except_handler([&__exec, __n, __first, __out_true, __out_false, __is_vector, __pred,
2089                                              &__mask_buf]() {
2090             bool* __mask = __mask_buf.get();
2091             _ReturnType __m{};
2092             __par_backend::__parallel_strict_scan(
2093                 std::forward<_ExecutionPolicy>(__exec), __n, std::make_pair(_DifferenceType(0), _DifferenceType(0)),
2094                 [=](_DifferenceType __i, _DifferenceType __len) { // Reduce
2095                     return __internal::__brick_calc_mask_1<_DifferenceType>(__first + __i, __first + (__i + __len),
2096                                                                             __mask + __i, __pred, __is_vector);
2097                 },
2098                 [](const _ReturnType& __x, const _ReturnType& __y) -> _ReturnType {
2099                     return std::make_pair(__x.first + __y.first, __x.second + __y.second);
2100                 },                                                                       // Combine
2101                 [=](_DifferenceType __i, _DifferenceType __len, _ReturnType __initial) { // Scan
2102                     __internal::__brick_partition_by_mask(__first + __i, __first + (__i + __len),
2103                                                           __out_true + __initial.first, __out_false + __initial.second,
2104                                                           __mask + __i, __is_vector);
2105                 },
2106                 [&__m](_ReturnType __total) { __m = __total; });
2107             return std::make_pair(__out_true + __m.first, __out_false + __m.second);
2108         });
2109     }
2110     // trivial sequence - use serial algorithm
2111     return __internal::__brick_partition_copy(__first, __last, __out_true, __out_false, __pred, __is_vector);
2112 }
2113 
2114 //------------------------------------------------------------------------
2115 // sort
2116 //------------------------------------------------------------------------
2117 
2118 template <class _ExecutionPolicy, class _RandomAccessIterator, class _Compare, class _IsVector,
2119           class _IsMoveConstructible>
2120 void
__pattern_sort(_ExecutionPolicy &&,_RandomAccessIterator __first,_RandomAccessIterator __last,_Compare __comp,_IsVector,std::false_type,_IsMoveConstructible)2121 __pattern_sort(_ExecutionPolicy&&, _RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp,
2122                _IsVector /*is_vector*/, /*is_parallel=*/std::false_type, _IsMoveConstructible) noexcept
2123 {
2124     std::sort(__first, __last, __comp);
2125 }
2126 
2127 template <class _ExecutionPolicy, class _RandomAccessIterator, class _Compare, class _IsVector>
2128 void
__pattern_sort(_ExecutionPolicy && __exec,_RandomAccessIterator __first,_RandomAccessIterator __last,_Compare __comp,_IsVector,std::true_type,std::true_type)2129 __pattern_sort(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp,
2130                _IsVector /*is_vector*/, /*is_parallel=*/std::true_type, /*is_move_constructible=*/std::true_type)
2131 {
2132     __internal::__except_handler([&]() {
2133         __par_backend::__parallel_stable_sort(std::forward<_ExecutionPolicy>(__exec), __first, __last, __comp,
2134                                               [](_RandomAccessIterator __first, _RandomAccessIterator __last,
2135                                                  _Compare __comp) { std::sort(__first, __last, __comp); });
2136     });
2137 }
2138 
2139 //------------------------------------------------------------------------
2140 // stable_sort
2141 //------------------------------------------------------------------------
2142 
2143 template <class _ExecutionPolicy, class _RandomAccessIterator, class _Compare, class _IsVector>
2144 void
__pattern_stable_sort(_ExecutionPolicy &&,_RandomAccessIterator __first,_RandomAccessIterator __last,_Compare __comp,_IsVector,std::false_type)2145 __pattern_stable_sort(_ExecutionPolicy&&, _RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp,
2146                       _IsVector /*is_vector*/, /*is_parallel=*/std::false_type) noexcept
2147 {
2148     std::stable_sort(__first, __last, __comp);
2149 }
2150 
2151 template <class _ExecutionPolicy, class _RandomAccessIterator, class _Compare, class _IsVector>
2152 void
__pattern_stable_sort(_ExecutionPolicy && __exec,_RandomAccessIterator __first,_RandomAccessIterator __last,_Compare __comp,_IsVector,std::true_type)2153 __pattern_stable_sort(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __last,
2154                       _Compare __comp, _IsVector /*is_vector*/, /*is_parallel=*/std::true_type)
2155 {
2156     __internal::__except_handler([&]() {
2157         __par_backend::__parallel_stable_sort(std::forward<_ExecutionPolicy>(__exec), __first, __last, __comp,
2158                                               [](_RandomAccessIterator __first, _RandomAccessIterator __last,
2159                                                  _Compare __comp) { std::stable_sort(__first, __last, __comp); });
2160     });
2161 }
2162 
2163 //------------------------------------------------------------------------
2164 // partial_sort
2165 //------------------------------------------------------------------------
2166 
2167 template <class _ExecutionPolicy, class _RandomAccessIterator, class _Compare, class _IsVector>
2168 void
__pattern_partial_sort(_ExecutionPolicy &&,_RandomAccessIterator __first,_RandomAccessIterator __middle,_RandomAccessIterator __last,_Compare __comp,_IsVector,std::false_type)2169 __pattern_partial_sort(_ExecutionPolicy&&, _RandomAccessIterator __first, _RandomAccessIterator __middle,
2170                        _RandomAccessIterator __last, _Compare __comp, _IsVector,
2171                        /*is_parallel=*/std::false_type) noexcept
2172 {
2173     std::partial_sort(__first, __middle, __last, __comp);
2174 }
2175 
2176 template <class _ExecutionPolicy, class _RandomAccessIterator, class _Compare, class _IsVector>
2177 void
__pattern_partial_sort(_ExecutionPolicy && __exec,_RandomAccessIterator __first,_RandomAccessIterator __middle,_RandomAccessIterator __last,_Compare __comp,_IsVector,std::true_type)2178 __pattern_partial_sort(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __middle,
2179                        _RandomAccessIterator __last, _Compare __comp, _IsVector, /*is_parallel=*/std::true_type)
2180 {
2181     const auto __n = __middle - __first;
2182     if (__n == 0)
2183         return;
2184 
2185     __internal::__except_handler([&]() {
2186         __par_backend::__parallel_stable_sort(
2187             std::forward<_ExecutionPolicy>(__exec), __first, __last, __comp,
2188             [__n](_RandomAccessIterator __begin, _RandomAccessIterator __end, _Compare __comp) {
2189                 if (__n < __end - __begin)
2190                     std::partial_sort(__begin, __begin + __n, __end, __comp);
2191                 else
2192                     std::sort(__begin, __end, __comp);
2193             },
2194             __n);
2195     });
2196 }
2197 
2198 //------------------------------------------------------------------------
2199 // partial_sort_copy
2200 //------------------------------------------------------------------------
2201 
2202 template <class _ExecutionPolicy, class _ForwardIterator, class _RandomAccessIterator, class _Compare, class _IsVector>
2203 _RandomAccessIterator
__pattern_partial_sort_copy(_ExecutionPolicy &&,_ForwardIterator __first,_ForwardIterator __last,_RandomAccessIterator __d_first,_RandomAccessIterator __d_last,_Compare __comp,_IsVector,std::false_type)2204 __pattern_partial_sort_copy(_ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __last,
2205                             _RandomAccessIterator __d_first, _RandomAccessIterator __d_last, _Compare __comp, _IsVector,
2206                             /*is_parallel=*/std::false_type) noexcept
2207 {
2208     return std::partial_sort_copy(__first, __last, __d_first, __d_last, __comp);
2209 }
2210 
2211 template <class _ExecutionPolicy, class _RandomAccessIterator1, class _RandomAccessIterator2, class _Compare,
2212           class _IsVector>
2213 _RandomAccessIterator2
__pattern_partial_sort_copy(_ExecutionPolicy && __exec,_RandomAccessIterator1 __first,_RandomAccessIterator1 __last,_RandomAccessIterator2 __d_first,_RandomAccessIterator2 __d_last,_Compare __comp,_IsVector __is_vector,std::true_type)2214 __pattern_partial_sort_copy(_ExecutionPolicy&& __exec, _RandomAccessIterator1 __first, _RandomAccessIterator1 __last,
2215                             _RandomAccessIterator2 __d_first, _RandomAccessIterator2 __d_last, _Compare __comp,
2216                             _IsVector __is_vector, /*is_parallel=*/std::true_type)
2217 {
2218     if (__last == __first || __d_last == __d_first)
2219     {
2220         return __d_first;
2221     }
2222     auto __n1 = __last - __first;
2223     auto __n2 = __d_last - __d_first;
2224     return __internal::__except_handler([&]() {
2225         if (__n2 >= __n1)
2226         {
2227             __par_backend::__parallel_stable_sort(
2228                 std::forward<_ExecutionPolicy>(__exec), __d_first, __d_first + __n1, __comp,
2229                 [__first, __d_first, __is_vector](_RandomAccessIterator2 __i, _RandomAccessIterator2 __j,
2230                                                   _Compare __comp) {
2231                     _RandomAccessIterator1 __i1 = __first + (__i - __d_first);
2232                     _RandomAccessIterator1 __j1 = __first + (__j - __d_first);
2233 
2234                 // 1. Copy elements from input to output
2235 #if !defined(_PSTL_ICC_18_OMP_SIMD_BROKEN)
2236                     __internal::__brick_copy(__i1, __j1, __i, __is_vector);
2237 #else
2238                     std::copy(__i1, __j1, __i);
2239 #endif
2240                     // 2. Sort elements in output sequence
2241                     std::sort(__i, __j, __comp);
2242                 },
2243                 __n1);
2244             return __d_first + __n1;
2245         }
2246         else
2247         {
2248             typedef typename std::iterator_traits<_RandomAccessIterator1>::value_type _T1;
2249             typedef typename std::iterator_traits<_RandomAccessIterator2>::value_type _T2;
2250             __par_backend::__buffer<_T1> __buf(__n1);
2251             _T1* __r = __buf.get();
2252 
2253             __par_backend::__parallel_stable_sort(std::forward<_ExecutionPolicy>(__exec), __r, __r + __n1, __comp,
2254                                                   [__n2, __first, __r](_T1* __i, _T1* __j, _Compare __comp) {
2255                                                       _RandomAccessIterator1 __it = __first + (__i - __r);
2256 
2257                                                       // 1. Copy elements from input to raw memory
2258                                                       for (_T1* __k = __i; __k != __j; ++__k, ++__it)
2259                                                       {
2260                                                           ::new (__k) _T2(*__it);
2261                                                       }
2262 
2263                                                       // 2. Sort elements in temporary __buffer
2264                                                       if (__n2 < __j - __i)
2265                                                           std::partial_sort(__i, __i + __n2, __j, __comp);
2266                                                       else
2267                                                           std::sort(__i, __j, __comp);
2268                                                   },
2269                                                   __n2);
2270 
2271             // 3. Move elements from temporary __buffer to output
2272             __par_backend::__parallel_for(std::forward<_ExecutionPolicy>(__exec), __r, __r + __n2,
2273                                           [__r, __d_first, __is_vector](_T1* __i, _T1* __j) {
2274                                               __brick_move_destroy()(__i, __j, __d_first + (__i - __r), __is_vector);
2275                                           });
2276             __par_backend::__parallel_for(
2277                 std::forward<_ExecutionPolicy>(__exec), __r + __n2, __r + __n1,
2278                 [__is_vector](_T1* __i, _T1* __j) { __brick_destroy(__i, __j, __is_vector); });
2279 
2280             return __d_first + __n2;
2281         }
2282     });
2283 }
2284 
2285 //------------------------------------------------------------------------
2286 // adjacent_find
2287 //------------------------------------------------------------------------
2288 template <class _RandomAccessIterator, class _BinaryPredicate>
2289 _RandomAccessIterator
__brick_adjacent_find(_RandomAccessIterator __first,_RandomAccessIterator __last,_BinaryPredicate __pred,std::true_type,bool __or_semantic)2290 __brick_adjacent_find(_RandomAccessIterator __first, _RandomAccessIterator __last, _BinaryPredicate __pred,
2291                       /* IsVector = */ std::true_type, bool __or_semantic) noexcept
2292 {
2293     return __unseq_backend::__simd_adjacent_find(__first, __last, __pred, __or_semantic);
2294 }
2295 
2296 template <class _ForwardIterator, class _BinaryPredicate>
2297 _ForwardIterator
__brick_adjacent_find(_ForwardIterator __first,_ForwardIterator __last,_BinaryPredicate __pred,std::false_type,bool)2298 __brick_adjacent_find(_ForwardIterator __first, _ForwardIterator __last, _BinaryPredicate __pred,
2299                       /* IsVector = */ std::false_type, bool) noexcept
2300 {
2301     return std::adjacent_find(__first, __last, __pred);
2302 }
2303 
2304 template <class _ExecutionPolicy, class _ForwardIterator, class _BinaryPredicate, class _IsVector>
2305 _ForwardIterator
__pattern_adjacent_find(_ExecutionPolicy &&,_ForwardIterator __first,_ForwardIterator __last,_BinaryPredicate __pred,std::false_type,_IsVector __is_vector,bool __or_semantic)2306 __pattern_adjacent_find(_ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __last, _BinaryPredicate __pred,
2307                         /* is_parallel */ std::false_type, _IsVector __is_vector, bool __or_semantic) noexcept
2308 {
2309     return __internal::__brick_adjacent_find(__first, __last, __pred, __is_vector, __or_semantic);
2310 }
2311 
2312 template <class _ExecutionPolicy, class _RandomAccessIterator, class _BinaryPredicate, class _IsVector>
2313 _RandomAccessIterator
__pattern_adjacent_find(_ExecutionPolicy && __exec,_RandomAccessIterator __first,_RandomAccessIterator __last,_BinaryPredicate __pred,std::true_type,_IsVector __is_vector,bool __or_semantic)2314 __pattern_adjacent_find(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __last,
2315                         _BinaryPredicate __pred, /* is_parallel */ std::true_type, _IsVector __is_vector,
2316                         bool __or_semantic)
2317 {
2318     if (__last - __first < 2)
2319         return __last;
2320 
2321     return __internal::__except_handler([&]() {
2322         return __par_backend::__parallel_reduce(
2323             std::forward<_ExecutionPolicy>(__exec), __first, __last, __last,
2324             [__last, __pred, __is_vector, __or_semantic](_RandomAccessIterator __begin, _RandomAccessIterator __end,
2325                                                          _RandomAccessIterator __value) -> _RandomAccessIterator {
2326                 // TODO: investigate performance benefits from the use of shared variable for the result,
2327                 // checking (compare_and_swap idiom) its __value at __first.
2328                 if (__or_semantic && __value < __last)
2329                 { //found
2330                     __par_backend::__cancel_execution();
2331                     return __value;
2332                 }
2333 
2334                 if (__value > __begin)
2335                 {
2336                     // modify __end to check the predicate on the boundary __values;
2337                     // TODO: to use a custom range with boundaries overlapping
2338                     // TODO: investigate what if we remove "if" below and run algorithm on range [__first, __last-1)
2339                     // then check the pair [__last-1, __last)
2340                     if (__end != __last)
2341                         ++__end;
2342 
2343                     //correct the global result iterator if the "brick" returns a local "__last"
2344                     const _RandomAccessIterator __res =
2345                         __internal::__brick_adjacent_find(__begin, __end, __pred, __is_vector, __or_semantic);
2346                     if (__res < __end)
2347                         __value = __res;
2348                 }
2349                 return __value;
2350             },
2351             [](_RandomAccessIterator __x, _RandomAccessIterator __y) -> _RandomAccessIterator {
2352                 return __x < __y ? __x : __y;
2353             } //reduce a __value
2354         );
2355     });
2356 }
2357 
2358 //------------------------------------------------------------------------
2359 // nth_element
2360 //------------------------------------------------------------------------
2361 
2362 template <class _ExecutionPolicy, class _RandomAccessIterator, class _Compare, class _IsVector>
2363 void
__pattern_nth_element(_ExecutionPolicy &&,_RandomAccessIterator __first,_RandomAccessIterator __nth,_RandomAccessIterator __last,_Compare __comp,_IsVector,std::false_type)2364 __pattern_nth_element(_ExecutionPolicy&&, _RandomAccessIterator __first, _RandomAccessIterator __nth,
2365                       _RandomAccessIterator __last, _Compare __comp, _IsVector,
2366                       /*is_parallel=*/std::false_type) noexcept
2367 {
2368     std::nth_element(__first, __nth, __last, __comp);
2369 }
2370 
2371 template <class _ExecutionPolicy, class _RandomAccessIterator, class _Compare, class _IsVector>
2372 void
__pattern_nth_element(_ExecutionPolicy && __exec,_RandomAccessIterator __first,_RandomAccessIterator __nth,_RandomAccessIterator __last,_Compare __comp,_IsVector __is_vector,std::true_type)2373 __pattern_nth_element(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __nth,
2374                       _RandomAccessIterator __last, _Compare __comp, _IsVector __is_vector,
2375                       /*is_parallel=*/std::true_type) noexcept
2376 {
2377     if (__first == __last || __nth == __last)
2378     {
2379         return;
2380     }
2381 
2382     using std::iter_swap;
2383     typedef typename std::iterator_traits<_RandomAccessIterator>::value_type _Tp;
2384     _RandomAccessIterator __x;
2385     do
2386     {
2387         __x = __internal::__pattern_partition(std::forward<_ExecutionPolicy>(__exec), __first + 1, __last,
2388                                               [&__comp, __first](const _Tp& __x) { return __comp(__x, *__first); },
2389                                               __is_vector,
2390                                               /*is_parallel=*/std::true_type());
2391         --__x;
2392         if (__x != __first)
2393         {
2394             iter_swap(__first, __x);
2395         }
2396         // if x > nth then our new range for partition is [first, x)
2397         if (__x - __nth > 0)
2398         {
2399             __last = __x;
2400         }
2401         // if x < nth then our new range for partition is [x, last)
2402         else if (__x - __nth < 0)
2403         {
2404             // if *x == *nth then we can start new partition with x+1
2405             if (!__comp(*__nth, *__x) && !__comp(*__x, *__nth))
2406             {
2407                 ++__x;
2408             }
2409             else
2410             {
2411                 iter_swap(__nth, __x);
2412             }
2413             __first = __x;
2414         }
2415     } while (__x != __nth);
2416 }
2417 
2418 //------------------------------------------------------------------------
2419 // fill, fill_n
2420 //------------------------------------------------------------------------
2421 template <class _RandomAccessIterator, class _Tp>
2422 void
__brick_fill(_RandomAccessIterator __first,_RandomAccessIterator __last,const _Tp & __value,std::true_type)2423 __brick_fill(_RandomAccessIterator __first, _RandomAccessIterator __last, const _Tp& __value,
2424              /* __is_vector = */ std::true_type) noexcept
2425 {
2426     __unseq_backend::__simd_fill_n(__first, __last - __first, __value);
2427 }
2428 
2429 template <class _ForwardIterator, class _Tp>
2430 void
__brick_fill(_ForwardIterator __first,_ForwardIterator __last,const _Tp & __value,std::false_type)2431 __brick_fill(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value,
2432              /* __is_vector = */ std::false_type) noexcept
2433 {
2434     std::fill(__first, __last, __value);
2435 }
2436 
2437 template <class _ExecutionPolicy, class _ForwardIterator, class _Tp, class _IsVector>
2438 void
__pattern_fill(_ExecutionPolicy &&,_ForwardIterator __first,_ForwardIterator __last,const _Tp & __value,std::false_type,_IsVector __is_vector)2439 __pattern_fill(_ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value,
2440                /*is_parallel=*/std::false_type, _IsVector __is_vector) noexcept
2441 {
2442     __internal::__brick_fill(__first, __last, __value, __is_vector);
2443 }
2444 
2445 template <class _ExecutionPolicy, class _RandomAccessIterator, class _Tp, class _IsVector>
2446 _RandomAccessIterator
__pattern_fill(_ExecutionPolicy && __exec,_RandomAccessIterator __first,_RandomAccessIterator __last,const _Tp & __value,std::true_type,_IsVector __is_vector)2447 __pattern_fill(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __last,
2448                const _Tp& __value,
2449                /*is_parallel=*/std::true_type, _IsVector __is_vector)
2450 {
2451     return __internal::__except_handler([&__exec, __first, __last, &__value, __is_vector]() {
2452         __par_backend::__parallel_for(
2453             std::forward<_ExecutionPolicy>(__exec), __first, __last,
2454             [&__value, __is_vector](_RandomAccessIterator __begin, _RandomAccessIterator __end) {
2455                 __internal::__brick_fill(__begin, __end, __value, __is_vector);
2456             });
2457         return __last;
2458     });
2459 }
2460 
2461 template <class _RandomAccessIterator, class _Size, class _Tp>
2462 _RandomAccessIterator
__brick_fill_n(_RandomAccessIterator __first,_Size __count,const _Tp & __value,std::true_type)2463 __brick_fill_n(_RandomAccessIterator __first, _Size __count, const _Tp& __value,
2464                /* __is_vector = */ std::true_type) noexcept
2465 {
2466     return __unseq_backend::__simd_fill_n(__first, __count, __value);
2467 }
2468 
2469 template <class _OutputIterator, class _Size, class _Tp>
2470 _OutputIterator
__brick_fill_n(_OutputIterator __first,_Size __count,const _Tp & __value,std::false_type)2471 __brick_fill_n(_OutputIterator __first, _Size __count, const _Tp& __value, /* __is_vector = */ std::false_type) noexcept
2472 {
2473     return std::fill_n(__first, __count, __value);
2474 }
2475 
2476 template <class _ExecutionPolicy, class _OutputIterator, class _Size, class _Tp, class _IsVector>
2477 _OutputIterator
__pattern_fill_n(_ExecutionPolicy &&,_OutputIterator __first,_Size __count,const _Tp & __value,std::false_type,_IsVector __is_vector)2478 __pattern_fill_n(_ExecutionPolicy&&, _OutputIterator __first, _Size __count, const _Tp& __value,
2479                  /*is_parallel=*/std::false_type, _IsVector __is_vector) noexcept
2480 {
2481     return __internal::__brick_fill_n(__first, __count, __value, __is_vector);
2482 }
2483 
2484 template <class _ExecutionPolicy, class _RandomAccessIterator, class _Size, class _Tp, class _IsVector>
2485 _RandomAccessIterator
__pattern_fill_n(_ExecutionPolicy && __exec,_RandomAccessIterator __first,_Size __count,const _Tp & __value,std::true_type,_IsVector __is_vector)2486 __pattern_fill_n(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _Size __count, const _Tp& __value,
2487                  /*is_parallel=*/std::true_type, _IsVector __is_vector)
2488 {
2489     return __internal::__pattern_fill(std::forward<_ExecutionPolicy>(__exec), __first, __first + __count, __value,
2490                                       std::true_type(), __is_vector);
2491 }
2492 
2493 //------------------------------------------------------------------------
2494 // generate, generate_n
2495 //------------------------------------------------------------------------
2496 template <class _RandomAccessIterator, class _Generator>
2497 void
__brick_generate(_RandomAccessIterator __first,_RandomAccessIterator __last,_Generator __g,std::true_type)2498 __brick_generate(_RandomAccessIterator __first, _RandomAccessIterator __last, _Generator __g,
2499                  /* is_vector = */ std::true_type) noexcept
2500 {
2501     __unseq_backend::__simd_generate_n(__first, __last - __first, __g);
2502 }
2503 
2504 template <class _ForwardIterator, class _Generator>
2505 void
__brick_generate(_ForwardIterator __first,_ForwardIterator __last,_Generator __g,std::false_type)2506 __brick_generate(_ForwardIterator __first, _ForwardIterator __last, _Generator __g,
2507                  /* is_vector = */ std::false_type) noexcept
2508 {
2509     std::generate(__first, __last, __g);
2510 }
2511 
2512 template <class _ExecutionPolicy, class _ForwardIterator, class _Generator, class _IsVector>
2513 void
__pattern_generate(_ExecutionPolicy &&,_ForwardIterator __first,_ForwardIterator __last,_Generator __g,std::false_type,_IsVector __is_vector)2514 __pattern_generate(_ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __last, _Generator __g,
2515                    /*is_parallel=*/std::false_type, _IsVector __is_vector) noexcept
2516 {
2517     __internal::__brick_generate(__first, __last, __g, __is_vector);
2518 }
2519 
2520 template <class _ExecutionPolicy, class _RandomAccessIterator, class _Generator, class _IsVector>
2521 _RandomAccessIterator
__pattern_generate(_ExecutionPolicy && __exec,_RandomAccessIterator __first,_RandomAccessIterator __last,_Generator __g,std::true_type,_IsVector __is_vector)2522 __pattern_generate(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __last,
2523                    _Generator __g,
2524                    /*is_parallel=*/std::true_type, _IsVector __is_vector)
2525 {
2526     return __internal::__except_handler([&]() {
2527         __par_backend::__parallel_for(std::forward<_ExecutionPolicy>(__exec), __first, __last,
2528                                       [__g, __is_vector](_RandomAccessIterator __begin, _RandomAccessIterator __end) {
2529                                           __internal::__brick_generate(__begin, __end, __g, __is_vector);
2530                                       });
2531         return __last;
2532     });
2533 }
2534 
2535 template <class _RandomAccessIterator, class Size, class _Generator>
2536 _RandomAccessIterator
__brick_generate_n(_RandomAccessIterator __first,Size __count,_Generator __g,std::true_type)2537 __brick_generate_n(_RandomAccessIterator __first, Size __count, _Generator __g,
2538                    /* is_vector = */ std::true_type) noexcept
2539 {
2540     return __unseq_backend::__simd_generate_n(__first, __count, __g);
2541 }
2542 
2543 template <class OutputIterator, class Size, class _Generator>
2544 OutputIterator
__brick_generate_n(OutputIterator __first,Size __count,_Generator __g,std::false_type)2545 __brick_generate_n(OutputIterator __first, Size __count, _Generator __g, /* is_vector = */ std::false_type) noexcept
2546 {
2547     return std::generate_n(__first, __count, __g);
2548 }
2549 
2550 template <class _ExecutionPolicy, class _OutputIterator, class _Size, class _Generator, class _IsVector>
2551 _OutputIterator
__pattern_generate_n(_ExecutionPolicy &&,_OutputIterator __first,_Size __count,_Generator __g,std::false_type,_IsVector __is_vector)2552 __pattern_generate_n(_ExecutionPolicy&&, _OutputIterator __first, _Size __count, _Generator __g,
2553                      /*is_parallel=*/std::false_type, _IsVector __is_vector) noexcept
2554 {
2555     return __internal::__brick_generate_n(__first, __count, __g, __is_vector);
2556 }
2557 
2558 template <class _ExecutionPolicy, class _RandomAccessIterator, class _Size, class _Generator, class _IsVector>
2559 _RandomAccessIterator
__pattern_generate_n(_ExecutionPolicy && __exec,_RandomAccessIterator __first,_Size __count,_Generator __g,std::true_type,_IsVector __is_vector)2560 __pattern_generate_n(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _Size __count, _Generator __g,
2561                      /*is_parallel=*/std::true_type, _IsVector __is_vector)
2562 {
2563     static_assert(__is_random_access_iterator<_RandomAccessIterator>::value,
2564                   "Pattern-brick error. Should be a random access iterator.");
2565     return __internal::__pattern_generate(std::forward<_ExecutionPolicy>(__exec), __first, __first + __count, __g,
2566                                           std::true_type(), __is_vector);
2567 }
2568 
2569 //------------------------------------------------------------------------
2570 // remove
2571 //------------------------------------------------------------------------
2572 
2573 template <class _ForwardIterator, class _UnaryPredicate>
2574 _ForwardIterator
__brick_remove_if(_ForwardIterator __first,_ForwardIterator __last,_UnaryPredicate __pred,std::false_type)2575 __brick_remove_if(_ForwardIterator __first, _ForwardIterator __last, _UnaryPredicate __pred,
2576                   /* __is_vector = */ std::false_type) noexcept
2577 {
2578     return std::remove_if(__first, __last, __pred);
2579 }
2580 
2581 template <class _RandomAccessIterator, class _UnaryPredicate>
2582 _RandomAccessIterator
__brick_remove_if(_RandomAccessIterator __first,_RandomAccessIterator __last,_UnaryPredicate __pred,std::true_type)2583 __brick_remove_if(_RandomAccessIterator __first, _RandomAccessIterator __last, _UnaryPredicate __pred,
2584                   /* __is_vector = */ std::true_type) noexcept
2585 {
2586 #if defined(_PSTL_MONOTONIC_PRESENT)
2587     return __unseq_backend::__simd_remove_if(__first, __last - __first, __pred);
2588 #else
2589     return std::remove_if(__first, __last, __pred);
2590 #endif
2591 }
2592 
2593 template <class _ExecutionPolicy, class _ForwardIterator, class _UnaryPredicate, class _IsVector>
2594 _ForwardIterator
__pattern_remove_if(_ExecutionPolicy &&,_ForwardIterator __first,_ForwardIterator __last,_UnaryPredicate __pred,_IsVector __is_vector,std::false_type)2595 __pattern_remove_if(_ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __last, _UnaryPredicate __pred,
2596                     _IsVector __is_vector, /*is_parallel*/ std::false_type) noexcept
2597 {
2598     return __internal::__brick_remove_if(__first, __last, __pred, __is_vector);
2599 }
2600 
2601 template <class _ExecutionPolicy, class _RandomAccessIterator, class _UnaryPredicate, class _IsVector>
2602 _RandomAccessIterator
__pattern_remove_if(_ExecutionPolicy && __exec,_RandomAccessIterator __first,_RandomAccessIterator __last,_UnaryPredicate __pred,_IsVector __is_vector,std::true_type)2603 __pattern_remove_if(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __last,
2604                     _UnaryPredicate __pred, _IsVector __is_vector, /*is_parallel*/ std::true_type) noexcept
2605 {
2606     typedef typename std::iterator_traits<_RandomAccessIterator>::reference _ReferenceType;
2607 
2608     if (__first == __last || __first + 1 == __last)
2609     {
2610         // Trivial sequence - use serial algorithm
2611         return __internal::__brick_remove_if(__first, __last, __pred, __is_vector);
2612     }
2613 
2614     return __internal::__remove_elements(
2615         std::forward<_ExecutionPolicy>(__exec), __first, __last,
2616         [&__pred, __is_vector](bool* __b, bool* __e, _RandomAccessIterator __it) {
2617             __internal::__brick_walk2(__b, __e, __it, [&__pred](bool& __x, _ReferenceType __y) { __x = !__pred(__y); },
2618                                       __is_vector);
2619         },
2620         __is_vector);
2621 }
2622 
2623 //------------------------------------------------------------------------
2624 // merge
2625 //------------------------------------------------------------------------
2626 
2627 template <class _ForwardIterator1, class _ForwardIterator2, class _OutputIterator, class _Compare>
2628 _OutputIterator
__brick_merge(_ForwardIterator1 __first1,_ForwardIterator1 __last1,_ForwardIterator2 __first2,_ForwardIterator2 __last2,_OutputIterator __d_first,_Compare __comp,std::false_type)2629 __brick_merge(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
2630               _ForwardIterator2 __last2, _OutputIterator __d_first, _Compare __comp,
2631               /* __is_vector = */ std::false_type) noexcept
2632 {
2633     return std::merge(__first1, __last1, __first2, __last2, __d_first, __comp);
2634 }
2635 
2636 template <class _RandomAccessIterator1, class _RandomAccessIterator2, class _RandomAccessIterator3, class _Compare>
2637 _RandomAccessIterator3
__brick_merge(_RandomAccessIterator1 __first1,_RandomAccessIterator1 __last1,_RandomAccessIterator2 __first2,_RandomAccessIterator2 __last2,_RandomAccessIterator3 __d_first,_Compare __comp,std::true_type)2638 __brick_merge(_RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1, _RandomAccessIterator2 __first2,
2639               _RandomAccessIterator2 __last2, _RandomAccessIterator3 __d_first, _Compare __comp,
2640               /* __is_vector = */ std::true_type) noexcept
2641 {
2642     _PSTL_PRAGMA_MESSAGE("Vectorized algorithm unimplemented, redirected to serial");
2643     return std::merge(__first1, __last1, __first2, __last2, __d_first, __comp);
2644 }
2645 
2646 template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _OutputIterator,
2647           class _Compare, class _IsVector>
2648 _OutputIterator
__pattern_merge(_ExecutionPolicy &&,_ForwardIterator1 __first1,_ForwardIterator1 __last1,_ForwardIterator2 __first2,_ForwardIterator2 __last2,_OutputIterator __d_first,_Compare __comp,_IsVector __is_vector,std::false_type)2649 __pattern_merge(_ExecutionPolicy&&, _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
2650                 _ForwardIterator2 __last2, _OutputIterator __d_first, _Compare __comp, _IsVector __is_vector,
2651                 /* is_parallel = */ std::false_type) noexcept
2652 {
2653     return __internal::__brick_merge(__first1, __last1, __first2, __last2, __d_first, __comp, __is_vector);
2654 }
2655 
2656 template <class _ExecutionPolicy, class _RandomAccessIterator1, class _RandomAccessIterator2,
2657           class _RandomAccessIterator3, class _Compare, class _IsVector>
2658 _RandomAccessIterator3
__pattern_merge(_ExecutionPolicy && __exec,_RandomAccessIterator1 __first1,_RandomAccessIterator1 __last1,_RandomAccessIterator2 __first2,_RandomAccessIterator2 __last2,_RandomAccessIterator3 __d_first,_Compare __comp,_IsVector __is_vector,std::true_type)2659 __pattern_merge(_ExecutionPolicy&& __exec, _RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1,
2660                 _RandomAccessIterator2 __first2, _RandomAccessIterator2 __last2, _RandomAccessIterator3 __d_first,
2661                 _Compare __comp, _IsVector __is_vector, /* is_parallel = */ std::true_type)
2662 {
2663     __par_backend::__parallel_merge(
2664         std::forward<_ExecutionPolicy>(__exec), __first1, __last1, __first2, __last2, __d_first, __comp,
2665         [__is_vector](_RandomAccessIterator1 __f1, _RandomAccessIterator1 __l1, _RandomAccessIterator2 __f2,
2666                       _RandomAccessIterator2 __l2, _RandomAccessIterator3 __f3, _Compare __comp) {
2667             return __internal::__brick_merge(__f1, __l1, __f2, __l2, __f3, __comp, __is_vector);
2668         });
2669     return __d_first + (__last1 - __first1) + (__last2 - __first2);
2670 }
2671 
2672 //------------------------------------------------------------------------
2673 // inplace_merge
2674 //------------------------------------------------------------------------
2675 template <class _BidirectionalIterator, class _Compare>
2676 void
__brick_inplace_merge(_BidirectionalIterator __first,_BidirectionalIterator __middle,_BidirectionalIterator __last,_Compare __comp,std::false_type)2677 __brick_inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last,
2678                       _Compare __comp, /* __is_vector = */ std::false_type) noexcept
2679 {
2680     std::inplace_merge(__first, __middle, __last, __comp);
2681 }
2682 
2683 template <class _RandomAccessIterator, class _Compare>
2684 void
__brick_inplace_merge(_RandomAccessIterator __first,_RandomAccessIterator __middle,_RandomAccessIterator __last,_Compare __comp,std::true_type)2685 __brick_inplace_merge(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last,
2686                       _Compare __comp, /* __is_vector = */ std::true_type) noexcept
2687 {
2688     _PSTL_PRAGMA_MESSAGE("Vectorized algorithm unimplemented, redirected to serial")
2689     std::inplace_merge(__first, __middle, __last, __comp);
2690 }
2691 
2692 template <class _ExecutionPolicy, class _BidirectionalIterator, class _Compare, class _IsVector>
2693 void
__pattern_inplace_merge(_ExecutionPolicy &&,_BidirectionalIterator __first,_BidirectionalIterator __middle,_BidirectionalIterator __last,_Compare __comp,_IsVector __is_vector,std::false_type)2694 __pattern_inplace_merge(_ExecutionPolicy&&, _BidirectionalIterator __first, _BidirectionalIterator __middle,
2695                         _BidirectionalIterator __last, _Compare __comp, _IsVector __is_vector,
2696                         /* is_parallel = */ std::false_type) noexcept
2697 {
2698     __internal::__brick_inplace_merge(__first, __middle, __last, __comp, __is_vector);
2699 }
2700 
2701 template <class _ExecutionPolicy, class _RandomAccessIterator, class _Compare, class _IsVector>
2702 void
__pattern_inplace_merge(_ExecutionPolicy && __exec,_RandomAccessIterator __first,_RandomAccessIterator __middle,_RandomAccessIterator __last,_Compare __comp,_IsVector __is_vector,std::true_type)2703 __pattern_inplace_merge(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __middle,
2704                         _RandomAccessIterator __last, _Compare __comp, _IsVector __is_vector,
2705                         /*is_parallel=*/std::true_type)
2706 {
2707     if (__first == __last || __first == __middle || __middle == __last)
2708     {
2709         return;
2710     }
2711     typedef typename std::iterator_traits<_RandomAccessIterator>::value_type _Tp;
2712     auto __n = __last - __first;
2713     __par_backend::__buffer<_Tp> __buf(__n);
2714     _Tp* __r = __buf.get();
2715     __internal::__except_handler([&]() {
2716         auto __move_values = [](_RandomAccessIterator __x, _Tp* __z) {
2717             __internal::__invoke_if_else(std::is_trivial<_Tp>(), [&]() { *__z = std::move(*__x); },
2718                                          [&]() { ::new (std::addressof(*__z)) _Tp(std::move(*__x)); });
2719         };
2720 
2721         auto __move_sequences = [](_RandomAccessIterator __first1, _RandomAccessIterator __last1, _Tp* __first2) {
2722             return __internal::__brick_uninitialized_move(__first1, __last1, __first2, _IsVector());
2723         };
2724 
2725         __par_backend::__parallel_merge(
2726             std::forward<_ExecutionPolicy>(__exec), __first, __middle, __middle, __last, __r, __comp,
2727             [__n, __move_values, __move_sequences](_RandomAccessIterator __f1, _RandomAccessIterator __l1,
2728                                                    _RandomAccessIterator __f2, _RandomAccessIterator __l2, _Tp* __f3,
2729                                                    _Compare __comp) {
2730                 (__utils::__serial_move_merge(__n))(__f1, __l1, __f2, __l2, __f3, __comp, __move_values, __move_values,
2731                                                     __move_sequences, __move_sequences);
2732                 return __f3 + (__l1 - __f1) + (__l2 - __f2);
2733             });
2734         __par_backend::__parallel_for(std::forward<_ExecutionPolicy>(__exec), __r, __r + __n,
2735                                       [__r, __first, __is_vector](_Tp* __i, _Tp* __j) {
2736                                           __brick_move_destroy()(__i, __j, __first + (__i - __r), __is_vector);
2737                                       });
2738     });
2739 }
2740 
2741 //------------------------------------------------------------------------
2742 // includes
2743 //------------------------------------------------------------------------
2744 
2745 template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _Compare, class _IsVector>
2746 bool
__pattern_includes(_ExecutionPolicy &&,_ForwardIterator1 __first1,_ForwardIterator1 __last1,_ForwardIterator2 __first2,_ForwardIterator2 __last2,_Compare __comp,_IsVector,std::false_type)2747 __pattern_includes(_ExecutionPolicy&&, _ForwardIterator1 __first1, _ForwardIterator1 __last1,
2748                    _ForwardIterator2 __first2, _ForwardIterator2 __last2, _Compare __comp, _IsVector,
2749                    /*is_parallel=*/std::false_type) noexcept
2750 {
2751     return std::includes(__first1, __last1, __first2, __last2, __comp);
2752 }
2753 
2754 template <class _ExecutionPolicy, class _RandomAccessIterator1, class _RandomAccessIterator2, class _Compare,
2755           class _IsVector>
2756 bool
__pattern_includes(_ExecutionPolicy && __exec,_RandomAccessIterator1 __first1,_RandomAccessIterator1 __last1,_RandomAccessIterator2 __first2,_RandomAccessIterator2 __last2,_Compare __comp,_IsVector,std::true_type)2757 __pattern_includes(_ExecutionPolicy&& __exec, _RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1,
2758                    _RandomAccessIterator2 __first2, _RandomAccessIterator2 __last2, _Compare __comp, _IsVector,
2759                    /*is_parallel=*/std::true_type)
2760 {
2761     if (__first2 >= __last2)
2762         return true;
2763 
2764     if (__first1 >= __last1 || __comp(*__first2, *__first1) || __comp(*(__last1 - 1), *(__last2 - 1)))
2765         return false;
2766 
2767     __first1 = std::lower_bound(__first1, __last1, *__first2, __comp);
2768     if (__first1 == __last1)
2769         return false;
2770 
2771     if (__last2 - __first2 == 1)
2772         return !__comp(*__first1, *__first2) && !__comp(*__first2, *__first1);
2773 
2774     return __internal::__except_handler([&]() {
2775         return !__internal::__parallel_or(
2776             std::forward<_ExecutionPolicy>(__exec), __first2, __last2,
2777             [__first1, __last1, __first2, __last2, &__comp](_RandomAccessIterator2 __i, _RandomAccessIterator2 __j) {
2778                 _PSTL_ASSERT(__j > __i);
2779                 //_PSTL_ASSERT(__j - __i > 1);
2780 
2781                 //1. moving boundaries to "consume" subsequence of equal elements
2782                 auto __is_equal = [&__comp](_RandomAccessIterator2 __a, _RandomAccessIterator2 __b) -> bool {
2783                     return !__comp(*__a, *__b) && !__comp(*__b, *__a);
2784                 };
2785 
2786                 //1.1 left bound, case "aaa[aaaxyz...]" - searching "x"
2787                 if (__i > __first2 && __is_equal(__i, __i - 1))
2788                 {
2789                     //whole subrange continues to content equal elements - return "no op"
2790                     if (__is_equal(__i, __j - 1))
2791                         return false;
2792 
2793                     __i = std::upper_bound(__i, __last2, *__i, __comp);
2794                 }
2795 
2796                 //1.2 right bound, case "[...aaa]aaaxyz" - searching "x"
2797                 if (__j < __last2 && __is_equal(__j - 1, __j))
2798                     __j = std::upper_bound(__j, __last2, *__j, __comp);
2799 
2800                 //2. testing is __a subsequence of the second range included into the first range
2801                 auto __b = std::lower_bound(__first1, __last1, *__i, __comp);
2802 
2803                 _PSTL_ASSERT(!__comp(*(__last1 - 1), *__b));
2804                 _PSTL_ASSERT(!__comp(*(__j - 1), *__i));
2805                 return !std::includes(__b, __last1, __i, __j, __comp);
2806             });
2807     });
2808 }
2809 
2810 constexpr auto __set_algo_cut_off = 1000;
2811 
2812 template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _OutputIterator,
2813           class _Compare, class _IsVector, class _SizeFunction, class _SetOP>
2814 _OutputIterator
__parallel_set_op(_ExecutionPolicy && __exec,_ForwardIterator1 __first1,_ForwardIterator1 __last1,_ForwardIterator2 __first2,_ForwardIterator2 __last2,_OutputIterator __result,_Compare __comp,_SizeFunction __size_func,_SetOP __set_op,_IsVector __is_vector)2815 __parallel_set_op(_ExecutionPolicy&& __exec, _ForwardIterator1 __first1, _ForwardIterator1 __last1,
2816                   _ForwardIterator2 __first2, _ForwardIterator2 __last2, _OutputIterator __result, _Compare __comp,
2817                   _SizeFunction __size_func, _SetOP __set_op, _IsVector __is_vector)
2818 {
2819     typedef typename std::iterator_traits<_ForwardIterator1>::difference_type _DifferenceType;
2820     typedef typename std::iterator_traits<_OutputIterator>::value_type _Tp;
2821 
2822     struct _SetRange
2823     {
2824         _DifferenceType __pos, __len, __buf_pos;
2825         bool
2826         empty() const
2827         {
2828             return __len == 0;
2829         }
2830     };
2831 
2832     const _DifferenceType __n1 = __last1 - __first1;
2833     const _DifferenceType __n2 = __last2 - __first2;
2834 
2835     __par_backend::__buffer<_Tp> __buf(__size_func(__n1, __n2));
2836 
2837     return __internal::__except_handler([&__exec, __n1, __first1, __last1, __first2, __last2, __result, __is_vector,
2838                                          __comp, __size_func, __set_op, &__buf]() {
2839         auto __buffer = __buf.get();
2840         _DifferenceType __m{};
2841         auto __scan = [=](_DifferenceType, _DifferenceType, const _SetRange& __s) { // Scan
2842             if (!__s.empty())
2843                 __brick_move_destroy()(__buffer + __s.__buf_pos, __buffer + (__s.__buf_pos + __s.__len),
2844                                        __result + __s.__pos, __is_vector);
2845         };
2846         __par_backend::__parallel_strict_scan(
2847             std::forward<_ExecutionPolicy>(__exec), __n1, _SetRange{0, 0, 0}, //-1, 0},
2848             [=](_DifferenceType __i, _DifferenceType __len) {                 // Reduce
2849                 //[__b; __e) - a subrange of the first sequence, to reduce
2850                 _ForwardIterator1 __b = __first1 + __i, __e = __first1 + (__i + __len);
2851 
2852                 //try searching for the first element which not equal to *__b
2853                 if (__b != __first1)
2854                     __b = std::upper_bound(__b, __last1, *__b, __comp);
2855 
2856                 //try searching for the first element which not equal to *__e
2857                 if (__e != __last1)
2858                     __e = std::upper_bound(__e, __last1, *__e, __comp);
2859 
2860                 //check is [__b; __e) empty
2861                 if (__e - __b < 1)
2862                 {
2863                     _ForwardIterator2 __bb = __last2;
2864                     if (__b != __last1)
2865                         __bb = std::lower_bound(__first2, __last2, *__b, __comp);
2866 
2867                     const _DifferenceType __buf_pos = __size_func((__b - __first1), (__bb - __first2));
2868                     return _SetRange{0, 0, __buf_pos};
2869                 }
2870 
2871                 //try searching for "corresponding" subrange [__bb; __ee) in the second sequence
2872                 _ForwardIterator2 __bb = __first2;
2873                 if (__b != __first1)
2874                     __bb = std::lower_bound(__first2, __last2, *__b, __comp);
2875 
2876                 _ForwardIterator2 __ee = __last2;
2877                 if (__e != __last1)
2878                     __ee = std::lower_bound(__bb, __last2, *__e, __comp);
2879 
2880                 const _DifferenceType __buf_pos = __size_func((__b - __first1), (__bb - __first2));
2881                 auto __buffer_b = __buffer + __buf_pos;
2882                 auto __res = __set_op(__b, __e, __bb, __ee, __buffer_b, __comp);
2883 
2884                 return _SetRange{0, __res - __buffer_b, __buf_pos};
2885             },
2886             [](const _SetRange& __a, const _SetRange& __b) { // Combine
2887                 if (__b.__buf_pos > __a.__buf_pos || ((__b.__buf_pos == __a.__buf_pos) && !__b.empty()))
2888                     return _SetRange{__a.__pos + __a.__len + __b.__pos, __b.__len, __b.__buf_pos};
2889                 return _SetRange{__b.__pos + __b.__len + __a.__pos, __a.__len, __a.__buf_pos};
2890             },
2891             __scan,                                     // Scan
2892             [&__m, &__scan](const _SetRange& __total) { // Apex
2893                 //final scan
2894                 __scan(0, 0, __total);
2895                 __m = __total.__pos + __total.__len;
2896             });
2897         return __result + __m;
2898     });
2899 }
2900 
2901 //a shared parallel pattern for '__pattern_set_union' and '__pattern_set_symmetric_difference'
2902 template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _OutputIterator,
2903           class _Compare, class _SetUnionOp, class _IsVector>
2904 _OutputIterator
__parallel_set_union_op(_ExecutionPolicy && __exec,_ForwardIterator1 __first1,_ForwardIterator1 __last1,_ForwardIterator2 __first2,_ForwardIterator2 __last2,_OutputIterator __result,_Compare __comp,_SetUnionOp __set_union_op,_IsVector __is_vector)2905 __parallel_set_union_op(_ExecutionPolicy&& __exec, _ForwardIterator1 __first1, _ForwardIterator1 __last1,
2906                         _ForwardIterator2 __first2, _ForwardIterator2 __last2, _OutputIterator __result,
2907                         _Compare __comp, _SetUnionOp __set_union_op, _IsVector __is_vector)
2908 {
2909     typedef typename std::iterator_traits<_ForwardIterator1>::difference_type _DifferenceType;
2910 
2911     const auto __n1 = __last1 - __first1;
2912     const auto __n2 = __last2 - __first2;
2913 
2914     auto copy_range1 = [__is_vector](_ForwardIterator1 __begin, _ForwardIterator1 __end, _OutputIterator __res) {
2915         return __internal::__brick_copy(__begin, __end, __res, __is_vector);
2916     };
2917     auto copy_range2 = [__is_vector](_ForwardIterator2 __begin, _ForwardIterator2 __end, _OutputIterator __res) {
2918         return __internal::__brick_copy(__begin, __end, __res, __is_vector);
2919     };
2920 
2921     // {1} {}: parallel copying just first sequence
2922     if (__n2 == 0)
2923         return __internal::__pattern_walk2_brick(std::forward<_ExecutionPolicy>(__exec), __first1, __last1, __result,
2924                                                  copy_range1, std::true_type());
2925 
2926     // {} {2}: parallel copying justmake  second sequence
2927     if (__n1 == 0)
2928         return __internal::__pattern_walk2_brick(std::forward<_ExecutionPolicy>(__exec), __first2, __last2, __result,
2929                                                  copy_range2, std::true_type());
2930 
2931     // testing  whether the sequences are intersected
2932     _ForwardIterator1 __left_bound_seq_1 = std::lower_bound(__first1, __last1, *__first2, __comp);
2933 
2934     if (__left_bound_seq_1 == __last1)
2935     {
2936         //{1} < {2}: seq2 is wholly greater than seq1, so, do parallel copying seq1 and seq2
2937         __par_backend::__parallel_invoke(
2938             std::forward<_ExecutionPolicy>(__exec),
2939             [=] {
2940                 __internal::__pattern_walk2_brick(std::forward<_ExecutionPolicy>(__exec), __first1, __last1, __result,
2941                                                   copy_range1, std::true_type());
2942             },
2943             [=] {
2944                 __internal::__pattern_walk2_brick(std::forward<_ExecutionPolicy>(__exec), __first2, __last2,
2945                                                   __result + __n1, copy_range2, std::true_type());
2946             });
2947         return __result + __n1 + __n2;
2948     }
2949 
2950     // testing  whether the sequences are intersected
2951     _ForwardIterator2 __left_bound_seq_2 = std::lower_bound(__first2, __last2, *__first1, __comp);
2952 
2953     if (__left_bound_seq_2 == __last2)
2954     {
2955         //{2} < {1}: seq2 is wholly greater than seq1, so, do parallel copying seq1 and seq2
2956         __par_backend::__parallel_invoke(
2957             std::forward<_ExecutionPolicy>(__exec),
2958             [=] {
2959                 __internal::__pattern_walk2_brick(std::forward<_ExecutionPolicy>(__exec), __first2, __last2, __result,
2960                                                   copy_range2, std::true_type());
2961             },
2962             [=] {
2963                 __internal::__pattern_walk2_brick(std::forward<_ExecutionPolicy>(__exec), __first1, __last1,
2964                                                   __result + __n2, copy_range1, std::true_type());
2965             });
2966         return __result + __n1 + __n2;
2967     }
2968 
2969     const auto __m1 = __left_bound_seq_1 - __first1;
2970     if (__m1 > __set_algo_cut_off)
2971     {
2972         auto __res_or = __result;
2973         __result += __m1; //we know proper offset due to [first1; left_bound_seq_1) < [first2; last2)
2974         __par_backend::__parallel_invoke(
2975             std::forward<_ExecutionPolicy>(__exec),
2976             //do parallel copying of [first1; left_bound_seq_1)
2977             [=] {
2978                 __internal::__pattern_walk2_brick(std::forward<_ExecutionPolicy>(__exec), __first1, __left_bound_seq_1,
2979                                                   __res_or, copy_range1, std::true_type());
2980             },
2981             [=, &__result] {
2982                 __result = __internal::__parallel_set_op(
2983                     std::forward<_ExecutionPolicy>(__exec), __left_bound_seq_1, __last1, __first2, __last2, __result,
2984                     __comp, [](_DifferenceType __n, _DifferenceType __m) { return __n + __m; }, __set_union_op,
2985                     __is_vector);
2986             });
2987         return __result;
2988     }
2989 
2990     const auto __m2 = __left_bound_seq_2 - __first2;
2991     _PSTL_ASSERT(__m1 == 0 || __m2 == 0);
2992     if (__m2 > __set_algo_cut_off)
2993     {
2994         auto __res_or = __result;
2995         __result += __m2; //we know proper offset due to [first2; left_bound_seq_2) < [first1; last1)
2996         __par_backend::__parallel_invoke(
2997             std::forward<_ExecutionPolicy>(__exec),
2998             //do parallel copying of [first2; left_bound_seq_2)
2999             [=] {
3000                 __internal::__pattern_walk2_brick(std::forward<_ExecutionPolicy>(__exec), __first2, __left_bound_seq_2,
3001                                                   __res_or, copy_range2, std::true_type());
3002             },
3003             [=, &__result] {
3004                 __result = __internal::__parallel_set_op(
3005                     std::forward<_ExecutionPolicy>(__exec), __first1, __last1, __left_bound_seq_2, __last2, __result,
3006                     __comp, [](_DifferenceType __n, _DifferenceType __m) { return __n + __m; }, __set_union_op,
3007                     __is_vector);
3008             });
3009         return __result;
3010     }
3011 
3012     return __internal::__parallel_set_op(
3013         std::forward<_ExecutionPolicy>(__exec), __first1, __last1, __first2, __last2, __result, __comp,
3014         [](_DifferenceType __n, _DifferenceType __m) { return __n + __m; }, __set_union_op, __is_vector);
3015 }
3016 
3017 //------------------------------------------------------------------------
3018 // set_union
3019 //------------------------------------------------------------------------
3020 
3021 template <class _ForwardIterator1, class _ForwardIterator2, class _OutputIterator, class _Compare>
3022 _OutputIterator
__brick_set_union(_ForwardIterator1 __first1,_ForwardIterator1 __last1,_ForwardIterator2 __first2,_ForwardIterator2 __last2,_OutputIterator __result,_Compare __comp,std::false_type)3023 __brick_set_union(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
3024                   _ForwardIterator2 __last2, _OutputIterator __result, _Compare __comp,
3025                   /*__is_vector=*/std::false_type) noexcept
3026 {
3027     return std::set_union(__first1, __last1, __first2, __last2, __result, __comp);
3028 }
3029 
3030 template <typename _IsVector>
3031 struct __BrickCopyConstruct
3032 {
3033     template <typename _ForwardIterator, typename _OutputIterator>
3034     _OutputIterator
operator__BrickCopyConstruct3035     operator()(_ForwardIterator __first, _ForwardIterator __last, _OutputIterator __result)
3036     {
3037         return __brick_uninitialized_copy(__first, __last, __result, _IsVector());
3038     }
3039 };
3040 
3041 template <class _RandomAccessIterator1, class _RandomAccessIterator2, class _OutputIterator, class _Compare>
3042 _OutputIterator
__brick_set_union(_RandomAccessIterator1 __first1,_RandomAccessIterator1 __last1,_RandomAccessIterator2 __first2,_RandomAccessIterator2 __last2,_OutputIterator __result,_Compare __comp,std::true_type)3043 __brick_set_union(_RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1, _RandomAccessIterator2 __first2,
3044                   _RandomAccessIterator2 __last2, _OutputIterator __result, _Compare __comp,
3045                   /*__is_vector=*/std::true_type) noexcept
3046 {
3047     _PSTL_PRAGMA_MESSAGE("Vectorized algorithm unimplemented, redirected to serial");
3048     return std::set_union(__first1, __last1, __first2, __last2, __result, __comp);
3049 }
3050 
3051 template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _OutputIterator,
3052           class _Compare, class _IsVector>
3053 _OutputIterator
__pattern_set_union(_ExecutionPolicy &&,_ForwardIterator1 __first1,_ForwardIterator1 __last1,_ForwardIterator2 __first2,_ForwardIterator2 __last2,_OutputIterator __result,_Compare __comp,_IsVector __is_vector,std::false_type)3054 __pattern_set_union(_ExecutionPolicy&&, _ForwardIterator1 __first1, _ForwardIterator1 __last1,
3055                     _ForwardIterator2 __first2, _ForwardIterator2 __last2, _OutputIterator __result, _Compare __comp,
3056                     _IsVector __is_vector,
3057                     /*is_parallel=*/std::false_type) noexcept
3058 {
3059     return __internal::__brick_set_union(__first1, __last1, __first2, __last2, __result, __comp, __is_vector);
3060 }
3061 
3062 template <class _ExecutionPolicy, class _RandomAccessIterator1, class _RandomAccessIterator2, class _OutputIterator,
3063           class _Compare, class _IsVector>
3064 _OutputIterator
__pattern_set_union(_ExecutionPolicy && __exec,_RandomAccessIterator1 __first1,_RandomAccessIterator1 __last1,_RandomAccessIterator2 __first2,_RandomAccessIterator2 __last2,_OutputIterator __result,_Compare __comp,_IsVector __is_vector,std::true_type)3065 __pattern_set_union(_ExecutionPolicy&& __exec, _RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1,
3066                     _RandomAccessIterator2 __first2, _RandomAccessIterator2 __last2, _OutputIterator __result,
3067                     _Compare __comp, _IsVector __is_vector, /*__is_parallel=*/std::true_type)
3068 {
3069 
3070     const auto __n1 = __last1 - __first1;
3071     const auto __n2 = __last2 - __first2;
3072 
3073     // use serial algorithm
3074     if (__n1 + __n2 <= __set_algo_cut_off)
3075         return std::set_union(__first1, __last1, __first2, __last2, __result, __comp);
3076 
3077     typedef typename std::iterator_traits<_OutputIterator>::value_type _Tp;
3078     return __parallel_set_union_op(
3079         std::forward<_ExecutionPolicy>(__exec), __first1, __last1, __first2, __last2, __result, __comp,
3080         [](_RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1, _RandomAccessIterator2 __first2,
3081            _RandomAccessIterator2 __last2, _Tp* __result, _Compare __comp) {
3082             return __pstl::__utils::__set_union_construct(__first1, __last1, __first2, __last2, __result, __comp,
3083                                                           __BrickCopyConstruct<_IsVector>());
3084         },
3085         __is_vector);
3086 }
3087 
3088 //------------------------------------------------------------------------
3089 // set_intersection
3090 //------------------------------------------------------------------------
3091 
3092 template <class _ForwardIterator1, class _ForwardIterator2, class _OutputIterator, class _Compare>
3093 _OutputIterator
__brick_set_intersection(_ForwardIterator1 __first1,_ForwardIterator1 __last1,_ForwardIterator2 __first2,_ForwardIterator2 __last2,_OutputIterator __result,_Compare __comp,std::false_type)3094 __brick_set_intersection(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
3095                          _ForwardIterator2 __last2, _OutputIterator __result, _Compare __comp,
3096                          /*__is_vector=*/std::false_type) noexcept
3097 {
3098     return std::set_intersection(__first1, __last1, __first2, __last2, __result, __comp);
3099 }
3100 
3101 template <class _RandomAccessIterator1, class _RandomAccessIterator2, class _RandomAccessIterator3, class _Compare>
3102 _RandomAccessIterator3
__brick_set_intersection(_RandomAccessIterator1 __first1,_RandomAccessIterator1 __last1,_RandomAccessIterator2 __first2,_RandomAccessIterator2 __last2,_RandomAccessIterator3 __result,_Compare __comp,std::true_type)3103 __brick_set_intersection(_RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1,
3104                          _RandomAccessIterator2 __first2, _RandomAccessIterator2 __last2,
3105                          _RandomAccessIterator3 __result, _Compare __comp,
3106                          /*__is_vector=*/std::true_type) noexcept
3107 {
3108     _PSTL_PRAGMA_MESSAGE("Vectorized algorithm unimplemented, redirected to serial");
3109     return std::set_intersection(__first1, __last1, __first2, __last2, __result, __comp);
3110 }
3111 
3112 template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _OutputIterator,
3113           class _Compare, class _IsVector>
3114 _OutputIterator
__pattern_set_intersection(_ExecutionPolicy &&,_ForwardIterator1 __first1,_ForwardIterator1 __last1,_ForwardIterator2 __first2,_ForwardIterator2 __last2,_OutputIterator __result,_Compare __comp,_IsVector __is_vector,std::false_type)3115 __pattern_set_intersection(_ExecutionPolicy&&, _ForwardIterator1 __first1, _ForwardIterator1 __last1,
3116                            _ForwardIterator2 __first2, _ForwardIterator2 __last2, _OutputIterator __result,
3117                            _Compare __comp, _IsVector __is_vector, /*is_parallel=*/std::false_type) noexcept
3118 {
3119     return __internal::__brick_set_intersection(__first1, __last1, __first2, __last2, __result, __comp, __is_vector);
3120 }
3121 
3122 template <class _ExecutionPolicy, class _RandomAccessIterator1, class _RandomAccessIterator2,
3123           class _RandomAccessIterator3, class _Compare, class _IsVector>
3124 _RandomAccessIterator3
__pattern_set_intersection(_ExecutionPolicy && __exec,_RandomAccessIterator1 __first1,_RandomAccessIterator1 __last1,_RandomAccessIterator2 __first2,_RandomAccessIterator2 __last2,_RandomAccessIterator3 __result,_Compare __comp,_IsVector __is_vector,std::true_type)3125 __pattern_set_intersection(_ExecutionPolicy&& __exec, _RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1,
3126                            _RandomAccessIterator2 __first2, _RandomAccessIterator2 __last2,
3127                            _RandomAccessIterator3 __result, _Compare __comp, _IsVector __is_vector,
3128                            /*is_parallel=*/std::true_type)
3129 {
3130     typedef typename std::iterator_traits<_RandomAccessIterator3>::value_type _Tp;
3131     typedef typename std::iterator_traits<_RandomAccessIterator1>::difference_type _DifferenceType;
3132 
3133     const auto __n1 = __last1 - __first1;
3134     const auto __n2 = __last2 - __first2;
3135 
3136     // intersection is empty
3137     if (__n1 == 0 || __n2 == 0)
3138         return __result;
3139 
3140     // testing  whether the sequences are intersected
3141     _RandomAccessIterator1 __left_bound_seq_1 = std::lower_bound(__first1, __last1, *__first2, __comp);
3142     //{1} < {2}: seq 2 is wholly greater than seq 1, so, the intersection is empty
3143     if (__left_bound_seq_1 == __last1)
3144         return __result;
3145 
3146     // testing  whether the sequences are intersected
3147     _RandomAccessIterator2 __left_bound_seq_2 = std::lower_bound(__first2, __last2, *__first1, __comp);
3148     //{2} < {1}: seq 1 is wholly greater than seq 2, so, the intersection is empty
3149     if (__left_bound_seq_2 == __last2)
3150         return __result;
3151 
3152     const auto __m1 = __last1 - __left_bound_seq_1 + __n2;
3153     if (__m1 > __set_algo_cut_off)
3154     {
3155         //we know proper offset due to [first1; left_bound_seq_1) < [first2; last2)
3156         return __internal::__parallel_set_op(
3157             std::forward<_ExecutionPolicy>(__exec), __left_bound_seq_1, __last1, __first2, __last2, __result, __comp,
3158             [](_DifferenceType __n, _DifferenceType __m) { return std::min(__n, __m); },
3159             [](_RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1, _RandomAccessIterator2 __first2,
3160                _RandomAccessIterator2 __last2, _Tp* __result, _Compare __comp) {
3161                 return __pstl::__utils::__set_intersection_construct(__first1, __last1, __first2, __last2, __result,
3162                                                                      __comp);
3163             },
3164             __is_vector);
3165     }
3166 
3167     const auto __m2 = __last2 - __left_bound_seq_2 + __n1;
3168     if (__m2 > __set_algo_cut_off)
3169     {
3170         //we know proper offset due to [first2; left_bound_seq_2) < [first1; last1)
3171         __result = __internal::__parallel_set_op(
3172             std::forward<_ExecutionPolicy>(__exec), __first1, __last1, __left_bound_seq_2, __last2, __result, __comp,
3173             [](_DifferenceType __n, _DifferenceType __m) { return std::min(__n, __m); },
3174             [](_RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1, _RandomAccessIterator2 __first2,
3175                _RandomAccessIterator2 __last2, _Tp* __result, _Compare __comp) {
3176                 return __pstl::__utils::__set_intersection_construct(__first2, __last2, __first1, __last1, __result,
3177                                                                      __comp);
3178             },
3179             __is_vector);
3180         return __result;
3181     }
3182 
3183     // [left_bound_seq_1; last1) and [left_bound_seq_2; last2) - use serial algorithm
3184     return std::set_intersection(__left_bound_seq_1, __last1, __left_bound_seq_2, __last2, __result, __comp);
3185 }
3186 
3187 //------------------------------------------------------------------------
3188 // set_difference
3189 //------------------------------------------------------------------------
3190 
3191 template <class _ForwardIterator1, class _ForwardIterator2, class _OutputIterator, class _Compare>
3192 _OutputIterator
__brick_set_difference(_ForwardIterator1 __first1,_ForwardIterator1 __last1,_ForwardIterator2 __first2,_ForwardIterator2 __last2,_OutputIterator __result,_Compare __comp,std::false_type)3193 __brick_set_difference(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
3194                        _ForwardIterator2 __last2, _OutputIterator __result, _Compare __comp,
3195                        /*__is_vector=*/std::false_type) noexcept
3196 {
3197     return std::set_difference(__first1, __last1, __first2, __last2, __result, __comp);
3198 }
3199 
3200 template <class _RandomAccessIterator1, class _RandomAccessIterator2, class _RandomAccessIterator3, class _Compare>
3201 _RandomAccessIterator3
__brick_set_difference(_RandomAccessIterator1 __first1,_RandomAccessIterator1 __last1,_RandomAccessIterator2 __first2,_RandomAccessIterator2 __last2,_RandomAccessIterator3 __result,_Compare __comp,std::true_type)3202 __brick_set_difference(_RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1, _RandomAccessIterator2 __first2,
3203                        _RandomAccessIterator2 __last2, _RandomAccessIterator3 __result, _Compare __comp,
3204                        /*__is_vector=*/std::true_type) noexcept
3205 {
3206     _PSTL_PRAGMA_MESSAGE("Vectorized algorithm unimplemented, redirected to serial");
3207     return std::set_difference(__first1, __last1, __first2, __last2, __result, __comp);
3208 }
3209 
3210 template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _OutputIterator,
3211           class _Compare, class _IsVector>
3212 _OutputIterator
__pattern_set_difference(_ExecutionPolicy &&,_ForwardIterator1 __first1,_ForwardIterator1 __last1,_ForwardIterator2 __first2,_ForwardIterator2 __last2,_OutputIterator __result,_Compare __comp,_IsVector __is_vector,std::false_type)3213 __pattern_set_difference(_ExecutionPolicy&&, _ForwardIterator1 __first1, _ForwardIterator1 __last1,
3214                          _ForwardIterator2 __first2, _ForwardIterator2 __last2, _OutputIterator __result,
3215                          _Compare __comp, _IsVector __is_vector, /*is_parallel=*/std::false_type) noexcept
3216 {
3217     return __internal::__brick_set_difference(__first1, __last1, __first2, __last2, __result, __comp, __is_vector);
3218 }
3219 
3220 template <class _ExecutionPolicy, class _RandomAccessIterator1, class _RandomAccessIterator2,
3221           class _RandomAccessIterator3, class _Compare, class _IsVector>
3222 _RandomAccessIterator3
__pattern_set_difference(_ExecutionPolicy && __exec,_RandomAccessIterator1 __first1,_RandomAccessIterator1 __last1,_RandomAccessIterator2 __first2,_RandomAccessIterator2 __last2,_RandomAccessIterator3 __result,_Compare __comp,_IsVector __is_vector,std::true_type)3223 __pattern_set_difference(_ExecutionPolicy&& __exec, _RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1,
3224                          _RandomAccessIterator2 __first2, _RandomAccessIterator2 __last2,
3225                          _RandomAccessIterator3 __result, _Compare __comp, _IsVector __is_vector,
3226                          /*is_parallel=*/std::true_type)
3227 {
3228     typedef typename std::iterator_traits<_RandomAccessIterator3>::value_type _Tp;
3229     typedef typename std::iterator_traits<_RandomAccessIterator1>::difference_type _DifferenceType;
3230 
3231     const auto __n1 = __last1 - __first1;
3232     const auto __n2 = __last2 - __first2;
3233 
3234     // {} \ {2}: the difference is empty
3235     if (__n1 == 0)
3236         return __result;
3237 
3238     // {1} \ {}: parallel copying just first sequence
3239     if (__n2 == 0)
3240         return __internal::__pattern_walk2_brick(
3241             std::forward<_ExecutionPolicy>(__exec), __first1, __last1, __result,
3242             [__is_vector](_RandomAccessIterator1 __begin, _RandomAccessIterator1 __end, _RandomAccessIterator3 __res) {
3243                 return __internal::__brick_copy(__begin, __end, __res, __is_vector);
3244             },
3245             std::true_type());
3246 
3247     // testing  whether the sequences are intersected
3248     _RandomAccessIterator1 __left_bound_seq_1 = std::lower_bound(__first1, __last1, *__first2, __comp);
3249     //{1} < {2}: seq 2 is wholly greater than seq 1, so, parallel copying just first sequence
3250     if (__left_bound_seq_1 == __last1)
3251         return __internal::__pattern_walk2_brick(
3252             std::forward<_ExecutionPolicy>(__exec), __first1, __last1, __result,
3253             [__is_vector](_RandomAccessIterator1 __begin, _RandomAccessIterator1 __end, _RandomAccessIterator3 __res) {
3254                 return __internal::__brick_copy(__begin, __end, __res, __is_vector);
3255             },
3256             std::true_type());
3257 
3258     // testing  whether the sequences are intersected
3259     _RandomAccessIterator2 __left_bound_seq_2 = std::lower_bound(__first2, __last2, *__first1, __comp);
3260     //{2} < {1}: seq 1 is wholly greater than seq 2, so, parallel copying just first sequence
3261     if (__left_bound_seq_2 == __last2)
3262         return __internal::__pattern_walk2_brick(
3263             std::forward<_ExecutionPolicy>(__exec), __first1, __last1, __result,
3264             [__is_vector](_RandomAccessIterator1 __begin, _RandomAccessIterator1 __end, _RandomAccessIterator3 __res) {
3265                 return __internal::__brick_copy(__begin, __end, __res, __is_vector);
3266             },
3267             std::true_type());
3268 
3269     if (__n1 + __n2 > __set_algo_cut_off)
3270         return __parallel_set_op(
3271             std::forward<_ExecutionPolicy>(__exec), __first1, __last1, __first2, __last2, __result, __comp,
3272             [](_DifferenceType __n, _DifferenceType) { return __n; },
3273             [](_RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1, _RandomAccessIterator2 __first2,
3274                _RandomAccessIterator2 __last2, _Tp* __result, _Compare __comp) {
3275                 return __pstl::__utils::__set_difference_construct(__first1, __last1, __first2, __last2, __result,
3276                                                                    __comp, __BrickCopyConstruct<_IsVector>());
3277             },
3278             __is_vector);
3279 
3280     // use serial algorithm
3281     return std::set_difference(__first1, __last1, __first2, __last2, __result, __comp);
3282 }
3283 
3284 //------------------------------------------------------------------------
3285 // set_symmetric_difference
3286 //------------------------------------------------------------------------
3287 
3288 template <class _ForwardIterator1, class _ForwardIterator2, class _OutputIterator, class _Compare>
3289 _OutputIterator
__brick_set_symmetric_difference(_ForwardIterator1 __first1,_ForwardIterator1 __last1,_ForwardIterator2 __first2,_ForwardIterator2 __last2,_OutputIterator __result,_Compare __comp,std::false_type)3290 __brick_set_symmetric_difference(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
3291                                  _ForwardIterator2 __last2, _OutputIterator __result, _Compare __comp,
3292                                  /*__is_vector=*/std::false_type) noexcept
3293 {
3294     return std::set_symmetric_difference(__first1, __last1, __first2, __last2, __result, __comp);
3295 }
3296 
3297 template <class _RandomAccessIterator1, class _RandomAccessIterator2, class _RandomAccessIterator3, class _Compare>
3298 _RandomAccessIterator3
__brick_set_symmetric_difference(_RandomAccessIterator1 __first1,_RandomAccessIterator1 __last1,_RandomAccessIterator2 __first2,_RandomAccessIterator2 __last2,_RandomAccessIterator3 __result,_Compare __comp,std::true_type)3299 __brick_set_symmetric_difference(_RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1,
3300                                  _RandomAccessIterator2 __first2, _RandomAccessIterator2 __last2,
3301                                  _RandomAccessIterator3 __result, _Compare __comp,
3302                                  /*__is_vector=*/std::true_type) noexcept
3303 {
3304     _PSTL_PRAGMA_MESSAGE("Vectorized algorithm unimplemented, redirected to serial");
3305     return std::set_symmetric_difference(__first1, __last1, __first2, __last2, __result, __comp);
3306 }
3307 
3308 template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _OutputIterator,
3309           class _Compare, class _IsVector>
3310 _OutputIterator
__pattern_set_symmetric_difference(_ExecutionPolicy &&,_ForwardIterator1 __first1,_ForwardIterator1 __last1,_ForwardIterator2 __first2,_ForwardIterator2 __last2,_OutputIterator __result,_Compare __comp,_IsVector __is_vector,std::false_type)3311 __pattern_set_symmetric_difference(_ExecutionPolicy&&, _ForwardIterator1 __first1, _ForwardIterator1 __last1,
3312                                    _ForwardIterator2 __first2, _ForwardIterator2 __last2, _OutputIterator __result,
3313                                    _Compare __comp, _IsVector __is_vector, /*is_parallel=*/std::false_type) noexcept
3314 {
3315     return __internal::__brick_set_symmetric_difference(__first1, __last1, __first2, __last2, __result, __comp,
3316                                                         __is_vector);
3317 }
3318 
3319 template <class _ExecutionPolicy, class _RandomAccessIterator1, class _RandomAccessIterator2,
3320           class _RandomAccessIterator3, class _Compare, class _IsVector>
3321 _RandomAccessIterator3
__pattern_set_symmetric_difference(_ExecutionPolicy && __exec,_RandomAccessIterator1 __first1,_RandomAccessIterator1 __last1,_RandomAccessIterator2 __first2,_RandomAccessIterator2 __last2,_RandomAccessIterator3 __result,_Compare __comp,_IsVector __is_vector,std::true_type)3322 __pattern_set_symmetric_difference(_ExecutionPolicy&& __exec, _RandomAccessIterator1 __first1,
3323                                    _RandomAccessIterator1 __last1, _RandomAccessIterator2 __first2,
3324                                    _RandomAccessIterator2 __last2, _RandomAccessIterator3 __result, _Compare __comp,
3325                                    _IsVector __is_vector, /*is_parallel=*/std::true_type)
3326 {
3327 
3328     const auto __n1 = __last1 - __first1;
3329     const auto __n2 = __last2 - __first2;
3330 
3331     // use serial algorithm
3332     if (__n1 + __n2 <= __set_algo_cut_off)
3333         return std::set_symmetric_difference(__first1, __last1, __first2, __last2, __result, __comp);
3334 
3335     typedef typename std::iterator_traits<_RandomAccessIterator3>::value_type _Tp;
3336     return __internal::__parallel_set_union_op(
3337         std::forward<_ExecutionPolicy>(__exec), __first1, __last1, __first2, __last2, __result, __comp,
3338         [](_RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1, _RandomAccessIterator2 __first2,
3339            _RandomAccessIterator2 __last2, _Tp* __result, _Compare __comp) {
3340             return __pstl::__utils::__set_symmetric_difference_construct(__first1, __last1, __first2, __last2, __result,
3341                                                                          __comp, __BrickCopyConstruct<_IsVector>());
3342         },
3343         __is_vector);
3344 }
3345 
3346 //------------------------------------------------------------------------
3347 // is_heap_until
3348 //------------------------------------------------------------------------
3349 
3350 template <class _RandomAccessIterator, class _Compare>
3351 _RandomAccessIterator
__brick_is_heap_until(_RandomAccessIterator __first,_RandomAccessIterator __last,_Compare __comp,std::false_type)3352 __brick_is_heap_until(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp,
3353                       /* __is_vector = */ std::false_type) noexcept
3354 {
3355     return std::is_heap_until(__first, __last, __comp);
3356 }
3357 
3358 template <class _RandomAccessIterator, class _Compare>
3359 _RandomAccessIterator
__brick_is_heap_until(_RandomAccessIterator __first,_RandomAccessIterator __last,_Compare __comp,std::true_type)3360 __brick_is_heap_until(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp,
3361                       /* __is_vector = */ std::true_type) noexcept
3362 {
3363     if (__last - __first < 2)
3364         return __last;
3365     typedef typename std::iterator_traits<_RandomAccessIterator>::difference_type _SizeType;
3366     return __unseq_backend::__simd_first(
3367         __first, _SizeType(0), __last - __first,
3368         [&__comp](_RandomAccessIterator __it, _SizeType __i) { return __comp(__it[(__i - 1) / 2], __it[__i]); });
3369 }
3370 
3371 template <class _ExecutionPolicy, class _RandomAccessIterator, class _Compare, class _IsVector>
3372 _RandomAccessIterator
__pattern_is_heap_until(_ExecutionPolicy &&,_RandomAccessIterator __first,_RandomAccessIterator __last,_Compare __comp,_IsVector __is_vector,std::false_type)3373 __pattern_is_heap_until(_ExecutionPolicy&&, _RandomAccessIterator __first, _RandomAccessIterator __last,
3374                         _Compare __comp, _IsVector __is_vector, /* is_parallel = */ std::false_type) noexcept
3375 {
3376     return __internal::__brick_is_heap_until(__first, __last, __comp, __is_vector);
3377 }
3378 
3379 template <class _RandomAccessIterator, class _DifferenceType, class _Compare>
3380 _RandomAccessIterator
__is_heap_until_local(_RandomAccessIterator __first,_DifferenceType __begin,_DifferenceType __end,_Compare __comp,std::false_type)3381 __is_heap_until_local(_RandomAccessIterator __first, _DifferenceType __begin, _DifferenceType __end, _Compare __comp,
3382                       /* __is_vector = */ std::false_type) noexcept
3383 {
3384     _DifferenceType __i = __begin;
3385     for (; __i < __end; ++__i)
3386     {
3387         if (__comp(__first[(__i - 1) / 2], __first[__i]))
3388         {
3389             break;
3390         }
3391     }
3392     return __first + __i;
3393 }
3394 
3395 template <class _RandomAccessIterator, class _DifferenceType, class _Compare>
3396 _RandomAccessIterator
__is_heap_until_local(_RandomAccessIterator __first,_DifferenceType __begin,_DifferenceType __end,_Compare __comp,std::true_type)3397 __is_heap_until_local(_RandomAccessIterator __first, _DifferenceType __begin, _DifferenceType __end, _Compare __comp,
3398                       /* __is_vector = */ std::true_type) noexcept
3399 {
3400     return __unseq_backend::__simd_first(
3401         __first, __begin, __end,
3402         [&__comp](_RandomAccessIterator __it, _DifferenceType __i) { return __comp(__it[(__i - 1) / 2], __it[__i]); });
3403 }
3404 
3405 template <class _ExecutionPolicy, class _RandomAccessIterator, class _Compare, class _IsVector>
3406 _RandomAccessIterator
__pattern_is_heap_until(_ExecutionPolicy && __exec,_RandomAccessIterator __first,_RandomAccessIterator __last,_Compare __comp,_IsVector __is_vector,std::true_type)3407 __pattern_is_heap_until(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __last,
3408                         _Compare __comp, _IsVector __is_vector, /* is_parallel = */ std::true_type) noexcept
3409 {
3410     if (__last - __first < 2)
3411         return __last;
3412 
3413     return __internal::__except_handler([&]() {
3414         return __parallel_find(
3415             std::forward<_ExecutionPolicy>(__exec), __first, __last,
3416             [__first, __comp, __is_vector](_RandomAccessIterator __i, _RandomAccessIterator __j) {
3417                 return __internal::__is_heap_until_local(__first, __i - __first, __j - __first, __comp, __is_vector);
3418             },
3419             std::less<typename std::iterator_traits<_RandomAccessIterator>::difference_type>(), /*is_first=*/true);
3420     });
3421 }
3422 
3423 //------------------------------------------------------------------------
3424 // min_element
3425 //------------------------------------------------------------------------
3426 
3427 template <typename _ForwardIterator, typename _Compare>
3428 _ForwardIterator
__brick_min_element(_ForwardIterator __first,_ForwardIterator __last,_Compare __comp,std::false_type)3429 __brick_min_element(_ForwardIterator __first, _ForwardIterator __last, _Compare __comp,
3430                     /* __is_vector = */ std::false_type) noexcept
3431 {
3432     return std::min_element(__first, __last, __comp);
3433 }
3434 
3435 template <typename _RandomAccessIterator, typename _Compare>
3436 _RandomAccessIterator
__brick_min_element(_RandomAccessIterator __first,_RandomAccessIterator __last,_Compare __comp,std::true_type)3437 __brick_min_element(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp,
3438                     /* __is_vector = */ std::true_type) noexcept
3439 {
3440 #if defined(_PSTL_UDR_PRESENT)
3441     return __unseq_backend::__simd_min_element(__first, __last - __first, __comp);
3442 #else
3443     return std::min_element(__first, __last, __comp);
3444 #endif
3445 }
3446 
3447 template <typename _ExecutionPolicy, typename _ForwardIterator, typename _Compare, typename _IsVector>
3448 _ForwardIterator
__pattern_min_element(_ExecutionPolicy &&,_ForwardIterator __first,_ForwardIterator __last,_Compare __comp,_IsVector __is_vector,std::false_type)3449 __pattern_min_element(_ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __last, _Compare __comp,
3450                       _IsVector __is_vector, /* is_parallel = */ std::false_type) noexcept
3451 {
3452     return __internal::__brick_min_element(__first, __last, __comp, __is_vector);
3453 }
3454 
3455 template <typename _ExecutionPolicy, typename _RandomAccessIterator, typename _Compare, typename _IsVector>
3456 _RandomAccessIterator
__pattern_min_element(_ExecutionPolicy && __exec,_RandomAccessIterator __first,_RandomAccessIterator __last,_Compare __comp,_IsVector __is_vector,std::true_type)3457 __pattern_min_element(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __last,
3458                       _Compare __comp, _IsVector __is_vector, /* is_parallel = */ std::true_type)
3459 {
3460     if (__first == __last)
3461         return __last;
3462 
3463     return __internal::__except_handler([&]() {
3464         return __par_backend::__parallel_reduce(
3465             std::forward<_ExecutionPolicy>(__exec), __first + 1, __last, __first,
3466             [=](_RandomAccessIterator __begin, _RandomAccessIterator __end,
3467                 _RandomAccessIterator __init) -> _RandomAccessIterator {
3468                 const _RandomAccessIterator subresult =
3469                     __internal::__brick_min_element(__begin, __end, __comp, __is_vector);
3470                 return __internal::__cmp_iterators_by_values(__init, subresult, __comp);
3471             },
3472             [=](_RandomAccessIterator __it1, _RandomAccessIterator __it2) -> _RandomAccessIterator {
3473                 return __internal::__cmp_iterators_by_values(__it1, __it2, __comp);
3474             });
3475     });
3476 }
3477 
3478 //------------------------------------------------------------------------
3479 // minmax_element
3480 //------------------------------------------------------------------------
3481 
3482 template <typename _ForwardIterator, typename _Compare>
3483 std::pair<_ForwardIterator, _ForwardIterator>
__brick_minmax_element(_ForwardIterator __first,_ForwardIterator __last,_Compare __comp,std::false_type)3484 __brick_minmax_element(_ForwardIterator __first, _ForwardIterator __last, _Compare __comp,
3485                        /* __is_vector = */ std::false_type) noexcept
3486 {
3487     return std::minmax_element(__first, __last, __comp);
3488 }
3489 
3490 template <typename _RandomAccessIterator, typename _Compare>
3491 std::pair<_RandomAccessIterator, _RandomAccessIterator>
__brick_minmax_element(_RandomAccessIterator __first,_RandomAccessIterator __last,_Compare __comp,std::true_type)3492 __brick_minmax_element(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp,
3493                        /* __is_vector = */ std::true_type) noexcept
3494 {
3495 #if defined(_PSTL_UDR_PRESENT)
3496     return __unseq_backend::__simd_minmax_element(__first, __last - __first, __comp);
3497 #else
3498     return std::minmax_element(__first, __last, __comp);
3499 #endif
3500 }
3501 
3502 template <typename _ExecutionPolicy, typename _ForwardIterator, typename _Compare, typename _IsVector>
3503 std::pair<_ForwardIterator, _ForwardIterator>
__pattern_minmax_element(_ExecutionPolicy &&,_ForwardIterator __first,_ForwardIterator __last,_Compare __comp,_IsVector __is_vector,std::false_type)3504 __pattern_minmax_element(_ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __last, _Compare __comp,
3505                          _IsVector __is_vector, /* is_parallel = */ std::false_type) noexcept
3506 {
3507     return __internal::__brick_minmax_element(__first, __last, __comp, __is_vector);
3508 }
3509 
3510 template <typename _ExecutionPolicy, typename _RandomAccessIterator, typename _Compare, typename _IsVector>
3511 std::pair<_RandomAccessIterator, _RandomAccessIterator>
__pattern_minmax_element(_ExecutionPolicy && __exec,_RandomAccessIterator __first,_RandomAccessIterator __last,_Compare __comp,_IsVector __is_vector,std::true_type)3512 __pattern_minmax_element(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __last,
3513                          _Compare __comp, _IsVector __is_vector, /* is_parallel = */ std::true_type)
3514 {
3515     if (__first == __last)
3516         return std::make_pair(__first, __first);
3517 
3518     return __internal::__except_handler([&]() {
3519         typedef std::pair<_RandomAccessIterator, _RandomAccessIterator> _Result;
3520 
3521         return __par_backend::__parallel_reduce(
3522             std::forward<_ExecutionPolicy>(__exec), __first + 1, __last, std::make_pair(__first, __first),
3523             [=](_RandomAccessIterator __begin, _RandomAccessIterator __end, _Result __init) -> _Result {
3524                 const _Result __subresult = __internal::__brick_minmax_element(__begin, __end, __comp, __is_vector);
3525                 return std::make_pair(
3526                     __internal::__cmp_iterators_by_values(__subresult.first, __init.first, __comp),
3527                     __internal::__cmp_iterators_by_values(__init.second, __subresult.second, std::not_fn(__comp)));
3528             },
3529             [=](_Result __p1, _Result __p2) -> _Result {
3530                 return std::make_pair(
3531                     __internal::__cmp_iterators_by_values(__p1.first, __p2.first, __comp),
3532                     __internal::__cmp_iterators_by_values(__p2.second, __p1.second, std::not_fn(__comp)));
3533             });
3534     });
3535 }
3536 
3537 //------------------------------------------------------------------------
3538 // mismatch
3539 //------------------------------------------------------------------------
3540 template <class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
3541 std::pair<_ForwardIterator1, _ForwardIterator2>
__mismatch_serial(_ForwardIterator1 __first1,_ForwardIterator1 __last1,_ForwardIterator2 __first2,_ForwardIterator2 __last2,_BinaryPredicate __pred)3542 __mismatch_serial(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
3543                   _ForwardIterator2 __last2, _BinaryPredicate __pred)
3544 {
3545 #if defined(_PSTL_CPP14_2RANGE_MISMATCH_EQUAL_PRESENT)
3546     return std::mismatch(__first1, __last1, __first2, __last2, __pred);
3547 #else
3548     for (; __first1 != __last1 && __first2 != __last2 && __pred(*__first1, *__first2); ++__first1, ++__first2)
3549     {
3550     }
3551     return std::make_pair(__first1, __first2);
3552 #endif
3553 }
3554 
3555 template <class _ForwardIterator1, class _ForwardIterator2, class _Predicate>
3556 std::pair<_ForwardIterator1, _ForwardIterator2>
__brick_mismatch(_ForwardIterator1 __first1,_ForwardIterator1 __last1,_ForwardIterator2 __first2,_ForwardIterator2 __last2,_Predicate __pred,std::false_type)3557 __brick_mismatch(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
3558                  _ForwardIterator2 __last2, _Predicate __pred, /* __is_vector = */ std::false_type) noexcept
3559 {
3560     return __mismatch_serial(__first1, __last1, __first2, __last2, __pred);
3561 }
3562 
3563 template <class _RandomAccessIterator1, class _RandomAccessIterator2, class _Predicate>
3564 std::pair<_RandomAccessIterator1, _RandomAccessIterator2>
__brick_mismatch(_RandomAccessIterator1 __first1,_RandomAccessIterator1 __last1,_RandomAccessIterator2 __first2,_RandomAccessIterator2 __last2,_Predicate __pred,std::true_type)3565 __brick_mismatch(_RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1, _RandomAccessIterator2 __first2,
3566                  _RandomAccessIterator2 __last2, _Predicate __pred, /* __is_vector = */ std::true_type) noexcept
3567 {
3568     auto __n = std::min(__last1 - __first1, __last2 - __first2);
3569     return __unseq_backend::__simd_first(__first1, __n, __first2, std::not_fn(__pred));
3570 }
3571 
3572 template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _Predicate, class _IsVector>
3573 std::pair<_ForwardIterator1, _ForwardIterator2>
__pattern_mismatch(_ExecutionPolicy &&,_ForwardIterator1 __first1,_ForwardIterator1 __last1,_ForwardIterator2 __first2,_ForwardIterator2 __last2,_Predicate __pred,_IsVector __is_vector,std::false_type)3574 __pattern_mismatch(_ExecutionPolicy&&, _ForwardIterator1 __first1, _ForwardIterator1 __last1,
3575                    _ForwardIterator2 __first2, _ForwardIterator2 __last2, _Predicate __pred, _IsVector __is_vector,
3576                    /* is_parallel = */ std::false_type) noexcept
3577 {
3578     return __internal::__brick_mismatch(__first1, __last1, __first2, __last2, __pred, __is_vector);
3579 }
3580 
3581 template <class _ExecutionPolicy, class _RandomAccessIterator1, class _RandomAccessIterator2, class _Predicate,
3582           class _IsVector>
3583 std::pair<_RandomAccessIterator1, _RandomAccessIterator2>
__pattern_mismatch(_ExecutionPolicy && __exec,_RandomAccessIterator1 __first1,_RandomAccessIterator1 __last1,_RandomAccessIterator2 __first2,_RandomAccessIterator2 __last2,_Predicate __pred,_IsVector __is_vector,std::true_type)3584 __pattern_mismatch(_ExecutionPolicy&& __exec, _RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1,
3585                    _RandomAccessIterator2 __first2, _RandomAccessIterator2 __last2, _Predicate __pred,
3586                    _IsVector __is_vector, /* is_parallel = */ std::true_type) noexcept
3587 {
3588     return __internal::__except_handler([&]() {
3589         auto __n = std::min(__last1 - __first1, __last2 - __first2);
3590         auto __result = __internal::__parallel_find(
3591             std::forward<_ExecutionPolicy>(__exec), __first1, __first1 + __n,
3592             [__first1, __first2, __pred, __is_vector](_RandomAccessIterator1 __i, _RandomAccessIterator1 __j) {
3593                 return __internal::__brick_mismatch(__i, __j, __first2 + (__i - __first1), __first2 + (__j - __first1),
3594                                                     __pred, __is_vector)
3595                     .first;
3596             },
3597             std::less<typename std::iterator_traits<_RandomAccessIterator1>::difference_type>(), /*is_first=*/true);
3598         return std::make_pair(__result, __first2 + (__result - __first1));
3599     });
3600 }
3601 
3602 //------------------------------------------------------------------------
3603 // lexicographical_compare
3604 //------------------------------------------------------------------------
3605 
3606 template <class _ForwardIterator1, class _ForwardIterator2, class _Compare>
3607 bool
__brick_lexicographical_compare(_ForwardIterator1 __first1,_ForwardIterator1 __last1,_ForwardIterator2 __first2,_ForwardIterator2 __last2,_Compare __comp,std::false_type)3608 __brick_lexicographical_compare(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
3609                                 _ForwardIterator2 __last2, _Compare __comp,
3610                                 /* __is_vector = */ std::false_type) noexcept
3611 {
3612     return std::lexicographical_compare(__first1, __last1, __first2, __last2, __comp);
3613 }
3614 
3615 template <class _RandomAccessIterator1, class _RandomAccessIterator2, class _Compare>
3616 bool
__brick_lexicographical_compare(_RandomAccessIterator1 __first1,_RandomAccessIterator1 __last1,_RandomAccessIterator2 __first2,_RandomAccessIterator2 __last2,_Compare __comp,std::true_type)3617 __brick_lexicographical_compare(_RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1,
3618                                 _RandomAccessIterator2 __first2, _RandomAccessIterator2 __last2, _Compare __comp,
3619                                 /* __is_vector = */ std::true_type) noexcept
3620 {
3621     if (__first2 == __last2)
3622     { // if second sequence is empty
3623         return false;
3624     }
3625     else if (__first1 == __last1)
3626     { // if first sequence is empty
3627         return true;
3628     }
3629     else
3630     {
3631         typedef typename std::iterator_traits<_RandomAccessIterator1>::reference ref_type1;
3632         typedef typename std::iterator_traits<_RandomAccessIterator2>::reference ref_type2;
3633         --__last1;
3634         --__last2;
3635         auto __n = std::min(__last1 - __first1, __last2 - __first2);
3636         std::pair<_RandomAccessIterator1, _RandomAccessIterator2> __result = __unseq_backend::__simd_first(
3637             __first1, __n, __first2, [__comp](const ref_type1 __x, const ref_type2 __y) mutable {
3638                 return __comp(__x, __y) || __comp(__y, __x);
3639             });
3640 
3641         if (__result.first == __last1 && __result.second != __last2)
3642         { // if first sequence shorter than second
3643             return !__comp(*__result.second, *__result.first);
3644         }
3645         else
3646         { // if second sequence shorter than first or both have the same number of elements
3647             return __comp(*__result.first, *__result.second);
3648         }
3649     }
3650 }
3651 
3652 template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _Compare, class _IsVector>
3653 bool
__pattern_lexicographical_compare(_ExecutionPolicy &&,_ForwardIterator1 __first1,_ForwardIterator1 __last1,_ForwardIterator2 __first2,_ForwardIterator2 __last2,_Compare __comp,_IsVector __is_vector,std::false_type)3654 __pattern_lexicographical_compare(_ExecutionPolicy&&, _ForwardIterator1 __first1, _ForwardIterator1 __last1,
3655                                   _ForwardIterator2 __first2, _ForwardIterator2 __last2, _Compare __comp,
3656                                   _IsVector __is_vector, /* is_parallel = */ std::false_type) noexcept
3657 {
3658     return __internal::__brick_lexicographical_compare(__first1, __last1, __first2, __last2, __comp, __is_vector);
3659 }
3660 
3661 template <class _ExecutionPolicy, class _RandomAccessIterator1, class _RandomAccessIterator2, class _Compare,
3662           class _IsVector>
3663 bool
__pattern_lexicographical_compare(_ExecutionPolicy && __exec,_RandomAccessIterator1 __first1,_RandomAccessIterator1 __last1,_RandomAccessIterator2 __first2,_RandomAccessIterator2 __last2,_Compare __comp,_IsVector __is_vector,std::true_type)3664 __pattern_lexicographical_compare(_ExecutionPolicy&& __exec, _RandomAccessIterator1 __first1,
3665                                   _RandomAccessIterator1 __last1, _RandomAccessIterator2 __first2,
3666                                   _RandomAccessIterator2 __last2, _Compare __comp, _IsVector __is_vector,
3667                                   /* is_parallel = */ std::true_type) noexcept
3668 {
3669     if (__first2 == __last2)
3670     { // if second sequence is empty
3671         return false;
3672     }
3673     else if (__first1 == __last1)
3674     { // if first sequence is empty
3675         return true;
3676     }
3677     else
3678     {
3679         typedef typename std::iterator_traits<_RandomAccessIterator1>::reference _RefType1;
3680         typedef typename std::iterator_traits<_RandomAccessIterator2>::reference _RefType2;
3681         --__last1;
3682         --__last2;
3683         auto __n = std::min(__last1 - __first1, __last2 - __first2);
3684         auto __result = __internal::__parallel_find(
3685             std::forward<_ExecutionPolicy>(__exec), __first1, __first1 + __n,
3686             [__first1, __first2, &__comp, __is_vector](_RandomAccessIterator1 __i, _RandomAccessIterator1 __j) {
3687                 return __internal::__brick_mismatch(__i, __j, __first2 + (__i - __first1), __first2 + (__j - __first1),
3688                                                     [&__comp](const _RefType1 __x, const _RefType2 __y) {
3689                                                         return !__comp(__x, __y) && !__comp(__y, __x);
3690                                                     },
3691                                                     __is_vector)
3692                     .first;
3693             },
3694             std::less<typename std::iterator_traits<_RandomAccessIterator1>::difference_type>(), /*is_first=*/true);
3695 
3696         if (__result == __last1 && __first2 + (__result - __first1) != __last2)
3697         { // if first sequence shorter than second
3698             return !__comp(*(__first2 + (__result - __first1)), *__result);
3699         }
3700         else
3701         { // if second sequence shorter than first or both have the same number of elements
3702             return __comp(*__result, *(__first2 + (__result - __first1)));
3703         }
3704     }
3705 }
3706 
3707 } // namespace __internal
3708 } // namespace __pstl
3709 
3710 _PSTL_HIDE_FROM_ABI_POP
3711 
3712 #endif /* _PSTL_ALGORITHM_IMPL_H */
3713