]> git.proxmox.com Git - ceph.git/blob - ceph/src/seastar/include/seastar/core/do_with.hh
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / seastar / include / seastar / core / do_with.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 * Copyright (C) 2015 Cloudius Systems, Ltd.
20 */
21
22 #pragma once
23
24 #include <seastar/core/future.hh>
25 #include <utility>
26 #include <memory>
27 #include <tuple>
28
29 namespace seastar {
30
31
32 /// \cond internal
33
34 namespace internal {
35
36 template <typename HeldState, typename Future>
37 class do_with_state final : public continuation_base_from_future<Future>::type {
38 HeldState _held;
39 typename Future::promise_type _pr;
40 public:
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));
45 delete this;
46 }
47 task* waiting_task() noexcept override {
48 return _pr.waiting_task();
49 }
50 HeldState& data() {
51 return _held;
52 }
53 Future get_future() {
54 return _pr.get_future();
55 }
56 };
57
58 }
59 /// \endcond
60
61 namespace internal {
62 template <typename Tuple, size_t... Idx>
63 inline
64 auto
65 cherry_pick_tuple(std::index_sequence<Idx...>, Tuple&& tuple) {
66 return std::forward_as_tuple(std::get<Idx>(std::forward<Tuple>(tuple))...);
67 }
68
69 template <typename Tuple, typename Seq>
70 struct subtuple;
71
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>>...>;
75 };
76
77 template <typename T1, typename T2, typename... More>
78 inline
79 auto
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(
92 [](auto&&... x) {
93 return std::make_unique<internal::do_with_state<value_tuple, ret_type>>(std::forward<decltype(x)>(x)...);
94 },
95 std::move(just_values));
96 auto fut = std::apply(just_func, task->data());
97 if (fut.available()) {
98 return fut;
99 }
100 auto ret = task->get_future();
101 internal::set_callback(fut, task.release());
102 return ret;
103 }
104 }
105
106 /// \addtogroup future-util
107 /// @{
108
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.
112 ///
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
118 /// function.
119 ///
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
123 /// is destructed.
124 ///
125 /// \return whatever the function returns
126 template <typename T1, typename T2, typename... More>
127 inline
128 auto
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)...);
132 }
133
134 /// Executes the function \c func making sure the lock \c lock is taken,
135 /// and later on properly released.
136 ///
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>
142 inline
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] {
146 lock.unlock();
147 });
148 });
149 }
150
151 /// @}
152
153 }