2 * Copyright 2014 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 #include "detail/State.h"
20 #include <folly/LifoSem.h>
22 namespace folly { namespace wangle {
26 static const bool value = false;
30 struct isFuture<Future<T> > {
31 static const bool value = true;
35 Future<T>::Future(Future<T>&& other) noexcept : state_(nullptr) {
36 *this = std::move(other);
40 Future<T>& Future<T>::operator=(Future<T>&& other) {
41 std::swap(state_, other.state_);
46 Future<T>::~Future() {
51 void Future<T>::detach() {
53 state_->detachFuture();
59 void Future<T>::throwIfInvalid() const {
66 void Future<T>::setCallback_(F&& func) {
68 state_->setCallback(std::move(func));
73 typename std::enable_if<
74 !isFuture<typename std::result_of<F(Try<T>&&)>::type>::value,
75 Future<typename std::result_of<F(Try<T>&&)>::type> >::type
76 Future<T>::then(F&& func) {
77 typedef typename std::result_of<F(Try<T>&&)>::type B;
81 // wrap these so we can move them into the lambda
82 folly::MoveWrapper<Promise<B>> p;
83 folly::MoveWrapper<F> funcm(std::forward<F>(func));
85 // grab the Future now before we lose our handle on the Promise
86 auto f = p->getFuture();
88 /* This is a bit tricky.
90 We can't just close over *this in case this Future gets moved. So we
91 make a new dummy Future. We could figure out something more
92 sophisticated that avoids making a new Future object when it can, as an
93 optimization. But this is correct.
95 state_ can't be moved, it is explicitly disallowed (as is copying). But
96 if there's ever a reason to allow it, this is one place that makes that
97 assumption and would need to be fixed. We use a standard shared pointer
98 for state_ (by copying it in), which means in essence obj holds a shared
99 pointer to itself. But this shouldn't leak because Promise will not
100 outlive the continuation, because Promise will setException() with a
101 broken Promise if it is destructed before completed. We could use a
102 weak pointer but it would have to be converted to a shared pointer when
103 func is executed (because the Future returned by func may possibly
104 persist beyond the callback, if it gets moved), and so it is an
105 optimization to just make it shared from the get-go.
107 We have to move in the Promise and func using the MoveWrapper
108 hack. (func could be copied but it's a big drag on perf).
110 Two subtle but important points about this design. detail::State has no
111 back pointers to Future or Promise, so if Future or Promise get moved
112 (and they will be moved in performant code) we don't have to do
113 anything fancy. And because we store the continuation in the
114 detail::State, not in the Future, we can execute the continuation even
115 after the Future has gone out of scope. This is an intentional design
116 decision. It is likely we will want to be able to cancel a continuation
117 in some circumstances, but I think it should be explicit not implicit
118 in the destruction of the Future used to create it.
121 [p, funcm](Try<T>&& t) mutable {
123 return (*funcm)(std::move(t));
132 typename std::enable_if<
133 isFuture<typename std::result_of<F(Try<T>&&)>::type>::value,
134 Future<typename std::result_of<F(Try<T>&&)>::type::value_type> >::type
135 Future<T>::then(F&& func) {
136 typedef typename std::result_of<F(Try<T>&&)>::type::value_type B;
140 // wrap these so we can move them into the lambda
141 folly::MoveWrapper<Promise<B>> p;
142 folly::MoveWrapper<F> funcm(std::forward<F>(func));
144 // grab the Future now before we lose our handle on the Promise
145 auto f = p->getFuture();
148 [p, funcm](Try<T>&& t) mutable {
150 auto f2 = (*funcm)(std::move(t));
151 // that didn't throw, now we can steal p
152 f2.setCallback_([p](Try<B>&& b) mutable {
153 p->fulfilTry(std::move(b));
156 p->setException(std::current_exception());
164 Future<void> Future<T>::then() {
165 return then([] (Try<T>&& t) {});
169 typename std::add_lvalue_reference<T>::type Future<T>::value() {
172 return state_->value();
176 typename std::add_lvalue_reference<const T>::type Future<T>::value() const {
179 return state_->value();
183 Try<T>& Future<T>::getTry() {
186 return state_->getTry();
190 template <typename Executor>
191 inline Future<T> Future<T>::via(Executor* executor) {
193 auto f = then([=](Try<T>&& t) {
194 MoveWrapper<Promise<T>> promise;
195 MoveWrapper<Try<T>> tw(std::move(t));
196 auto f2 = promise->getFuture();
197 executor->add([=]() mutable { promise->fulfilTry(std::move(*tw)); });
205 bool Future<T>::isReady() const {
207 return state_->ready();
213 Future<typename std::decay<T>::type> makeFuture(T&& t) {
214 Promise<typename std::decay<T>::type> p;
215 auto f = p.getFuture();
216 p.setValue(std::forward<T>(t));
220 inline // for multiple translation units
221 Future<void> makeFuture() {
223 auto f = p.getFuture();
231 typename std::enable_if<!std::is_reference<F>::value, bool>::type sdf)
232 -> Future<decltype(func())> {
233 Promise<decltype(func())> p;
234 auto f = p.getFuture();
243 auto makeFutureTry(F const& func) -> Future<decltype(func())> {
245 return makeFutureTry(std::move(copy));
249 Future<T> makeFuture(std::exception_ptr const& e) {
251 auto f = p.getFuture();
256 template <class T, class E>
257 typename std::enable_if<std::is_base_of<std::exception, E>::value, Future<T>>::type
258 makeFuture(E const& e) {
260 auto f = p.getFuture();
261 p.fulfil([&]() -> T { throw e; });
266 Future<T> makeFuture(Try<T>&& t) {
268 return makeFuture<T>(std::move(t.value()));
270 return makeFuture<T>(std::current_exception());
275 inline Future<void> makeFuture(Try<void>&& t) {
280 return makeFuture<void>(std::current_exception());
286 template <typename... Fs>
287 typename detail::VariadicContext<
288 typename std::decay<Fs>::type::value_type...>::type
292 new detail::VariadicContext<typename std::decay<Fs>::type::value_type...>();
293 ctx->total = sizeof...(fs);
294 auto f_saved = ctx->p.getFuture();
295 detail::whenAllVariadicHelper(ctx,
296 std::forward<typename std::decay<Fs>::type>(fs)...);
297 return std::move(f_saved);
302 template <class InputIterator>
305 Try<typename std::iterator_traits<InputIterator>::value_type::value_type>>>
306 whenAll(InputIterator first, InputIterator last)
309 typename std::iterator_traits<InputIterator>::value_type::value_type T;
311 auto n = std::distance(first, last);
313 return makeFuture(std::vector<Try<T>>());
316 auto ctx = new detail::WhenAllContext<T>();
319 ctx->results.resize(ctx->total);
321 auto f_saved = ctx->p.getFuture();
323 for (size_t i = 0; first != last; ++first, ++i) {
325 f.setCallback_([ctx, i](Try<T>&& t) {
326 ctx->results[i] = std::move(t);
327 if (++ctx->count == ctx->total) {
328 ctx->p.setValue(std::move(ctx->results));
334 return std::move(f_saved);
337 template <class InputIterator>
342 std::iterator_traits<InputIterator>::value_type::value_type> > >
343 whenAny(InputIterator first, InputIterator last) {
345 typename std::iterator_traits<InputIterator>::value_type::value_type T;
347 auto ctx = new detail::WhenAnyContext<T>(std::distance(first, last));
348 auto f_saved = ctx->p.getFuture();
350 for (size_t i = 0; first != last; first++, i++) {
352 f.setCallback_([i, ctx](Try<T>&& t) {
353 if (!ctx->done.exchange(true)) {
354 ctx->p.setValue(std::make_pair(i, std::move(t)));
360 return std::move(f_saved);
363 template <class InputIterator>
364 Future<std::vector<std::pair<size_t, Try<typename
365 std::iterator_traits<InputIterator>::value_type::value_type>>>>
366 whenN(InputIterator first, InputIterator last, size_t n) {
368 std::iterator_traits<InputIterator>::value_type::value_type T;
369 typedef std::vector<std::pair<size_t, Try<T>>> V;
376 auto ctx = std::make_shared<ctx_t>();
379 // for each completed Future, increase count and add to vector, until we
380 // have n completed futures at which point we fulfil our Promise with the
385 it->then([ctx, n, i](Try<T>&& t) {
387 auto c = ++ctx->completed;
389 assert(ctx->v.size() < n);
390 v.push_back(std::make_pair(i, std::move(t)));
392 ctx->p.fulfilTry(Try<V>(std::move(v)));
402 ctx->p.setException(std::runtime_error("Not enough futures"));
405 return ctx->p.getFuture();
408 template <typename T>
410 waitWithSemaphore(Future<T>&& f) {
412 auto done = f.then([&](Try<T> &&t) {
414 return std::move(t.value());
421 inline Future<void> waitWithSemaphore<void>(Future<void>&& f) {
423 auto done = f.then([&](Try<void> &&t) {
431 template <typename T, class Duration>
433 waitWithSemaphore(Future<T>&& f, Duration timeout) {
434 auto sem = std::make_shared<LifoSem>();
435 auto done = f.then([sem](Try<T> &&t) {
437 return std::move(t.value());
439 std::thread t([sem, timeout](){
440 std::this_thread::sleep_for(timeout);
446 } catch (ShutdownSemError & ign) { }
450 template <class Duration>
452 waitWithSemaphore(Future<void>&& f, Duration timeout) {
453 auto sem = std::make_shared<LifoSem>();
454 auto done = f.then([sem](Try<void> &&t) {
458 std::thread t([sem, timeout](){
459 std::this_thread::sleep_for(timeout);
465 } catch (ShutdownSemError & ign) { }
471 // I haven't included a Future<T&> specialization because I don't forsee us
472 // using it, however it is not difficult to add when needed. Refer to
473 // Future<void> for guidance. std::future and boost::future code would also be