• 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

83.33
/libs/core/async_combinators/include/hpx/async_combinators/wait_some.hpp
1
//  Copyright (c) 2007-2022 Hartmut Kaiser
2
//  Copyright (c) 2013 Agustin Berge
3
//
4
//  SPDX-License-Identifier: BSL-1.0
5
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
6
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7

8
/// \file wait_some.hpp
9

10
#pragma once
11

12
#if defined(DOXYGEN)
13
namespace hpx {
14
    /// The function \a wait_some is an operator allowing to join on the result
15
    /// of all given futures. It AND-composes all future objects given and
16
    /// returns a new future object representing the same list of futures
17
    /// after n of them finished executing.
18
    ///
19
    /// \param n        [in] The number of futures out of the arguments which
20
    ///                 have to become ready in order for the function to return.
21
    /// \param first    [in] The iterator pointing to the first element of a
22
    ///                 sequence of \a future or \a shared_future objects for
23
    ///                 which \a when_all should wait.
24
    /// \param last     [in] The iterator pointing to the last element of a
25
    ///                 sequence of \a future or \a shared_future objects for
26
    ///                 which \a when_all should wait.
27
    ///
28
    /// \note The function \a wait_some returns after \a n futures have become
29
    ///       ready. All input futures are still valid after \a wait_some
30
    ///       returns.
31
    ///
32
    /// \note           The function wait_some will rethrow any exceptions
33
    ///                 captured by the futures while becoming ready. If this
34
    ///                 behavior is undesirable, use \a wait_some_nothrow
35
    ///                 instead.
36
    ///
37
    template <typename InputIter>
38
    void wait_some(std::size_t n, InputIter first, InputIter last);
39

40
    /// The function \a wait_some is an operator allowing to join on the result
41
    /// of all given futures. It AND-composes all future objects given and
42
    /// returns a new future object representing the same list of futures
43
    /// after n of them finished executing.
44
    ///
45
    /// \param n        [in] The number of futures out of the arguments which
46
    ///                 have to become ready in order for the returned future
47
    ///                 to get ready.
48
    /// \param futures  [in] A vector holding an arbitrary amount of \a future
49
    ///                 or \a shared_future objects for which \a wait_some
50
    ///                 should wait.
51
    ///
52
    /// \note The function \a wait_some returns after \a n futures have become
53
    ///       ready. All input futures are still valid after \a wait_some
54
    ///       returns.
55
    ///
56
    /// \note           The function wait_some will rethrow any exceptions
57
    ///                 captured by the futures while becoming ready. If this
58
    ///                 behavior is undesirable, use \a wait_some_nothrow
59
    ///                 instead.
60
    ///
61
    template <typename R>
62
    void wait_some(std::size_t n, std::vector<future<R>>&& futures);
63

64
    /// The function \a wait_some is an operator allowing to join on the result
65
    /// of all given futures. It AND-composes all future objects given and
66
    /// returns a new future object representing the same list of futures
67
    /// after n of them finished executing.
68
    ///
69
    /// \param n        [in] The number of futures out of the arguments which
70
    ///                 have to become ready in order for the returned future
71
    ///                 to get ready.
72
    /// \param futures  [in] An array holding an arbitrary amount of \a future
73
    ///                 or \a shared_future objects for which \a wait_some
74
    ///                 should wait.
75
    ///
76
    /// \note The function \a wait_some returns after \a n futures have become
77
    ///       ready. All input futures are still valid after \a wait_some
78
    ///       returns.
79
    ///
80
    /// \note           The function wait_some will rethrow any exceptions
81
    ///                 captured by the futures while becoming ready. If this
82
    ///                 behavior is undesirable, use \a wait_some_nothrow
83
    ///                 instead.
84
    ///
85
    template <typename R, std::size_t N>
86
    void wait_some(std::size_t n, std::array<future<R>, N>&& futures);
87

88
    /// The function \a wait_some is an operator allowing to join on the result
89
    /// of all given futures. It AND-composes all future objects given and
90
    /// returns a new future object representing the same list of futures
91
    /// after n of them finished executing.
92
    ///
93
    /// \param n        [in] The number of futures out of the arguments which
94
    ///                 have to become ready in order for the returned future
95
    ///                 to get ready.
96
    /// \param futures  [in] An arbitrary number of \a future or \a shared_future
97
    ///                 objects, possibly holding different types for which
98
    ///                 \a wait_some should wait.
99
    /// \param ec       [in,out] this represents the error status on exit, if
100
    ///                 this is pre-initialized to \a hpx#throws the function
101
    ///                 will throw on error instead.
102
    ///
103
    /// \note The function \a wait_all returns after \a n futures have become
104
    ///       ready. All input futures are still valid after \a wait_some
105
    ///       returns.
106
    ///
107
    /// \note           The function wait_some will rethrow any exceptions
108
    ///                 captured by the futures while becoming ready. If this
109
    ///                 behavior is undesirable, use \a wait_some_nothrow
110
    ///                 instead.
111
    ///
112
    template <typename... T>
113
    void wait_some(std::size_t n, T&&... futures);
114

115
    /// The function \a wait_some_n is an operator allowing to join on the result
116
    /// of all given futures. It AND-composes all future objects given and
117
    /// returns a new future object representing the same list of futures
118
    /// after n of them finished executing.
119
    ///
120
    /// \param n        [in] The number of futures out of the arguments which
121
    ///                 have to become ready in order for the returned future
122
    ///                 to get ready.
123
    /// \param first    [in] The iterator pointing to the first element of a
124
    ///                 sequence of \a future or \a shared_future objects for
125
    ///                 which \a when_all should wait.
126
    /// \param count    [in] The number of elements in the sequence starting at
127
    ///                 \a first.
128
    ///
129
    /// \note The function \a wait_some_n returns after \a n futures have become
130
    ///       ready. All input futures are still valid after \a wait_some_n
131
    ///       returns.
132
    ///
133
    /// \note           The function wait_some_n will rethrow any exceptions
134
    ///                 captured by the futures while becoming ready. If this
135
    ///                 behavior is undesirable, use \a wait_some_n_nothrow
136
    ///                 instead.
137
    ///
138
    template <typename InputIter>
139
    void wait_some_n(std::size_t n, InputIter first, std::size_t count);
140
}    // namespace hpx
141
#else
142

143
#include <hpx/config.hpp>
144
#include <hpx/assert.hpp>
145
#include <hpx/async_combinators/detail/throw_if_exceptional.hpp>
146
#include <hpx/datastructures/tuple.hpp>
147
#include <hpx/functional/deferred_call.hpp>
148
#include <hpx/functional/tag_invoke.hpp>
149
#include <hpx/futures/future.hpp>
150
#include <hpx/futures/traits/acquire_shared_state.hpp>
151
#include <hpx/futures/traits/detail/future_traits.hpp>
152
#include <hpx/futures/traits/future_access.hpp>
153
#include <hpx/futures/traits/is_future.hpp>
154
#include <hpx/iterator_support/traits/is_iterator.hpp>
155
#include <hpx/modules/errors.hpp>
156
#include <hpx/preprocessor/strip_parens.hpp>
157
#include <hpx/type_support/pack.hpp>
158

159
#include <algorithm>
160
#include <array>
161
#include <atomic>
162
#include <cstddef>
163
#include <iterator>
164
#include <memory>
165
#include <type_traits>
166
#include <utility>
167
#include <vector>
168

169
///////////////////////////////////////////////////////////////////////////////
170
namespace hpx {
171

172
    namespace detail {
173

174
        ///////////////////////////////////////////////////////////////////////
175
        template <typename Sequence>
176
        struct wait_some;
177

178
        template <typename Sequence>
179
        struct set_wait_some_callback_impl
180
        {
181
            explicit set_wait_some_callback_impl(
30✔
182
                wait_some<Sequence>& wait) noexcept
183
              : wait_(wait)
30✔
184
            {
185
            }
30✔
186

187
            template <typename SharedState>
188
            void operator()(SharedState const& shared_state) const
64✔
189
            {
190
                if constexpr (!traits::is_shared_state_v<SharedState>)
191
                {
192
                    apply(shared_state);
4✔
193
                }
194
                else
195
                {
196
                    std::size_t counter =
60✔
197
                        wait_.count_.load(std::memory_order_acquire);
60✔
198

199
                    if (counter < wait_.needed_count_ && shared_state)
60✔
200
                    {
201
                        if (!shared_state->is_ready(std::memory_order_relaxed))
58✔
202
                        {
203
                            // handle future only if not enough futures are
204
                            // ready yet also, do not touch any futures which
205
                            // are already ready
206
                            shared_state->execute_deferred();
38✔
207

208
                            // execute_deferred might have made the future ready
209
                            if (!shared_state->is_ready(
38✔
210
                                    std::memory_order_relaxed))
211
                            {
212
                                shared_state->set_on_completed(
76✔
213
                                    util::deferred_call(
38✔
214
                                        &wait_some<Sequence>::on_future_ready,
38✔
215
                                        wait_.shared_from_this(),
38✔
216
                                        hpx::execution_base::this_thread::
38✔
217
                                            agent()));
218
                                return;
38✔
219
                            }
220
                        }
×
221

222
                        // check whether the current future is exceptional
223
                        if (!wait_.has_exceptional_results_ &&
20✔
224
                            shared_state->has_exception())
20✔
225
                        {
226
                            wait_.has_exceptional_results_ = true;
18✔
227
                        }
18✔
228
                    }
20✔
229

230
                    if (wait_.count_.fetch_add(1) + 1 == wait_.needed_count_)
22✔
231
                    {
232
                        wait_.goal_reached_on_calling_thread_ = true;
20✔
233
                    }
20✔
234
                }
235
            }
64✔
236

237
            template <typename Tuple, std::size_t... Is>
238
            HPX_FORCEINLINE void apply(
6✔
239
                Tuple const& tuple, hpx::util::index_pack<Is...>) const
240
            {
241
                ((*this)(hpx::get<Is>(tuple)), ...);
6✔
242
            }
6✔
243

244
            template <typename... Ts>
245
            HPX_FORCEINLINE void apply(hpx::tuple<Ts...> const& sequence) const
6✔
246
            {
247
                apply(sequence, hpx::util::make_index_pack_t<sizeof...(Ts)>());
6✔
248
            }
6✔
249

250
            template <typename Sequence_>
251
            HPX_FORCEINLINE void apply(Sequence_ const& sequence) const
28✔
252
            {
253
                std::for_each(sequence.begin(), sequence.end(), *this);
28✔
254
            }
28✔
255

256
            wait_some<Sequence>& wait_;
257
        };
258

259
        template <typename Sequence>
260
        void set_on_completed_callback(wait_some<Sequence>& wait)
30✔
261
        {
262
            set_wait_some_callback_impl<Sequence> callback(wait);
30✔
263
            callback.apply(wait.values_);
30✔
264
        }
30✔
265

266
        template <typename Sequence>
267
        struct wait_some
30✔
268
          : std::enable_shared_from_this<wait_some<Sequence>>    //-V690
269
        {
270
        public:
271
            void on_future_ready(hpx::execution_base::agent_ref ctx)
38✔
272
            {
273
                if (count_.fetch_add(1) + 1 == needed_count_)
38✔
274
                {
275
                    // reactivate waiting thread only if it's not us
276
                    if (ctx != hpx::execution_base::this_thread::agent())
10✔
277
                    {
278
                        ctx.resume();
10✔
279
                    }
10✔
280
                    else
281
                    {
282
                        goal_reached_on_calling_thread_ = true;
×
283
                    }
284
                }
10✔
285
            }
38✔
286

287
        private:
288
            wait_some(wait_some const&) = delete;
289
            wait_some(wait_some&&) = delete;
290

291
            wait_some& operator=(wait_some const&) = delete;
292
            wait_some& operator=(wait_some&&) = delete;
293

294
        public:
295
            using argument_type = Sequence;
296

297
            wait_some(argument_type const& values, std::size_t n) noexcept
30✔
298
              : values_(values)
30✔
299
              , count_(0)
30✔
300
              , needed_count_(n)
30✔
301
            {
30✔
302
            }
30✔
303

304
            bool operator()()
30✔
305
            {
306
                // set callback functions to executed wait future is ready
307
                set_on_completed_callback(*this);
30✔
308

309
                // if all of the requested futures are already set, our
310
                // callback above has already been called often enough, otherwise
311
                // we suspend ourselves
312
                if (!goal_reached_on_calling_thread_)
30✔
313
                {
314
                    // wait for any of the futures to return to become ready
315
                    hpx::execution_base::this_thread::suspend(
10✔
316
                        "hpx::detail::wait_some::operator()");
317
                }
10✔
318

319
                // at least N futures should be ready
320
                HPX_ASSERT(
30✔
321
                    count_.load(std::memory_order_acquire) >= needed_count_);
322

323
                return has_exceptional_results_;
30✔
324
            }
325

326
            argument_type const& values_;
327
            std::atomic<std::size_t> count_;
328
            std::size_t const needed_count_;
329
            bool goal_reached_on_calling_thread_ = false;
30✔
330
            bool has_exceptional_results_ = false;
30✔
331
        };
332

333
        template <typename T>
334
        auto get_wait_some_frame(T const& values, std::size_t n)
30✔
335
        {
336
            return std::make_shared<hpx::detail::wait_some<T>>(values, n);
30✔
337
        }
338
    }    // namespace detail
339

340
    ///////////////////////////////////////////////////////////////////////////
341
    inline constexpr struct wait_some_nothrow_t final
342
      : hpx::functional::tag<wait_some_nothrow_t>
343
    {
344
    private:
345
        template <typename Future>
346
        friend bool tag_invoke(wait_some_nothrow_t, std::size_t n,
6✔
347
            std::vector<Future> const& values)
348
        {
349
            static_assert(hpx::traits::is_future_v<Future>,
350
                "invalid use of hpx::wait_some");
351

352
            if (n == 0)
6✔
353
            {
354
                return false;
×
355
            }
356

357
            if (n > values.size())
6✔
358
            {
359
                HPX_THROW_EXCEPTION(hpx::error::bad_parameter, "hpx::wait_some",
×
360
                    "number of results to wait for is out of bounds");
361
                return false;
362
            }
363

364
            auto lazy_values = traits::acquire_shared_state_disp()(values);
6✔
365
            auto f = detail::get_wait_some_frame(lazy_values, n);
6✔
366

367
            return (*f)();
6✔
368
        }
6✔
369

370
        template <typename Future>
371
        friend HPX_FORCEINLINE bool tag_invoke(
2✔
372
            wait_some_nothrow_t, std::size_t n, std::vector<Future>& values)
373
        {
374
            return tag_invoke(wait_some_nothrow_t{}, n,
4✔
375
                const_cast<std::vector<Future> const&>(values));
2✔
376
        }
377

378
        template <typename Future>
379
        friend HPX_FORCEINLINE bool tag_invoke(
380
            wait_some_nothrow_t, std::size_t n, std::vector<Future>&& values)
381
        {
382
            return tag_invoke(wait_some_nothrow_t{}, n,
383
                const_cast<std::vector<Future> const&>(values));
384
        }
385

386
        template <typename Future, std::size_t N>
387
        friend bool tag_invoke(wait_some_nothrow_t, std::size_t n,
6✔
388
            std::array<Future, N> const& values)
389
        {
390
            static_assert(
391
                hpx::traits::is_future_v<Future>, "invalid use of wait_some");
392

393
            if (n == 0)
6✔
394
            {
395
                return false;
×
396
            }
397

398
            if (n > values.size())
6✔
399
            {
400
                HPX_THROW_EXCEPTION(hpx::error::bad_parameter, "hpx::wait_some",
×
401
                    "number of results to wait for is out of bounds");
402
                return false;
403
            }
404

405
            auto lazy_values = traits::acquire_shared_state_disp()(values);
6✔
406
            auto f = detail::get_wait_some_frame(lazy_values, n);
6✔
407

408
            return (*f)();
6✔
409
        }
6✔
410

411
        template <typename Future, std::size_t N>
412
        friend HPX_FORCEINLINE bool tag_invoke(wait_some_nothrow_t,
2✔
413
            std::size_t n, std::array<Future, N>& lazy_values)
414
        {
415
            return tag_invoke(wait_some_nothrow_t{}, n,
4✔
416
                const_cast<std::array<Future, N> const&>(lazy_values));
2✔
417
        }
418

419
        template <typename Future, std::size_t N>
420
        friend HPX_FORCEINLINE bool tag_invoke(wait_some_nothrow_t,
421
            std::size_t n, std::array<Future, N>&& lazy_values)
422
        {
423
            return tag_invoke(wait_some_nothrow_t{}, n,
424
                const_cast<std::array<Future, N> const&>(lazy_values));
425
        }
426

427
        template <typename Iterator,
428
            typename Enable =
429
                std::enable_if_t<hpx::traits::is_iterator_v<Iterator>>>
430
        friend bool tag_invoke(
431
            wait_some_nothrow_t, std::size_t n, Iterator begin, Iterator end)
432
        {
433
            auto values = traits::acquire_shared_state<Iterator>()(begin, end);
434
            auto f = detail::get_wait_some_frame(values, n);
435

436
            return (*f)();
437
        }
438

439
        friend bool tag_invoke(wait_some_nothrow_t, std::size_t n)
440
        {
441
            if (n != 0)
442
            {
443
                HPX_THROW_EXCEPTION(hpx::error::bad_parameter,
444
                    "hpx::wait_some_nothrow",
445
                    "number of results to wait for is out of bounds");
446
            }
447
            return false;
448
        }
449

450
        template <typename T>
451
        friend bool tag_invoke(
452
            wait_some_nothrow_t, std::size_t n, hpx::future<T>&& f)
453
        {
454
            if (n != 1)
455
            {
456
                HPX_THROW_EXCEPTION(hpx::error::bad_parameter, "hpx::wait_some",
457
                    "number of results to wait for is out of bounds");
458
                return false;
459
            }
460

461
            f.wait();
462
            return f.has_exception();
463
        }
464

465
        template <typename T>
466
        friend bool tag_invoke(
467
            wait_some_nothrow_t, std::size_t n, hpx::shared_future<T>&& f)
468
        {
469
            if (n != 1)
470
            {
471
                HPX_THROW_EXCEPTION(hpx::error::bad_parameter, "hpx::wait_some",
472
                    "number of results to wait for is out of bounds");
473
                return false;
474
            }
475

476
            f.wait();
477
            return f.has_exception();
478
        }
479

480
        template <typename... Ts>
481
        friend bool tag_invoke(wait_some_nothrow_t, std::size_t n, Ts&&... ts)
6✔
482
        {
483
            if (n == 0)
6✔
484
            {
485
                return false;
×
486
            }
487

488
            if (n > sizeof...(Ts))
6✔
489
            {
490
                HPX_THROW_EXCEPTION(hpx::error::bad_parameter,
×
491
                    "hpx::lcos::wait_some",
492
                    "number of results to wait for is out of bounds");
493
                return false;
494
            }
495

496
            using result_type =
497
                hpx::tuple<traits::detail::shared_state_ptr_for_t<Ts>...>;
498

499
            result_type values(traits::detail::get_shared_state(ts)...);
6✔
500
            auto f = detail::get_wait_some_frame(values, n);
6✔
501

502
            return (*f)();
6✔
503
        }
6✔
504
    } wait_some_nothrow{};
505

506
    ///////////////////////////////////////////////////////////////////////////
507
    inline constexpr struct wait_some_t final
508
      : hpx::functional::tag<wait_some_t>
509
    {
510
    private:
511
        template <typename Future>
512
        friend void tag_invoke(
1✔
513
            wait_some_t, std::size_t n, std::vector<Future> const& values)
514
        {
515
            if (hpx::wait_some_nothrow(n, values))
1✔
516
            {
517
                hpx::detail::throw_if_exceptional(values);
×
518
            }
×
519
        }
×
520

521
        template <typename Future>
522
        friend void tag_invoke(
1✔
523
            wait_some_t, std::size_t n, std::vector<Future>& values)
524
        {
525
            if (hpx::wait_some_nothrow(
1✔
526
                    n, const_cast<std::vector<Future> const&>(values)))
1✔
527
            {
528
                hpx::detail::throw_if_exceptional(values);
×
529
            }
×
530
        }
×
531

532
        template <typename Future>
533
        friend void tag_invoke(
534
            wait_some_t, std::size_t n, std::vector<Future>&& values)
535
        {
536
            if (hpx::wait_some_nothrow(
537
                    n, const_cast<std::vector<Future> const&>(values)))
538
            {
539
                hpx::detail::throw_if_exceptional(values);
540
            }
541
        }
542

543
        template <typename Future, std::size_t N>
544
        friend void tag_invoke(wait_some_t, std::size_t n,
1✔
545
            std::array<Future, N> const& lazy_values)
546
        {
547
            if (hpx::wait_some_nothrow(n, lazy_values))
1✔
548
            {
549
                hpx::detail::throw_if_exceptional(lazy_values);
×
550
            }
×
551
        }
×
552

553
        template <typename Future, std::size_t N>
554
        friend void tag_invoke(
1✔
555
            wait_some_t, std::size_t n, std::array<Future, N>& lazy_values)
556
        {
557
            if (hpx::wait_some_nothrow(
1✔
558
                    n, const_cast<std::array<Future, N> const&>(lazy_values)))
1✔
559
            {
560
                hpx::detail::throw_if_exceptional(lazy_values);
×
561
            }
×
562
        }
×
563

564
        template <typename Future, std::size_t N>
565
        friend void tag_invoke(
566
            wait_some_t, std::size_t n, std::array<Future, N>&& lazy_values)
567
        {
568
            if (hpx::wait_some_nothrow(
569
                    n, const_cast<std::array<Future, N> const&>(lazy_values)))
570
            {
571
                hpx::detail::throw_if_exceptional(lazy_values);
572
            }
573
        }
574

575
        template <typename Iterator,
576
            typename Enable =
577
                std::enable_if_t<hpx::traits::is_iterator_v<Iterator>>>
578
        friend void tag_invoke(
579
            wait_some_t, std::size_t n, Iterator begin, Iterator end)
580
        {
581
            auto values = traits::acquire_shared_state<Iterator>()(begin, end);
582
            auto f = detail::get_wait_some_frame(values, n);
583

584
            if ((*f)())
585
            {
586
                hpx::detail::throw_if_exceptional(values);
587
            }
588
        }
589

590
        friend void tag_invoke(wait_some_t, std::size_t n)
591
        {
592
            if (n != 0)
593
            {
594
                HPX_THROW_EXCEPTION(hpx::error::bad_parameter, "hpx::wait_some",
595
                    "number of results to wait for is out of bounds");
596
            }
597
        }
598

599
        template <typename T>
600
        friend void tag_invoke(wait_some_t, std::size_t n, hpx::future<T>&& f)
601
        {
602
            if (hpx::wait_some_nothrow(n, HPX_MOVE(f)))
603
            {
604
                hpx::detail::throw_if_exceptional(f);
605
            }
606
        }
607

608
        template <typename T>
609
        friend void tag_invoke(
610
            wait_some_t, std::size_t n, hpx::shared_future<T>&& f)
611
        {
612
            if (hpx::wait_some_nothrow(n, HPX_MOVE(f)))
613
            {
614
                hpx::detail::throw_if_exceptional(f);
615
            }
616
        }
617

618
        template <typename... Ts>
619
        friend void tag_invoke(wait_some_t, std::size_t n, Ts&&... ts)
4✔
620
        {
621
            if (hpx::wait_some_nothrow(n, ts...))
4✔
622
            {
623
                hpx::detail::throw_if_exceptional(HPX_FORWARD(Ts, ts)...);
×
624
            }
×
625
        }
2✔
626
    } wait_some{};
627

628
    ///////////////////////////////////////////////////////////////////////////
629
    inline constexpr struct wait_some_n_nothrow_t final
630
      : hpx::functional::tag<wait_some_n_nothrow_t>
631
    {
632
    private:
633
        template <typename Iterator,
634
            typename Enable =
635
                std::enable_if_t<hpx::traits::is_iterator_v<Iterator>>>
636
        friend bool tag_invoke(wait_some_n_nothrow_t, std::size_t n,
8✔
637
            Iterator begin, std::size_t count)
638
        {
639
            auto values =
640
                traits::acquire_shared_state<Iterator>()(begin, count);
8✔
641
            auto f = detail::get_wait_some_frame(values, n);
8✔
642

643
            return (*f)();
8✔
644
        }
8✔
645
    } wait_some_n_nothrow{};
646

647
    ///////////////////////////////////////////////////////////////////////////
648
    inline constexpr struct wait_some_n_t final
649
      : hpx::functional::tag<wait_some_n_t>
650
    {
651
    private:
652
        template <typename Iterator,
653
            typename Enable =
654
                std::enable_if_t<hpx::traits::is_iterator_v<Iterator>>>
655
        friend void tag_invoke(
4✔
656
            wait_some_n_t, std::size_t n, Iterator begin, std::size_t count)
657
        {
658
            auto values =
659
                traits::acquire_shared_state<Iterator>()(begin, count);
4✔
660
            auto f = detail::get_wait_some_frame(values, n);
4✔
661

662
            if ((*f)())
4✔
663
            {
664
                hpx::detail::throw_if_exceptional(values);
4✔
665
            }
×
666
        }
4✔
667
    } wait_some_n{};
668
}    // namespace hpx
669

670
namespace hpx::lcos {
671

672
    template <typename Future>
673
    HPX_DEPRECATED_V(
674
        1, 8, "hpx::lcos::wait_some is deprecated. Use hpx::wait_some instead.")
675
    void wait_some(std::size_t n, std::vector<Future> const& lazy_values,
676
        error_code& = throws)
677
    {
678
        hpx::wait_some(n, lazy_values);
679
    }
680

681
    template <typename Future>
682
    HPX_DEPRECATED_V(
683
        1, 8, "hpx::lcos::wait_some is deprecated. Use hpx::wait_some instead.")
684
    void wait_some(
685
        std::size_t n, std::vector<Future>& lazy_values, error_code& = throws)
686
    {
687
        hpx::wait_some(n, const_cast<std::vector<Future> const&>(lazy_values));
688
    }
689

690
    template <typename Future>
691
    HPX_DEPRECATED_V(
692
        1, 8, "hpx::lcos::wait_some is deprecated. Use hpx::wait_some instead.")
693
    void wait_some(
694
        std::size_t n, std::vector<Future>&& lazy_values, error_code& = throws)
695
    {
696
        hpx::wait_some(n, const_cast<std::vector<Future> const&>(lazy_values));
697
    }
698

699
    template <typename Future, std::size_t N>
700
    HPX_DEPRECATED_V(
701
        1, 8, "hpx::lcos::wait_some is deprecated. Use hpx::wait_some instead.")
702
    void wait_some(std::size_t n, std::array<Future, N> const& lazy_values,
703
        error_code& = throws)
704
    {
705
        hpx::wait_some(n, lazy_values);
706
    }
707

708
    template <typename Future, std::size_t N>
709
    HPX_DEPRECATED_V(
710
        1, 8, "hpx::lcos::wait_some is deprecated. Use hpx::wait_some instead.")
711
    void wait_some(
712
        std::size_t n, std::array<Future, N>& lazy_values, error_code& = throws)
713
    {
714
        hpx::wait_some(
715
            n, const_cast<std::array<Future, N> const&>(lazy_values));
716
    }
717

718
    template <typename Future, std::size_t N>
719
    HPX_DEPRECATED_V(
720
        1, 8, "hpx::lcos::wait_some is deprecated. Use hpx::wait_some instead.")
721
    void wait_some(std::size_t n, std::array<Future, N>&& lazy_values,
722
        error_code& = throws)
723
    {
724
        hpx::wait_some(
725
            n, const_cast<std::array<Future, N> const&>(lazy_values));
726
    }
727

728
    template <typename Iterator,
729
        typename Enable =
730
            std::enable_if_t<hpx::traits::is_iterator_v<Iterator>>>
731
    HPX_DEPRECATED_V(
732
        1, 8, "hpx::lcos::wait_some is deprecated. Use hpx::wait_some instead.")
733
    void wait_some(
734
        std::size_t n, Iterator begin, Iterator end, error_code& = throws)
735
    {
736
        hpx::wait_some(n, begin, end);
737
    }
738

739
    template <typename Iterator,
740
        typename Enable =
741
            std::enable_if_t<hpx::traits::is_iterator_v<Iterator>>>
742
    HPX_DEPRECATED_V(
743
        1, 8, "hpx::lcos::wait_some is deprecated. Use hpx::wait_some instead.")
744
    Iterator wait_some_n(
745
        std::size_t n, Iterator begin, std::size_t count, error_code& = throws)
746
    {
747
        hpx::wait_some(n, begin, count);
748
    }
749

750
    HPX_DEPRECATED_V(
751
        1, 8, "hpx::lcos::wait_some is deprecated. Use hpx::wait_some instead.")
752
    inline void wait_some(std::size_t n, error_code& = throws)
753
    {
754
        hpx::wait_some(n);
755
    }
756

757
    template <typename T>
758
    HPX_DEPRECATED_V(
759
        1, 8, "hpx::lcos::wait_some is deprecated. Use hpx::wait_some instead.")
760
    void wait_some(std::size_t n, hpx::future<T>&& f, error_code& = throws)
761
    {
762
        hpx::wait_some(n, HPX_MOVE(f));
763
    }
764

765
    template <typename T>
766
    HPX_DEPRECATED_V(
767
        1, 8, "hpx::lcos::wait_some is deprecated. Use hpx::wait_some instead.")
768
    void wait_some(
769
        std::size_t n, hpx::shared_future<T>&& f, error_code& = throws)
770
    {
771
        hpx::wait_some(n, HPX_MOVE(f));
772
    }
773

774
    template <typename... Ts>
775
    HPX_DEPRECATED_V(
776
        1, 8, "hpx::lcos::wait_some is deprecated. Use hpx::wait_some instead.")
777
    void wait_some(std::size_t n, error_code&, Ts&&... ts)
778
    {
779
        hpx::wait_some(n, HPX_FORWARD(Ts, ts)...);
780
    }
781

782
    template <typename... Ts>
783
    HPX_DEPRECATED_V(
784
        1, 8, "hpx::lcos::wait_some is deprecated. Use hpx::wait_some instead.")
785
    void wait_some(std::size_t n, Ts&&... ts)
786
    {
787
        hpx::wait_some(n, HPX_FORWARD(Ts, ts)...);
788
    }
789
}    // namespace hpx::lcos
790

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