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

STEllAR-GROUP / hpx / #863

11 Jan 2023 05:02PM UTC coverage: 86.533% (-0.05%) from 86.582%
#863

push

StellarBot
Merge #6126

6126: Deprecate hpx::parallel::task_block in favor of hpx::experimental::ta… r=hkaiser a=dimitraka



Co-authored-by: kadimitra <kadimitra@ece.auth.gr>

174614 of 201789 relevant lines covered (86.53%)

1954694.49 hits per line

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

96.0
/libs/core/algorithms/include/hpx/parallel/algorithms/copy.hpp
1
//  Copyright (c) 2022 Bhumit Attarde
2
//  Copyright (c) 2014 Grant Mercer
3
//  Copyright (c) 2015 Daniel Bourgeois
4
//  Copyright (c) 2016-2022 Hartmut Kaiser
5
//
6
//  SPDX-License-Identifier: BSL-1.0
7
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
8
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9

10
/// \file parallel/algorithms/copy.hpp
11

12
#pragma once
13

14
#if defined(DOXYGEN)
15
namespace hpx {
16
    // clang-format off
17

18
    /// Copies the elements in the range, defined by [first, last), to another
19
    /// range beginning at \a dest. Executed according to the policy.
20
    ///
21
    /// \note   Complexity: Performs exactly \a last - \a first assignments.
22
    ///
23
    /// \tparam ExPolicy    The type of the execution policy to use (deduced).
24
    ///                     It describes the manner in which the execution
25
    ///                     of the algorithm may be parallelized and the manner
26
    ///                     in which it executes the assignments.
27
    /// \tparam FwdIter1    The type of the source iterators used (deduced).
28
    ///                     This iterator type must meet the requirements of an
29
    ///                     forward iterator.
30
    /// \tparam FwdIter2    The type of the iterator representing the
31
    ///                     destination range (deduced).
32
    ///                     This iterator type must meet the requirements of an
33
    ///                     forward iterator.
34
    ///
35
    /// \param policy       The execution policy to use for the scheduling of
36
    ///                     the iterations.
37
    /// \param first        Refers to the beginning of the sequence of elements
38
    ///                     the algorithm will be applied to.
39
    /// \param last         Refers to the end of the sequence of elements the
40
    ///                     algorithm will be applied to.
41
    /// \param dest         Refers to the beginning of the destination range.
42
    ///
43
    /// The assignments in the parallel \a copy algorithm invoked with an
44
    /// execution policy object of type \a sequenced_policy
45
    /// execute in sequential order in the calling thread.
46
    ///
47
    /// The assignments in the parallel \a copy algorithm invoked with
48
    /// an execution policy object of type \a parallel_policy or
49
    /// \a parallel_task_policy are permitted to execute in an unordered
50
    /// fashion in unspecified threads, and indeterminately sequenced
51
    /// within each thread.
52
    ///
53
    /// \returns  The \a copy algorithm returns a
54
    ///           \a hpx::future<FwdIter2> >
55
    ///           if the execution policy is of type
56
    ///           \a sequenced_task_policy or
57
    ///           \a parallel_task_policy and
58
    ///           returns \a FwdIter2> otherwise.
59
    ///           The \a copy algorithm returns the pair of the input iterator
60
    ///           \a last and the output iterator to the
61
    ///           element in the destination range, one past the last element
62
    ///           copied.
63
    ///
64
    template <typename ExPolicy, typename FwdIter1, typename FwdIter2>
65
    typename hpx::parallel::util::detail::algorithm_result<ExPolicy, FwdIter2>::type
66
    copy(ExPolicy&& policy, FwdIter1 first, FwdIter1 last, FwdIter2 dest);
67

68
    /// Copies the elements in the range, defined by [first, last), to another
69
    /// range beginning at \a dest.
70
    ///
71
    /// \note   Complexity: Performs exactly \a last - \a first assignments.
72
    ///
73
    /// \tparam FwdIter1    The type of the source iterators used (deduced).
74
    ///                     This iterator type must meet the requirements of an
75
    ///                     forward iterator.
76
    /// \tparam FwdIter2    The type of the iterator representing the
77
    ///                     destination range (deduced).
78
    ///                     This iterator type must meet the requirements of an
79
    ///                     forward iterator.
80
    ///
81
    /// \param first        Refers to the beginning of the sequence of elements
82
    ///                     the algorithm will be applied to.
83
    /// \param last         Refers to the end of the sequence of elements the
84
    ///                     algorithm will be applied to.
85
    /// \param dest         Refers to the beginning of the destination range.
86
    ///
87
    /// \returns  The \a copy algorithm returns a \a FwdIter2 .
88
    ///           The \a copy algorithm returns the pair of the input iterator
89
    ///           \a last and the output iterator to the
90
    ///           element in the destination range, one past the last element
91
    ///           copied.
92
    ///
93
    template <typename FwdIter1, typename FwdIter2>
94
    FwdIter2 copy(FwdIter1 first, FwdIter1 last, FwdIter2 dest);
95

96

97
    /// Copies the elements in the range [first, first + count), starting from
98
    /// first and proceeding to first + count - 1., to another range beginning
99
    /// at dest. Executed according to the policy.
100
    ///
101
    /// \note   Complexity: Performs exactly \a count assignments, if
102
    ///         count > 0, no assignments otherwise.
103
    ///
104
    /// \tparam ExPolicy    The type of the execution policy to use (deduced).
105
    ///                     It describes the manner in which the execution
106
    ///                     of the algorithm may be parallelized and the manner
107
    ///                     in which it executes the assignments.
108
    /// \tparam FwdIter1    The type of the source iterators used (deduced).
109
    ///                     This iterator type must meet the requirements of an
110
    ///                     forward iterator.
111
    /// \tparam Size        The type of the argument specifying the number of
112
    ///                     elements to apply \a f to.
113
    /// \tparam FwdIter2    The type of the iterator representing the
114
    ///                     destination range (deduced).
115
    ///                     This iterator type must meet the requirements of an
116
    ///                     forward iterator.
117
    ///
118
    /// \param policy       The execution policy to use for the scheduling of
119
    ///                     the iterations.
120
    /// \param first        Refers to the beginning of the sequence of elements
121
    ///                     the algorithm will be applied to.
122
    /// \param count        Refers to the number of elements starting at
123
    ///                     \a first the algorithm will be applied to.
124
    /// \param dest         Refers to the beginning of the destination range.
125
    ///
126
    /// The assignments in the parallel \a copy_n algorithm invoked with
127
    /// an execution policy object of type \a sequenced_policy
128
    /// execute in sequential order in the calling thread.
129
    ///
130
    /// The assignments in the parallel \a copy_n algorithm invoked with
131
    /// an execution policy object of type \a parallel_policy or
132
    /// \a parallel_task_policy are permitted to execute in an unordered
133
    /// fashion in unspecified threads, and indeterminately sequenced
134
    /// within each thread.
135
    ///
136
    /// \returns  The \a copy_n algorithm returns a
137
    ///           \a hpx::future<FwdIter2>
138
    ///           if the execution policy is of type
139
    ///           \a sequenced_task_policy or
140
    ///           \a parallel_task_policy and
141
    ///           returns \a FwdIter2
142
    ///           otherwise.
143
    ///           The \a copy_n algorithm returns Iterator in the destination range,
144
    ///           pointing past the last element copied if count>0 or result
145
    ///           otherwise.
146
    ///
147
    template <typename ExPolicy, typename FwdIter1, typename Size, typename FwdIter2>
148
    typename hpx::parallel::util::detail::algorithm_result<ExPolicy, FwdIter2>::type
149
    copy_n(ExPolicy&& policy, FwdIter1 first, Size count, FwdIter2 dest);
150

151
    /// Copies the elements in the range [first, first + count), starting from
152
    /// first and proceeding to first + count - 1., to another range beginning
153
    /// at dest.
154
    ///
155
    /// \note   Complexity: Performs exactly \a count assignments, if
156
    ///         count > 0, no assignments otherwise.
157
    ///
158
    /// \tparam FwdIter1    The type of the source iterators used (deduced).
159
    ///                     This iterator type must meet the requirements of an
160
    ///                     forward iterator.
161
    /// \tparam Size        The type of the argument specifying the number of
162
    ///                     elements to apply \a f to.
163
    /// \tparam FwdIter2    The type of the iterator representing the
164
    ///                     destination range (deduced).
165
    ///                     This iterator type must meet the requirements of an
166
    ///                     forward iterator.
167
    ///
168
    /// \param first        Refers to the beginning of the sequence of elements
169
    ///                     the algorithm will be applied to.
170
    /// \param count        Refers to the number of elements starting at
171
    ///                     \a first the algorithm will be applied to.
172
    /// \param dest         Refers to the beginning of the destination range.
173
    ///
174
    /// \returns  The \a copy_n algorithm returns a \a FwdIter2 .
175
    ///           The \a copy_n algorithm returns Iterator in the destination range,
176
    ///           pointing past the last element copied if count>0 or result
177
    ///           otherwise.
178
    ///
179
    template <typename FwdIter1, typename Size, typename FwdIter2>
180
    FwdIter2 copy_n(FwdIter1 first, Size count, FwdIter2 dest);
181

182

183
    /// Copies the elements in the range, defined by [first, last), to another
184
    /// range beginning at \a dest. Copies only the elements for which the
185
    /// predicate \a f returns true. The order of the elements that are not
186
    /// removed is preserved. Executed according to the policy.
187
    ///
188
    /// \note   Complexity: Performs not more than \a last - \a first
189
    ///         assignments, exactly \a last - \a first applications of the
190
    ///         predicate \a f.
191
    ///
192
    /// \tparam ExPolicy    The type of the execution policy to use (deduced).
193
    ///                     It describes the manner in which the execution
194
    ///                     of the algorithm may be parallelized and the manner
195
    ///                     in which it executes the assignments.
196
    /// \tparam FwdIter1    The type of the source iterators used (deduced).
197
    ///                     This iterator type must meet the requirements of an
198
    ///                     forward iterator.
199
    /// \tparam FwdIter2    The type of the iterator representing the
200
    ///                     destination range (deduced).
201
    ///                     This iterator type must meet the requirements of an
202
    ///                     forward iterator.
203
    /// \tparam Pred        The type of the function/function object to use
204
    ///                     (deduced). Unlike its sequential form, the parallel
205
    ///                     overload of \a copy_if requires \a F to meet the
206
    ///                     requirements of \a CopyConstructible.
207
    ///
208
    /// \param policy       The execution policy to use for the scheduling of
209
    ///                     the iterations.
210
    /// \param first        Refers to the beginning of the sequence of elements
211
    ///                     the algorithm will be applied to.
212
    /// \param last         Refers to the end of the sequence of elements the
213
    ///                     algorithm will be applied to.
214
    /// \param dest         Refers to the beginning of the destination range.
215
    /// \param pred         Specifies the function (or function object) which
216
    ///                     will be invoked for each of the elements in the
217
    ///                     sequence specified by [first, last).This is an
218
    ///                     unary predicate which returns \a true for the
219
    ///                     required elements. The signature of this predicate
220
    ///                     should be equivalent to:
221
    ///                     \code
222
    ///                     bool pred(const Type &a);
223
    ///                     \endcode \n
224
    ///                     The signature does not need to have const&, but
225
    ///                     the function must not modify the objects passed to
226
    ///                     it. The type \a Type must be such that an object of
227
    ///                     type \a FwdIter1 can be dereferenced and then
228
    ///                     implicitly converted to Type.
229
    ///
230
    /// The assignments in the parallel \a copy_if algorithm invoked with
231
    /// an execution policy object of type \a sequenced_policy
232
    /// execute in sequential order in the calling thread.
233
    ///
234
    /// The assignments in the parallel \a copy_if algorithm invoked with
235
    /// an execution policy object of type \a parallel_policy or
236
    /// \a parallel_task_policy are permitted to execute in an unordered
237
    /// fashion in unspecified threads, and indeterminately sequenced
238
    /// within each thread.
239
    ///
240
    /// \returns  The \a copy_if algorithm returns a
241
    ///           \a hpx::future<FwdIter2> >
242
    ///           if the execution policy is of type
243
    ///           \a sequenced_task_policy or
244
    ///           \a parallel_task_policy and
245
    ///           returns \a FwdIter2 otherwise.
246
    ///           The \a copy_if algorithm returns output iterator to the element in
247
    ///           the destination range, one past the last element copied.
248
    ///
249
    template <typename ExPolicy, typename FwdIter1, typename FwdIter2,
250
        typename Pred>
251
    typename hpx::parallel::util::detail::algorithm_result<ExPolicy, FwdIter2> >::type
252
    copy_if(ExPolicy&& policy, FwdIter1 first, FwdIter1 last, FwdIter2 dest,
253
        Pred&& pred);
254

255
    /// Copies the elements in the range, defined by [first, last), to another
256
    /// range beginning at \a dest. Copies only the elements for which the
257
    /// predicate \a f returns true. The order of the elements that are not
258
    /// removed is preserved.
259
    ///
260
    /// \note   Complexity: Performs not more than \a last - \a first
261
    ///         assignments, exactly \a last - \a first applications of the
262
    ///         predicate \a f.
263
    ///
264
    /// \tparam FwdIter1    The type of the source iterators used (deduced).
265
    ///                     This iterator type must meet the requirements of an
266
    ///                     forward iterator.
267
    /// \tparam FwdIter2    The type of the iterator representing the
268
    ///                     destination range (deduced).
269
    ///                     This iterator type must meet the requirements of an
270
    ///                     forward iterator.
271
    /// \tparam Pred        The type of the function/function object to use
272
    ///                     (deduced). Unlike its sequential form, the parallel
273
    ///                     overload of \a copy_if requires \a F to meet the
274
    ///                     requirements of \a CopyConstructible.
275
    ///
276
    /// \param first        Refers to the beginning of the sequence of elements
277
    ///                     the algorithm will be applied to.
278
    /// \param last         Refers to the end of the sequence of elements the
279
    ///                     algorithm will be applied to.
280
    /// \param dest         Refers to the beginning of the destination range.
281
    /// \param pred         Specifies the function (or function object) which
282
    ///                     will be invoked for each of the elements in the
283
    ///                     sequence specified by [first, last).This is an
284
    ///                     unary predicate which returns \a true for the
285
    ///                     required elements. The signature of this predicate
286
    ///                     should be equivalent to:
287
    ///                     \code
288
    ///                     bool pred(const Type &a);
289
    ///                     \endcode \n
290
    ///                     The signature does not need to have const&, but
291
    ///                     the function must not modify the objects passed to
292
    ///                     it. The type \a Type must be such that an object of
293
    ///                     type \a FwdIter1 can be dereferenced and then
294
    ///                     implicitly converted to Type.
295
    ///
296
    /// \returns  The \a copy_if algorithm returns a \a FwdIter2 .
297
    ///           The \a copy_if algorithm returns output iterator to the element in
298
    ///           the destination range, one past the last element copied.
299
    ///
300
    template <typename FwdIter1, typename FwdIter2, typename Pred>
301
    FwdIter2 copy_if(FwdIter1 first, FwdIter1 last, FwdIter2 dest,
302
        Pred&& pred);
303

304
    // clang-format on
305
}    // namespace hpx
306

307
#else    // DOXYGEN
308

309
#include <hpx/config.hpp>
310
#include <hpx/assert.hpp>
311
#include <hpx/concepts/concepts.hpp>
312
#include <hpx/functional/invoke.hpp>
313
#include <hpx/iterator_support/traits/is_iterator.hpp>
314
#include <hpx/parallel/util/detail/sender_util.hpp>
315

316
#include <hpx/algorithms/traits/projected.hpp>
317
#include <hpx/execution/algorithms/detail/is_negative.hpp>
318
#include <hpx/execution/algorithms/detail/predicates.hpp>
319
#include <hpx/executors/execution_policy.hpp>
320
#include <hpx/parallel/algorithms/detail/dispatch.hpp>
321
#include <hpx/parallel/algorithms/detail/distance.hpp>
322
#include <hpx/parallel/algorithms/detail/transfer.hpp>
323
#include <hpx/parallel/util/detail/algorithm_result.hpp>
324
#include <hpx/parallel/util/detail/clear_container.hpp>
325
#include <hpx/parallel/util/foreach_partitioner.hpp>
326
#include <hpx/parallel/util/loop.hpp>
327
#include <hpx/parallel/util/projection_identity.hpp>
328
#include <hpx/parallel/util/result_types.hpp>
329
#include <hpx/parallel/util/scan_partitioner.hpp>
330
#include <hpx/parallel/util/transfer.hpp>
331
#include <hpx/parallel/util/zip_iterator.hpp>
332
#include <hpx/type_support/unused.hpp>
333

334
#if !defined(HPX_HAVE_CXX17_SHARED_PTR_ARRAY)
335
#include <boost/shared_array.hpp>
336
#endif
337

338
#include <algorithm>
339
#include <cstddef>
340
#include <cstring>
341
#include <iterator>
342
#include <memory>
343
#include <type_traits>
344
#include <utility>
345
#include <vector>
346

347
namespace hpx { namespace parallel { inline namespace v1 {
348

349
    ///////////////////////////////////////////////////////////////////////////
350
    // copy
351
    namespace detail {
352

353
        template <typename ExPolicy>
354
        struct copy_iteration
355
        {
356
            using execution_policy_type = std::decay_t<ExPolicy>;
357

358
            template <typename Iter>
359
            HPX_HOST_DEVICE HPX_FORCEINLINE constexpr void operator()(
27,922✔
360
                Iter part_begin, std::size_t part_size, std::size_t) const
361
            {
362
                using hpx::get;
363
                auto iters = part_begin.get_iterator_tuple();
27,922✔
364
                util::copy_n<execution_policy_type>(
27,922✔
365
                    get<0>(iters), part_size, get<1>(iters));
27,922✔
366
            }
27,922✔
367
        };
368

369
        template <typename IterPair>
370
        struct copy : public detail::algorithm<copy<IterPair>, IterPair>
371
        {
372
            copy()
4,769✔
373
              : copy::algorithm("copy")
4,769✔
374
            {
4,769✔
375
            }
4,769✔
376

377
            template <typename ExPolicy, typename InIter, typename Sent,
378
                typename OutIter>
379
            static constexpr std::enable_if_t<
380
                !hpx::traits::is_random_access_iterator_v<InIter>,
381
                util::in_out_result<InIter, OutIter>>
382
            sequential(ExPolicy, InIter first, Sent last, OutIter dest)
15✔
383
            {
384
                util::in_out_result<InIter, OutIter> result =
9✔
385
                    util::copy(first, last, dest);
15✔
386
                util::copy_synchronize(first, dest);
6✔
387
                return result;
6✔
388
            }
9✔
389

390
            template <typename ExPolicy, typename InIter, typename Sent,
391
                typename OutIter>
392
            static constexpr std::enable_if_t<
393
                hpx::traits::is_random_access_iterator_v<InIter>,
394
                util::in_out_result<InIter, OutIter>>
395
            sequential(ExPolicy, InIter first, Sent last, OutIter dest)
2,213✔
396
            {
397
                util::in_out_result<InIter, OutIter> result =
45✔
398
                    util::copy_n<ExPolicy>(
2,213✔
399
                        first, detail::distance(first, last), dest);
2,213✔
400
                util::copy_synchronize(first, dest);
2,204✔
401
                return result;
2,204✔
402
            }
45✔
403

404
            template <typename ExPolicy, typename FwdIter1, typename Sent1,
405
                typename FwdIter2>
406
            static typename util::detail::algorithm_result<ExPolicy,
407
                util::in_out_result<FwdIter1, FwdIter2>>::type
408
            parallel(
2,565✔
409
                ExPolicy&& policy, FwdIter1 first, Sent1 last, FwdIter2 dest)
410
            {
411
#if defined(HPX_COMPUTE_DEVICE_CODE)
412
                HPX_UNUSED(policy);
413
                HPX_UNUSED(first);
414
                HPX_UNUSED(last);
415
                HPX_UNUSED(dest);
416
                HPX_ASSERT(false);
417
                typename util::detail::algorithm_result<ExPolicy,
418
                    util::in_out_result<FwdIter1, FwdIter2>>::type* dummy =
419
                    nullptr;
420
                return HPX_MOVE(*dummy);
421
#else
422
                using zip_iterator =
423
                    hpx::util::zip_iterator<FwdIter1, FwdIter2>;
424

425
                return util::detail::get_in_out_result(
2,565✔
426
                    util::foreach_partitioner<ExPolicy>::call(
2,565✔
427
                        HPX_FORWARD(ExPolicy, policy),
2,565✔
428
                        zip_iterator(first, dest),
2,565✔
429
                        detail::distance(first, last),
2,565✔
430
                        copy_iteration<ExPolicy>(),
431
                        [](zip_iterator&& last) -> zip_iterator {
2,521✔
432
                            using hpx::get;
433
                            auto iters = last.get_iterator_tuple();
2,521✔
434
                            util::copy_synchronize(
2,521✔
435
                                get<0>(iters), get<1>(iters));
2,521✔
436
                            return HPX_MOVE(last);
2,521✔
437
                        }));
48✔
438
#endif
439
            }
16✔
440
        };
441

442
#if defined(HPX_COMPUTE_DEVICE_CODE)
443
        template <typename FwdIter1, typename FwdIter2, typename Enable = void>
444
        struct copy_iter : public copy<util::in_out_result<FwdIter1, FwdIter2>>
445
        {
446
        };
447
#else
448
        ///////////////////////////////////////////////////////////////////////
449
        template <typename FwdIter1, typename FwdIter2, typename Enable = void>
450
        struct copy_iter;
451

452
        template <typename FwdIter1, typename FwdIter2>
453
        struct copy_iter<FwdIter1, FwdIter2,
48✔
454
            std::enable_if_t<
455
                iterators_are_segmented<FwdIter1, FwdIter2>::value>>
456
          : public copy<util::in_out_result<
457
                typename hpx::traits::segmented_iterator_traits<
458
                    FwdIter1>::local_iterator,
459
                typename hpx::traits::segmented_iterator_traits<
460
                    FwdIter2>::local_iterator>>
461
        {
462
        };
463

464
        template <typename FwdIter1, typename FwdIter2>
465
        struct copy_iter<FwdIter1, FwdIter2,
325✔
466
            std::enable_if_t<
467
                iterators_are_not_segmented<FwdIter1, FwdIter2>::value>>
468
          : public copy<util::in_out_result<FwdIter1, FwdIter2>>
469
        {
470
        };
471
#endif
472
    }    // namespace detail
473

474
    /////////////////////////////////////////////////////////////////////////////
475
    // copy_n
476
    namespace detail {
477

478
        // sequential copy_n
479
        template <typename IterPair>
480
        struct copy_n : public detail::algorithm<copy_n<IterPair>, IterPair>
481
        {
482
            copy_n()
60✔
483
              : copy_n::algorithm("copy_n")
60✔
484
            {
60✔
485
            }
60✔
486

487
            template <typename ExPolicy, typename InIter, typename OutIter>
488
            static constexpr util::in_out_result<InIter, OutIter> sequential(
32✔
489
                ExPolicy, InIter first, std::size_t count, OutIter dest)
490
            {
491
                util::in_out_result<InIter, OutIter> result =
×
492
                    util::copy_n<ExPolicy>(first, count, dest);
12✔
493
                util::copy_synchronize(first, dest);
12✔
494
                return result;
12✔
495
            }
×
496

497
            template <typename ExPolicy, typename FwdIter1, typename FwdIter2>
498
            static typename util::detail::algorithm_result<ExPolicy,
499
                util::in_out_result<FwdIter1, FwdIter2>>::type
500
            parallel(ExPolicy&& policy, FwdIter1 first, std::size_t count,
28✔
501
                FwdIter2 dest)
502
            {
503
                using zip_iterator =
504
                    hpx::util::zip_iterator<FwdIter1, FwdIter2>;
505

506
                return util::detail::get_in_out_result(
28✔
507
                    util::foreach_partitioner<ExPolicy>::call(
28✔
508
                        HPX_FORWARD(ExPolicy, policy),
28✔
509
                        zip_iterator(first, dest), count,
28✔
510
                        [](zip_iterator part_begin, std::size_t part_size,
184✔
511
                            std::size_t) {
512
                            auto iters = part_begin.get_iterator_tuple();
184✔
513
                            util::copy_n<ExPolicy>(hpx::get<0>(iters),
368✔
514
                                part_size, hpx::get<1>(iters));
184✔
515
                        },
184✔
516
                        [](zip_iterator&& last) -> zip_iterator {
12✔
517
                            auto iters = last.get_iterator_tuple();
12✔
518
                            util::copy_synchronize(
12✔
519
                                hpx::get<0>(iters), hpx::get<1>(iters));
12✔
520
                            return HPX_MOVE(last);
12✔
521
                        }));
×
522
            }
8✔
523
        };
524
    }    // namespace detail
525

526
    /////////////////////////////////////////////////////////////////////////////
527
    // copy_if
528
    namespace detail {
529

530
        // sequential copy_if with projection function
531
        template <typename InIter1, typename InIter2, typename OutIter,
532
            typename Pred, typename Proj>
533
        inline util::in_out_result<InIter1, OutIter> sequential_copy_if(
87✔
534
            InIter1 first, InIter2 last, OutIter dest, Pred&& pred, Proj&& proj)
535
        {
536
            while (first != last)
2,207,462✔
537
            {
538
                if (HPX_INVOKE(pred, HPX_INVOKE(proj, *first)))
2,207,375✔
539
                    *dest++ = *first;
71,403✔
540
                first++;
2,207,375✔
541
            }
542
            return util::in_out_result<InIter1, OutIter>{
231✔
543
                HPX_MOVE(first), HPX_MOVE(dest)};
154✔
544
        }
545

546
        template <typename IterPair>
547
        struct copy_if : public detail::algorithm<copy_if<IterPair>, IterPair>
548
        {
549
            copy_if()
261✔
550
              : copy_if::algorithm("copy_if")
261✔
551
            {
261✔
552
            }
261✔
553

554
            template <typename ExPolicy, typename InIter1, typename InIter2,
555
                typename OutIter, typename Pred,
556
                typename Proj = util::projection_identity>
557
            static util::in_out_result<InIter1, OutIter> sequential(ExPolicy,
87✔
558
                InIter1 first, InIter2 last, OutIter dest, Pred&& pred,
559
                Proj&& proj /* = Proj()*/)
560
            {
561
                return sequential_copy_if(first, last, dest,
174✔
562
                    HPX_FORWARD(Pred, pred), HPX_FORWARD(Proj, proj));
87✔
563
            }
564

565
            template <typename ExPolicy, typename FwdIter1, typename FwdIter2,
566
                typename FwdIter3, typename Pred,
567
                typename Proj = util::projection_identity>
568
            static typename util::detail::algorithm_result<ExPolicy,
569
                util::in_out_result<FwdIter1, FwdIter3>>::type
570
            parallel(ExPolicy&& policy, FwdIter1 first, FwdIter2 last,
174✔
571
                FwdIter3 dest, Pred&& pred, Proj&& proj /* = Proj()*/)
572
            {
573
                typedef hpx::util::zip_iterator<FwdIter1, bool*> zip_iterator;
574
                typedef util::detail::algorithm_result<ExPolicy,
575
                    util::in_out_result<FwdIter1, FwdIter3>>
576
                    result;
577
                typedef typename std::iterator_traits<FwdIter1>::difference_type
578
                    difference_type;
579

580
                if (first == last)
174✔
581
                {
582
                    return result::get(util::in_out_result<FwdIter1, FwdIter3>{
26✔
583
                        HPX_MOVE(first), HPX_MOVE(dest)});
12✔
584
                }
585

586
                difference_type count = detail::distance(first, last);
168✔
587

588
#if defined(HPX_HAVE_CXX17_SHARED_PTR_ARRAY)
589
                std::shared_ptr<bool[]> flags(new bool[count]);
168✔
590
#else
591
                boost::shared_array<bool> flags(new bool[count]);
592
#endif
593
                std::size_t init = 0;
168✔
594

595
                using hpx::get;
596
                typedef util::scan_partitioner<ExPolicy,
597
                    util::in_out_result<FwdIter1, FwdIter3>, std::size_t>
598
                    scan_partitioner_type;
599

600
                auto f1 = [pred = HPX_FORWARD(Pred, pred),
1,272✔
601
                              proj = HPX_FORWARD(decltype(proj), proj)](
168✔
602
                              zip_iterator part_begin,
603
                              std::size_t part_size) -> std::size_t {
604
                    std::size_t curr = 0;
1,104✔
605

606
                    // Note: replacing the invoke() with HPX_INVOKE()
607
                    // below makes gcc generate errors
608

609
                    // MSVC complains if proj is captured by ref below
610
                    util::loop_n<std::decay_t<ExPolicy>>(part_begin, part_size,
1,104✔
611
                        [&pred, proj, &curr](zip_iterator it) mutable -> void {
2,217,408✔
612
                            bool f = hpx::invoke(
2,213,553✔
613
                                pred, hpx::invoke(proj, get<0>(*it)));
2,213,553✔
614

615
                            if ((get<1>(*it) = f))
2,213,553✔
616
                                ++curr;
122,458✔
617
                        });
2,206,740✔
618

619
                    return curr;
1,104✔
620
                };
621
                auto f3 = [dest, flags](zip_iterator part_begin,
4,096✔
622
                              std::size_t part_size, std::size_t val) mutable {
623
                    HPX_UNUSED(flags);
704✔
624
                    std::advance(dest, val);
704✔
625
                    util::loop_n<std::decay_t<ExPolicy>>(part_begin, part_size,
704✔
626
                        [&dest](zip_iterator it) mutable {
2,000,453✔
627
                            if (get<1>(*it))
2,009,432✔
628
                                *dest++ = get<0>(*it);
124,867✔
629
                        });
2,025,965✔
630
                };
704✔
631

632
                auto f4 = [first, dest, flags](std::vector<std::size_t>&& items,
704✔
633
                              std::vector<hpx::future<void>>&& data) mutable
634
                    -> util::in_out_result<FwdIter1, FwdIter3> {
635
                    HPX_UNUSED(flags);
128✔
636

637
                    auto dist = items.back();
128✔
638
                    std::advance(first, dist);
128✔
639
                    std::advance(dest, dist);
128✔
640

641
                    // make sure iterators embedded in function object that is
642
                    // attached to futures are invalidated
643
                    util::detail::clear_container(data);
128✔
644

645
                    return util::in_out_result<FwdIter1, FwdIter3>{
384✔
646
                        HPX_MOVE(first), HPX_MOVE(dest)};
256✔
647
                };
648

649
                return scan_partitioner_type::call(
168✔
650
                    HPX_FORWARD(ExPolicy, policy),
168✔
651
                    zip_iterator(first, flags.get()), count, init,
168✔
652
                    // step 1 performs first part of scan algorithm
653
                    HPX_MOVE(f1),
654
                    // step 2 propagates the partition results from left
655
                    // to right
656
                    std::plus<std::size_t>(),
657
                    // step 3 runs final accumulation on each partition
658
                    HPX_MOVE(f3),
659
                    // step 4 use this return value
660
                    HPX_MOVE(f4));
661
            }
182✔
662
        };
663
    }    // namespace detail
664
}}}      // namespace hpx::parallel::v1
665

666
namespace hpx {
667

668
    ///////////////////////////////////////////////////////////////////////////
669
    // CPO for hpx::copy
670
    inline constexpr struct copy_t final
671
      : hpx::detail::tag_parallel_algorithm<copy_t>
672
    {
673
    private:
674
        // clang-format off
675
        template <typename ExPolicy, typename FwdIter1, typename FwdIter2,
676
            HPX_CONCEPT_REQUIRES_(
677
                hpx::is_execution_policy_v<ExPolicy> &&
678
                hpx::traits::is_iterator_v<FwdIter1> &&
679
                hpx::traits::is_iterator_v<FwdIter2>
680
            )>
681
        // clang-format on
682
        friend typename parallel::util::detail::algorithm_result<ExPolicy,
683
            FwdIter2>::type
684
        tag_fallback_invoke(hpx::copy_t, ExPolicy&& policy, FwdIter1 first,
293✔
685
            FwdIter1 last, FwdIter2 dest)
686
        {
687
            return parallel::util::get_second_element(
293✔
688
                parallel::v1::detail::transfer<
293✔
689
                    parallel::v1::detail::copy_iter<FwdIter1, FwdIter2>>(
690
                    HPX_FORWARD(ExPolicy, policy), first, last, dest));
293✔
691
        }
8✔
692

693
        // clang-format off
694
        template <typename FwdIter1, typename FwdIter2,
695
            HPX_CONCEPT_REQUIRES_(
696
                hpx::traits::is_iterator_v<FwdIter1> &&
697
                hpx::traits::is_iterator_v<FwdIter2>
698
            )>
699
        // clang-format on
700
        friend FwdIter2 tag_fallback_invoke(
4✔
701
            hpx::copy_t, FwdIter1 first, FwdIter1 last, FwdIter2 dest)
702
        {
703
            return parallel::util::get_second_element(
4✔
704
                parallel::v1::detail::transfer<
4✔
705
                    parallel::v1::detail::copy_iter<FwdIter1, FwdIter2>>(
706
                    hpx::execution::seq, first, last, dest));
4✔
707
        }
2✔
708
    } copy{};
709

710
    ///////////////////////////////////////////////////////////////////////////
711
    // CPO for hpx::copy_n
712
    inline constexpr struct copy_n_t final
713
      : hpx::detail::tag_parallel_algorithm<copy_n_t>
714
    {
715
    private:
716
        // clang-format off
717
        template <typename ExPolicy, typename FwdIter1, typename Size,
718
            typename FwdIter2,
719
            HPX_CONCEPT_REQUIRES_(
720
                hpx::is_execution_policy_v<ExPolicy> &&
721
                hpx::traits::is_iterator_v<FwdIter1> &&
722
                hpx::traits::is_iterator_v<FwdIter2>
723
            )>
724
        // clang-format on
725
        friend typename hpx::parallel::util::detail::algorithm_result<ExPolicy,
726
            FwdIter2>::type
727
        tag_fallback_invoke(hpx::copy_n_t, ExPolicy&& policy, FwdIter1 first,
26✔
728
            Size count, FwdIter2 dest)
729
        {
730
            static_assert((hpx::traits::is_forward_iterator_v<FwdIter1>),
731
                "Required at least forward iterator.");
732
            static_assert(hpx::traits::is_forward_iterator_v<FwdIter2> ||
733
                    (hpx::is_sequenced_execution_policy_v<ExPolicy> &&
734
                        hpx::traits::is_output_iterator_v<FwdIter2>),
735
                "Requires at least forward iterator or sequential execution.");
736

737
            // if count is representing a negative value, we do nothing
738
            if (hpx::parallel::v1::detail::is_negative(count))
739
            {
740
                return hpx::parallel::util::detail::algorithm_result<ExPolicy,
741
                    FwdIter2>::get(HPX_MOVE(dest));
742
            }
743

744
            return hpx::parallel::util::get_second_element(
26✔
745
                hpx::parallel::v1::detail::copy_n<
18✔
746
                    hpx::parallel::util::in_out_result<FwdIter1, FwdIter2>>()
747
                    .call(HPX_FORWARD(ExPolicy, policy), first,
52✔
748
                        std::size_t(count), dest));
18✔
749
        }
×
750

751
        // clang-format off
752
        template <typename FwdIter1, typename Size, typename FwdIter2,
753
            HPX_CONCEPT_REQUIRES_(
754
                hpx::traits::is_iterator_v<FwdIter1> &&
755
                hpx::traits::is_iterator_v<FwdIter2>
756
            )>
757
        // clang-format on
758
        friend FwdIter2 tag_fallback_invoke(
4✔
759
            hpx::copy_n_t, FwdIter1 first, Size count, FwdIter2 dest)
760
        {
761
            static_assert((hpx::traits::is_forward_iterator_v<FwdIter1>),
762
                "Required at least forward iterator.");
763
            static_assert((hpx::traits::is_output_iterator_v<FwdIter2>),
764
                "Requires at least output iterator.");
765

766
            // if count is representing a negative value, we do nothing
767
            if (hpx::parallel::v1::detail::is_negative(count))
768
            {
769
                return hpx::parallel::util::detail::algorithm_result<
770
                    hpx::execution::sequenced_policy,
771
                    FwdIter2>::get(HPX_MOVE(dest));
772
            }
773

774
            return hpx::parallel::util::get_second_element(
4✔
775
                hpx::parallel::v1::detail::copy_n<
2✔
776
                    hpx::parallel::util::in_out_result<FwdIter1, FwdIter2>>()
777
                    .call(
2✔
778
                        hpx::execution::seq, first, std::size_t(count), dest));
2✔
779
        }
×
780
    } copy_n{};
781

782
    ///////////////////////////////////////////////////////////////////////////
783
    // CPO for hpx::copy_if
784
    inline constexpr struct copy_if_t final
785
      : hpx::detail::tag_parallel_algorithm<copy_if_t>
786
    {
787
    private:
788
        // clang-format off
789
        template <typename ExPolicy, typename FwdIter1, typename FwdIter2,
790
            typename Pred,
791
            HPX_CONCEPT_REQUIRES_(
792
                hpx::is_execution_policy_v<ExPolicy> &&
793
                hpx::traits::is_iterator_v<FwdIter1> &&
794
                hpx::traits::is_iterator_v<FwdIter2> &&
795
                hpx::is_invocable_v<Pred,
796
                    typename std::iterator_traits<FwdIter1>::value_type
797
                >
798
            )>
799
        // clang-format on
800
        friend typename hpx::parallel::util::detail::algorithm_result<ExPolicy,
801
            FwdIter2>::type
802
        tag_fallback_invoke(hpx::copy_if_t, ExPolicy&& policy, FwdIter1 first,
86✔
803
            FwdIter1 last, FwdIter2 dest, Pred&& pred)
804
        {
805
            static_assert((hpx::traits::is_forward_iterator_v<FwdIter1>),
806
                "Required at least forward iterator.");
807
            static_assert(hpx::traits::is_forward_iterator_v<FwdIter2> ||
808
                    (hpx::is_sequenced_execution_policy_v<ExPolicy> &&
809
                        hpx::traits::is_output_iterator_v<FwdIter2>),
810
                "Requires at least forward iterator or sequential execution.");
811

812
            return hpx::parallel::util::get_second_element(
86✔
813
                hpx::parallel::v1::detail::copy_if<
86✔
814
                    hpx::parallel::util::in_out_result<FwdIter1, FwdIter2>>()
815
                    .call(HPX_FORWARD(ExPolicy, policy), first, last, dest,
172✔
816
                        HPX_FORWARD(Pred, pred),
86✔
817
                        hpx::parallel::util::projection_identity{}));
818
        }
×
819

820
        // clang-format off
821
        template <typename FwdIter1, typename FwdIter2, typename Pred,
822
            HPX_CONCEPT_REQUIRES_(
823
                hpx::traits::is_iterator_v<FwdIter1> &&
824
                hpx::traits::is_iterator_v<FwdIter2> &&
825
                hpx::is_invocable_v<Pred,
826
                    typename std::iterator_traits<FwdIter1>::value_type
827
                >
828
            )>
829
        // clang-format on
830
        friend FwdIter2 tag_fallback_invoke(hpx::copy_if_t, FwdIter1 first,
64✔
831
            FwdIter1 last, FwdIter2 dest, Pred&& pred)
832
        {
833
            static_assert((hpx::traits::is_forward_iterator_v<FwdIter1>),
834
                "Required at least forward iterator.");
835
            static_assert((hpx::traits::is_output_iterator_v<FwdIter2>),
836
                "Requires at least output iterator.");
837

838
            return hpx::parallel::util::get_second_element(
64✔
839
                hpx::parallel::v1::detail::copy_if<
64✔
840
                    hpx::parallel::util::in_out_result<FwdIter1, FwdIter2>>()
841
                    .call(hpx::execution::seq, first, last, dest,
64✔
842
                        HPX_FORWARD(Pred, pred),
64✔
843
                        hpx::parallel::util::projection_identity{}));
844
        }
845
    } copy_if{};
846

847
}    // namespace hpx
848

849
#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

© 2026 Coveralls, Inc