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

STEllAR-GROUP / hpx / #871

22 Jan 2023 11:22PM UTC coverage: 86.624% (+0.7%) from 85.97%
#871

push

StellarBot
Merge #6144

6144: General improvements to scheduling and related fixes r=hkaiser a=hkaiser

This is a collection of unrelated improvements applied to different parts of the code

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

152 of 152 new or added lines in 23 files covered. (100.0%)

174953 of 201969 relevant lines covered (86.62%)

1838882.76 hits per line

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

83.8
/libs/core/async_combinators/include/hpx/async_combinators/wait_some.hpp
1
//  Copyright (c) 2007-2023 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
        static bool wait_some_nothrow_impl(
6✔
347
            std::size_t n, 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 bool tag_invoke(wait_some_nothrow_t, std::size_t n,
4✔
372
            std::vector<Future> const& values)
373
        {
374
            return wait_some_nothrow_t::wait_some_nothrow_impl(n, values);
4✔
375
        }
376

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

385
        template <typename Future>
386
        friend HPX_FORCEINLINE bool tag_invoke(
387
            wait_some_nothrow_t, std::size_t n, std::vector<Future>&& values)
388
        {
389
            return wait_some_nothrow_t::wait_some_nothrow_impl(
390
                n, const_cast<std::vector<Future> const&>(values));
391
        }
392

393
        template <typename Future, std::size_t N>
394
        static bool wait_some_nothrow_impl(
6✔
395
            std::size_t n, std::array<Future, N> const& values)
396
        {
397
            static_assert(
398
                hpx::traits::is_future_v<Future>, "invalid use of wait_some");
399

400
            if (n == 0)
6✔
401
            {
402
                return false;
×
403
            }
404

405
            if (n > values.size())
6✔
406
            {
407
                HPX_THROW_EXCEPTION(hpx::error::bad_parameter, "hpx::wait_some",
×
408
                    "number of results to wait for is out of bounds");
409
                return false;
410
            }
411

412
            auto lazy_values = traits::acquire_shared_state_disp()(values);
6✔
413
            auto f = detail::get_wait_some_frame(lazy_values, n);
6✔
414

415
            return (*f)();
6✔
416
        }
6✔
417

418
        template <typename Future, std::size_t N>
419
        friend bool tag_invoke(wait_some_nothrow_t, std::size_t n,
4✔
420
            std::array<Future, N> const& values)
421
        {
422
            return wait_some_nothrow_t::wait_some_nothrow_impl(n, values);
4✔
423
        }
424

425
        template <typename Future, std::size_t N>
426
        friend HPX_FORCEINLINE bool tag_invoke(wait_some_nothrow_t,
2✔
427
            std::size_t n, std::array<Future, N>& lazy_values)
428
        {
429
            return wait_some_nothrow_t::wait_some_nothrow_impl(
2✔
430
                n, const_cast<std::array<Future, N> const&>(lazy_values));
2✔
431
        }
432

433
        template <typename Future, std::size_t N>
434
        friend HPX_FORCEINLINE bool tag_invoke(wait_some_nothrow_t,
435
            std::size_t n, std::array<Future, N>&& lazy_values)
436
        {
437
            return wait_some_nothrow_t::wait_some_nothrow_impl(
438
                n, const_cast<std::array<Future, N> const&>(lazy_values));
439
        }
440

441
        template <typename Iterator,
442
            typename Enable =
443
                std::enable_if_t<hpx::traits::is_iterator_v<Iterator>>>
444
        friend bool tag_invoke(
445
            wait_some_nothrow_t, std::size_t n, Iterator begin, Iterator end)
446
        {
447
            auto values = traits::acquire_shared_state<Iterator>()(begin, end);
448
            auto f = detail::get_wait_some_frame(values, n);
449

450
            return (*f)();
451
        }
452

453
        friend bool tag_invoke(wait_some_nothrow_t, std::size_t n)
454
        {
455
            if (n != 0)
456
            {
457
                HPX_THROW_EXCEPTION(hpx::error::bad_parameter,
458
                    "hpx::wait_some_nothrow",
459
                    "number of results to wait for is out of bounds");
460
            }
461
            return false;
462
        }
463

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

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

479
        template <typename T>
480
        friend bool tag_invoke(
481
            wait_some_nothrow_t, std::size_t n, hpx::shared_future<T>&& f)
482
        {
483
            if (n != 1)
484
            {
485
                HPX_THROW_EXCEPTION(hpx::error::bad_parameter, "hpx::wait_some",
486
                    "number of results to wait for is out of bounds");
487
                return false;
488
            }
489

490
            f.wait();
491
            return f.has_exception();
492
        }
493

494
        template <typename... Ts>
495
        friend bool tag_invoke(wait_some_nothrow_t, std::size_t n, Ts&&... ts)
6✔
496
        {
497
            if (n == 0)
6✔
498
            {
499
                return false;
×
500
            }
501

502
            if (n > sizeof...(Ts))
6✔
503
            {
504
                HPX_THROW_EXCEPTION(hpx::error::bad_parameter,
×
505
                    "hpx::lcos::wait_some",
506
                    "number of results to wait for is out of bounds");
507
                return false;
508
            }
509

510
            using result_type =
511
                hpx::tuple<traits::detail::shared_state_ptr_for_t<Ts>...>;
512

513
            result_type values(traits::detail::get_shared_state(ts)...);
6✔
514
            auto f = detail::get_wait_some_frame(values, n);
6✔
515

516
            return (*f)();
6✔
517
        }
6✔
518
    } wait_some_nothrow{};
519

520
    ///////////////////////////////////////////////////////////////////////////
521
    inline constexpr struct wait_some_t final
522
      : hpx::functional::tag<wait_some_t>
523
    {
524
    private:
525
        template <typename Future>
526
        friend void tag_invoke(
1✔
527
            wait_some_t, std::size_t n, std::vector<Future> const& values)
528
        {
529
            if (hpx::wait_some_nothrow(n, values))
1✔
530
            {
531
                hpx::detail::throw_if_exceptional(values);
×
532
            }
×
533
        }
×
534

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

546
        template <typename Future>
547
        friend void tag_invoke(
548
            wait_some_t, std::size_t n, std::vector<Future>&& values)
549
        {
550
            if (hpx::wait_some_nothrow(
551
                    n, const_cast<std::vector<Future> const&>(values)))
552
            {
553
                hpx::detail::throw_if_exceptional(values);
554
            }
555
        }
556

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

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

578
        template <typename Future, std::size_t N>
579
        friend void tag_invoke(
580
            wait_some_t, std::size_t n, std::array<Future, N>&& lazy_values)
581
        {
582
            if (hpx::wait_some_nothrow(
583
                    n, const_cast<std::array<Future, N> const&>(lazy_values)))
584
            {
585
                hpx::detail::throw_if_exceptional(lazy_values);
586
            }
587
        }
588

589
        template <typename Iterator,
590
            typename Enable =
591
                std::enable_if_t<hpx::traits::is_iterator_v<Iterator>>>
592
        friend void tag_invoke(
593
            wait_some_t, std::size_t n, Iterator begin, Iterator end)
594
        {
595
            auto values = traits::acquire_shared_state<Iterator>()(begin, end);
596
            auto f = detail::get_wait_some_frame(values, n);
597

598
            if ((*f)())
599
            {
600
                hpx::detail::throw_if_exceptional(values);
601
            }
602
        }
603

604
        friend void tag_invoke(wait_some_t, std::size_t n)
605
        {
606
            if (n != 0)
607
            {
608
                HPX_THROW_EXCEPTION(hpx::error::bad_parameter, "hpx::wait_some",
609
                    "number of results to wait for is out of bounds");
610
            }
611
        }
612

613
        template <typename T>
614
        friend void tag_invoke(wait_some_t, std::size_t n, hpx::future<T>&& f)
615
        {
616
            if (hpx::wait_some_nothrow(n, HPX_MOVE(f)))
617
            {
618
                hpx::detail::throw_if_exceptional(f);
619
            }
620
        }
621

622
        template <typename T>
623
        friend void tag_invoke(
624
            wait_some_t, std::size_t n, hpx::shared_future<T>&& f)
625
        {
626
            if (hpx::wait_some_nothrow(n, HPX_MOVE(f)))
627
            {
628
                hpx::detail::throw_if_exceptional(f);
629
            }
630
        }
631

632
        template <typename... Ts>
633
        friend void tag_invoke(wait_some_t, std::size_t n, Ts&&... ts)
4✔
634
        {
635
            if (hpx::wait_some_nothrow(n, ts...))
4✔
636
            {
637
                hpx::detail::throw_if_exceptional(HPX_FORWARD(Ts, ts)...);
×
638
            }
×
639
        }
2✔
640
    } wait_some{};
641

642
    ///////////////////////////////////////////////////////////////////////////
643
    inline constexpr struct wait_some_n_nothrow_t final
644
      : hpx::functional::tag<wait_some_n_nothrow_t>
645
    {
646
    private:
647
        template <typename Iterator,
648
            typename Enable =
649
                std::enable_if_t<hpx::traits::is_iterator_v<Iterator>>>
650
        friend bool tag_invoke(wait_some_n_nothrow_t, std::size_t n,
8✔
651
            Iterator begin, std::size_t count)
652
        {
653
            auto values =
654
                traits::acquire_shared_state<Iterator>()(begin, count);
8✔
655
            auto f = detail::get_wait_some_frame(values, n);
8✔
656

657
            return (*f)();
8✔
658
        }
8✔
659
    } wait_some_n_nothrow{};
660

661
    ///////////////////////////////////////////////////////////////////////////
662
    inline constexpr struct wait_some_n_t final
663
      : hpx::functional::tag<wait_some_n_t>
664
    {
665
    private:
666
        template <typename Iterator,
667
            typename Enable =
668
                std::enable_if_t<hpx::traits::is_iterator_v<Iterator>>>
669
        friend void tag_invoke(
4✔
670
            wait_some_n_t, std::size_t n, Iterator begin, std::size_t count)
671
        {
672
            auto values =
673
                traits::acquire_shared_state<Iterator>()(begin, count);
4✔
674
            auto f = detail::get_wait_some_frame(values, n);
4✔
675

676
            if ((*f)())
4✔
677
            {
678
                hpx::detail::throw_if_exceptional(values);
4✔
679
            }
×
680
        }
4✔
681
    } wait_some_n{};
682
}    // namespace hpx
683

684
namespace hpx::lcos {
685

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

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

704
    template <typename Future>
705
    HPX_DEPRECATED_V(
706
        1, 8, "hpx::lcos::wait_some is deprecated. Use hpx::wait_some instead.")
707
    void wait_some(
708
        std::size_t n, std::vector<Future>&& lazy_values, error_code& = throws)
709
    {
710
        hpx::wait_some(n, const_cast<std::vector<Future> const&>(lazy_values));
711
    }
712

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

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

732
    template <typename Future, std::size_t N>
733
    HPX_DEPRECATED_V(
734
        1, 8, "hpx::lcos::wait_some is deprecated. Use hpx::wait_some instead.")
735
    void wait_some(std::size_t n, std::array<Future, N>&& lazy_values,
736
        error_code& = throws)
737
    {
738
        hpx::wait_some(
739
            n, const_cast<std::array<Future, N> const&>(lazy_values));
740
    }
741

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

753
    template <typename Iterator,
754
        typename Enable =
755
            std::enable_if_t<hpx::traits::is_iterator_v<Iterator>>>
756
    HPX_DEPRECATED_V(
757
        1, 8, "hpx::lcos::wait_some is deprecated. Use hpx::wait_some instead.")
758
    Iterator wait_some_n(
759
        std::size_t n, Iterator begin, std::size_t count, error_code& = throws)
760
    {
761
        hpx::wait_some(n, begin, count);
762
    }
763

764
    HPX_DEPRECATED_V(
765
        1, 8, "hpx::lcos::wait_some is deprecated. Use hpx::wait_some instead.")
766
    inline void wait_some(std::size_t n, error_code& = throws)
767
    {
768
        hpx::wait_some(n);
769
    }
770

771
    template <typename T>
772
    HPX_DEPRECATED_V(
773
        1, 8, "hpx::lcos::wait_some is deprecated. Use hpx::wait_some instead.")
774
    void wait_some(std::size_t n, hpx::future<T>&& f, error_code& = throws)
775
    {
776
        hpx::wait_some(n, HPX_MOVE(f));
777
    }
778

779
    template <typename T>
780
    HPX_DEPRECATED_V(
781
        1, 8, "hpx::lcos::wait_some is deprecated. Use hpx::wait_some instead.")
782
    void wait_some(
783
        std::size_t n, hpx::shared_future<T>&& f, error_code& = throws)
784
    {
785
        hpx::wait_some(n, HPX_MOVE(f));
786
    }
787

788
    template <typename... Ts>
789
    HPX_DEPRECATED_V(
790
        1, 8, "hpx::lcos::wait_some is deprecated. Use hpx::wait_some instead.")
791
    void wait_some(std::size_t n, error_code&, Ts&&... ts)
792
    {
793
        hpx::wait_some(n, HPX_FORWARD(Ts, ts)...);
794
    }
795

796
    template <typename... Ts>
797
    HPX_DEPRECATED_V(
798
        1, 8, "hpx::lcos::wait_some is deprecated. Use hpx::wait_some instead.")
799
    void wait_some(std::size_t n, Ts&&... ts)
800
    {
801
        hpx::wait_some(n, HPX_FORWARD(Ts, ts)...);
802
    }
803
}    // namespace hpx::lcos
804

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