Seastar
High performance C++ framework for concurrent servers
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 * reviewers: Avi Kivity, Benny Halevy
22 * November 2021
23 */
24
25#pragma once
26
27#ifndef SEASTAR_MODULE
28#include <iterator>
29#include <cstddef>
30#include <type_traits>
31#include <vector>
32#include <tuple>
33#include <utility>
34#include <seastar/core/future.hh>
35#include <seastar/core/shared_ptr.hh>
36#include <seastar/util/modules.hh>
37#endif
38
39namespace seastar {
40
41template <class Sequence>
43 std::size_t index;
44 Sequence futures;
45};
46
47namespace internal {
48class waiter {
49 bool _done = false;
50 promise<std::size_t> _promise;
51
52public:
53 void done(std::size_t index) {
54 if (!_done) {
55 _done = true;
56 _promise.set_value(index);
57 }
58 }
59 auto get_future() { return _promise.get_future(); }
60};
61
62} // namespace internal
63
76SEASTAR_MODULE_EXPORT
77template <class FutureIterator>
78requires requires (FutureIterator i) { { *i++ }; requires is_future<std::remove_reference_t<decltype(*i)>>::value; }
79auto when_any(FutureIterator begin, FutureIterator end) noexcept
81{
83 if (begin == end) {
84 return make_ready_future<ReturnType>();
85 }
86 ReturnType result;
87 result.futures.reserve(std::distance(begin, end));
88 auto waiter_obj = make_lw_shared<internal::waiter>();
89 std::size_t index{0};
90 for (auto it = begin; it != end; ++it) {
91 if (it->available()) {
92 result.futures.push_back(std::move(*it));
93 waiter_obj->done(index);
94 } else {
95 result.futures.push_back(it->finally([waiter_obj, index] {
96 waiter_obj->done(index);
97 }));
98 }
99 index++;
100 }
101 return waiter_obj->get_future().then(
102 [result = std::move(result)](std::size_t index) mutable {
103 result.index = index;
104 return std::move(result);
105 }
106 );
107}
108
109namespace internal {
110
111template <class... Futures, std::size_t... I>
112future<when_any_result<std::tuple<Futures...>>>
113when_any_impl(std::index_sequence<I...>, Futures&&... futs) noexcept
114{
115 auto waiter_obj = make_lw_shared<waiter>();
116 auto attach_notifier = [&](auto&& fut, size_t index) {
117 if (fut.available()) {
118 waiter_obj->done(index);
119 return std::move(fut);
120 }
121 else {
122 return fut.finally([waiter_obj, index] { waiter_obj->done(index); });
123 }
124 };
125
126 auto result =
127 when_any_result<std::tuple<Futures...>>{0, std::make_tuple(attach_notifier(std::forward<Futures>(futs), I)...)};
128 return waiter_obj->get_future().then([result = std::move(result)](std::size_t index) mutable {
129 result.index = index;
130 return std::move(result);
131 });
132}
133
134} // namespace internal
135
149SEASTAR_MODULE_EXPORT
150template <class... FutOrFuncs>
151auto when_any(FutOrFuncs&&... fut_or_funcs) noexcept
152{
153 return internal::when_any_impl(std::make_index_sequence<sizeof...(FutOrFuncs)>{},
154 futurize_invoke_if_func(std::forward<FutOrFuncs>(fut_or_funcs))...);
155}
156
157} // namespace seastar
A representation of a possibly not-yet-computed value.
Definition: future.hh:1240
promise - allows a future value to be made available at a later time.
Definition: future.hh:934
void set_value(A &&... a) noexcept
Sets the promises value.
Definition: future.hh:990
future< T > get_future() noexcept
Gets the promise's associated future.
Definition: future.hh:1926
Seastar API namespace.
Definition: abort_on_ebadf.hh:26
auto when_any(FutureIterator begin, FutureIterator end) noexcept -> future< when_any_result< std::vector< std::decay_t< typename std::iterator_traits< FutureIterator >::value_type > > > >
Definition: when_any.hh:79
Definition: when_any.hh:42