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.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
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
19 * Copyright (C) 2015 Cloudius Systems, Ltd.
24 #include <seastar/core/future.hh>
36 template <typename HeldState, typename Future>
37 class do_with_state final : public continuation_base_from_future<Future>::type {
39 typename Future::promise_type _pr;
41 template<typename... T>
42 explicit do_with_state(T&&... args) : _held(std::forward<T>(args)...) {}
43 virtual void run_and_dispose() noexcept override {
44 _pr.set_urgent_state(std::move(this->_state));
47 task* waiting_task() noexcept override {
48 return _pr.waiting_task();
54 return _pr.get_future();
62 template <typename Tuple, size_t... Idx>
65 cherry_pick_tuple(std::index_sequence<Idx...>, Tuple&& tuple) {
66 return std::forward_as_tuple(std::get<Idx>(std::forward<Tuple>(tuple))...);
69 template <typename Tuple, typename Seq>
72 template <typename Tuple, size_t... Idx>
73 struct subtuple<Tuple, std::index_sequence<Idx...>> {
74 using type = std::tuple<std::decay_t<std::tuple_element_t<Idx, Tuple>>...>;
77 template <typename T1, typename T2, typename... More>
80 do_with_impl(T1&& rv1, T2&& rv2, More&&... more) {
81 auto all = std::forward_as_tuple(
82 std::forward<T1>(rv1),
83 std::forward<T2>(rv2),
84 std::forward<More>(more)...);
85 constexpr size_t nr = std::tuple_size<decltype(all)>::value - 1;
86 using idx = std::make_index_sequence<nr>;
87 auto&& just_values = cherry_pick_tuple(idx(), std::move(all));
88 auto&& just_func = std::move(std::get<nr>(std::move(all)));
89 using value_tuple = typename subtuple<decltype(all), idx>::type;
90 using ret_type = decltype(std::apply(just_func, std::declval<value_tuple&>()));
91 auto task = std::apply(
93 return std::make_unique<internal::do_with_state<value_tuple, ret_type>>(std::forward<decltype(x)>(x)...);
95 std::move(just_values));
96 auto fut = std::apply(just_func, task->data());
97 if (fut.available()) {
100 auto ret = task->get_future();
101 internal::set_callback(fut, task.release());
106 /// \addtogroup future-util
109 /// do_with() holds a objects alive until a future completes, and
110 /// allow the code involved in making the future complete to have easy
111 /// access to this object.
113 /// do_with() takes multiple arguments: The last is a function
114 /// returning a future. The other are temporary objects (rvalue). The
115 /// function is given (a moved copy of) these temporary object, by
116 /// reference, and it is ensured that the objects will not be
117 /// destructed until the completion of the future returned by the
120 /// do_with() returns a future which resolves to whatever value the given future
121 /// (returned by the given function) resolves to. This returned value must not
122 /// contain references to the temporary object, as at that point the temporary
125 /// \return whatever the function returns
126 template <typename T1, typename T2, typename... More>
129 do_with(T1&& rv1, T2&& rv2, More&&... more) noexcept {
130 auto func = internal::do_with_impl<T1, T2, More...>;
131 return futurize_invoke(func, std::forward<T1>(rv1), std::forward<T2>(rv2), std::forward<More>(more)...);
134 /// Executes the function \c func making sure the lock \c lock is taken,
135 /// and later on properly released.
137 /// \param lock the lock, which is any object having providing a lock() / unlock() semantics.
138 /// Caller must make sure that it outlives \c func.
139 /// \param func function to be executed
140 /// \returns whatever \c func returns
141 template<typename Lock, typename Func>
143 auto with_lock(Lock& lock, Func&& func) {
144 return lock.lock().then([&lock, func = std::forward<Func>(func)] () mutable {
145 return futurize_invoke(func).finally([&lock] {