• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

STEllAR-GROUP / hpx / #848

07 Dec 2022 11:00PM CUT coverage: 86.456% (+0.6%) from 85.835%
#848

push

StellarBot
Merge #6096

6096: Forking Boost.Tokenizer r=hkaiser a=hkaiser

- flyby: remove more Boost headers that are not needed anymore

Working towards #3440 

Co-authored-by: Hartmut Kaiser <hartmut.kaiser@gmail.com>

525 of 525 new or added lines in 20 files covered. (100.0%)

173087 of 200202 relevant lines covered (86.46%)

1845223.38 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.97
/libs/core/algorithms/include/hpx/parallel/algorithms/partition.hpp
1
//  Copyright (c) 2014-2017 Hartmut Kaiser
2
//  Copyright (c)      2017 Taeguk Kwon
3
//  Copyright (c)      2021 Akhil J Nair
4
//
5
//  SPDX-License-Identifier: BSL-1.0
6
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
7
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8

9
#pragma once
10

11
#if defined(DOXYGEN)
12
namespace hpx {
13
    // clang-format off
14

15
    ///////////////////////////////////////////////////////////////////////////
16
    /// Reorders the elements in the range [first, last) in such a way that
17
    /// all elements for which the predicate \a pred returns true precede
18
    /// the elements for which the predicate \a pred returns false.
19
    /// Relative order of the elements is not preserved.
20
    ///
21
    /// \note   Complexity: At most 2 * (last - first) swaps.
22
    ///         Exactly \a last - \a first applications of the predicate and
23
    ///         projection.
24
    ///
25
    /// \tparam FwdIter     The type of the source iterators used (deduced).
26
    ///                     This iterator type must meet the requirements of a
27
    ///                     forward iterator.
28
    /// \tparam Pred        The type of the function/function object to use
29
    ///                     (deduced). Unlike its sequential form, the parallel
30
    ///                     overload of \a partition requires \a Pred to meet
31
    ///                     the requirements of \a CopyConstructible.
32
    /// \tparam Proj        The type of an optional projection function. This
33
    ///                     defaults to \a util::projection_identity
34
    ///
35
    /// \param first        Refers to the beginning of the sequence of elements
36
    ///                     the algorithm will be applied to.
37
    /// \param last         Refers to the end of the sequence of elements the
38
    ///                     algorithm will be applied to.
39
    /// \param pred         Specifies the function (or function object) which
40
    ///                     will be invoked for each of the elements in the
41
    ///                     sequence specified by [first, last). This is an
42
    ///                     unary predicate for partitioning the source
43
    ///                     iterators. The signature of
44
    ///                     this predicate should be equivalent to:
45
    ///                     \code
46
    ///                     bool pred(const Type &a);
47
    ///                     \endcode \n
48
    ///                     The signature does not need to have const&, but
49
    ///                     the function must not modify the objects passed to
50
    ///                     it. The type \a Type must be such that an object of
51
    ///                     type \a FwdIter can be dereferenced and then
52
    ///                     implicitly converted to Type.
53
    /// \param proj         Specifies the function (or function object) which
54
    ///                     will be invoked for each of the elements as a
55
    ///                     projection operation before the actual predicate
56
    ///                     \a is invoked.
57
    ///
58
    /// The assignments in the parallel \a partition algorithm invoked without
59
    /// an execution policy object execute in sequential order in the calling
60
    /// thread.
61
    ///
62
    /// \returns  The \a partition algorithm returns returns \a FwdIter.
63
    ///           The \a partition algorithm returns the iterator to
64
    ///           the first element of the second group.
65
    ///
66
    template <typename FwdIter, typename Pred,
67
        typename Proj = parallel::util::projection_identity>
68
    FwdIter partition(FwdIter first, FwdIter last,
69
        Pred&& pred, Proj&& proj = Proj());
70

71
    ///////////////////////////////////////////////////////////////////////////
72
    /// Reorders the elements in the range [first, last) in such a way that
73
    /// all elements for which the predicate \a pred returns true precede
74
    /// the elements for which the predicate \a pred returns false.
75
    /// Relative order of the elements is not preserved.
76
    ///
77
    /// \note   Complexity: At most 2 * (last - first) swaps.
78
    ///         Exactly \a last - \a first applications of the predicate and
79
    ///         projection.
80
    ///
81
    /// \tparam ExPolicy    The type of the execution policy to use (deduced).
82
    ///                     It describes the manner in which the execution
83
    ///                     of the algorithm may be parallelized and the manner
84
    ///                     in which it executes the assignments.
85
    /// \tparam FwdIter     The type of the source iterators used (deduced).
86
    ///                     This iterator type must meet the requirements of an
87
    ///                     forward iterator.
88
    /// \tparam Pred        The type of the function/function object to use
89
    ///                     (deduced). Unlike its sequential form, the parallel
90
    ///                     overload of \a partition requires \a Pred to meet
91
    ///                     the requirements of \a CopyConstructible.
92
    /// \tparam Proj        The type of an optional projection function. This
93
    ///                     defaults to \a util::projection_identity
94
    ///
95
    /// \param policy       The execution policy to use for the scheduling of
96
    ///                     the iterations.
97
    /// \param first        Refers to the beginning of the sequence of elements
98
    ///                     the algorithm will be applied to.
99
    /// \param last         Refers to the end of the sequence of elements the
100
    ///                     algorithm will be applied to.
101
    /// \param pred         Specifies the function (or function object) which
102
    ///                     will be invoked for each of the elements in the
103
    ///                     sequence specified by [first, last). This is an
104
    ///                     unary predicate for partitioning the source
105
    ///                     iterators. The signature of
106
    ///                     this predicate should be equivalent to:
107
    ///                     \code
108
    ///                     bool pred(const Type &a);
109
    ///                     \endcode \n
110
    ///                     The signature does not need to have const&, but
111
    ///                     the function must not modify the objects passed to
112
    ///                     it. The type \a Type must be such that an object of
113
    ///                     type \a FwdIter can be dereferenced and then
114
    ///                     implicitly converted to Type.
115
    /// \param proj         Specifies the function (or function object) which
116
    ///                     will be invoked for each of the elements as a
117
    ///                     projection operation before the actual predicate
118
    ///                     \a is invoked.
119
    ///
120
    /// The assignments in the parallel \a partition algorithm invoked with
121
    /// an execution policy object of type \a sequenced_policy
122
    /// execute in sequential order in the calling thread.
123
    ///
124
    /// The assignments in the parallel \a partition algorithm invoked with
125
    /// an execution policy object of type \a parallel_policy or
126
    /// \a parallel_task_policy are permitted to execute in an unordered
127
    /// fashion in unspecified threads, and indeterminately sequenced
128
    /// within each thread.
129
    ///
130
    /// \returns  The \a partition algorithm returns a \a hpx::future<FwdIter>
131
    ///           if the execution policy is of type \a parallel_task_policy
132
    ///           and returns \a FwdIter otherwise.
133
    ///           The \a partition algorithm returns the iterator to
134
    ///           the first element of the second group.
135
    ///
136
    template <typename ExPolicy, typename FwdIter, typename Pred,
137
        typename Proj = parallel::util::projection_identity>
138
    parallel::util::detail::algorithm_result_t<ExPolicy, FwdIter>
139
    partition(ExPolicy&& policy, FwdIter first, FwdIter last, Pred&& pred,
140
        Proj&& proj = Proj());
141

142
    ///////////////////////////////////////////////////////////////////////////
143
    /// Permutes the elements in the range [first, last) such that there exists
144
    /// an iterator i such that for every iterator j in the range [first, i)
145
    /// INVOKE(f, INVOKE (proj, *j)) != false, and for every iterator k in the
146
    /// range [i, last), INVOKE(f, INVOKE (proj, *k)) == false
147
    ///
148
    /// \note   Complexity: At most (last - first) * log(last - first) swaps,
149
    ///         but only linear number of swaps if there is enough extra memory.
150
    ///         Exactly \a last - \a first applications of the predicate and
151
    ///         projection.
152
    ///
153
    /// \tparam BidirIter   The type of the source iterators used (deduced).
154
    ///                     This iterator type must meet the requirements of a
155
    ///                     bidirectional iterator.
156
    /// \tparam F           The type of the function/function object to use
157
    ///                     (deduced). Unlike its sequential form, the parallel
158
    ///                     overload of \a transform requires \a F to meet the
159
    ///                     requirements of \a CopyConstructible.
160
    /// \tparam Proj        The type of an optional projection function. This
161
    ///                     defaults to \a util::projection_identity
162
    ///
163
    /// \param first        Refers to the beginning of the sequence of elements
164
    ///                     the algorithm will be applied to.
165
    /// \param last         Refers to the end of the sequence of elements the
166
    ///                     algorithm will be applied to.
167
    /// \param f            Unary predicate which returns true if the element
168
    ///                     should be ordered before other elements.
169
    ///                     Specifies the function (or function object) which
170
    ///                     will be invoked for each of the elements in the
171
    ///                     sequence specified by [first, last). The signature
172
    ///                     of this predicate should be equivalent to:
173
    ///                     \code
174
    ///                     bool fun(const Type &a);
175
    ///                     \endcode \n
176
    ///                     The signature does not need to have const&.
177
    ///                     The type \a Type must be such that an object of
178
    ///                     type \a BidirIter can be dereferenced and then
179
    ///                     implicitly converted to \a Type.
180
    /// \param proj         Specifies the function (or function object) which
181
    ///                     will be invoked for each of the elements as a
182
    ///                     projection operation before the actual predicate
183
    ///                     \a f is invoked.
184
    ///
185
    /// The invocations of \a f in the parallel \a stable_partition algorithm
186
    /// invoked without an execution policy object executes in sequential order
187
    /// in the calling thread.
188
    ///
189
    /// \returns  The \a stable_partition algorithm returns an iterator i such
190
    ///           that for every iterator j in the range [first, i), f(*j) !=
191
    ///           false INVOKE(f, INVOKE(proj, *j)) != false, and for every
192
    ///           iterator k in the range [i, last), f(*k) == false
193
    ///           INVOKE(f, INVOKE (proj, *k)) == false. The relative order of
194
    ///           the elements in both groups is preserved.
195
    ///
196
    template <typename BidirIter, typename F,
197
        typename Proj = parallel::util::projection_identity>
198
    BidirIter stable_partition(BidirIter first, BidirIter last, F&& f,
199
        Proj&& proj = Proj());
200

201
    ///////////////////////////////////////////////////////////////////////////
202
    /// Permutes the elements in the range [first, last) such that there exists
203
    /// an iterator i such that for every iterator j in the range [first, i)
204
    /// INVOKE(f, INVOKE (proj, *j)) != false, and for every iterator k in the
205
    /// range [i, last), INVOKE(f, INVOKE (proj, *k)) == false
206
    ///
207
    /// \note   Complexity: At most (last - first) * log(last - first) swaps,
208
    ///         but only linear number of swaps if there is enough extra memory.
209
    ///         Exactly \a last - \a first applications of the predicate and
210
    ///         projection.
211
    ///
212
    /// \tparam ExPolicy    The type of the execution policy to use (deduced).
213
    ///                     It describes the manner in which the execution
214
    ///                     of the algorithm may be parallelized and the manner
215
    ///                     in which it executes the invocations of \a f.
216
    /// \tparam BidirIter   The type of the source iterators used (deduced).
217
    ///                     This iterator type must meet the requirements of a
218
    ///                     bidirectional iterator.
219
    /// \tparam F           The type of the function/function object to use
220
    ///                     (deduced). Unlike its sequential form, the parallel
221
    ///                     overload of \a transform requires \a F to meet the
222
    ///                     requirements of \a CopyConstructible.
223
    /// \tparam Proj        The type of an optional projection function. This
224
    ///                     defaults to \a util::projection_identity
225
    ///
226
    /// \param policy       The execution policy to use for the scheduling of
227
    ///                     the iterations.
228
    /// \param first        Refers to the beginning of the sequence of elements
229
    ///                     the algorithm will be applied to.
230
    /// \param last         Refers to the end of the sequence of elements the
231
    ///                     algorithm will be applied to.
232
    /// \param f            Unary predicate which returns true if the element
233
    ///                     should be ordered before other elements.
234
    ///                     Specifies the function (or function object) which
235
    ///                     will be invoked for each of the elements in the
236
    ///                     sequence specified by [first, last). The signature
237
    ///                     of this predicate should be equivalent to:
238
    ///                     \code
239
    ///                     bool fun(const Type &a);
240
    ///                     \endcode \n
241
    ///                     The signature does not need to have const&.
242
    ///                     The type \a Type must be such that an object of
243
    ///                     type \a BidirIter can be dereferenced and then
244
    ///                     implicitly converted to \a Type.
245
    /// \param proj         Specifies the function (or function object) which
246
    ///                     will be invoked for each of the elements as a
247
    ///                     projection operation before the actual predicate
248
    ///                     \a f is invoked.
249
    ///
250
    /// The invocations of \a f in the parallel \a stable_partition algorithm
251
    /// invoked with an execution policy object of type
252
    /// \a sequenced_policy executes in sequential order in the
253
    /// calling thread.
254
    ///
255
    /// The invocations of \a f in the parallel \a stable_partition algorithm
256
    /// invoked with an execution policy object of type \a parallel_policy
257
    /// or \a parallel_task_policy are permitted to execute in an
258
    /// unordered fashion in unspecified threads, and indeterminately sequenced
259
    /// within each thread.
260
    ///
261
    /// \returns  The \a stable_partition algorithm returns an iterator i such
262
    ///           that for every iterator j in the range [first, i), f(*j) !=
263
    ///           false INVOKE(f, INVOKE(proj, *j)) != false, and for every
264
    ///           iterator k in the range [i, last), f(*k) == false
265
    ///           INVOKE(f, INVOKE (proj, *k)) == false. The relative order of
266
    ///           the elements in both groups is preserved.
267
    ///           If the execution policy is of type \a parallel_task_policy
268
    ///           the algorithm returns a \a future<> referring to this iterator.
269
    ///
270
    template <typename ExPolicy, typename BidirIter, typename F,
271
        typename Proj = parallel::util::projection_identity>
272
    parallel::util::detail::algorithm_result_t<ExPolicy, BidirIter>
273
    stable_partition(ExPolicy&& policy, BidirIter first, BidirIter last,
274
        F&& f, Proj&& proj = Proj());
275

276
    ///////////////////////////////////////////////////////////////////////////
277
    /// Copies the elements in the range, defined by [first, last),
278
    /// to two different ranges depending on the value returned by
279
    /// the predicate \a pred. The elements, that satisfy the predicate \a pred
280
    /// are copied to the range beginning at \a dest_true. The rest of
281
    /// the elements are copied to the range beginning at \a dest_false.
282
    /// The order of the elements is preserved.
283
    ///
284
    /// \note   Complexity: Performs not more than \a last - \a first
285
    ///         assignments, exactly \a last - \a first applications of the
286
    ///         predicate \a pred.
287
    ///
288
    /// \tparam FwdIter1    The type of the source iterators used (deduced).
289
    ///                     This iterator type must meet the requirements of an
290
    ///                     forward iterator.
291
    /// \tparam FwdIter2    The type of the iterator representing the
292
    ///                     destination range for the elements that satisfy
293
    ///                     the predicate \a pred (deduced).
294
    ///                     This iterator type must meet the requirements of an
295
    ///                     forward iterator.
296
    /// \tparam FwdIter3    The type of the iterator representing the
297
    ///                     destination range for the elements that don't
298
    ///                     satisfy the predicate \a pred (deduced).
299
    ///                     This iterator type must meet the requirements of an
300
    ///                     forward iterator.
301
    /// \tparam Pred        The type of the function/function object to use
302
    ///                     (deduced). Unlike its sequential form, the parallel
303
    ///                     overload of \a partition_copy requires \a Pred to
304
    ///                     meet the requirements of \a CopyConstructible.
305
    /// \tparam Proj        The type of an optional projection function. This
306
    ///                     defaults to \a util::projection_identity
307
    ///
308
    /// \param first        Refers to the beginning of the sequence of elements
309
    ///                     the algorithm will be applied to.
310
    /// \param last         Refers to the end of the sequence of elements the
311
    ///                     algorithm will be applied to.
312
    /// \param dest_true    Refers to the beginning of the destination range
313
    ///                     for the elements that satisfy the predicate \a pred
314
    /// \param dest_false   Refers to the beginning of the destination range
315
    ///                     for the elements that don't satisfy the predicate
316
    ///                     \a pred.
317
    /// \param pred         Specifies the function (or function object) which
318
    ///                     will be invoked for each of the elements in the
319
    ///                     sequence specified by [first, last). This is an
320
    ///                     unary predicate for partitioning the source
321
    ///                     iterators. The signature of
322
    ///                     this predicate should be equivalent to:
323
    ///                     \code
324
    ///                     bool pred(const Type &a);
325
    ///                     \endcode \n
326
    ///                     The signature does not need to have const&, but
327
    ///                     the function must not modify the objects passed to
328
    ///                     it. The type \a Type must be such that an object of
329
    ///                     type \a FwdIter1 can be dereferenced and then
330
    ///                     implicitly converted to Type.
331
    /// \param proj         Specifies the function (or function object) which
332
    ///                     will be invoked for each of the elements as a
333
    ///                     projection operation before the actual predicate
334
    ///                     \a is invoked.
335
    ///
336
    /// The assignments in the parallel \a partition_copy algorithm invoked
337
    /// without an execution policy object execute in sequential order in the
338
    /// calling thread.
339
    ///
340
    /// \returns  The \a partition_copy algorithm returns
341
    ///           \a std::pair<OutIter1, OutIter2>.
342
    ///           The \a partition_copy algorithm returns the pair of
343
    ///           the destination iterator to the end of the \a dest_true
344
    ///           range, and the destination iterator to the end of the \a
345
    ///           dest_false range.
346
    ///
347
    template <typename FwdIter1, typename FwdIter2, typename FwdIter3,
348
        typename Pred, typename Proj = parallel::util::projection_identity>
349
    std::pair<FwdIter2 ,FwdIter3>
350
    partition_copy(FwdIter1 first, FwdIter1 last,
351
        FwdIter2 dest_true, FwdIter3 dest_false, Pred&& pred,
352
        Proj&& proj = Proj());
353

354
    ///////////////////////////////////////////////////////////////////////////
355
    /// Copies the elements in the range, defined by [first, last),
356
    /// to two different ranges depending on the value returned by
357
    /// the predicate \a pred. The elements, that satisfy the predicate \a pred,
358
    /// are copied to the range beginning at \a dest_true. The rest of
359
    /// the elements are copied to the range beginning at \a dest_false.
360
    /// The order of the elements is preserved.
361
    ///
362
    /// \note   Complexity: Performs not more than \a last - \a first
363
    ///         assignments, exactly \a last - \a first applications of the
364
    ///         predicate \a pred.
365
    ///
366
    /// \tparam ExPolicy    The type of the execution policy to use (deduced).
367
    ///                     It describes the manner in which the execution
368
    ///                     of the algorithm may be parallelized and the manner
369
    ///                     in which it executes the assignments.
370
    /// \tparam FwdIter1    The type of the source iterators used (deduced).
371
    ///                     This iterator type must meet the requirements of an
372
    ///                     forward iterator.
373
    /// \tparam FwdIter2    The type of the iterator representing the
374
    ///                     destination range for the elements that satisfy
375
    ///                     the predicate \a pred (deduced).
376
    ///                     This iterator type must meet the requirements of an
377
    ///                     forward iterator.
378
    /// \tparam FwdIter3    The type of the iterator representing the
379
    ///                     destination range for the elements that don't
380
    ///                     satisfy the predicate \a pred (deduced).
381
    ///                     This iterator type must meet the requirements of an
382
    ///                     forward iterator.
383
    /// \tparam Pred        The type of the function/function object to use
384
    ///                     (deduced). Unlike its sequential form, the parallel
385
    ///                     overload of \a partition_copy requires \a Pred to
386
    ///                     meet the requirements of \a CopyConstructible.
387
    /// \tparam Proj        The type of an optional projection function. This
388
    ///                     defaults to \a util::projection_identity
389
    ///
390
    /// \param policy       The execution policy to use for the scheduling of
391
    ///                     the iterations.
392
    /// \param first        Refers to the beginning of the sequence of elements
393
    ///                     the algorithm will be applied to.
394
    /// \param last         Refers to the end of the sequence of elements the
395
    ///                     algorithm will be applied to.
396
    /// \param dest_true    Refers to the beginning of the destination range
397
    ///                     for the elements that satisfy the predicate \a pred
398
    /// \param dest_false   Refers to the beginning of the destination range
399
    ///                     for the elements that don't satisfy the predicate
400
    ///                     \a pred.
401
    /// \param pred         Specifies the function (or function object) which
402
    ///                     will be invoked for each of the elements in the
403
    ///                     sequence specified by [first, last). This is an
404
    ///                     unary predicate for partitioning the source
405
    ///                     iterators. The signature of
406
    ///                     this predicate should be equivalent to:
407
    ///                     \code
408
    ///                     bool pred(const Type &a);
409
    ///                     \endcode \n
410
    ///                     The signature does not need to have const&, but
411
    ///                     the function must not modify the objects passed to
412
    ///                     it. The type \a Type must be such that an object of
413
    ///                     type \a FwdIter1 can be dereferenced and then
414
    ///                     implicitly converted to Type.
415
    /// \param proj         Specifies the function (or function object) which
416
    ///                     will be invoked for each of the elements as a
417
    ///                     projection operation before the actual predicate
418
    ///                     \a is invoked.
419
    ///
420
    /// The assignments in the parallel \a partition_copy algorithm invoked
421
    /// with an execution policy object of type \a sequenced_policy
422
    /// execute in sequential order in the calling thread.
423
    ///
424
    /// The assignments in the parallel \a partition_copy algorithm invoked
425
    /// with an execution policy object of type \a parallel_policy or
426
    /// \a parallel_task_policy are permitted to execute in an unordered
427
    /// fashion in unspecified threads, and indeterminately sequenced
428
    /// within each thread.
429
    ///
430
    /// \returns  The \a partition_copy algorithm returns a
431
    ///           \a hpx::future<std::pair<OutIter1, OutIter2>>
432
    ///           if the execution policy is of type \a parallel_task_policy
433
    ///           and returns
434
    ///           \a std::pair<OutIter1, OutIter2> otherwise.
435
    ///           The \a partition_copy algorithm returns the pair of
436
    ///           the destination iterator to the end of the \a dest_true
437
    ///           range, and the destination iterator to the end of the \a
438
    ///           dest_false range.
439
    ///
440
    template <typename ExPolicy, typename FwdIter1, typename FwdIter2,
441
        typename FwdIter3, typename Pred,
442
        typename Proj = parallel::util::projection_identity>
443
    parallel::util::detail::algorithm_result_t
444
        <ExPolicy, std::pair<FwdIter2, FwdIter3>>
445
    partition_copy(ExPolicy&& policy, FwdIter1 first, FwdIter1 last,
446
        FwdIter2 dest_true, FwdIter3 dest_false, Pred&& pred, Proj&& proj = Proj());
447

448
    // clang-format on
449
}    // namespace hpx
450

451
#else    // DOXYGEN
452

453
#include <hpx/config.hpp>
454
#include <hpx/assert.hpp>
455
#include <hpx/concepts/concepts.hpp>
456
#include <hpx/functional/invoke.hpp>
457
#include <hpx/functional/traits/is_invocable.hpp>
458
#include <hpx/futures/future.hpp>
459
#include <hpx/iterator_support/traits/is_iterator.hpp>
460
#include <hpx/modules/async_local.hpp>
461
#include <hpx/synchronization/spinlock.hpp>
462
#include <hpx/type_support/unused.hpp>
463

464
#include <hpx/algorithms/traits/projected.hpp>
465
#include <hpx/execution/executors/execution.hpp>
466
#include <hpx/execution/executors/execution_information.hpp>
467
#include <hpx/execution/executors/execution_parameters.hpp>
468
#include <hpx/executors/exception_list.hpp>
469
#include <hpx/executors/execution_policy.hpp>
470
#include <hpx/parallel/algorithms/detail/advance_and_get_distance.hpp>
471
#include <hpx/parallel/algorithms/detail/advance_to_sentinel.hpp>
472
#include <hpx/parallel/algorithms/detail/dispatch.hpp>
473
#include <hpx/parallel/algorithms/detail/distance.hpp>
474
#include <hpx/parallel/util/detail/algorithm_result.hpp>
475
#include <hpx/parallel/util/detail/chunk_size.hpp>
476
#include <hpx/parallel/util/detail/handle_local_exceptions.hpp>
477
#include <hpx/parallel/util/detail/sender_util.hpp>
478
#include <hpx/parallel/util/invoke_projected.hpp>
479
#include <hpx/parallel/util/loop.hpp>
480
#include <hpx/parallel/util/projection_identity.hpp>
481
#include <hpx/parallel/util/scan_partitioner.hpp>
482
#include <hpx/parallel/util/transfer.hpp>
483
#include <hpx/parallel/util/zip_iterator.hpp>
484

485
#if !defined(HPX_HAVE_CXX17_SHARED_PTR_ARRAY)
486
#include <boost/shared_array.hpp>
487
#else
488
#include <memory>
489
#endif
490

491
#include <algorithm>
492
#include <cstddef>
493
#include <cstdint>
494
#include <exception>
495
#include <iterator>
496
#include <list>
497
#include <type_traits>
498
#include <utility>
499
#include <vector>
500

501
namespace hpx { namespace parallel { inline namespace v1 {
502

503
    template <typename Tuple>
504
    constexpr HPX_FORCEINLINE
505
        std::pair<typename hpx::tuple_element<1, Tuple>::type,
506
            typename hpx::tuple_element<2, Tuple>::type>
507
        tuple_to_pair(Tuple&& t)
72✔
508
    {
509
        return std::make_pair(hpx::get<1>(t), hpx::get<2>(t));
72✔
510
    }
511

512
    template <typename Tuple>
513
    hpx::future<std::pair<typename hpx::tuple_element<1, Tuple>::type,
514
        typename hpx::tuple_element<2, Tuple>::type>>
515
    tuple_to_pair(hpx::future<Tuple>&& f)
24✔
516
    {
517
        using result_type =
518
            std::pair<typename hpx::tuple_element<1, Tuple>::type,
519
                typename hpx::tuple_element<2, Tuple>::type>;
520

521
        return hpx::make_future<result_type>(
24✔
522
            HPX_MOVE(f), [](Tuple&& t) -> result_type {
36✔
523
                return tuple_to_pair(HPX_MOVE(t));
12✔
524
            });
525
    }
526

527
    ///////////////////////////////////////////////////////////////////////////
528
    // stable_partition
529
    namespace detail {
530
        /// \cond NOINTERNAL
531
        struct stable_partition_helper
532
        {
533
            template <typename ExPolicy, typename RandIter, typename F,
534
                typename Proj>
535
            hpx::future<RandIter> operator()(ExPolicy&& policy, RandIter first,
195✔
536
                RandIter last, std::size_t size, F&& f, Proj&& proj,
537
                std::size_t chunks)
538
            {
539
                if (chunks < 2)
195✔
540
                {
541
                    return execution::async_execute(policy.executor(),
208✔
542
                        [first, last, f = HPX_FORWARD(F, f),
208✔
543
                            proj = HPX_FORWARD(Proj, proj)]() -> RandIter {
104✔
544
                            return std::stable_partition(first, last,
208✔
545
                                util::invoke_projected<F, Proj>(f, proj));
104✔
546
                        });
547
                }
548

549
                std::size_t mid_point = size / 2;
91✔
550
                chunks /= 2;
91✔
551

552
                RandIter mid = first;
91✔
553
                std::advance(mid, mid_point);
91✔
554

555
                hpx::future<RandIter> left =
556
                    execution::async_execute(policy.executor(), *this, policy,
182✔
557
                        first, mid, mid_point, f, proj, chunks);
91✔
558
                hpx::future<RandIter> right =
559
                    execution::async_execute(policy.executor(), *this, policy,
182✔
560
                        mid, last, size - mid_point, f, proj, chunks);
91✔
561

562
                return dataflow(
91✔
563
                    policy.executor(),
91✔
564
                    [mid](hpx::future<RandIter>&& left,
182✔
565
                        hpx::future<RandIter>&& right) -> RandIter {
566
                        if (left.has_exception() || right.has_exception())
91✔
567
                        {
568
                            std::list<std::exception_ptr> errors;
28✔
569
                            if (left.has_exception())
28✔
570
                            {
571
                                hpx::parallel::util::detail::
28✔
572
                                    handle_local_exceptions<ExPolicy>::call(
573
                                        left.get_exception_ptr(), errors);
28✔
574
                            }
14✔
575
                            if (right.has_exception())
14✔
576
                            {
577
                                hpx::parallel::util::detail::
14✔
578
                                    handle_local_exceptions<ExPolicy>::call(
579
                                        right.get_exception_ptr(), errors);
14✔
580
                            }
14✔
581

582
                            if (!errors.empty())
14✔
583
                            {
584
                                throw exception_list(HPX_MOVE(errors));
14✔
585
                            }
586
                        }
28✔
587
                        RandIter first = left.get();
63✔
588
                        RandIter last = right.get();
63✔
589

590
                        std::rotate(first, mid, last);
63✔
591

592
                        // for some library implementations std::rotate
593
                        // does not return the new middle point
594
                        std::advance(first, std::distance(mid, last));
63✔
595
                        return first;
63✔
596
                    },
28✔
597
                    HPX_MOVE(left), HPX_MOVE(right));
598
            }
195✔
599
        };
600

601
        template <typename BidirIter, typename Sent, typename F, typename Proj>
602
        static BidirIter stable_partition_seq(
25✔
603
            BidirIter first, Sent last, F&& f, Proj&& proj)
604
        {
605
            using value_type =
606
                typename std::iterator_traits<BidirIter>::value_type;
607
            std::vector<value_type> falseValues;
25✔
608

609
            BidirIter next = first;
25✔
610
            while (first != last)
130,115✔
611
            {
612
                if (HPX_INVOKE(f, HPX_INVOKE(proj, *first)))
130,102✔
613
                {
614
                    *next = HPX_MOVE(*first);
70,048✔
615
                    ++next;
70,048✔
616
                }
70,048✔
617
                else
618
                {
619
                    falseValues.emplace_back(HPX_MOVE(*first));
60,042✔
620
                }
621

622
                ++first;
130,090✔
623
            }
624

625
            util::move(std::begin(falseValues), std::end(falseValues), next);
13✔
626
            return next;
627
        }
25✔
628

629
        template <typename Iter>
630
        struct stable_partition
631
          : public detail::algorithm<stable_partition<Iter>, Iter>
632
        {
633
            stable_partition()
38✔
634
              : stable_partition::algorithm("stable_partition")
38✔
635
            {
38✔
636
            }
38✔
637

638
            template <typename ExPolicy, typename BidirIter, typename Sent,
639
                typename F, typename Proj>
640
            static BidirIter sequential(
25✔
641
                ExPolicy&&, BidirIter first, Sent last, F&& f, Proj&& proj)
642
            {
643
                return stable_partition_seq(
25✔
644
                    first, last, HPX_FORWARD(F, f), HPX_FORWARD(Proj, proj));
25✔
645
            }
646

647
            template <typename ExPolicy, typename RandIter, typename Sent,
648
                typename F, typename Proj>
649
            static typename util::detail::algorithm_result<ExPolicy,
650
                RandIter>::type
651
            parallel(ExPolicy&& policy, RandIter first, Sent last, F&& f,
13✔
652
                Proj&& proj)
653
            {
654
                using algorithm_result =
655
                    util::detail::algorithm_result<ExPolicy, RandIter>;
656
                using difference_type =
657
                    typename std::iterator_traits<RandIter>::difference_type;
658

659
                future<RandIter> result;
13✔
660
                auto last_iter = first;
13✔
661

662
                try
663
                {
664
                    // advances last_iter to last and gets distance
665
                    difference_type size =
13✔
666
                        detail::advance_and_get_distance(last_iter, last);
13✔
667

668
                    if (size == 0)
13✔
669
                    {
670
                        result = hpx::make_ready_future(HPX_MOVE(last_iter));
×
671
                    }
×
672
                    else
673
                    {
674
                        std::size_t const cores =
13✔
675
                            execution::processing_units_count(
13✔
676
                                policy.parameters(), policy.executor());
13✔
677

678
                        std::size_t chunk_size = execution::get_chunk_size(
13✔
679
                            policy.parameters(), policy.executor(),
13✔
680
                            [](std::size_t) { return 0; }, cores, size);
681

682
                        std::size_t max_chunks =
13✔
683
                            execution::maximal_number_of_chunks(
13✔
684
                                policy.parameters(), policy.executor(), cores,
13✔
685
                                size);
686

687
                        util::detail::adjust_chunk_size_and_max_chunks(
13✔
688
                            cores, size, chunk_size, max_chunks);
13✔
689

690
                        result = stable_partition_helper()(
13✔
691
                            HPX_FORWARD(ExPolicy, policy), first, last_iter,
13✔
692
                            size, HPX_FORWARD(F, f), HPX_FORWARD(Proj, proj),
13✔
693
                            max_chunks);
13✔
694
                    }
695
                }
13✔
696
                catch (...)
697
                {
698
                    result = hpx::make_exceptional_future<RandIter>(
×
699
                        std::current_exception());
×
700
                }
×
701

702
                if (result.has_exception())
13✔
703
                {
704
                    return algorithm_result::get(
×
705
                        detail::handle_exception<ExPolicy, RandIter>::call(
×
706
                            HPX_MOVE(result)));
×
707
                }
708

709
                return algorithm_result::get(HPX_MOVE(result));
13✔
710
            }
13✔
711
        };
712
        /// \endcond
713
    }    // namespace detail
714

715
    // clang-format off
716
    template <typename ExPolicy, typename BidirIter, typename F,
717
        typename Proj = util::projection_identity,
718
        HPX_CONCEPT_REQUIRES_(
719
            hpx::is_execution_policy_v<ExPolicy> &&
720
            hpx::traits::is_iterator_v<BidirIter> &&
721
            traits::is_projected_v<Proj, BidirIter> &&
722
            traits::is_indirect_callable_v<ExPolicy, F,
723
                            traits::projected<Proj, BidirIter>>
724
        )>
725
    // clang-format on
726
    HPX_DEPRECATED_V(1, 8,
727
        "hpx::parallel::stable_partition is deprecated, use "
728
        "hpx::stable_partition instead")
729
        util::detail::algorithm_result_t<ExPolicy, BidirIter> stable_partition(
730
            ExPolicy&& policy, BidirIter first, BidirIter last, F&& f,
731
            Proj&& proj = Proj())
732
    {
733
        static_assert((hpx::traits::is_bidirectional_iterator_v<BidirIter>),
734
            "Requires at least bidirectional iterator.");
735

736
#if defined(HPX_GCC_VERSION) && HPX_GCC_VERSION >= 100000
737
#pragma GCC diagnostic push
738
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
739
#endif
740
        using is_seq = std::integral_constant<bool,
741
            hpx::is_sequenced_execution_policy_v<ExPolicy> ||
742
                !hpx::traits::is_random_access_iterator_v<BidirIter>>;
743

744
        return detail::stable_partition<BidirIter>().call2(
745
            HPX_FORWARD(ExPolicy, policy), is_seq(), first, last,
746
            HPX_FORWARD(F, f), HPX_FORWARD(Proj, proj));
747
#if defined(HPX_GCC_VERSION) && HPX_GCC_VERSION >= 100000
748
#pragma GCC diagnostic pop
749
#endif
750
    }
751

752
    /////////////////////////////////////////////////////////////////////////////
753
    // partition
754
    namespace detail {
755
        /// \cond NOINTERNAL
756

757
        // sequential partition with projection function for bidirectional iterator.
758
        template <typename BidirIter, typename Pred, typename Proj,
759
            HPX_CONCEPT_REQUIRES_(
760
                hpx::traits::is_bidirectional_iterator_v<BidirIter>)>
761
        BidirIter sequential_partition(
130,123✔
762
            BidirIter first, BidirIter last, Pred&& pred, Proj&& proj)
763
        {
764
            while (true)
51,673,925✔
765
            {
766
                while (
153,961,666✔
767
                    first != last && HPX_INVOKE(pred, HPX_INVOKE(proj, *first)))
102,287,749✔
768
                    ++first;
50,613,824✔
769
                if (first == last)
51,673,917✔
770
                    break;
63,052✔
771

772
                while (first != --last &&
184,798,530✔
773
                    !HPX_INVOKE(pred, HPX_INVOKE(proj, *last)))
133,120,602✔
774
                    ;
775
                if (first == last)
51,610,865✔
776
                    break;
67,063✔
777

778
#if defined(HPX_HAVE_CXX20_STD_RANGES_ITER_SWAP)
779
                std::ranges::iter_swap(first++, last);
780
#else
781
                std::iter_swap(first++, last);
51,543,802✔
782
#endif
783
            }
784

785
            return first;
130,115✔
786
        }
×
787

788
        // sequential partition with projection function for forward iterator.
789
        template <typename FwdIter, typename Pred, typename Proj,
790
            HPX_CONCEPT_REQUIRES_(hpx::traits::is_forward_iterator_v<FwdIter> &&
791
                !hpx::traits::is_bidirectional_iterator_v<FwdIter>)>
792
        FwdIter sequential_partition(
18✔
793
            FwdIter first, FwdIter last, Pred&& pred, Proj&& proj)
794
        {
795
            while (first != last && HPX_INVOKE(pred, HPX_INVOKE(proj, *first)))
10,028✔
796
                ++first;
10,010✔
797

798
            if (first == last)
14✔
799
                return first;
1✔
800

801
            for (FwdIter it = std::next(first); it != last; ++it)
259,990✔
802
            {
803
                if (HPX_INVOKE(pred, HPX_INVOKE(proj, *it)))
259,977✔
804
                {
805
#if defined(HPX_HAVE_CXX20_STD_RANGES_ITER_SWAP)
806
                    std::ranges::iter_swap(first++, it);
807
#else
808
                    std::iter_swap(first++, it);
119,867✔
809
#endif
810
                }
119,867✔
811
            }
259,977✔
812

813
            return first;
13✔
814
        }
14✔
815

816
        struct partition_helper
817
        {
818
            template <typename FwdIter>
819
            struct block
×
820
            {
821
                FwdIter first;
822
                FwdIter last;
823
                // Maybe 'std::int64_t' is enough to avoid overflow.
824
                std::int64_t block_no;
825

826
                block()
391,749✔
827
                  : first()
391,749✔
828
                  , last()
391,749✔
829
                  , block_no(-1)
391,749✔
830
                {
831
                }
391,749✔
832

833
                block(FwdIter first, FwdIter last, std::int64_t block_no = -1)
555,418✔
834
                  : first(first)
555,418✔
835
                  , last(last)
555,418✔
836
                  , block_no(block_no)
555,418✔
837
                {
838
                }
555,418✔
839

840
                bool empty() const
772,655,212✔
841
                {
842
                    return first == last;
772,676,208✔
843
                }
844

845
                // The blocks are sorted by their positions.
846
                // The block_no implies block's position.
847
                // If the block is on leftside of boundary, block_no is negative number.
848
                // Otherwise, block_no is positive number.
849
                // The farther from the boundary, the larger its absolute value.
850
                // The example of sorted blocks below (the number means block_no):
851
                //     -3  -2  -1  1  2  3  4
852
                bool operator<(block<FwdIter> const& other) const
46✔
853
                {
854
                    if ((this->block_no < 0 && other.block_no < 0) ||
69✔
855
                        (this->block_no > 0 && other.block_no > 0))
30✔
856
                        return this->block_no > other.block_no;
26✔
857
                    else
858
                        return this->block_no < other.block_no;
20✔
859
                }
46✔
860
            };
861

862
            template <typename Iter, typename Enable = void>
863
            class block_manager;
24✔
864

865
            // block manager for random access iterator.
866
            template <typename RandIter>
867
            class block_manager<RandIter,
868
                std::enable_if_t<
869
                    hpx::traits::is_random_access_iterator_v<RandIter>>>
870
            {
871
            public:
872
                block_manager(
130,079✔
873
                    RandIter first, RandIter last, std::size_t block_size)
874
                  : first_(first)
130,079✔
875
                  , left_(0)
130,079✔
876
                  , right_(std::distance(first, last))
130,079✔
877
                  , block_size_(block_size)
130,079✔
878
                {
879
                }
130,079✔
880
                block_manager(const block_manager&) = delete;
881
                block_manager& operator=(const block_manager&) = delete;
882

883
                // Get block from the end of leftside of boundary.
884
                block<RandIter> get_left_block()
155,029✔
885
                {
886
                    std::lock_guard<decltype(mutex_)> lk(mutex_);
155,029✔
887

888
                    if (left_ >= right_)
155,029✔
889
                        return {first_, first_};
5,790✔
890

891
                    std::size_t begin_index = left_;
149,239✔
892
                    std::size_t end_index =
149,239✔
893
                        (std::min)(left_ + block_size_, right_);
149,239✔
894

895
                    left_ += end_index - begin_index;
149,239✔
896

897
                    RandIter begin_iter = std::next(first_, begin_index);
149,239✔
898
                    RandIter end_iter = std::next(first_, end_index);
149,239✔
899

900
                    boundary_ = end_iter;
149,239✔
901

902
                    return {begin_iter, end_iter, left_block_no_--};
149,239✔
903
                }
155,029✔
904

905
                // Get block from the end of rightside of boundary.
906
                block<RandIter> get_right_block()
269,946✔
907
                {
908
                    std::lock_guard<decltype(mutex_)> lk(mutex_);
269,946✔
909

910
                    if (left_ >= right_)
269,946✔
911
                        return {first_, first_};
260,577✔
912

913
                    std::size_t begin_index =
9,369✔
914
                        (std::max)(right_ - block_size_, left_);
9,369✔
915
                    std::size_t end_index = right_;
9,369✔
916

917
                    right_ -= end_index - begin_index;
9,369✔
918

919
                    RandIter begin_iter = std::next(first_, begin_index);
9,369✔
920
                    RandIter end_iter = std::next(first_, end_index);
9,369✔
921

922
                    boundary_ = begin_iter;
9,369✔
923

924
                    return {begin_iter, end_iter, right_block_no_++};
9,369✔
925
                }
269,946✔
926

927
                RandIter boundary()
130,075✔
928
                {
929
                    return boundary_;
130,075✔
930
                }
931

932
            private:
933
                RandIter first_, boundary_;
934
                std::size_t left_, right_;
935
                std::size_t block_size_;
936
                std::int64_t left_block_no_{-1}, right_block_no_{1};
130,079✔
937
                hpx::spinlock mutex_;
938
            };
939

940
            // block manager for forward access iterator.
941
            template <typename FwdIter>
942
            class block_manager<FwdIter,
943
                std::enable_if_t<hpx::traits::is_forward_iterator_v<FwdIter> &&
944
                    !hpx::traits::is_random_access_iterator_v<FwdIter>>>
945
            {
946
            public:
947
                // In constructor, prepare all blocks for fast acquirements of blocks.
948
                block_manager(
48✔
949
                    FwdIter first, FwdIter last, std::size_t block_size)
950
                  : boundary_(first)
24✔
951
                  , blocks_((std::distance(first, last) + block_size - 1) /
48✔
952
                        block_size)
24✔
953
                {
954
                    left_ = 0;
24✔
955
                    right_ = blocks_.size();
24✔
956

957
                    if (blocks_.size() == 1)
24✔
958
                    {
959
                        blocks_.front() = {first, last};
×
960
                        return;
×
961
                    }
962

963
                    FwdIter next = std::next(first, block_size);
24✔
964

965
                    blocks_.front() = {first, next};
24✔
966

967
                    for (std::size_t i = 1; i < blocks_.size() - 1; ++i)
24✔
968
                    {
969
                        first = next;
×
970
                        next = std::next(first, block_size);
×
971
                        blocks_[i] = {first, next};
×
972
                    }
×
973

974
                    blocks_.back() = {next, last};
24✔
975
                }
24✔
976

977
                block_manager(const block_manager&) = delete;
978
                block_manager& operator=(const block_manager&) = delete;
979

980
                // Get block from the end of leftside of boundary.
981
                block<FwdIter> get_left_block()
170✔
982
                {
983
                    std::lock_guard<decltype(mutex_)> lk(mutex_);
170✔
984

985
                    if (left_ >= right_)
170✔
986
                        return {boundary_, boundary_};
146✔
987

988
                    boundary_ = blocks_[left_].last;
24✔
989
                    blocks_[left_].block_no = left_block_no_--;
24✔
990

991
                    // NOLINTNEXTLINE(bugprone-macro-repeated-side-effects)
992
                    return HPX_MOVE(blocks_[left_++]);
24✔
993
                }
170✔
994

995
                // // Get block from the end of rightside of boundary.
996
                block<FwdIter> get_right_block()
182✔
997
                {
998
                    std::lock_guard<decltype(mutex_)> lk(mutex_);
182✔
999

1000
                    if (left_ >= right_)
182✔
1001
                        return {boundary_, boundary_};
158✔
1002

1003
                    boundary_ = blocks_[--right_].first;
24✔
1004
                    blocks_[right_].block_no = right_block_no_++;
24✔
1005

1006
                    return HPX_MOVE(blocks_[right_]);
24✔
1007
                }
182✔
1008

1009
                FwdIter boundary()
16✔
1010
                {
1011
                    return boundary_;
16✔
1012
                }
1013

1014
            private:
1015
                FwdIter boundary_;
1016
                std::vector<block<FwdIter>> blocks_;
1017
                std::size_t left_, right_;
1018
                std::int64_t left_block_no_{-1}, right_block_no_{1};
24✔
1019
                hpx::spinlock mutex_;
1020
            };
1021

1022
            // std::swap_ranges doesn't support overlapped ranges in standard.
1023
            // But, actually general implementations of std::swap_ranges are useful
1024
            //     in specific cases.
1025
            // The problem is that standard doesn't guarantee that implementation.
1026
            // The swap_ranges_forward is the general implementation of
1027
            //     std::swap_ranges for guaranteeing utilizations in specific cases.
1028
            // If dest is previous to first, the range [first, last) can be
1029
            //     successfully moved to the range [dest, dest+distance(first, last)).
1030
            template <class FwdIter1, class FwdIter2>
1031
            static FwdIter2 swap_ranges_forward(
117✔
1032
                FwdIter1 first, FwdIter1 last, FwdIter2 dest)
1033
            {
1034
                while (first != last)
1,091,142✔
1035
                {
1036
#if defined(HPX_HAVE_CXX20_STD_RANGES_ITER_SWAP)
1037
                    std::ranges::iter_swap(first++, dest++);
1038
#else
1039
                    std::iter_swap(first++, dest++);
1,091,025✔
1040
#endif
1041
                }
1042

1043
                return dest;
117✔
1044
            }
×
1045

1046
            // The function which performs sub-partitioning.
1047
            template <typename FwdIter, typename Pred, typename Proj>
1048
            static block<FwdIter> partition_thread(
130,583✔
1049
                block_manager<FwdIter>& block_manager, Pred pred, Proj proj)
1050
            {
1051
                block<FwdIter> left_block, right_block;
130,583✔
1052

1053
                left_block = block_manager.get_left_block();
130,583✔
1054
                right_block = block_manager.get_right_block();
130,583✔
1055

1056
                while (true)
100,604,436✔
1057
                {
1058
                    while ((!left_block.empty() ||
487,088,979✔
1059
                               !(left_block = block_manager.get_left_block())
24,616✔
1060
                                    .empty()) &&
24,616✔
1061
                        HPX_INVOKE(pred, HPX_INVOKE(proj, *left_block.first)))
386,455,544✔
1062
                    {
1063
                        ++left_block.first;
285,914,104✔
1064
                    }
1065

1066
                    while ((!right_block.empty() ||
285,718,870✔
1067
                               !(right_block = block_manager.get_right_block())
139,545✔
1068
                                    .empty()) &&
139,545✔
1069
                        !HPX_INVOKE(pred, HPX_INVOKE(proj, *right_block.first)))
184,975,665✔
1070
                    {
1071
                        ++right_block.first;
84,542,397✔
1072
                    }
1073

1074
                    if (left_block.empty())
100,597,902✔
1075
                        return right_block;
5,480✔
1076
                    if (right_block.empty())
100,598,944✔
1077
                        return left_block;
125,091✔
1078

1079
#if defined(HPX_HAVE_CXX20_STD_RANGES_ITER_SWAP)
1080
                    std::ranges::iter_swap(
1081
                        left_block.first++, right_block.first++);
1082
#else
1083
                    std::iter_swap(left_block.first++, right_block.first++);
100,497,372✔
1084
#endif
1085
                }
1086
            }
130,571✔
1087

1088
            // The function which collapses remaining blocks.
1089
            // Performs sequential sub-partitioning to remaining blocks for
1090
            //     reducing the number and size of remaining blocks.
1091
            template <typename FwdIter, typename Pred, typename Proj>
1092
            static void collapse_remaining_blocks(
130,091✔
1093
                std::vector<block<FwdIter>>& remaining_blocks, Pred& pred,
1094
                Proj& proj)
1095
            {
1096
                if (remaining_blocks.empty())
130,091✔
1097
                    return;
4,897✔
1098

1099
                auto left_iter = std::begin(remaining_blocks);
125,194✔
1100
                auto right_iter = std::end(remaining_blocks) - 1;
125,194✔
1101

1102
                if (left_iter->block_no > 0 || right_iter->block_no < 0)
125,194✔
1103
                    return;
125,187✔
1104

1105
                while (true)
930✔
1106
                {
1107
                    while (true)
1,783✔
1108
                    {
1109
                        if (left_iter->empty())
1,783✔
1110
                        {
1111
                            ++left_iter;
6✔
1112
                            if (left_iter == std::end(remaining_blocks) ||
6✔
1113
                                left_iter->block_no > 0)
6✔
1114
                                break;
×
1115
                        }
6✔
1116
                        if (!HPX_INVOKE(
1,783✔
1117
                                pred, HPX_INVOKE(proj, *left_iter->first)))
1118
                            break;
930✔
1119
                        ++left_iter->first;
853✔
1120
                    }
1121

1122
                    while (true)
1,770✔
1123
                    {
1124
                        if (right_iter->empty())
1,770✔
1125
                        {
1126
                            if (right_iter == std::begin(remaining_blocks) ||
11✔
1127
                                (--right_iter)->block_no < 0)
11✔
1128
                                break;
7✔
1129
                        }
4✔
1130
                        if (HPX_INVOKE(
1,763✔
1131
                                pred, HPX_INVOKE(proj, *right_iter->first)))
1132
                            break;
923✔
1133
                        ++right_iter->first;
840✔
1134
                    }
1135

1136
                    if (left_iter == std::end(remaining_blocks) ||
930✔
1137
                        left_iter->block_no > 0)
930✔
1138
                        break;
×
1139
                    if (right_iter->empty() || right_iter->block_no < 0)
930✔
1140
                        break;
7✔
1141

1142
#if defined(HPX_HAVE_CXX20_STD_RANGES_ITER_SWAP)
1143
                    std::ranges::iter_swap(
1144
                        left_iter->first++, right_iter->first++);
1145
#else
1146
                    std::iter_swap(left_iter->first++, right_iter->first++);
923✔
1147
#endif
1148
                }
1149

1150
                if (left_iter < right_iter ||
13✔
1151
                    (!right_iter->empty() && left_iter == right_iter))
6✔
1152
                {
1153
                    remaining_blocks.erase(
14✔
1154
                        right_iter->empty() ? right_iter : right_iter + 1,
7✔
1155
                        std::end(remaining_blocks));
7✔
1156

1157
                    remaining_blocks.erase(
14✔
1158
                        std::begin(remaining_blocks), left_iter);
7✔
1159
                }
7✔
1160
                else
1161
                {
1162
                    remaining_blocks.clear();
×
1163
                }
1164
            }
130,091✔
1165

1166
            // The function which merges remaining blocks that are placed
1167
            //     leftside of boundary. Requires bidirectional iterator.
1168
            // Move remaining blocks to the adjacent left of the boundary.
1169
            // In the end, all remaining blocks are merged into one block which
1170
            //     is adjacent to the left of boundary.
1171
            // clang-format off
1172
            template <typename BidirIter,
1173
                HPX_CONCEPT_REQUIRES_(
1174
                    hpx::traits::is_bidirectional_iterator_v<BidirIter>
1175
                )>
1176
            // clang-format on
1177
            static block<BidirIter> merge_leftside_remaining_blocks(
125,074✔
1178
                std::vector<block<BidirIter>>& remaining_blocks,
1179
                BidirIter boundary, BidirIter first)
1180
            {
1181
                HPX_ASSERT(!remaining_blocks.empty());
125,074✔
1182
                HPX_UNUSED(first);
125,074✔
1183

1184
                auto boundary_rbegin =
1185
                    std::reverse_iterator<BidirIter>(boundary);
125,074✔
1186
                for (auto it = remaining_blocks.rbegin();
250,152✔
1187
                     it != remaining_blocks.rend(); ++it)
250,152✔
1188
                {
1189
                    auto rbegin = std::reverse_iterator<BidirIter>(it->last);
125,078✔
1190
                    auto rend = std::reverse_iterator<BidirIter>(it->first);
125,078✔
1191

1192
                    if (boundary_rbegin == rbegin)
125,078✔
1193
                    {
1194
                        boundary_rbegin = rend;
125,074✔
1195
                        continue;
125,074✔
1196
                    }
1197

1198
                    boundary_rbegin =
4✔
1199
                        swap_ranges_forward(rbegin, rend, boundary_rbegin);
4✔
1200
                }
4✔
1201

1202
                return {boundary_rbegin.base(), boundary};
125,074✔
1203
            }
×
1204

1205
            // The function which merges remaining blocks that are placed
1206
            //     leftside of boundary. Requires forward iterator.
1207
            // Move remaining blocks to the adjacent left of the boundary.
1208
            // In the end, all remaining blocks are merged into one block which
1209
            //     is adjacent to the left of boundary.
1210
            // clang-format off
1211
            template <typename FwdIter,
1212
                HPX_CONCEPT_REQUIRES_(
1213
                    hpx::traits::is_forward_iterator_v<FwdIter> &&
1214
                    !hpx::traits::is_bidirectional_iterator_v<FwdIter>
1215
                )>
1216
            // clang-format on
1217
            static block<FwdIter> merge_leftside_remaining_blocks(
7✔
1218
                std::vector<block<FwdIter>>& remaining_blocks, FwdIter boundary,
1219
                FwdIter first)
1220
            {
1221
                HPX_ASSERT(!remaining_blocks.empty());
7✔
1222

1223
                std::vector<FwdIter> dest_iters(remaining_blocks.size());
7✔
1224
                std::vector<std::size_t> dest_iter_indexes(
7✔
1225
                    remaining_blocks.size());
7✔
1226
                std::vector<std::size_t> remaining_block_indexes(
7✔
1227
                    remaining_blocks.size());
7✔
1228
                std::vector<std::size_t> counts(remaining_blocks.size());
7✔
1229
                std::size_t count_sum = 0u;
7✔
1230

1231
                for (std::size_t i = 0; i < counts.size(); ++i)
14✔
1232
                {
1233
                    counts[i] = std::distance(
7✔
1234
                        remaining_blocks[i].first, remaining_blocks[i].last);
7✔
1235
                    count_sum += counts[i];
7✔
1236
                }
7✔
1237

1238
                remaining_block_indexes[0] =
7✔
1239
                    std::distance(first, remaining_blocks[0].first);
7✔
1240
                for (std::size_t i = 1; i < remaining_block_indexes.size(); ++i)
7✔
1241
                {
1242
                    remaining_block_indexes[i] =
×
1243
                        remaining_block_indexes[i - 1] + counts[i - 1] +
×
1244
                        std::distance(remaining_blocks[i - 1].last,
×
1245
                            remaining_blocks[i].first);
×
1246
                }
×
1247

1248
                std::size_t boundary_end_index = std::distance(first, boundary);
7✔
1249
                std::size_t boundary_begin_index =
7✔
1250
                    boundary_end_index - count_sum;
7✔
1251

1252
                dest_iters[0] = std::next(first, boundary_begin_index);
7✔
1253
                dest_iter_indexes[0] = boundary_begin_index;
7✔
1254

1255
                for (std::size_t i = 0; i < dest_iters.size() - 1; ++i)
7✔
1256
                {
1257
                    dest_iters[i + 1] = std::next(dest_iters[i], counts[i]);
×
1258
                    dest_iter_indexes[i + 1] = dest_iter_indexes[i] + counts[i];
×
1259
                }
×
1260

1261
                for (std::int64_t i = std::int64_t(dest_iters.size() - 1);
14✔
1262
                     i >= 0; --i)
14✔
1263
                {
1264
                    if (remaining_blocks[i].first == dest_iters[i])
7✔
1265
                        continue;
7✔
1266

1267
                    if (remaining_block_indexes[i] + counts[i] <=
×
1268
                        dest_iter_indexes[i])
×
1269
                    {
1270
                        // when the ranges are not overlapped each other.
1271
                        swap_ranges_forward(remaining_blocks[i].first,
×
1272
                            remaining_blocks[i].last, dest_iters[i]);
×
1273
                    }
×
1274
                    else
1275
                    {
1276
                        // when the ranges are overlapped each other.
1277
                        swap_ranges_forward(remaining_blocks[i].first,
×
1278
                            dest_iters[i], remaining_blocks[i].last);
×
1279
                    }
1280
                }
×
1281

1282
                return {dest_iters[0], boundary};
7✔
1283
            }
7✔
1284

1285
            // The function which merges remaining blocks into
1286
            //     one block which is adjacent to boundary.
1287
            template <typename FwdIter>
1288
            static block<FwdIter> merge_remaining_blocks(
130,091✔
1289
                std::vector<block<FwdIter>>& remaining_blocks, FwdIter boundary,
1290
                FwdIter first)
1291
            {
1292
                if (remaining_blocks.empty())
130,091✔
1293
                    return {boundary, boundary};
4,897✔
1294

1295
                if (remaining_blocks.front().block_no < 0)
125,194✔
1296
                {
1297
                    // when blocks are placed in left side of boundary.
1298
                    return merge_leftside_remaining_blocks(
125,081✔
1299
                        remaining_blocks, boundary, first);
125,081✔
1300
                }
1301
                else
1302
                {
1303
                    // when blocks are placed in right side of boundary.
1304
                    FwdIter boundary_end = boundary;
113✔
1305
                    for (auto& block : remaining_blocks)
229✔
1306
                    {
1307
                        if (block.first == boundary_end)
116✔
1308
                        {
1309
                            boundary_end = block.last;
3✔
1310
                            continue;
3✔
1311
                        }
1312

1313
                        boundary_end = swap_ranges_forward(
113✔
1314
                            block.first, block.last, boundary_end);
113✔
1315
                    }
1316

1317
                    return {boundary, boundary_end};
113✔
1318
                }
×
1319
            }
130,091✔
1320

1321
            template <typename ExPolicy, typename FwdIter, typename Pred,
1322
                typename Proj>
1323
            static FwdIter call(ExPolicy&& policy, FwdIter first, FwdIter last,
133,467✔
1324
                Pred&& pred, Proj&& proj)
1325
            {
1326
                if (first == last)
133,467✔
1327
                    return first;
3,364✔
1328

1329
                std::size_t const cores = execution::processing_units_count(
130,103✔
1330
                    policy.parameters(), policy.executor());
130,103✔
1331

1332
                // TODO: Find more better block size.
1333
                const std::size_t block_size = std::size_t(20000);
130,103✔
1334
                block_manager<FwdIter> block_manager(first, last, block_size);
130,103✔
1335

1336
                std::vector<hpx::future<block<FwdIter>>>
1337
                    remaining_block_futures(cores);
130,107✔
1338

1339
                // Main parallel phase: perform sub-partitioning in each thread.
1340
                for (std::size_t i = 0; i < remaining_block_futures.size(); ++i)
260,686✔
1341
                {
1342
                    remaining_block_futures[i] = execution::async_execute(
130,583✔
1343
                        policy.executor(), [&block_manager, pred, proj]() {
261,166✔
1344
                            return partition_thread(block_manager, pred, proj);
130,583✔
1345
                        });
1346
                }
130,583✔
1347

1348
                // Wait sub-partitioning to be all finished.
1349
                hpx::wait_all_nothrow(remaining_block_futures);
130,103✔
1350

1351
                // Handle exceptions in parallel phrase.
1352
                std::list<std::exception_ptr> errors;
130,103✔
1353

1354
                util::detail::handle_local_exceptions<ExPolicy>::call(
130,103✔
1355
                    remaining_block_futures, errors);
1356

1357
                std::vector<block<FwdIter>> remaining_blocks(
130,091✔
1358
                    remaining_block_futures.size());
130,091✔
1359

1360
                // Get remaining blocks from the result of sub-partitioning.
1361
                for (std::size_t i = 0; i < remaining_block_futures.size(); ++i)
260,626✔
1362
                    remaining_blocks[i] = remaining_block_futures[i].get();
130,535✔
1363

1364
                // Remove blocks that are empty.
1365
                FwdIter boundary = block_manager.boundary();
130,091✔
1366
                remaining_blocks.erase(
130,091✔
1367
                    std::remove_if(std::begin(remaining_blocks),
130,091✔
1368
                        std::end(remaining_blocks),
130,091✔
1369
                        [](block<FwdIter> const& block) -> bool {
130,535✔
1370
                            return block.empty();
130,535✔
1371
                        }),
1372
                    std::end(remaining_blocks));
130,091✔
1373

1374
                // Sort remaining blocks to be listed from left to right.
1375
                std::sort(
130,091✔
1376
                    std::begin(remaining_blocks), std::end(remaining_blocks));
130,091✔
1377

1378
                // Collapse remaining blocks each other.
1379
                collapse_remaining_blocks(remaining_blocks, pred, proj);
130,091✔
1380

1381
                // Merge remaining blocks into one block
1382
                //     which is adjacent to boundary.
1383
                block<FwdIter> unpartitioned_block =
1384
                    merge_remaining_blocks(remaining_blocks, boundary, first);
130,091✔
1385

1386
                // Perform sequential partition to unpartitioned range.
1387
                FwdIter real_boundary =
1388
                    sequential_partition(unpartitioned_block.first,
260,182✔
1389
                        unpartitioned_block.last, pred, proj);
130,091✔
1390

1391
                return real_boundary;
130,091✔
1392
            }
133,467✔
1393
        };
1394

1395
        template <typename ExPolicy, typename FwdIter, typename Pred,
1396
            typename Proj>
1397
        hpx::future<FwdIter> parallel_partition(ExPolicy&& policy,
133,467✔
1398
            FwdIter first, FwdIter last, Pred&& pred, Proj&& proj)
1399
        {
1400
            return execution::async_execute(
133,467✔
1401
                policy.executor(), [=]() mutable -> FwdIter {
266,934✔
1402
                    try
1403
                    {
1404
                        return partition_helper::call(
133,467✔
1405
                            policy, first, last, pred, proj);
133,467✔
1406
                    }
12✔
1407
                    catch (...)
1408
                    {
1409
                        util::detail::handle_local_exceptions<ExPolicy>::call(
12✔
1410
                            std::current_exception());
12✔
1411
                    }
12✔
1412
                });
24✔
1413
        }
×
1414

1415
        template <typename FwdIter>
1416
        struct partition : public detail::algorithm<partition<FwdIter>, FwdIter>
1417
        {
1418
            partition()
133,517✔
1419
              : partition::algorithm("partition")
133,517✔
1420
            {
133,517✔
1421
            }
133,517✔
1422

1423
            template <typename ExPolicy, typename Sent, typename Pred,
1424
                typename Proj = util::projection_identity>
1425
            static FwdIter sequential(
50✔
1426
                ExPolicy, FwdIter first, Sent last, Pred&& pred, Proj&& proj)
1427
            {
1428
                auto last_iter = detail::advance_to_sentinel(first, last);
50✔
1429
                return sequential_partition(first, last_iter,
100✔
1430
                    HPX_FORWARD(Pred, pred), HPX_FORWARD(Proj, proj));
50✔
1431
            }
1432

1433
            template <typename ExPolicy, typename Sent, typename Pred,
1434
                typename Proj = util::projection_identity>
1435
            static
1436
                typename util::detail::algorithm_result<ExPolicy, FwdIter>::type
1437
                parallel(ExPolicy&& policy, FwdIter first, Sent last,
133,467✔
1438
                    Pred&& pred, Proj&& proj)
1439
            {
1440
                using algorithm_result =
1441
                    util::detail::algorithm_result<ExPolicy, FwdIter>;
1442
                auto last_iter = detail::advance_to_sentinel(first, last);
133,467✔
1443

1444
                try
1445
                {
1446
                    return algorithm_result::get(parallel_partition(
133,467✔
1447
                        HPX_FORWARD(ExPolicy, policy), first, last_iter,
133,467✔
1448
                        HPX_FORWARD(Pred, pred), HPX_FORWARD(Proj, proj)));
133,467✔
1449
                }
6✔
1450
                catch (...)
1451
                {
1452
                    return algorithm_result::get(
6✔
1453
                        detail::handle_exception<ExPolicy, FwdIter>::call(
6✔
1454
                            std::current_exception()));
6✔
1455
                }
6✔
1456
            }
133,473✔
1457
        };
1458
        /// \endcond
1459
    }    // namespace detail
1460

1461
    // clang-format off
1462
    template <typename ExPolicy, typename FwdIter, typename Pred,
1463
        typename Proj = util::projection_identity,
1464
        HPX_CONCEPT_REQUIRES_(
1465
            hpx::is_execution_policy_v<ExPolicy> &&
1466
            hpx::traits::is_iterator_v<FwdIter> &&
1467
            traits::is_projected_v<Proj, FwdIter> &&
1468
            traits::is_indirect_callable_v<ExPolicy,
1469
                    Pred, traits::projected<Proj, FwdIter>>
1470
        )>
1471
    // clang-format on
1472
    HPX_DEPRECATED_V(1, 8,
1473
        "hpx::parallel::partition is deprecated, use "
1474
        "hpx::partition instead")
1475
        util::detail::algorithm_result_t<ExPolicy, FwdIter> partition(
1476
            ExPolicy&& policy, FwdIter first, FwdIter last, Pred&& pred,
1477
            Proj&& proj = Proj())
1478
    {
1479
        static_assert((hpx::traits::is_forward_iterator_v<FwdIter>),
1480
            "Required at least forward iterator.");
1481

1482
#if defined(HPX_GCC_VERSION) && HPX_GCC_VERSION >= 100000
1483
#pragma GCC diagnostic push
1484
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1485
#endif
1486
        return detail::partition<FwdIter>().call(HPX_FORWARD(ExPolicy, policy),
1487
            first, last, HPX_FORWARD(Pred, pred), HPX_FORWARD(Proj, proj));
1488
#if defined(HPX_GCC_VERSION) && HPX_GCC_VERSION >= 100000
1489
#pragma GCC diagnostic pop
1490
#endif
1491
    }
1492

1493
    /////////////////////////////////////////////////////////////////////////////
1494
    // partition_copy
1495
    namespace detail {
1496
        /// \cond NOINTERNAL
1497

1498
        // sequential partition_copy with projection function
1499
        template <typename InIter, typename OutIter1, typename OutIter2,
1500
            typename Pred, typename Proj>
1501
        hpx::tuple<InIter, OutIter1, OutIter2> sequential_partition_copy(
50✔
1502
            InIter first, InIter last, OutIter1 dest_true, OutIter2 dest_false,
1503
            Pred&& pred, Proj&& proj)
1504
        {
1505
            while (first != last)
10,280,242✔
1506
            {
1507
                if (HPX_INVOKE(pred, HPX_INVOKE(proj, *first)))
10,280,192✔
1508
                    *dest_true++ = *first;
5,807,380✔
1509
                else
1510
                    *dest_false++ = *first;
4,472,812✔
1511
                first++;
10,280,192✔
1512
            }
1513
            return hpx::make_tuple(
38✔
1514
                HPX_MOVE(last), HPX_MOVE(dest_true), HPX_MOVE(dest_false));
1515
        }
1516

1517
        template <typename IterTuple>
1518
        struct partition_copy
1519
          : public detail::algorithm<partition_copy<IterTuple>, IterTuple>
1520
        {
1521
            partition_copy()
116✔
1522
              : partition_copy::algorithm("partition_copy")
116✔
1523
            {
116✔
1524
            }
116✔
1525

1526
            template <typename ExPolicy, typename InIter, typename Sent,
1527
                typename OutIter1, typename OutIter2, typename Pred,
1528
                typename Proj = util::projection_identity>
1529
            static hpx::tuple<InIter, OutIter1, OutIter2> sequential(ExPolicy,
50✔
1530
                InIter first, Sent last, OutIter1 dest_true,
1531
                OutIter2 dest_false, Pred&& pred, Proj&& proj)
1532
            {
1533
                auto last_iter = detail::advance_to_sentinel(first, last);
50✔
1534
                return sequential_partition_copy(first, last_iter, dest_true,
100✔
1535
                    dest_false, HPX_FORWARD(Pred, pred),
50✔
1536
                    HPX_FORWARD(Proj, proj));
50✔
1537
            }
1538

1539
            template <typename ExPolicy, typename FwdIter1, typename Sent,
1540
                typename FwdIter2, typename FwdIter3, typename Pred,
1541
                typename Proj = util::projection_identity>
1542
            static typename util::detail::algorithm_result<ExPolicy,
1543
                hpx::tuple<FwdIter1, FwdIter2, FwdIter3>>::type
1544
            parallel(ExPolicy&& policy, FwdIter1 first, Sent last,
66✔
1545
                FwdIter2 dest_true, FwdIter3 dest_false, Pred&& pred,
1546
                Proj&& proj)
1547
            {
1548
                using zip_iterator = hpx::util::zip_iterator<FwdIter1, bool*>;
1549
                using result = util::detail::algorithm_result<ExPolicy,
1550
                    hpx::tuple<FwdIter1, FwdIter2, FwdIter3>>;
1551
                using difference_type =
1552
                    typename std::iterator_traits<FwdIter1>::difference_type;
1553
                using output_iterator_offset =
1554
                    std::pair<std::size_t, std::size_t>;
1555

1556
                if (first == last)
66✔
1557
                    return result::get(
×
1558
                        hpx::make_tuple(first, dest_true, dest_false));
×
1559

1560
                auto last_iter = first;
66✔
1561
                difference_type count =
66✔
1562
                    detail::advance_and_get_distance(last_iter, last);
66✔
1563

1564
#if defined(HPX_HAVE_CXX17_SHARED_PTR_ARRAY)
1565
                std::shared_ptr<bool[]> flags(new bool[count]);
66✔
1566
#else
1567
                boost::shared_array<bool> flags(new bool[count]);
1568
#endif
1569
                output_iterator_offset init = {0, 0};
66✔
1570

1571
                using hpx::get;
1572
                using scan_partitioner_type = util::scan_partitioner<ExPolicy,
1573
                    hpx::tuple<FwdIter1, FwdIter2, FwdIter3>,
1574
                    output_iterator_offset>;
1575

1576
                // Note: replacing the invoke() with HPX_INVOKE()
1577
                // below makes gcc generate errors
1578
                auto f1 = [pred = HPX_FORWARD(Pred, pred),
546✔
1579
                              proj = HPX_FORWARD(Proj, proj)](
66✔
1580
                              zip_iterator part_begin,
1581
                              std::size_t part_size) -> output_iterator_offset {
1582
                    std::size_t true_count = 0;
480✔
1583

1584
                    // MSVC complains if pred or proj is captured by ref below
1585
                    util::loop_n<std::decay_t<ExPolicy>>(part_begin, part_size,
480✔
1586
                        [pred, proj, &true_count](
20,335,917✔
1587
                            zip_iterator it) mutable -> void {
1588
                            bool f = hpx::invoke(
20,337,880✔
1589
                                pred, hpx::invoke(proj, get<0>(*it)));
20,337,880✔
1590

1591
                            if ((get<1>(*it) = f))
20,337,880✔
1592
                                ++true_count;
11,504,461✔
1593
                        });
20,335,729✔
1594

1595
                    return output_iterator_offset(
480✔
1596
                        true_count, part_size - true_count);
480✔
1597
                };
1598

1599
                auto f2 = [](output_iterator_offset const& prev_sum,
360✔
1600
                              output_iterator_offset const& curr)
1601
                    -> output_iterator_offset {
1602
                    return output_iterator_offset(
360✔
1603
                        get<0>(prev_sum) + get<0>(curr),
360✔
1604
                        get<1>(prev_sum) + get<1>(curr));
360✔
1605
                };
1606
                auto f3 = [dest_true, dest_false, flags](
2,016✔
1607
                              zip_iterator part_begin, std::size_t part_size,
1608
                              output_iterator_offset val) mutable -> void {
1609
                    HPX_UNUSED(flags);
360✔
1610
                    output_iterator_offset offset = val;
360✔
1611
                    std::size_t count_true = get<0>(offset);
360✔
1612
                    std::size_t count_false = get<1>(offset);
360✔
1613
                    std::advance(dest_true, count_true);
360✔
1614
                    std::advance(dest_false, count_false);
360✔
1615

1616
                    util::loop_n<std::decay_t<ExPolicy>>(part_begin, part_size,
360✔
1617
                        [&dest_true, &dest_false](zip_iterator it) mutable {
20,335,384✔
1618
                            if (get<1>(*it))
20,338,344✔
1619
                                *dest_true++ = get<0>(*it);
11,504,544✔
1620
                            else
1621
                                *dest_false++ = get<0>(*it);
8,833,474✔
1622
                        });
20,335,928✔
1623
                };
360✔
1624

1625
                auto f4 = [last_iter, dest_true, dest_false, flags](
270✔
1626
                              std::vector<output_iterator_offset>&& items,
1627
                              std::vector<hpx::future<void>>&&) mutable
1628
                    -> hpx::tuple<FwdIter1, FwdIter2, FwdIter3> {
1629
                    HPX_UNUSED(flags);
54✔
1630

1631
                    output_iterator_offset count_pair = items.back();
54✔
1632
                    std::size_t count_true = get<0>(count_pair);
54✔
1633
                    std::size_t count_false = get<1>(count_pair);
54✔
1634
                    std::advance(dest_true, count_true);
54✔
1635
                    std::advance(dest_false, count_false);
54✔
1636

1637
                    return hpx::make_tuple(last_iter, dest_true, dest_false);
54✔
1638
                };
1639

1640
                return scan_partitioner_type::call(
66✔
1641
                    HPX_FORWARD(ExPolicy, policy),
66✔
1642
                    zip_iterator(first, flags.get()), count, init,
66✔
1643
                    // step 1 performs first part of scan algorithm
1644
                    HPX_MOVE(f1),
1645
                    // step 2 propagates the partition results from left
1646
                    // to right
1647
                    HPX_MOVE(f2),
1648
                    // step 3 runs final accumulation on each partition
1649
                    HPX_MOVE(f3),
1650
                    // step 4 use this return value
1651
                    HPX_MOVE(f4));
1652
            }
66✔
1653
        };
1654
        /// \endcond
1655
    }    // namespace detail
1656

1657
    // clang-format off
1658
    template <typename ExPolicy, typename FwdIter1, typename FwdIter2,
1659
        typename FwdIter3, typename Pred,
1660
        typename Proj = util::projection_identity,
1661
        HPX_CONCEPT_REQUIRES_(
1662
            hpx::is_execution_policy_v<ExPolicy> &&
1663
            hpx::traits::is_iterator_v<FwdIter1> &&
1664
            hpx::traits::is_iterator_v<FwdIter2> &&
1665
            hpx::traits::is_iterator_v<FwdIter3> &&
1666
            traits::is_projected_v<Proj, FwdIter1> &&
1667
            traits::is_indirect_callable_v<ExPolicy, Pred,
1668
                traits::projected<Proj, FwdIter1>>
1669
        )>
1670
    // clang-format on
1671
    util::detail::algorithm_result_t<ExPolicy, std::pair<FwdIter2, FwdIter3>>
1672
    partition_copy(ExPolicy&& policy, FwdIter1 first, FwdIter1 last,
30✔
1673
        FwdIter2 dest_true, FwdIter3 dest_false, Pred&& pred,
1674
        Proj&& proj = Proj())
1675
    {
1676
        static_assert((hpx::traits::is_forward_iterator_v<FwdIter1>),
1677
            "Required at least forward iterator.");
1678
        static_assert((hpx::traits::is_forward_iterator_v<FwdIter2>),
1679
            "Requires at least forward iterator.");
1680
        static_assert((hpx::traits::is_forward_iterator_v<FwdIter3>),
1681
            "Requires at least forward iterator.");
1682

1683
#if defined(HPX_GCC_VERSION) && HPX_GCC_VERSION >= 100000
1684
#pragma GCC diagnostic push
1685
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1686
#endif
1687
        using result_type = hpx::tuple<FwdIter1, FwdIter2, FwdIter3>;
1688

1689
        return parallel::v1::tuple_to_pair(
30✔
1690
            detail::partition_copy<result_type>().call(
60✔
1691
                HPX_FORWARD(ExPolicy, policy), first, last, dest_true,
30✔
1692
                dest_false, HPX_FORWARD(Pred, pred), HPX_FORWARD(Proj, proj)));
30✔
1693
#if defined(HPX_GCC_VERSION) && HPX_GCC_VERSION >= 100000
1694
#pragma GCC diagnostic pop
1695
#endif
1696
    }
1697
}}}    // namespace hpx::parallel::v1
1698

1699
namespace hpx {
1700
    ///////////////////////////////////////////////////////////////////////////
1701
    // CPO for hpx::stable_partition
1702
    inline constexpr struct stable_partition_t final
1703
      : hpx::detail::tag_parallel_algorithm<stable_partition_t>
1704
    {
1705
        // clang-format off
1706
        template <typename BidirIter, typename F,
1707
            typename Proj = parallel::util::projection_identity,
1708
            HPX_CONCEPT_REQUIRES_(
1709
                hpx::traits::is_iterator_v<BidirIter> &&
1710
                parallel::traits::is_projected_v<Proj, BidirIter> &&
1711
                parallel::traits::is_indirect_callable_v<
1712
                    hpx::execution::sequenced_policy, F,
1713
                    parallel::traits::projected<Proj, BidirIter>>
1714
        )>
1715
        // clang-format on
1716
        friend BidirIter tag_fallback_invoke(hpx::stable_partition_t,
2✔
1717
            BidirIter first, BidirIter last, F&& f, Proj&& proj = Proj())
1718
        {
1719
            static_assert(hpx::traits::is_bidirectional_iterator_v<BidirIter>,
1720
                "Requires at least bidirectional iterator.");
1721

1722
            return hpx::parallel::v1::detail::stable_partition<BidirIter>()
4✔
1723
                .call2(hpx::execution::seq, std::true_type{}, first, last,
2✔
1724
                    HPX_FORWARD(F, f), HPX_FORWARD(Proj, proj));
2✔
1725
        }
1726

1727
        // clang-format off
1728
        template <typename ExPolicy, typename BidirIter, typename F,
1729
            typename Proj = parallel::util::projection_identity,
1730
            HPX_CONCEPT_REQUIRES_(
1731
                hpx::is_execution_policy_v<ExPolicy> &&
1732
                hpx::traits::is_iterator_v<BidirIter> &&
1733
                parallel::traits::is_projected_v<Proj, BidirIter> &&
1734
                parallel::traits::is_indirect_callable_v<ExPolicy, F,
1735
                    parallel::traits::projected<Proj, BidirIter>>
1736
        )>
1737
        // clang-format on
1738
        friend typename parallel::util::detail::algorithm_result_t<ExPolicy,
1739
            BidirIter>
1740
        tag_fallback_invoke(hpx::stable_partition_t, ExPolicy&& policy,
26✔
1741
            BidirIter first, BidirIter last, F&& f, Proj&& proj = Proj())
1742
        {
1743
            static_assert(hpx::traits::is_bidirectional_iterator_v<BidirIter>,
1744
                "Requires at least bidirectional iterator.");
1745

1746
            using is_seq = std::integral_constant<bool,
1747
                hpx::is_sequenced_execution_policy_v<ExPolicy> ||
1748
                    !hpx::traits::is_random_access_iterator_v<BidirIter>>;
1749

1750
            return hpx::parallel::v1::detail::stable_partition<BidirIter>()
52✔
1751
                .call2(HPX_FORWARD(ExPolicy, policy), is_seq(), first, last,
45✔
1752
                    HPX_FORWARD(F, f), HPX_FORWARD(Proj, proj));
26✔
1753
        }
1754
    } stable_partition{};
1755

1756
    ///////////////////////////////////////////////////////////////////////////
1757
    // CPO for hpx::partition
1758
    inline constexpr struct partition_t final
1759
      : hpx::detail::tag_parallel_algorithm<partition_t>
1760
    {
1761
        // clang-format off
1762
        template <typename FwdIter, typename Pred,
1763
            typename Proj = parallel::util::projection_identity,
1764
            HPX_CONCEPT_REQUIRES_(
1765
                hpx::traits::is_iterator_v<FwdIter> &&
1766
                parallel::traits::is_projected_v<Proj, FwdIter> &&
1767
                parallel::traits::is_indirect_callable_v<
1768
                    hpx::execution::sequenced_policy,
1769
                    Pred, parallel::traits::projected<Proj, FwdIter>>
1770
        )>
1771
        // clang-format on
1772
        friend FwdIter tag_fallback_invoke(hpx::partition_t, FwdIter first,
6✔
1773
            FwdIter last, Pred&& pred, Proj&& proj = Proj())
1774
        {
1775
            static_assert(hpx::traits::is_forward_iterator_v<FwdIter>,
1776
                "Required at least forward iterator.");
1777

1778
            return hpx::parallel::v1::detail::partition<FwdIter>().call(
12✔
1779
                hpx::execution::seq, first, last, HPX_FORWARD(Pred, pred),
6✔
1780
                HPX_FORWARD(Proj, proj));
6✔
1781
        }
1782

1783
        // clang-format off
1784
        template <typename ExPolicy, typename FwdIter, typename Pred,
1785
            typename Proj = parallel::util::projection_identity,
1786
            HPX_CONCEPT_REQUIRES_(
1787
                hpx::is_execution_policy_v<ExPolicy> &&
1788
                hpx::traits::is_iterator_v<FwdIter> &&
1789
                parallel::traits::is_projected_v<Proj, FwdIter> &&
1790
                parallel::traits::is_indirect_callable_v<ExPolicy,
1791
                    Pred, parallel::traits::projected<Proj, FwdIter>>
1792
        )>
1793
        // clang-format on
1794
        friend typename parallel::util::detail::algorithm_result_t<ExPolicy,
1795
            FwdIter>
1796
        tag_fallback_invoke(hpx::partition_t, ExPolicy&& policy, FwdIter first,
90✔
1797
            FwdIter last, Pred&& pred, Proj&& proj = Proj())
1798
        {
1799
            static_assert(hpx::traits::is_forward_iterator_v<FwdIter>,
1800
                "Required at least forward iterator.");
1801

1802
            return hpx::parallel::v1::detail::partition<FwdIter>().call(
180✔
1803
                HPX_FORWARD(ExPolicy, policy), first, last,
90✔
1804
                HPX_FORWARD(Pred, pred), HPX_FORWARD(Proj, proj));
90✔
1805
        }
1806
    } partition{};
1807

1808
    ///////////////////////////////////////////////////////////////////////////
1809
    // CPO for hpx::partition_copy
1810
    inline constexpr struct partition_copy_t final
1811
      : hpx::detail::tag_parallel_algorithm<partition_copy_t>
1812
    {
1813
        // clang-format off
1814
        template <typename FwdIter1, typename FwdIter2,
1815
            typename FwdIter3, typename Pred,
1816
            typename Proj = parallel::util::projection_identity,
1817
            HPX_CONCEPT_REQUIRES_(
1818
                hpx::traits::is_iterator_v<FwdIter1> &&
1819
                hpx::traits::is_iterator_v<FwdIter2> &&
1820
                hpx::traits::is_iterator_v<FwdIter3> &&
1821
                parallel::traits::is_projected_v<Proj, FwdIter1> &&
1822
                parallel::traits::is_indirect_callable_v<
1823
                    hpx::execution::sequenced_policy, Pred,
1824
                    parallel::traits::projected<Proj, FwdIter1>>
1825
            )>
1826
        // clang-format on
1827
        friend std::pair<FwdIter2, FwdIter3> tag_fallback_invoke(
6✔
1828
            hpx::partition_copy_t, FwdIter1 first, FwdIter1 last,
1829
            FwdIter2 dest_true, FwdIter3 dest_false, Pred&& pred,
1830
            Proj&& proj = Proj())
1831
        {
1832
            static_assert((hpx::traits::is_forward_iterator_v<FwdIter1>),
1833
                "Required at least forward iterator.");
1834
            static_assert((hpx::traits::is_forward_iterator_v<FwdIter2>),
1835
                "Requires at least forward iterator.");
1836
            static_assert((hpx::traits::is_forward_iterator_v<FwdIter3>),
1837
                "Requires at least forward iterator.");
1838

1839
            using result_type = hpx::tuple<FwdIter1, FwdIter2, FwdIter3>;
1840

1841
            return parallel::v1::tuple_to_pair(
6✔
1842
                parallel::v1::detail::partition_copy<result_type>().call(
12✔
1843
                    hpx::execution::seq, first, last, dest_true, dest_false,
1844
                    HPX_FORWARD(Pred, pred), HPX_FORWARD(Proj, proj)));
6✔
1845
        }
1846

1847
        // clang-format off
1848
        template <typename ExPolicy, typename FwdIter1, typename FwdIter2,
1849
            typename FwdIter3, typename Pred,
1850
            typename Proj = parallel::util::projection_identity,
1851
            HPX_CONCEPT_REQUIRES_(
1852
                hpx::is_execution_policy_v<ExPolicy> &&
1853
                hpx::traits::is_iterator_v<FwdIter1> &&
1854
                hpx::traits::is_iterator_v<FwdIter2> &&
1855
                hpx::traits::is_iterator_v<FwdIter3> &&
1856
                parallel::traits::is_projected_v<Proj, FwdIter1> &&
1857
                parallel::traits::is_indirect_callable_v<ExPolicy, Pred,
1858
                    parallel::traits::projected<Proj, FwdIter1>>
1859
            )>
1860
        // clang-format on
1861
        friend parallel::util::detail::algorithm_result_t<ExPolicy,
1862
            std::pair<FwdIter2, FwdIter3>>
1863
        tag_fallback_invoke(hpx::partition_copy_t, ExPolicy&& policy,
60✔
1864
            FwdIter1 first, FwdIter1 last, FwdIter2 dest_true,
1865
            FwdIter3 dest_false, Pred&& pred, Proj&& proj = Proj())
1866
        {
1867
            static_assert((hpx::traits::is_forward_iterator_v<FwdIter1>),
1868
                "Required at least forward iterator.");
1869
            static_assert((hpx::traits::is_forward_iterator_v<FwdIter2>),
1870
                "Requires at least forward iterator.");
1871
            static_assert((hpx::traits::is_forward_iterator_v<FwdIter3>),
1872
                "Requires at least forward iterator.");
1873

1874
            using result_type = hpx::tuple<FwdIter1, FwdIter2, FwdIter3>;
1875

1876
            return parallel::v1::tuple_to_pair(
60✔
1877
                parallel::v1::detail::partition_copy<result_type>().call(
120✔
1878
                    HPX_FORWARD(ExPolicy, policy), first, last, dest_true,
60✔
1879
                    dest_false, HPX_FORWARD(Pred, pred),
60✔
1880
                    HPX_FORWARD(Proj, proj)));
60✔
1881
        }
×
1882
    } partition_copy{};
1883
}    // namespace hpx
1884

1885
#endif    // DOXYGEN
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc