]> git.proxmox.com Git - ceph.git/blob - ceph/src/seastar/include/seastar/core/when_any.hh
import quincy beta 17.1.0
[ceph.git] / ceph / src / seastar / include / seastar / core / when_any.hh
1 /*
2 * This file is open source software, licensed to you under the terms
3 * of the Apache License, Version 2.0 (the "License"). See the NOTICE file
4 * distributed with this work for additional information regarding copyright
5 * ownership. You may not use this file except in compliance with the License.
6 *
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing,
12 * software distributed under the License is distributed on an
13 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 * KIND, either express or implied. See the License for the
15 * specific language governing permissions and limitations
16 * under the License.
17 */
18
19 /*
20 * author: Niek J Bouman
21 * reviewer: Avi Kivity
22 * November 2021
23 */
24
25 #pragma once
26
27 #include <iterator>
28 #include <cstddef>
29 #include <type_traits>
30 #include <vector>
31 #include <seastar/core/future.hh>
32 #include <seastar/core/shared_ptr.hh>
33
34 namespace seastar {
35
36 template <class Sequence>
37 struct when_any_result {
38 std::size_t index;
39 Sequence futures;
40 };
41
42 namespace internal {
43 class waiter {
44 bool _done = false;
45 promise<std::size_t> _promise;
46
47 public:
48 void done(std::size_t index) {
49 if (!_done) {
50 _done = true;
51 _promise.set_value(index);
52 }
53 }
54 auto get_future() { return _promise.get_future(); }
55 };
56
57 } // namespace internal
58
59 /// Wait for the first of multiple futures to complete (iterator version).
60 ///
61 /// Given a range of futures as input, wait for the first of them
62 /// to resolve (either successfully or with an exception), and return
63 /// all of them in a \c when_any_result (following the concurrency TS from
64 /// the standard library), containing a std::vector to all futures
65 /// and the index (into the vector) of the future that resolved.
66 ///
67 /// \param begin an \c InputIterator designating the beginning of the range of futures
68 /// \param end an \c InputIterator designating the end of the range of futures
69 /// \return a \c when_any_result of all the futures in the input; when
70 /// ready, at least one of the contained futures (the one indicated by index) will be ready.
71 template <class FutureIterator>
72 SEASTAR_CONCEPT( requires requires (FutureIterator i) { { *i++ }; requires is_future<std::remove_reference_t<decltype(*i)>>::value; } )
73 auto when_any(FutureIterator begin, FutureIterator end) noexcept
74 -> future<when_any_result<std::vector<std::decay_t<typename std::iterator_traits<FutureIterator>::value_type>>>>
75 {
76 using ReturnType = when_any_result<std::vector<typename std::iterator_traits<FutureIterator>::value_type>>;
77 if (begin == end) {
78 return make_ready_future<ReturnType>();
79 }
80 ReturnType result;
81 result.futures.reserve(std::distance(begin, end));
82 auto waiter_obj = make_lw_shared<internal::waiter>();
83 std::size_t index{0};
84 for (auto it = begin; it != end; ++it) {
85 if (it->available()) {
86 result.futures.push_back(std::move(*it));
87 waiter_obj->done(index);
88 } else {
89 result.futures.push_back(it->finally([waiter_obj, index] {
90 waiter_obj->done(index);
91 }));
92 }
93 index++;
94 }
95 return waiter_obj->get_future().then(
96 [result = std::move(result)](std::size_t index) mutable {
97 result.index = index;
98 return std::move(result);
99 }
100 );
101 }
102 } // namespace seastar