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

STEllAR-GROUP / hpx / #882

31 Aug 2023 07:44PM UTC coverage: 41.798% (-44.7%) from 86.546%
#882

push

19442 of 46514 relevant lines covered (41.8%)

126375.38 hits per line

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

57.58
/libs/core/algorithms/include/hpx/parallel/util/loop.hpp
1
//  Copyright (c) 2007-2025 Hartmut Kaiser
2
//
3
//  SPDX-License-Identifier: BSL-1.0
4
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
5
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6

7
#pragma once
8

9
#include <hpx/config.hpp>
10
#include <hpx/assert.hpp>
11
#include <hpx/modules/datastructures.hpp>
12
#include <hpx/modules/execution.hpp>
13
#include <hpx/modules/executors.hpp>
14
#include <hpx/modules/iterator_support.hpp>
15
#include <hpx/modules/tag_invoke.hpp>
16
#include <hpx/modules/type_support.hpp>
17
#include <hpx/parallel/algorithms/detail/advance_and_get_distance.hpp>
18
#include <hpx/parallel/algorithms/detail/dispatch.hpp>
19

20
#include <algorithm>
21
#include <cstddef>
22
#include <iterator>
23
#include <type_traits>
24
#include <utility>
25
#include <vector>
26

27
namespace hpx::parallel::util {
28

29
    ///////////////////////////////////////////////////////////////////////////
30
    namespace detail {
31

32
        // Helper class to repeatedly call a function starting from a given
33
        // iterator position.
34
        HPX_CXX_EXPORT template <typename Iterator>
35
        struct loop
36
        {
37
            ///////////////////////////////////////////////////////////////////
38
            template <typename Begin, typename End, typename F>
39
            HPX_HOST_DEVICE HPX_FORCEINLINE static constexpr Begin call(
40
                Begin it, End end, F&& f)
41
            {
42
                return call(hpx::execution::seq, it, end, HPX_FORWARD(F, f));
43
            }
44

45
            template <typename Begin, typename End, typename CancelToken,
46
                typename F>
47
                requires(hpx::traits::is_iterator_v<End> &&
48
                    hpx::traits::is_forward_iterator_v<Begin>)
49
            HPX_HOST_DEVICE HPX_FORCEINLINE static Begin call(
50
                Begin it, End end, CancelToken& tok, F&& f)
51
            {
52
                return call(
53
                    hpx::execution::seq, it, end, tok, HPX_FORWARD(F, f));
54
            }
55

56
            template <typename ExPolicy, typename Begin, typename End,
57
                typename F>
58
                requires(    // forces hpx::execution::unseq
59
                    hpx::is_unsequenced_execution_policy_v<ExPolicy> &&
60
                    !hpx::is_parallel_execution_policy_v<ExPolicy>)
61
            HPX_HOST_DEVICE HPX_FORCEINLINE static Begin call(
62
                ExPolicy&&, Begin it, End last, F&& f)
63
            {
64
                // clang-format off
65
                HPX_IVDEP HPX_UNROLL HPX_VECTORIZE
66
                for (Begin& iter = it; iter != last; ++iter)
67
                {
68
                    HPX_INVOKE(f, iter);
69
                }
70
                // clang-format on
71

72
                return it;
73
            }
74

75
            template <typename ExPolicy, typename Begin, typename End,
76
                typename F>
77
                requires(!hpx::is_unsequenced_execution_policy_v<ExPolicy>)
78
            HPX_HOST_DEVICE HPX_FORCEINLINE static constexpr Begin call(
79
                ExPolicy&&, Begin it, End last, F&& f)
80
            {
81
                for (/**/; it != last; ++it)
82
                {
×
83
                    HPX_INVOKE(f, it);
84
                }
×
85
                return it;
86
            }
87

88
            template <typename ExPolicy, typename Begin, typename End,
89
                typename CancelToken, typename F>
90
                requires(hpx::is_execution_policy_v<ExPolicy>)
91
            HPX_HOST_DEVICE HPX_FORCEINLINE static Begin call(
92
                ExPolicy&& policy, Begin it, End end, CancelToken& tok, F&& f)
93
            {
94
                // check at the start of a partition only
95
                if (tok.was_cancelled())
96
                    return it;
97

98
                return call(
99
                    HPX_FORWARD(ExPolicy, policy), it, end, HPX_FORWARD(F, f));
100
            }
101
        };
102
    }    // namespace detail
103

104
    HPX_CXX_EXPORT struct loop_t final
105
      : hpx::functional::detail::tag_fallback<loop_t>
106
    {
107
    private:
108
        template <typename ExPolicy, typename Begin, typename End, typename F>
109
        friend HPX_HOST_DEVICE HPX_FORCEINLINE constexpr Begin
110
        tag_fallback_invoke(hpx::parallel::util::loop_t, ExPolicy&& policy,
111
            Begin begin, End end, F&& f)
112
        {
113
            return detail::loop<Begin>::call(
114
                HPX_FORWARD(ExPolicy, policy), begin, end, HPX_FORWARD(F, f));
×
115
        }
116

117
        template <typename ExPolicy, typename Begin, typename End,
118
            typename CancelToken, typename F>
119
        friend HPX_HOST_DEVICE HPX_FORCEINLINE constexpr Begin
120
        tag_fallback_invoke(hpx::parallel::util::loop_t, ExPolicy&& policy,
121
            Begin begin, End end, CancelToken& tok, F&& f)
122
        {
123
            return detail::loop<Begin>::call(HPX_FORWARD(ExPolicy, policy),
124
                begin, end, tok, HPX_FORWARD(F, f));
125
        }
126
    };
127

128
#if !defined(HPX_COMPUTE_DEVICE_CODE)
129
    HPX_CXX_EXPORT inline constexpr loop_t loop = loop_t{};
130
#else
131
    HPX_CXX_EXPORT template <typename ExPolicy, typename Begin, typename End,
132
        typename F>
133
    HPX_HOST_DEVICE HPX_FORCEINLINE constexpr decltype(auto) loop(
134
        ExPolicy&& policy, Begin begin, End end, F&& f)
135
    {
136
        return hpx::parallel::util::loop_t{}(
137
            HPX_FORWARD(ExPolicy, policy), begin, end, HPX_FORWARD(F, f));
138
    }
139

140
    HPX_CXX_EXPORT template <typename ExPolicy, typename Begin, typename End,
141
        typename CancelToken, typename F>
142
    HPX_HOST_DEVICE HPX_FORCEINLINE constexpr decltype(auto) loop(
143
        ExPolicy&& policy, Begin begin, End end, CancelToken& tok, F&& f)
144
    {
145
        return hpx::parallel::util::loop_t{}(
146
            HPX_FORWARD(ExPolicy, policy), begin, end, tok, HPX_FORWARD(F, f));
147
    }
148
#endif
149

150
    ///////////////////////////////////////////////////////////////////////////
151
    namespace detail {
152

153
        // Helper class to repeatedly call a function starting from a given
154
        // iterator position till the predicate returns true.
155
        HPX_CXX_EXPORT template <typename Iterator>
156
        struct loop_pred
157
        {
158
            ///////////////////////////////////////////////////////////////////
159
            template <typename Begin, typename End, typename Pred>
160
            HPX_HOST_DEVICE HPX_FORCEINLINE static constexpr Begin call(
161
                Begin it, End end, Pred&& pred)
162
            {
163
                for (/**/; it != end; ++it)
164
                {
165
                    if (HPX_INVOKE(pred, it))
166
                        return it;
167
                }
168
                return it;
169
            }
170
        };
171
    }    // namespace detail
172

173
    HPX_CXX_EXPORT template <typename ExPolicy>
174
    struct loop_pred_t final
175
      : hpx::functional::detail::tag_fallback<loop_pred_t<ExPolicy>>
176
    {
177
    private:
178
        template <typename Begin, typename End, typename Pred>
179
        friend HPX_HOST_DEVICE HPX_FORCEINLINE constexpr Begin
180
        tag_fallback_invoke(hpx::parallel::util::loop_pred_t<ExPolicy>,
181
            Begin begin, End end, Pred&& pred)
182
        {
183
            return detail::loop_pred<Begin>::call(
184
                begin, end, HPX_FORWARD(Pred, pred));
185
        }
186
    };
187

188
#if !defined(HPX_COMPUTE_DEVICE_CODE)
189
    HPX_CXX_EXPORT template <typename ExPolicy>
190
    inline constexpr loop_pred_t<ExPolicy> loop_pred = loop_pred_t<ExPolicy>{};
191
#else
192
    HPX_CXX_EXPORT template <typename ExPolicy, typename Begin, typename End,
193
        typename Pred>
194
    HPX_HOST_DEVICE HPX_FORCEINLINE constexpr decltype(auto) loop_pred(
195
        Begin begin, End end, Pred&& pred)
196
    {
197
        return hpx::parallel::util::loop_pred_t<ExPolicy>{}(
198
            begin, end, HPX_FORWARD(Pred, pred));
199
    }
200
#endif
201

202
    ///////////////////////////////////////////////////////////////////////////
203
    namespace detail {
204

205
        // Helper class to repeatedly call a function starting from a given
206
        // iterator position.
207
        HPX_CXX_EXPORT template <typename Iterator>
208
        struct loop_ind
209
        {
210
            ///////////////////////////////////////////////////////////////////
211
            template <typename Begin, typename End, typename F>
212
            HPX_HOST_DEVICE HPX_FORCEINLINE static constexpr Begin call(
213
                Begin start, End sent, F&& f)
214
            {
1,010,025✔
215
                if constexpr (hpx::traits::is_random_access_iterator_v<Begin>)
216
                {
10,012✔
217
                    auto end = start;
218
                    auto const len =
10✔
219
                        parallel::detail::advance_and_get_distance(end, sent);
220

221
                    if (len != 0)
222
                    {
223
                        auto it = hpx::util::get_unwrapped(start);
224
                        for (auto count = len; count != 0; (void) ++it, --count)
225
                        {
226
                            HPX_INVOKE(f, *it);
227
                        }
228
                    }
229
                    return std::next(start, len);
230
                }
231
                else
232
                {
233
                    for (/**/; start != sent; ++start)
234
                    {
235
                        HPX_INVOKE(f, *start);
236
                    }
237
                    return start;
238
                }
239
            }
240

241
            template <typename Begin, typename End, typename CancelToken,
242
                typename F>
243
            HPX_HOST_DEVICE HPX_FORCEINLINE static Begin call(
244
                Begin it, End end, CancelToken& tok, F&& f)
245
            {
246
                // check at the start of a partition only
20✔
247
                if (tok.was_cancelled())
248
                    return it;
249

250
                return call(it, end, HPX_FORWARD(F, f));
251
            }
252
        };
253
    }    // namespace detail
254

255
    HPX_CXX_EXPORT template <typename ExPolicy>
256
    struct loop_ind_t final
257
      : hpx::functional::detail::tag_fallback<loop_ind_t<ExPolicy>>
258
    {
259
    private:
260
        template <typename Begin, typename End, typename F>
261
        friend HPX_HOST_DEVICE HPX_FORCEINLINE constexpr Begin
262
        tag_fallback_invoke(hpx::parallel::util::loop_ind_t<ExPolicy>,
263
            Begin begin, End end, F&& f)
264
        {
265
            return detail::loop_ind<std::decay_t<Begin>>::call(
266
                begin, end, HPX_FORWARD(F, f));
267
        }
268

269
        template <typename Begin, typename End, typename CancelToken,
270
            typename F>
271
        friend HPX_HOST_DEVICE HPX_FORCEINLINE constexpr Begin
272
        tag_fallback_invoke(hpx::parallel::util::loop_ind_t<ExPolicy>,
273
            Begin begin, End end, CancelToken& tok, F&& f)
274
        {
275
            return detail::loop_ind<std::decay_t<Begin>>::call(
276
                begin, end, tok, HPX_FORWARD(F, f));
277
        }
278
    };
279

280
#if !defined(HPX_COMPUTE_DEVICE_CODE)
281
    HPX_CXX_EXPORT template <typename ExPolicy>
282
    inline constexpr loop_ind_t<ExPolicy> loop_ind = loop_ind_t<ExPolicy>{};
283
#else
284
    HPX_CXX_EXPORT template <typename ExPolicy, typename Begin, typename End,
285
        typename F>
286
    HPX_HOST_DEVICE HPX_FORCEINLINE constexpr decltype(auto) loop_ind(
287
        Begin begin, End end, F&& f)
288
    {
289
        return hpx::parallel::util::loop_ind_t<ExPolicy>{}(
290
            begin, end, HPX_FORWARD(F, f));
291
    }
292

293
    HPX_CXX_EXPORT template <typename ExPolicy, typename Begin, typename End,
294
        typename CancelToken, typename F>
295
    HPX_HOST_DEVICE HPX_FORCEINLINE constexpr Begin loop_ind(
296
        Begin begin, End end, CancelToken& tok, F&& f)
297
    {
298
        return hpx::parallel::util::loop_ind_t<ExPolicy>{}(
299
            begin, end, tok, HPX_FORWARD(F, f));
300
    }
301
#endif
302

303
    ///////////////////////////////////////////////////////////////////////////
304
    namespace detail {
305

306
        // Helper class to repeatedly call a function starting from a given
307
        // iterator position.
308
        HPX_CXX_EXPORT template <typename Iter1, typename Iter2>
309
        struct loop2
310
        {
311
            ///////////////////////////////////////////////////////////////////
312
            template <typename Begin1, typename End1, typename Begin2,
313
                typename F>
314
            HPX_HOST_DEVICE
315
                HPX_FORCEINLINE static constexpr std::pair<Begin1, Begin2>
316
                call(Begin1 it1, End1 last1, Begin2 it2, F&& f)
317
            {
318
                for (/**/; it1 != last1; (void) ++it1, ++it2)
319
                {
320
                    HPX_INVOKE(f, it1, it2);
321
                }
322
                return std::make_pair(it1, it2);
323
            }
324
        };
325
    }    // namespace detail
326

327
    HPX_CXX_EXPORT template <typename ExPolicy>
328
    struct loop2_t final
329
      : hpx::functional::detail::tag_fallback<loop2_t<ExPolicy>>
330
    {
331
    private:
332
        template <typename Begin1, typename End1, typename Begin2, typename F>
333
        friend HPX_HOST_DEVICE
334
            HPX_FORCEINLINE constexpr std::pair<Begin1, Begin2>
335
            tag_fallback_invoke(hpx::parallel::util::loop2_t<ExPolicy>,
336
                Begin1 begin1, End1 end1, Begin2 begin2, F&& f)
337
        {
338
            return detail::loop2<Begin1, Begin2>::call(
339
                begin1, end1, begin2, HPX_FORWARD(F, f));
340
        }
341
    };
342

343
#if !defined(HPX_COMPUTE_DEVICE_CODE)
344
    HPX_CXX_EXPORT template <typename ExPolicy>
345
    inline constexpr loop2_t<ExPolicy> loop2 = loop2_t<ExPolicy>{};
346
#else
347
    HPX_CXX_EXPORT template <typename ExPolicy, typename Begin1, typename End1,
348
        typename Begin2, typename F>
349
    HPX_HOST_DEVICE HPX_FORCEINLINE constexpr decltype(auto) loop2(
350
        Begin1 begin1, End1 end1, Begin2 begin2, F&& f)
351
    {
352
        return hpx::parallel::util::loop2_t<ExPolicy>{}(
353
            begin1, end1, begin2, HPX_FORWARD(F, f));
354
    }
355
#endif
356

357
    ///////////////////////////////////////////////////////////////////////////
358
    namespace detail {
359

360
        // Helper class to repeatedly call a function a given number of times
361
        // starting from a given iterator position.
362
        HPX_CXX_EXPORT struct loop_n_helper
363
        {
364
            ///////////////////////////////////////////////////////////////////
365
            // handle sequences of non-futures
366
            template <typename Iter, typename F>
367
            HPX_HOST_DEVICE HPX_FORCEINLINE static constexpr Iter call(
368
                Iter it, std::size_t num, F&& f, std::false_type)
369
            {
370
                std::size_t count(
7✔
371
                    num & static_cast<std::size_t>(-4));    // -V112
372
                for (std::size_t i = 0; i < count;
×
373
                    (void) ++it, i += 4)    // -V112
×
374
                {
×
375
                    HPX_INVOKE(f, it);
×
376
                    HPX_INVOKE(f, ++it);
377
                    HPX_INVOKE(f, ++it);
×
378
                    HPX_INVOKE(f, ++it);
×
379
                }
380
                for (/**/; count < num; (void) ++count, ++it)
381
                {
7✔
382
                    HPX_INVOKE(f, it);
383
                }
4✔
384

4✔
385
                return it;
4✔
386
            }
4✔
387

4✔
388
            template <typename Iter, typename F>
389
            HPX_HOST_DEVICE HPX_FORCEINLINE static constexpr Iter call(
3✔
390
                Iter it, std::size_t num, F&& f, std::true_type)
3✔
391
            {
3✔
392
                while (num >= 4)    //-V112
3✔
393
                {
394
                    HPX_INVOKE(f, it);
×
395
                    HPX_INVOKE(f, it + 1);
×
396
                    HPX_INVOKE(f, it + 2);
×
397
                    HPX_INVOKE(f, it + 3);
398

399
                    it += 4;     //-V112
400
                    num -= 4;    //-V112
401
                }
402

403
                switch (num)
404
                {
405
                case 3:
406
                    HPX_INVOKE(f, it);
407
                    HPX_INVOKE(f, it + 1);
408
                    HPX_INVOKE(f, it + 2);
409
                    it += 3;
410
                    break;
411

412
                case 2:
413
                    HPX_INVOKE(f, it);
414
                    HPX_INVOKE(f, it + 1);
415
                    it += 2;
416
                    break;
417

418
                case 1:
419
                    HPX_INVOKE(f, it);
420
                    ++it;
421
                    break;
422

423
                default:
424
                    break;
425
                }
426

427
                return it;
428
            }
429

430
            template <typename Iter, typename CancelToken, typename F,
431
                typename Tag>
432
            HPX_HOST_DEVICE HPX_FORCEINLINE static Iter call(
433
                Iter it, std::size_t num, CancelToken& tok, F&& f, Tag tag)
434
            {
435
                // check at the start of a partition only
436
                if (tok.was_cancelled())
437
                    return it;
438

439
                return call(it, num, HPX_FORWARD(F, f), tag);
440
            }
441
        };
442
    }    // namespace detail
443

444
    ///////////////////////////////////////////////////////////////////////
445
    HPX_CXX_EXPORT template <typename ExPolicy>
446
    struct loop_n_t final
447
      : hpx::functional::detail::tag_fallback<loop_n_t<ExPolicy>>
448
    {
449
    private:
450
        template <typename Iter, typename F>
451
        friend HPX_HOST_DEVICE HPX_FORCEINLINE constexpr Iter
452
        tag_fallback_invoke(hpx::parallel::util::loop_n_t<ExPolicy>, Iter it,
453
            std::size_t count, F&& f)
454
        {
455
            using pred = std::integral_constant<bool,
456
                hpx::traits::is_random_access_iterator_v<Iter> ||
457
                    std::is_integral_v<Iter>>;
458

459
            return detail::loop_n_helper::call(
460
                it, count, HPX_FORWARD(F, f), pred());
461
        }
462

463
        template <typename Iter, typename CancelToken, typename F>
464
        friend HPX_HOST_DEVICE HPX_FORCEINLINE Iter tag_fallback_invoke(
465
            hpx::parallel::util::loop_n_t<ExPolicy>, Iter it, std::size_t count,
466
            CancelToken& tok, F&& f)
467
        {
468
            using pred = std::integral_constant<bool,
469
                hpx::traits::is_random_access_iterator_v<Iter> ||
470
                    std::is_integral_v<Iter>>;
471

472
            return detail::loop_n_helper::call(
473
                it, count, tok, HPX_FORWARD(F, f), pred());
474
        }
475
    };
476

477
#if !defined(HPX_COMPUTE_DEVICE_CODE)
478
    HPX_CXX_EXPORT template <typename ExPolicy>
479
    inline constexpr loop_n_t<ExPolicy> loop_n = loop_n_t<ExPolicy>{};
480
#else
481
    HPX_CXX_EXPORT template <typename ExPolicy, typename Iter, typename F>
482
    HPX_HOST_DEVICE HPX_FORCEINLINE constexpr decltype(auto) loop_n(
483
        Iter it, std::size_t count, F&& f)
484
    {
485
        return hpx::parallel::util::loop_n_t<ExPolicy>{}(
486
            it, count, HPX_FORWARD(F, f));
487
    }
488

489
    HPX_CXX_EXPORT template <typename ExPolicy, typename Iter,
490
        typename CancelToken, typename F>
491
    HPX_HOST_DEVICE HPX_FORCEINLINE constexpr decltype(auto) loop_n(
492
        Iter it, std::size_t count, CancelToken& tok, F&& f)
493
    {
494
        return hpx::parallel::util::loop_n_t<ExPolicy>{}(
495
            it, count, tok, HPX_FORWARD(F, f));
496
    }
497
#endif
498

499
    namespace detail {
500

501
        ///////////////////////////////////////////////////////////////////////
502
        // Helper class to repeatedly call a function a given number of times
503
        // starting from a given iterator position.
504
        HPX_CXX_EXPORT struct loop_n_ind_helper
505
        {
506
            ///////////////////////////////////////////////////////////////////
507
            // handle sequences of non-futures
508
            template <typename Iter, typename F>
7,775✔
509
            HPX_HOST_DEVICE HPX_FORCEINLINE static constexpr Iter
510
            call_iteration(Iter it, std::size_t num, F&& f, std::false_type)
5,236✔
511
            {
7,736✔
512
                std::size_t count(
7,736✔
513
                    num & static_cast<std::size_t>(-4));    // -V112
7,736✔
514

515
                for (std::size_t i = 0; i < count;
7,485✔
516
                    (void) ++it, i += 4)    // -V112
7,740✔
517
                {
518
                    HPX_INVOKE(f, *it);
519
                    HPX_INVOKE(f, *++it);
35✔
520
                    HPX_INVOKE(f, *++it);
521
                    HPX_INVOKE(f, *++it);
18✔
522
                }
18✔
523

18✔
524
                for (/**/; count < num; (void) ++count, ++it)
18✔
525
                {
18✔
526
                    HPX_INVOKE(f, *it);
527
                }
2✔
528

2✔
529
                return it;
2✔
530
            }
4✔
531

532
            template <typename Iter, typename F>
2✔
533
            HPX_HOST_DEVICE HPX_FORCEINLINE static constexpr Iter
2✔
534
            call_iteration(Iter it, std::size_t num, F&& f, std::true_type)
1✔
535
            {
536
                while (num >= 4)    //-V112
537
                {
538
                    HPX_INVOKE(f, *it);
539
                    HPX_INVOKE(f, *(it + 1));
540
                    HPX_INVOKE(f, *(it + 2));
32✔
541
                    HPX_INVOKE(f, *(it + 3));
542

543
                    it += 4;     //-V112
544
                    num -= 4;    //-V112
545
                }
546

547
                switch (num)
548
                {
549
                case 3:
550
                    HPX_INVOKE(f, *it);
551
                    HPX_INVOKE(f, *(it + 1));
552
                    HPX_INVOKE(f, *(it + 2));
553
                    it += 3;
554
                    break;
555

556
                case 2:
557
                    HPX_INVOKE(f, *it);
558
                    HPX_INVOKE(f, *(it + 1));
559
                    it += 2;
560
                    break;
561

562
                case 1:
563
                    HPX_INVOKE(f, *it);
564
                    ++it;
565
                    break;
566

567
                default:
568
                    break;
569
                }
570

571
                return it;
572
            }
22✔
573

10✔
574
            template <typename Iter, typename F, typename Tag>
575
            HPX_HOST_DEVICE HPX_FORCEINLINE static constexpr Iter call(
576
                Iter start, std::size_t num, F&& f, Tag tag)
577
            {
578
                if (num == 0)
579
                {
580
                    return start;
581
                }
582

583
                if constexpr (hpx::traits::is_random_access_iterator_v<Iter>)
584
                {
585
                    auto it = hpx::util::get_unwrapped(start);
586

587
                    call_iteration(it, num, HPX_FORWARD(F, f), tag);
588

589
                    return parallel::detail::next(start, num);
590
                }
591
                else
592
                {
593
                    return call_iteration(start, num, HPX_FORWARD(F, f), tag);
594
                }
595
            }
596

597
            template <typename Iter, typename CancelToken, typename F,
598
                typename Tag>
599
            HPX_HOST_DEVICE HPX_FORCEINLINE static Iter call(
600
                Iter it, std::size_t num, CancelToken& tok, F&& f, Tag tag)
601
            {
602
                // check at the start of a partition only
603
                if (tok.was_cancelled())
604
                    return it;
605

606
                return call(it, num, HPX_FORWARD(F, f), tag);
607
            }
608
        };
609
    }    // namespace detail
610

611
    ///////////////////////////////////////////////////////////////////////
612
    HPX_CXX_EXPORT template <typename ExPolicy>
613
    struct loop_n_ind_t final
614
      : hpx::functional::detail::tag_fallback<loop_n_ind_t<ExPolicy>>
615
    {
616
    private:
617
        template <typename Iter, typename F>
618
        friend HPX_HOST_DEVICE HPX_FORCEINLINE constexpr Iter
619
        tag_fallback_invoke(hpx::parallel::util::loop_n_ind_t<ExPolicy>,
620
            Iter it, std::size_t count, F&& f)
621
        {
622
            using pred = std::integral_constant<bool,
623
                hpx::traits::is_random_access_iterator_v<Iter> ||
624
                    std::is_integral_v<Iter>>;
625

626
            return detail::loop_n_ind_helper::call(
627
                it, count, HPX_FORWARD(F, f), pred());
628
        }
629

630
        template <typename Iter, typename CancelToken, typename F>
631
        friend HPX_HOST_DEVICE HPX_FORCEINLINE constexpr Iter
632
        tag_fallback_invoke(hpx::parallel::util::loop_n_ind_t<ExPolicy>,
633
            Iter it, std::size_t count, CancelToken& tok, F&& f)
634
        {
635
            using pred = std::integral_constant<bool,
636
                hpx::traits::is_random_access_iterator_v<Iter> ||
637
                    std::is_integral_v<Iter>>;
638

639
            return detail::loop_n_ind_helper::call(
640
                it, count, tok, HPX_FORWARD(F, f), pred());
641
        }
642
    };
643

644
#if !defined(HPX_COMPUTE_DEVICE_CODE)
645
    HPX_CXX_EXPORT template <typename ExPolicy>
646
    inline constexpr loop_n_ind_t<ExPolicy> loop_n_ind =
647
        loop_n_ind_t<ExPolicy>{};
648
#else
649
    HPX_CXX_EXPORT template <typename ExPolicy, typename Iter, typename F>
650
    HPX_HOST_DEVICE HPX_FORCEINLINE constexpr decltype(auto) loop_n_ind(
651
        Iter it, std::size_t count, F&& f)
652
    {
653
        return hpx::parallel::util::loop_n_ind_t<ExPolicy>{}(
654
            it, count, HPX_FORWARD(F, f));
655
    }
656

657
    HPX_CXX_EXPORT template <typename ExPolicy, typename Iter,
658
        typename CancelToken, typename F>
659
    HPX_HOST_DEVICE HPX_FORCEINLINE constexpr decltype(auto) loop_n_ind(
660
        Iter it, std::size_t count, CancelToken& tok, F&& f)
661
    {
662
        return hpx::parallel::util::loop_n_ind_t<ExPolicy>{}(
663
            it, count, tok, HPX_FORWARD(F, f));
664
    }
665
#endif
666

667
    namespace detail {
668

669
        ///////////////////////////////////////////////////////////////////////
670
        // Helper class to repeatedly call a function a given number of times
671
        // starting from a given iterator position. If an exception is thrown,
672
        // the given cleanup function will be called.
673
        HPX_CXX_EXPORT struct loop_with_cleanup final
674
          : hpx::functional::detail::tag_fallback<loop_with_cleanup>
675
        {
676
            ///////////////////////////////////////////////////////////////////
677
            template <typename ExPolicy, typename FwdIter, typename F,
678
                typename Sent, typename Cleanup>
679
            static FwdIter call(
680
                ExPolicy&&, FwdIter first, Sent last, F&& f, Cleanup&& cleanup)
681
            {
682
                auto it = first;
683
                try
684
                {
685
                    for (/**/; it != last; (void) ++it)
686
                    {
687
                        HPX_INVOKE(f, it);
688
                    }
689
                    return it;
690
                }
691
                catch (...)
692
                {
693
                    for (/**/; first != it; ++first)
694
                    {
695
                        HPX_INVOKE(cleanup, first);
696
                    }
697
                    throw;
698
                }
699
            }
700

701
            template <typename ExPolicy, typename Iter, typename Sent,
702
                typename FwdIter, typename F, typename Cleanup>
703
            static FwdIter call(ExPolicy&&, Iter it, Sent last, FwdIter dest,
704
                F&& f, Cleanup&& cleanup)
705
            {
706
                FwdIter base = dest;
707
                try
708
                {
709
                    for (/**/; it != last; (void) ++it, ++dest)
710
                    {
711
                        HPX_INVOKE(f, it, dest);
712
                    }
713
                    return dest;
714
                }
715
                catch (...)
716
                {
717
                    for (/**/; base != dest; ++base)
718
                    {
719
                        HPX_INVOKE(cleanup, base);
720
                    }
721
                    throw;
722
                }
723
            }
724

725
            template <typename ExPolicy, typename FwdIter, typename F,
726
                typename Sent, typename Cleanup>
727
            friend HPX_HOST_DEVICE HPX_FORCEINLINE FwdIter tag_fallback_invoke(
728
                hpx::parallel::util::detail::loop_with_cleanup,
729
                ExPolicy&& policy, FwdIter first, Sent last, F&& f,
730
                Cleanup&& cleanup)
731
            {
732
                return call(HPX_FORWARD(ExPolicy, policy), first, last,
733
                    HPX_FORWARD(F, f), HPX_FORWARD(Cleanup, cleanup));
734
            }
735

736
            template <typename ExPolicy, typename Iter, typename Sent,
737
                typename FwdIter, typename F, typename Cleanup>
738
            friend HPX_HOST_DEVICE HPX_FORCEINLINE FwdIter tag_fallback_invoke(
739
                hpx::parallel::util::detail::loop_with_cleanup,
740
                ExPolicy&& policy, Iter it, Sent last, FwdIter dest, F&& f,
741
                Cleanup&& cleanup)
742
            {
743
                return call(HPX_FORWARD(ExPolicy, policy), it, last, dest,
744
                    HPX_FORWARD(F, f), HPX_FORWARD(Cleanup, cleanup));
745
            }
746

747
            template <typename ExPolicy, typename FwdIter, typename F,
748
                typename Sent, typename Cleanup>
749
            static FwdIter unseq_call(
750
                ExPolicy&&, FwdIter first, Sent last, F&& f, Cleanup&& cleanup)
751
            {
752
                auto it = first;
753
                try
754
                {
755
                    // clang-format off
756
                    HPX_IVDEP HPX_UNROLL HPX_VECTORIZE
757
                    for (FwdIter& iter = it; iter != last; ++iter)
758
                    {
759
                        HPX_INVOKE(f, iter);
760
                    }
761
                    // clang-format on
762

763
                    return it;
764
                }
765
                catch (...)
766
                {
767
                    for (/**/; first != it; ++first)
768
                    {
769
                        HPX_INVOKE(cleanup, first);
770
                    }
771
                    throw;
772
                }
773
            }
774

775
            template <typename ExPolicy, typename Iter, typename Sent,
776
                typename FwdIter, typename F, typename Cleanup>
777
            static FwdIter unseq_call(ExPolicy&&, Iter it, Sent last,
778
                FwdIter dest, F&& f, Cleanup&& cleanup)
779
            {
780
                FwdIter base = dest;
781
                try
782
                {
783
                    // clang-format off
784
                    HPX_IVDEP HPX_UNROLL HPX_VECTORIZE
785
                    for (Iter& iter = it; iter != last; ++iter)
786
                    {
787
                        HPX_INVOKE(f, iter, dest++);
788
                    }
789
                    // clang-format on
790

791
                    return dest;
792
                }
793
                catch (...)
794
                {
795
                    for (/**/; base != dest; ++base)
796
                    {
797
                        HPX_INVOKE(cleanup, base);
798
                    }
799
                    throw;
800
                }
801
            }
802
        };
803
    }    // namespace detail
804

805
#if !defined(HPX_COMPUTE_DEVICE_CODE)
806
    HPX_CXX_EXPORT inline constexpr detail::loop_with_cleanup
807
        loop_with_cleanup = detail::loop_with_cleanup{};
808
#else
809
    HPX_CXX_EXPORT template <typename ExPolicy, typename Begin, typename Sent,
810
        typename F, typename Cleanup>
811
    HPX_HOST_DEVICE HPX_FORCEINLINE constexpr decltype(auto) loop_with_cleanup(
812
        ExPolicy&& policy, Begin begin, Sent end, F&& f, Cleanup&& cleanup)
813
    {
814
        return hpx::parallel::util::detail::loop_with_cleanup{}(
815
            HPX_FORWARD(ExPolicy, policy), begin, end, HPX_FORWARD(F, f),
816
            HPX_FORWARD(Cleanup, cleanup));
817
    }
818

819
    HPX_CXX_EXPORT template <typename ExPolicy, typename Begin, typename Sent,
820
        typename Begin2, typename F, typename Cleanup>
821
    HPX_HOST_DEVICE HPX_FORCEINLINE constexpr decltype(auto) loop_with_cleanup(
822
        ExPolicy&& policy, Begin begin, Sent end, Begin2 dest, F&& f,
823
        Cleanup&& cleanup)
824
    {
825
        return hpx::parallel::util::detail::loop_with_cleanup{}(
826
            HPX_FORWARD(ExPolicy, policy), begin, end, dest, HPX_FORWARD(F, f),
827
            HPX_FORWARD(Cleanup, cleanup));
828
    }
829
#endif
830

831
    HPX_CXX_EXPORT template <typename Begin, typename Sent, typename F,
832
        typename Cleanup>
833
    HPX_HOST_DEVICE HPX_FORCEINLINE Begin tag_invoke(
834
        hpx::parallel::util::detail::loop_with_cleanup,
835
        hpx::execution::unsequenced_policy, Begin HPX_RESTRICT begin, Sent end,
836
        F&& f, Cleanup&& cleanup)
837
    {
838
        return hpx::parallel::util::detail::loop_with_cleanup::unseq_call(
839
            begin, end, HPX_FORWARD(F, f), HPX_FORWARD(Cleanup, cleanup));
840
    }
841

842
    HPX_CXX_EXPORT template <typename Begin, typename Sent, typename F,
843
        typename Cleanup>
844
    HPX_HOST_DEVICE HPX_FORCEINLINE Begin tag_invoke(
845
        hpx::parallel::util::detail::loop_with_cleanup,
846
        hpx::execution::unsequenced_task_policy, Begin HPX_RESTRICT begin,
847
        Sent end, F&& f, Cleanup&& cleanup)
848
    {
849
        return hpx::parallel::util::detail::loop_with_cleanup::unseq_call(
850
            begin, end, HPX_FORWARD(F, f), HPX_FORWARD(Cleanup, cleanup));
851
    }
852

853
    HPX_CXX_EXPORT template <typename Begin, typename Sent, typename Begin2,
×
854
        typename F, typename Cleanup>
855
    HPX_HOST_DEVICE HPX_FORCEINLINE Begin tag_invoke(
856
        hpx::parallel::util::detail::loop_with_cleanup,
857
        hpx::execution::unsequenced_policy, Begin HPX_RESTRICT begin, Sent end,
858
        Begin2 dest, F&& f, Cleanup&& cleanup)
859
    {
×
860
        return hpx::parallel::util::detail::loop_with_cleanup::unseq_call(
×
861
            begin, end, dest, HPX_FORWARD(F, f), HPX_FORWARD(Cleanup, cleanup));
×
862
    }
863

×
864
    HPX_CXX_EXPORT template <typename Begin, typename Sent, typename Begin2,
×
865
        typename F, typename Cleanup>
×
866
    HPX_HOST_DEVICE HPX_FORCEINLINE Begin tag_invoke(
×
867
        hpx::parallel::util::detail::loop_with_cleanup,
868
        hpx::execution::unsequenced_task_policy, Begin HPX_RESTRICT begin,
×
869
        Sent end, Begin2 dest, F&& f, Cleanup&& cleanup)
870
    {
×
871
        return hpx::parallel::util::detail::loop_with_cleanup::unseq_call(
872
            begin, end, dest, HPX_FORWARD(F, f), HPX_FORWARD(Cleanup, cleanup));
×
873
    }
874

875
    namespace detail {
876

877
        // Helper class to repeatedly call a function a given number of times
878
        // starting from a given iterator position.
879
        HPX_CXX_EXPORT struct loop_with_cleanup_n final
880
          : hpx::functional::detail::tag_fallback<loop_with_cleanup_n>
881
        {
882
            ///////////////////////////////////////////////////////////////////
883
            template <typename ExPolicy, typename Iter, typename FwdIter,
884
                typename F, typename Cleanup>
885
            static FwdIter call(ExPolicy&&, Iter it, std::size_t num,
886
                FwdIter dest, F&& f, Cleanup&& cleanup)
887
            {
888
                FwdIter base = dest;
889
                try
890
                {
891
                    std::size_t count(
892
                        num & static_cast<std::size_t>(-4));    // -V112
893
                    for (std::size_t i = 0; i < count;
894
                        (void) ++it, ++dest, i += 4)    // -V112
895
                    {
896
                        HPX_INVOKE(f, it, dest);
897
                        HPX_INVOKE(f, ++it, ++dest);
898
                        HPX_INVOKE(f, ++it, ++dest);
899
                        HPX_INVOKE(f, ++it, ++dest);
900
                    }
901
                    for (/**/; count < num; (void) ++count, ++it, ++dest)
902
                    {
903
                        HPX_INVOKE(f, it, dest);
904
                    }
905

906
                    return dest;
907
                }
908
                catch (...)
909
                {
910
                    for (/**/; base != dest; ++base)
911
                    {
912
                        HPX_INVOKE(cleanup, base);
913
                    }
914
                    throw;
915
                }
916
            }
917

918
            template <typename ExPolicy, typename FwdIter, typename F,
919
                typename Cleanup>
920
            static FwdIter call(ExPolicy&&, FwdIter it, std::size_t num, F&& f,
921
                Cleanup&& cleanup)
922
            {
923
                FwdIter base = it;
924
                try
925
                {
926
                    std::size_t count(
927
                        num & static_cast<std::size_t>(-4));    // -V112
928
                    for (std::size_t i = 0; i < count;
929
                        (void) ++it, i += 4)    // -V112
930
                    {
931
                        HPX_INVOKE(f, it);
932
                        HPX_INVOKE(f, ++it);
933
                        HPX_INVOKE(f, ++it);
934
                        HPX_INVOKE(f, ++it);
935
                    }
936
                    for (/**/; count < num; (void) ++count, ++it)
937
                    {
938
                        HPX_INVOKE(f, it);
939
                    }
940
                    return it;
941
                }
942
                catch (...)
943
                {
944
                    for (/**/; base != it; ++base)
945
                    {
946
                        HPX_INVOKE(cleanup, base);
947
                    }
948
                    throw;
949
                }
950
            }
951

952
            template <typename ExPolicy, typename Iter, typename FwdIter,
953
                typename F, typename Cleanup>
954
            friend HPX_HOST_DEVICE HPX_FORCEINLINE FwdIter tag_fallback_invoke(
955
                loop_with_cleanup_n, ExPolicy&& policy, Iter it,
956
                std::size_t num, FwdIter dest, F&& f, Cleanup&& cleanup)
957
            {
958
                return call(HPX_FORWARD(ExPolicy, policy), it, num, dest,
959
                    HPX_FORWARD(F, f), HPX_FORWARD(Cleanup, cleanup));
960
            }
961

962
            template <typename ExPolicy, typename FwdIter, typename F,
963
                typename Cleanup>
964
            friend HPX_HOST_DEVICE HPX_FORCEINLINE FwdIter tag_fallback_invoke(
965
                loop_with_cleanup_n, ExPolicy&& policy, FwdIter it,
966
                std::size_t num, F&& f, Cleanup&& cleanup)
967
            {
968
                return call(HPX_FORWARD(ExPolicy, policy), it, num,
969
                    HPX_FORWARD(F, f), HPX_FORWARD(Cleanup, cleanup));
970
            }
971

972
            template <typename ExPolicy, typename Iter, typename FwdIter,
973
                typename F, typename Cleanup>
974
            FwdIter unseq_call(Iter it, std::size_t num, FwdIter dest, F&& f,
975
                Cleanup&& cleanup)
976
            {
977
                FwdIter base = dest;
978
                try
979
                {
980
                    std::size_t const count(
981
                        num & static_cast<std::size_t>(-4));    // -V112
982

983
                    // clang-format off
984
                    HPX_IVDEP HPX_UNROLL HPX_VECTORIZE
985
                    for (std::size_t i = 0; i < count; ++i)
×
986
                    {
×
987
                        HPX_INVOKE(f, it++, dest++);
988
                    }
×
989

×
990
                    HPX_IVDEP HPX_UNROLL HPX_VECTORIZE
991
                    for (std::size_t i = count; i < num; ++i)
992
                    {
993
                        HPX_INVOKE(f, it++, dest++);
994
                    }
995
                    // clang-format on
996

997
                    return dest;
998
                }
999
                catch (...)
1000
                {
1001
                    for (/**/; base != dest; ++base)
1002
                    {
1003
                        HPX_INVOKE(cleanup, base);
1004
                    }
1005
                    throw;
1006
                }
1007
            }
1008

1009
            template <typename ExPolicy, typename FwdIter, typename F,
1010
                typename Cleanup>
1011
            static FwdIter unseq_call(
1012
                ExPolicy, FwdIter it, std::size_t num, F&& f, Cleanup&& cleanup)
1013
            {
1014
                FwdIter base = it;
1015
                try
1016
                {
1017
                    std::size_t const count(
1018
                        num & static_cast<std::size_t>(-4));    // -V112
1019

1020
                    // clang-format off
1021
                    HPX_IVDEP HPX_UNROLL HPX_VECTORIZE
1022
                    for (std::size_t i = 0; i < count; ++i)
1023
                    {
1024
                        HPX_INVOKE(f, it++);
1025
                    }
1026

1027
                    HPX_IVDEP HPX_UNROLL HPX_VECTORIZE
1028
                    for (std::size_t i = count; i < num; ++i)
1029
                    {
1030
                        HPX_INVOKE(f, it++);
1031
                    }
1032
                    // clang-format on
1033

1034
                    return it;
1035
                }
1036
                catch (...)
1037
                {
1038
                    for (/**/; base != it; ++base)
1039
                    {
1040
                        HPX_INVOKE(cleanup, base);
1041
                    }
1042
                    throw;
1043
                }
1044
            }
1045

1046
            template <typename ExPolicy, typename FwdIter, typename CancelToken,
1047
                typename F, typename Cleanup>
1048
            HPX_HOST_DEVICE HPX_FORCEINLINE static FwdIter call_with_token(
1049
                ExPolicy&& policy, FwdIter it, std::size_t num,
1050
                CancelToken& tok, F&& f, Cleanup&& cleanup)
1051
            {
1052
                // check at the start of a partition only
1053
                if (tok.was_cancelled())
1054
                    return it;
1055

1056
                return call(HPX_FORWARD(ExPolicy, policy), it, num,
1057
                    HPX_FORWARD(F, f), HPX_FORWARD(Cleanup, cleanup));
1058
            }
1059

1060
            template <typename ExPolicy, typename Iter, typename FwdIter,
1061
                typename CancelToken, typename F, typename Cleanup>
1062
            static FwdIter call_with_token(ExPolicy&& policy, Iter it,
1063
                std::size_t num, FwdIter dest, CancelToken& tok, F&& f,
1064
                Cleanup&& cleanup)
1065
            {
1066
                // check at the start of a partition only
1067
                if (tok.was_cancelled())
1068
                    return dest;
1069

1070
                return call(HPX_FORWARD(ExPolicy, policy), it, num, dest,
1071
                    HPX_FORWARD(F, f), HPX_FORWARD(Cleanup, cleanup));
1072
            }
1073
        };
1074
    }    // namespace detail
1075

1076
#if !defined(HPX_COMPUTE_DEVICE_CODE)
1077
    HPX_CXX_EXPORT inline constexpr detail::loop_with_cleanup_n
1078
        loop_with_cleanup_n = detail::loop_with_cleanup_n{};
1079
#else
×
1080
    HPX_CXX_EXPORT template <typename ExPolicy, typename Begin, typename F,
1081
        typename Cleanup>
1082
    HPX_HOST_DEVICE HPX_FORCEINLINE constexpr decltype(auto)
1083
    loop_with_cleanup_n(
1084
        ExPolicy&& policy, Begin begin, std::size_t n, F&& f, Cleanup&& cleanup)
1085
    {
1086
        return hpx::parallel::util::detail::loop_with_cleanup_n{}(
1087
            HPX_FORWARD(ExPolicy, policy), begin, n, HPX_FORWARD(F, f),
1088
            HPX_FORWARD(Cleanup, cleanup));
1089
    }
1090

1091
    HPX_CXX_EXPORT template <typename ExPolicy, typename Begin, typename Begin2,
1092
        typename F, typename Cleanup>
1093
    HPX_HOST_DEVICE HPX_FORCEINLINE constexpr decltype(auto)
1094
    loop_with_cleanup_n(ExPolicy&& policy, Begin begin, std::size_t n,
1095
        Begin2 dest, F&& f, Cleanup&& cleanup)
1096
    {
1097
        return hpx::parallel::util::detail::loop_with_cleanup_n{}(
1098
            HPX_FORWARD(ExPolicy, policy), begin, n, dest, HPX_FORWARD(F, f),
1099
            HPX_FORWARD(Cleanup, cleanup));
1100
    }
1101
#endif
1102

1103
    HPX_CXX_EXPORT template <typename Begin, typename F, typename Cleanup>
1104
    HPX_HOST_DEVICE HPX_FORCEINLINE Begin tag_invoke(
1105
        hpx::parallel::util::detail::loop_with_cleanup_n,
1106
        hpx::execution::unsequenced_policy, Begin HPX_RESTRICT begin,
1107
        std::size_t n, F&& f, Cleanup&& cleanup)
1108
    {
1109
        return hpx::parallel::util::detail::loop_with_cleanup_n::unseq_call(
1110
            begin, n, HPX_FORWARD(F, f), HPX_FORWARD(Cleanup, cleanup));
1111
    }
1112

1113
    HPX_CXX_EXPORT template <typename Begin, typename F, typename Cleanup>
1114
    HPX_HOST_DEVICE HPX_FORCEINLINE Begin tag_invoke(
1115
        hpx::parallel::util::detail::loop_with_cleanup_n,
1116
        hpx::execution::unsequenced_task_policy, Begin HPX_RESTRICT begin,
1117
        std::size_t n, F&& f, Cleanup&& cleanup)
1118
    {
1119
        return hpx::parallel::util::detail::loop_with_cleanup_n::unseq_call(
1120
            begin, n, HPX_FORWARD(F, f), HPX_FORWARD(Cleanup, cleanup));
1121
    }
1122

1123
    HPX_CXX_EXPORT template <typename Begin, typename Begin2, typename F,
1124
        typename Cleanup>
1125
    HPX_HOST_DEVICE HPX_FORCEINLINE Begin tag_invoke(
1126
        hpx::parallel::util::detail::loop_with_cleanup_n,
1127
        hpx::execution::unsequenced_policy, Begin HPX_RESTRICT begin,
1128
        std::size_t n, Begin2 dest, F&& f, Cleanup&& cleanup)
1129
    {
1130
        return hpx::parallel::util::detail::loop_with_cleanup_n::unseq_call(
1131
            begin, n, dest, HPX_FORWARD(F, f), HPX_FORWARD(Cleanup, cleanup));
1132
    }
1133

1134
    HPX_CXX_EXPORT template <typename Begin, typename Begin2, typename F,
1135
        typename Cleanup>
1136
    HPX_HOST_DEVICE HPX_FORCEINLINE Begin tag_invoke(
1137
        hpx::parallel::util::detail::loop_with_cleanup_n,
1138
        hpx::execution::unsequenced_task_policy, Begin HPX_RESTRICT begin,
1139
        std::size_t n, Begin2 dest, F&& f, Cleanup&& cleanup)
1140
    {
1141
        return hpx::parallel::util::detail::loop_with_cleanup_n::unseq_call(
1142
            begin, n, dest, HPX_FORWARD(F, f), HPX_FORWARD(Cleanup, cleanup));
1143
    }
1144

1145
    HPX_CXX_EXPORT template <typename Iter, typename CancelToken, typename F,
1146
        typename Cleanup>
1147
        requires(hpx::traits::is_iterator_v<Iter>)
1148
    HPX_FORCEINLINE constexpr Iter loop_with_cleanup_n_with_token(
1149
        Iter it, std::size_t count, CancelToken& tok, F&& f, Cleanup&& cleanup)
1150
    {
1151
        return detail::loop_with_cleanup_n::call_with_token(
1152
            ::hpx::execution::seq, it, count, tok, HPX_FORWARD(F, f),
1153
            HPX_FORWARD(Cleanup, cleanup));
1154
    }
1155

1156
    HPX_CXX_EXPORT template <typename Iter, typename FwdIter,
1157
        typename CancelToken, typename F, typename Cleanup>
1158
        requires(hpx::traits::is_iterator_v<Iter> &&
1159
            hpx::traits::is_iterator_v<FwdIter>)
1160
    HPX_FORCEINLINE constexpr FwdIter loop_with_cleanup_n_with_token(Iter it,
1161
        std::size_t count, FwdIter dest, CancelToken& tok, F&& f,
1162
        Cleanup&& cleanup)
1163
    {
1164
        return detail::loop_with_cleanup_n::call_with_token(
1165
            ::hpx::execution::seq, it, count, dest, tok, HPX_FORWARD(F, f),
1166
            HPX_FORWARD(Cleanup, cleanup));
1167
    }
1168

1169
    HPX_CXX_EXPORT template <typename ExPolicy, typename Iter,
1170
        typename CancelToken, typename F, typename Cleanup>
1171
        requires(hpx::is_execution_policy_v<ExPolicy> &&
1172
            hpx::traits::is_iterator_v<Iter>)
1173
    HPX_FORCEINLINE constexpr Iter loop_with_cleanup_n_with_token(
1174
        ExPolicy&& policy, Iter it, std::size_t count, CancelToken& tok, F&& f,
1175
        Cleanup&& cleanup)
1176
    {
1177
        return detail::loop_with_cleanup_n::call_with_token(
1178
            HPX_FORWARD(ExPolicy, policy), it, count, tok, HPX_FORWARD(F, f),
1179
            HPX_FORWARD(Cleanup, cleanup));
1180
    }
1181

1182
    HPX_CXX_EXPORT template <typename ExPolicy, typename Iter, typename FwdIter,
1183
        typename CancelToken, typename F, typename Cleanup>
1184
        requires(hpx::is_execution_policy_v<ExPolicy> &&
1185
            hpx::traits::is_iterator_v<Iter> &&
1186
            hpx::traits::is_iterator_v<FwdIter>)
1187
    HPX_FORCEINLINE constexpr FwdIter loop_with_cleanup_n_with_token(
1188
        ExPolicy&& policy, Iter it, std::size_t count, FwdIter dest,
1189
        CancelToken& tok, F&& f, Cleanup&& cleanup)
1190
    {
1191
        return detail::loop_with_cleanup_n::call_with_token(
1192
            HPX_FORWARD(ExPolicy, policy), it, count, dest, tok,
1193
            HPX_FORWARD(F, f), HPX_FORWARD(Cleanup, cleanup));
1194
    }
1195

1196
    ///////////////////////////////////////////////////////////////////////////
1197
    namespace detail {
1198

1199
        // Helper class to repeatedly call a function a given number of times
1200
        // starting from a given iterator position.
1201
        HPX_CXX_EXPORT template <typename IterCat>
1202
        struct loop_idx_n
1203
        {
1204
            ///////////////////////////////////////////////////////////////////
1205
            // handle sequences of non-futures
1206
            template <typename Iter, typename F>
1207
            HPX_HOST_DEVICE HPX_FORCEINLINE static Iter call(
1208
                std::size_t base_idx, Iter start, std::size_t num, F&& f)
1209
            {
1210
                if (num == 0)
1211
                {
1212
                    return start;
1213
                }
1214

1215
                std::size_t count(
1216
                    num & static_cast<std::size_t>(-4));    // -V112
1217

1218
                auto it = hpx::util::get_unwrapped(start);
1219

1220
                for (std::size_t i = 0; i < count;
1221
                    (void) ++it, i += 4)    // -V112
1222
                {
1223
                    HPX_INVOKE(f, *it, base_idx++);
1224
                    HPX_INVOKE(f, *++it, base_idx++);
1225
                    HPX_INVOKE(f, *++it, base_idx++);
1226
                    HPX_INVOKE(f, *++it, base_idx++);
1227
                }
1228

1229
                for (/**/; count < num; (void) ++count, ++it, ++base_idx)
1230
                {
1231
                    HPX_INVOKE(f, *it, base_idx);
1232
                }
1233

1234
                return it;
1235
            }
1236

1237
            template <typename Iter, typename CancelToken, typename F>
1238
            HPX_HOST_DEVICE HPX_FORCEINLINE static Iter call(
1239
                std::size_t base_idx, Iter it, std::size_t count,
1240
                CancelToken& tok, F&& f)
1241
            {
1242
                if (tok.was_cancelled(base_idx))
1243
                    return it;
1244

1245
                return call(base_idx, it, count, HPX_FORWARD(F, f));
1246
            }
1247
        };
1248

1249
        template <>
1250
        struct loop_idx_n<std::random_access_iterator_tag>
1251
        {
1252
            ///////////////////////////////////////////////////////////////////
1253
            // handle sequences of non-futures
1254
            template <typename Iter, typename F>
1255
            HPX_HOST_DEVICE HPX_FORCEINLINE static constexpr Iter call(
1256
                std::size_t base_idx, Iter start, std::size_t num, F&& f)
1257
            {
1258
                if (num == 0)
1259
                {
1260
                    return start;
1261
                }
1262

1263
                auto it = hpx::util::get_unwrapped(start);
1264

1265
                while (num >= 4)    //-V112
1266
                {
1267
                    HPX_INVOKE(f, *it, base_idx++);
1268
                    HPX_INVOKE(f, *(it + 1), base_idx++);
1269
                    HPX_INVOKE(f, *(it + 2), base_idx++);
1270
                    HPX_INVOKE(f, *(it + 3), base_idx++);
1271

1272
                    it += 4;     //-V112
1273
                    num -= 4;    //-V112
1274
                }
1275

1276
                switch (num)
1277
                {
1278
                case 3:
1279
                    HPX_INVOKE(f, *it, base_idx++);
1280
                    HPX_INVOKE(f, *(it + 1), base_idx++);
1281
                    HPX_INVOKE(f, *(it + 2), base_idx);
1282
                    it += 3;
1283
                    break;
1284

1285
                case 2:
1286
                    HPX_INVOKE(f, *it, base_idx++);
1287
                    HPX_INVOKE(f, *(it + 1), base_idx);
1288
                    it += 2;
1289
                    break;
1290

1291
                case 1:
1292
                    HPX_INVOKE(f, *it, base_idx);
1293
                    ++it;
1294
                    break;
1295

1296
                default:
1297
                    break;
1298
                }
1299

1300
                return std::next(start, num);
1301
            }
1302

1303
            template <typename Iter, typename CancelToken, typename F>
1304
            HPX_HOST_DEVICE HPX_FORCEINLINE static Iter call(
1305
                std::size_t base_idx, Iter it, std::size_t num,
1306
                CancelToken& tok, F&& f)
1307
            {
1308
                if (tok.was_cancelled(base_idx))
1309
                    return it;
1310

1311
                return call(base_idx, it, num, HPX_FORWARD(F, f));
1312
            }
1313
        };
1314
    }    // namespace detail
1315

1316
    ///////////////////////////////////////////////////////////////////////
1317
    HPX_CXX_EXPORT template <typename ExPolicy>
1318
    struct loop_idx_n_t final
1319
      : hpx::functional::detail::tag_fallback<loop_idx_n_t<ExPolicy>>
1320
    {
1321
    private:
1322
        template <typename Iter, typename F>
1323
        friend HPX_HOST_DEVICE HPX_FORCEINLINE constexpr Iter
1324
        tag_fallback_invoke(hpx::parallel::util::loop_idx_n_t<ExPolicy>,
1325
            std::size_t base_idx, Iter it, std::size_t count, F&& f)
1326
        {
1327
            using cat = typename std::iterator_traits<Iter>::iterator_category;
1328
            return detail::loop_idx_n<cat>::call(
1329
                base_idx, it, count, HPX_FORWARD(F, f));
1330
        }
1331

1332
        template <typename Iter, typename CancelToken, typename F>
1333
        friend HPX_HOST_DEVICE HPX_FORCEINLINE constexpr Iter
1334
        tag_fallback_invoke(hpx::parallel::util::loop_idx_n_t<ExPolicy>,
1335
            std::size_t base_idx, Iter it, std::size_t count, CancelToken& tok,
1336
            F&& f)
1337
        {
1338
            using cat = typename std::iterator_traits<Iter>::iterator_category;
1339
            return detail::loop_idx_n<cat>::call(
1340
                base_idx, it, count, tok, HPX_FORWARD(F, f));
1341
        }
1342
    };
1343

1344
#if !defined(HPX_COMPUTE_DEVICE_CODE)
1345
    HPX_CXX_EXPORT template <typename ExPolicy>
1346
    inline constexpr loop_idx_n_t<ExPolicy> loop_idx_n =
1347
        loop_idx_n_t<ExPolicy>{};
1348
#else
1349
    HPX_CXX_EXPORT template <typename ExPolicy, typename Iter, typename F>
1350
    HPX_HOST_DEVICE HPX_FORCEINLINE constexpr decltype(auto) loop_idx_n(
1351
        std::size_t base_idx, Iter it, std::size_t count, F&& f)
1352
    {
1353
        return hpx::parallel::util::loop_idx_n_t<ExPolicy>{}(
1354
            base_idx, it, count, HPX_FORWARD(F, f));
1355
    }
1356

1357
    HPX_CXX_EXPORT template <typename ExPolicy, typename Iter,
1358
        typename CancelToken, typename F>
1359
    HPX_HOST_DEVICE HPX_FORCEINLINE constexpr decltype(auto) loop_idx_n(
1360
        std::size_t base_idx, Iter it, std::size_t count, CancelToken& tok,
1361
        F&& f)
1362
    {
1363
        return hpx::parallel::util::loop_idx_n_t<ExPolicy>{}(
1364
            base_idx, it, count, tok, HPX_FORWARD(F, f));
1365
    }
1366
#endif
1367

1368
    ///////////////////////////////////////////////////////////////////////////
1369
    namespace detail {
1370

1371
        // Helper class to repeatedly call a function a given number of times
1372
        // starting from a given iterator position.
1373
        HPX_CXX_EXPORT template <typename IterCat>
1374
        struct accumulate_n
1375
        {
1376
            template <typename Iter, typename T, typename Pred>
1377
            static constexpr T call(
1378
                Iter it, std::size_t count, T init, Pred&& f)
1379
            {
1380
                for (/**/; count != 0; (void) --count, ++it)
1381
                {
1382
                    init = HPX_INVOKE(f, init, *it);
1383
                }
1384
                return init;
1385
            }
1386
        };
1387
    }    // namespace detail
1388

1389
    ///////////////////////////////////////////////////////////////////////////
1390
    HPX_CXX_EXPORT template <typename Iter, typename T, typename Pred>
1391
    HPX_FORCEINLINE constexpr T accumulate_n(
1392
        Iter it, std::size_t count, T init, Pred&& f)
1393
    {
1394
        using cat = typename std::iterator_traits<Iter>::iterator_category;
1395
        return detail::accumulate_n<cat>::call(
1396
            it, count, HPX_MOVE(init), HPX_FORWARD(Pred, f));
1397
    }
1398

1399
    HPX_CXX_EXPORT template <typename T, typename Iter, typename Sent,
1400
        typename Reduce, typename Conv = hpx::identity>
1401
    HPX_FORCEINLINE constexpr T accumulate(
1402
        Iter first, Sent last, Reduce&& r, Conv&& conv = Conv())
1403
    {
1404
        T val = HPX_INVOKE(conv, *first);
1405
        ++first;
1406
        while (first != last)
1407
        {
1408
            val = HPX_INVOKE(r, val, HPX_INVOKE(conv, *first));
1409
            ++first;
1410
        }
1411
        return val;
1412
    }
1413

1414
    HPX_CXX_EXPORT template <typename T, typename Iter1, typename Sent1,
1415
        typename Iter2, typename Reduce, typename Conv>
1416
    HPX_FORCEINLINE constexpr T accumulate(
1417
        Iter1 first1, Sent1 last1, Iter2 first2, Reduce&& r, Conv&& conv)
1418
    {
1419
        T val = HPX_INVOKE(conv, *first1, *first2);
1420
        ++first1;
1421
        ++first2;
1422
        while (first1 != last1)
1423
        {
1424
            val = HPX_INVOKE(r, val, HPX_INVOKE(conv, *first1, *first2));
1425
            ++first1;
1426
            ++first2;
1427
        }
1428
        return val;
1429
    }
1430
}    // namespace hpx::parallel::util
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