2 * Copyright 2017 Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 // included by Future.h, do not include directly.
23 template <class> class Promise;
29 struct isSemiFuture : std::false_type {
30 using Inner = typename Unit::Lift<T>::type;
34 struct isSemiFuture<SemiFuture<T>> : std::true_type {
39 struct isSemiFuture<Future<T>> : std::true_type {
44 struct isFuture : std::false_type {
45 using Inner = typename Unit::Lift<T>::type;
49 struct isFuture<Future<T>> : std::true_type {
54 struct isTry : std::false_type {};
57 struct isTry<Try<T>> : std::true_type {};
62 template <class> class Core;
63 template <class...> struct CollectAllVariadicContext;
64 template <class...> struct CollectVariadicContext;
65 template <class> struct CollectContext;
67 template <typename F, typename... Args>
68 using resultOf = decltype(std::declval<F>()(std::declval<Args>()...));
70 template <typename...>
73 template <typename Arg, typename... Args>
74 struct ArgType<Arg, Args...> {
80 typedef void FirstArg;
83 template <bool isTry, typename F, typename... Args>
85 using Result = resultOf<F, Args...>;
88 template <typename F, typename... Args>
90 template <typename T, typename = detail::resultOf<T, Args...>>
91 static constexpr std::true_type
92 check(std::nullptr_t) { return std::true_type{}; }
95 static constexpr std::false_type
96 check(...) { return std::false_type{}; }
98 typedef decltype(check<F>(nullptr)) type;
99 static constexpr bool value = type::value;
102 template <typename T, typename F>
103 struct callableResult {
104 typedef typename std::conditional<
105 callableWith<F>::value,
106 detail::argResult<false, F>,
107 typename std::conditional<
108 callableWith<F, T&&>::value,
109 detail::argResult<false, F, T&&>,
110 typename std::conditional<
111 callableWith<F, T&>::value,
112 detail::argResult<false, F, T&>,
113 typename std::conditional<
114 callableWith<F, Try<T>&&>::value,
115 detail::argResult<true, F, Try<T>&&>,
116 detail::argResult<true, F, Try<T>&>>::type>::type>::type>::type Arg;
117 typedef isFuture<typename Arg::Result> ReturnsFuture;
118 typedef Future<typename ReturnsFuture::Inner> Return;
121 template <typename L>
122 struct Extract : Extract<decltype(&L::operator())> { };
124 template <typename Class, typename R, typename... Args>
125 struct Extract<R(Class::*)(Args...) const> {
126 typedef isFuture<R> ReturnsFuture;
127 typedef Future<typename ReturnsFuture::Inner> Return;
128 typedef typename ReturnsFuture::Inner RawReturn;
129 typedef typename ArgType<Args...>::FirstArg FirstArg;
132 template <typename Class, typename R, typename... Args>
133 struct Extract<R(Class::*)(Args...)> {
134 typedef isFuture<R> ReturnsFuture;
135 typedef Future<typename ReturnsFuture::Inner> Return;
136 typedef typename ReturnsFuture::Inner RawReturn;
137 typedef typename ArgType<Args...>::FirstArg FirstArg;
140 template <typename R, typename... Args>
141 struct Extract<R (*)(Args...)> {
142 typedef isFuture<R> ReturnsFuture;
143 typedef Future<typename ReturnsFuture::Inner> Return;
144 typedef typename ReturnsFuture::Inner RawReturn;
145 typedef typename ArgType<Args...>::FirstArg FirstArg;
148 template <typename R, typename... Args>
149 struct Extract<R (&)(Args...)> {
150 typedef isFuture<R> ReturnsFuture;
151 typedef Future<typename ReturnsFuture::Inner> Return;
152 typedef typename ReturnsFuture::Inner RawReturn;
153 typedef typename ArgType<Args...>::FirstArg FirstArg;
157 * Defer work until executor is actively boosted.
159 * NOTE: that this executor is a private implementation detail belonging to the
160 * Folly Futures library and not intended to be used elsewhere. It is designed
161 * specifically for the use case of deferring work on a SemiFuture. It is NOT
162 * thread safe. Please do not use for any other purpose without great care.
164 class DeferredExecutor final : public Executor {
166 template <typename Class, typename F>
167 struct DeferredWorkWrapper;
170 * Work wrapper class to capture the keepalive and forward the argument
171 * list to the captured function.
173 template <typename F, typename R, typename... Args>
174 struct DeferredWorkWrapper<F, R (F::*)(Args...) const> {
175 R operator()(Args... args) {
176 return func(std::forward<Args>(args)...);
179 Executor::KeepAlive a;
184 * Construction is private to ensure that creation and deletion are
187 static KeepAlive create() {
188 std::unique_ptr<futures::detail::DeferredExecutor> devb{
189 new futures::detail::DeferredExecutor{}};
190 auto keepAlive = devb->getKeepAliveToken();
195 /// Enqueue a function to executed by this executor. This is not thread-safe.
196 void add(Func func) override {
197 // If we already have a function, wrap and chain. Otherwise assign.
199 func_ = [oldFunc = std::move(func_), func = std::move(func)]() mutable {
204 func_ = std::move(func);
208 // Boost is like drive for certain types of deferred work
209 // Unlike drive it is safe to run on another executor because it
210 // will only be implemented on deferred-safe executors
212 // Ensure that the DeferredExecutor outlives its run operation
218 // Drain the executor
219 while (auto func = std::move(func_)) {
224 KeepAlive getKeepAliveToken() override {
226 return makeKeepAlive();
229 ~DeferredExecutor() = default;
232 static auto wrap(Executor::KeepAlive keepAlive, F&& func)
233 -> DeferredWorkWrapper<F, decltype(&F::operator())> {
234 return DeferredExecutor::DeferredWorkWrapper<F, decltype(&F::operator())>{
235 std::move(keepAlive), std::forward<F>(func)};
239 void keepAliveAcquire() override {
243 void keepAliveRelease() override {
247 void releaseAndTryFree() {
249 if (keepAliveCount_ == 0) {
256 ssize_t keepAliveCount_{0};
258 DeferredExecutor() = default;
261 } // namespace detail
262 } // namespace futures