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

STEllAR-GROUP / hpx / #853

19 Dec 2022 01:01AM UTC coverage: 86.287% (+0.4%) from 85.912%
#853

push

StellarBot
Merge #6109

6109: Modernize serialization module r=hkaiser a=hkaiser

- flyby separate serialization of Boost types

working towards https://github.com/STEllAR-GROUP/hpx/issues/5497

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

53 of 53 new or added lines in 6 files covered. (100.0%)

173939 of 201582 relevant lines covered (86.29%)

1931657.12 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
    namespace detail {
172
        ///////////////////////////////////////////////////////////////////////
173
        template <typename Sequence>
174
        struct wait_some;
175

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

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

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

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

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

226
                    if (wait_.count_.fetch_add(1) + 1 == wait_.needed_count_)
22✔
227
                    {
228
                        wait_.goal_reached_on_calling_thread_ = true;
20✔
229
                    }
20✔
230
                }
231
            }
64✔
232

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

240
            template <typename... Ts>
241
            HPX_FORCEINLINE void apply(hpx::tuple<Ts...> const& sequence) const
6✔
242
            {
243
                apply(sequence, hpx::util::make_index_pack_t<sizeof...(Ts)>());
6✔
244
            }
6✔
245

246
            template <typename Sequence_>
247
            HPX_FORCEINLINE void apply(Sequence_ const& sequence) const
28✔
248
            {
249
                std::for_each(sequence.begin(), sequence.end(), *this);
28✔
250
            }
28✔
251

252
            wait_some<Sequence>& wait_;
253
        };
254

255
        template <typename Sequence>
256
        void set_on_completed_callback(wait_some<Sequence>& wait)
30✔
257
        {
258
            set_wait_some_callback_impl<Sequence> callback(wait);
30✔
259
            callback.apply(wait.values_);
30✔
260
        }
30✔
261

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

283
        private:
284
            wait_some(wait_some const&) = delete;
285
            wait_some(wait_some&&) = delete;
286

287
            wait_some& operator=(wait_some const&) = delete;
288
            wait_some& operator=(wait_some&&) = delete;
289

290
        public:
291
            using argument_type = Sequence;
292

293
            wait_some(argument_type const& values, std::size_t n)
30✔
294
              : values_(values)
30✔
295
              , count_(0)
30✔
296
              , needed_count_(n)
30✔
297
            {
30✔
298
            }
30✔
299

300
            bool operator()()
30✔
301
            {
302
                // set callback functions to executed wait future is ready
303
                set_on_completed_callback(*this);
30✔
304

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

315
                // at least N futures should be ready
316
                HPX_ASSERT(
30✔
317
                    count_.load(std::memory_order_acquire) >= needed_count_);
318

319
                return has_exceptional_results_;
30✔
320
            }
321

322
            argument_type const& values_;
323
            std::atomic<std::size_t> count_;
324
            std::size_t const needed_count_;
325
            bool goal_reached_on_calling_thread_ = false;
30✔
326
            bool has_exceptional_results_ = false;
30✔
327
        };
328

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

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

348
            if (n == 0)
6✔
349
            {
350
                return false;
×
351
            }
352

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

360
            auto lazy_values = traits::acquire_shared_state_disp()(values);
6✔
361
            auto f = detail::get_wait_some_frame(lazy_values, n);
6✔
362

363
            return (*f)();
6✔
364
        }
6✔
365

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

374
        template <typename Future>
375
        friend HPX_FORCEINLINE bool tag_invoke(
376
            wait_some_nothrow_t, std::size_t n, std::vector<Future>&& values)
377
        {
378
            return tag_invoke(wait_some_nothrow_t{}, n,
379
                const_cast<std::vector<Future> const&>(values));
380
        }
381

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

389
            if (n == 0)
6✔
390
            {
391
                return false;
×
392
            }
393

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

401
            auto lazy_values = traits::acquire_shared_state_disp()(values);
6✔
402
            auto f = detail::get_wait_some_frame(lazy_values, n);
6✔
403

404
            return (*f)();
6✔
405
        }
6✔
406

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

415
        template <typename Future, std::size_t N>
416
        friend HPX_FORCEINLINE bool tag_invoke(wait_some_nothrow_t,
417
            std::size_t n, std::array<Future, N>&& lazy_values)
418
        {
419
            return tag_invoke(wait_some_nothrow_t{}, n,
420
                const_cast<std::array<Future, N> const&>(lazy_values));
421
        }
422

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

432
            return (*f)();
433
        }
434

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

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

457
            f.wait();
458
            return f.has_exception();
459
        }
460

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

472
            f.wait();
473
            return f.has_exception();
474
        }
475

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

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

492
            using result_type =
493
                hpx::tuple<traits::detail::shared_state_ptr_for_t<Ts>...>;
494

495
            result_type values(traits::detail::get_shared_state(ts)...);
6✔
496
            auto f = detail::get_wait_some_frame(values, n);
6✔
497

498
            return (*f)();
6✔
499
        }
6✔
500
    } wait_some_nothrow{};
501

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

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

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

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

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

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

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

580
            if ((*f)())
581
            {
582
                hpx::detail::throw_if_exceptional(values);
583
            }
584
        }
585

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

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

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

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

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

639
            return (*f)();
8✔
640
        }
8✔
641
    } wait_some_n_nothrow{};
642

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

658
            if ((*f)())
4✔
659
            {
660
                hpx::detail::throw_if_exceptional(values);
4✔
661
            }
×
662
        }
4✔
663
    } wait_some_n{};
664
}    // namespace hpx
665

666
namespace hpx::lcos {
667

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

677
    template <typename Future>
678
    HPX_DEPRECATED_V(
679
        1, 8, "hpx::lcos::wait_some is deprecated. Use hpx::wait_some instead.")
680
    void wait_some(
681
        std::size_t n, std::vector<Future>& lazy_values, error_code& = throws)
682
    {
683
        hpx::wait_some(n, const_cast<std::vector<Future> const&>(lazy_values));
684
    }
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(
690
        std::size_t n, std::vector<Future>&& lazy_values, error_code& = throws)
691
    {
692
        hpx::wait_some(n, const_cast<std::vector<Future> const&>(lazy_values));
693
    }
694

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

704
    template <typename Future, std::size_t N>
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::array<Future, N>& lazy_values, error_code& = throws)
709
    {
710
        hpx::wait_some(
711
            n, const_cast<std::array<Future, N> const&>(lazy_values));
712
    }
713

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

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

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

746
    HPX_DEPRECATED_V(
747
        1, 8, "hpx::lcos::wait_some is deprecated. Use hpx::wait_some instead.")
748
    inline void wait_some(std::size_t n, error_code& = throws)
749
    {
750
        hpx::wait_some(n);
751
    }
752

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

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

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

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

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