2 * Copyright 2015 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.
22 #include <folly/experimental/fibers/Baton.h>
23 #include <folly/Optional.h>
24 #include <folly/futures/detail/Core.h>
25 #include <folly/futures/Timekeeper.h>
32 Timekeeper* getTimekeeperSingleton();
36 Future<T>::Future(Future<T>&& other) noexcept : core_(other.core_) {
37 other.core_ = nullptr;
41 Future<T>& Future<T>::operator=(Future<T>&& other) noexcept {
42 std::swap(core_, other.core_);
47 template <class T2, typename>
48 Future<T>::Future(T2&& val)
49 : core_(new detail::Core<T>(Try<T>(std::forward<T2>(val)))) {}
52 template <typename, typename>
54 : core_(new detail::Core<T>(Try<T>(T()))) {}
57 Future<T>::~Future() {
62 void Future<T>::detach() {
64 core_->detachFuture();
70 void Future<T>::throwIfInvalid() const {
77 void Future<T>::setCallback_(F&& func) {
79 core_->setCallback(std::move(func));
86 typename std::enable_if<isFuture<F>::value,
87 Future<typename isFuture<T>::Inner>>::type
89 return then([](Future<typename isFuture<T>::Inner> internal_future) {
90 return internal_future;
96 // Variant: returns a value
97 // e.g. f.then([](Try<T>&& t){ return t.value(); });
99 template <typename F, typename R, bool isTry, typename... Args>
100 typename std::enable_if<!R::ReturnsFuture::value, typename R::Return>::type
101 Future<T>::thenImplementation(F func, detail::argResult<isTry, F, Args...>) {
102 static_assert(sizeof...(Args) <= 1, "Then must take zero/one argument");
103 typedef typename R::ReturnsFuture::Inner B;
107 // wrap these so we can move them into the lambda
108 folly::MoveWrapper<Promise<B>> p;
109 p->core_->setInterruptHandlerNoLock(core_->getInterruptHandler());
110 folly::MoveWrapper<F> funcm(std::forward<F>(func));
112 // grab the Future now before we lose our handle on the Promise
113 auto f = p->getFuture();
114 f.core_->setExecutorNoLock(getExecutor());
116 /* This is a bit tricky.
118 We can't just close over *this in case this Future gets moved. So we
119 make a new dummy Future. We could figure out something more
120 sophisticated that avoids making a new Future object when it can, as an
121 optimization. But this is correct.
123 core_ can't be moved, it is explicitly disallowed (as is copying). But
124 if there's ever a reason to allow it, this is one place that makes that
125 assumption and would need to be fixed. We use a standard shared pointer
126 for core_ (by copying it in), which means in essence obj holds a shared
127 pointer to itself. But this shouldn't leak because Promise will not
128 outlive the continuation, because Promise will setException() with a
129 broken Promise if it is destructed before completed. We could use a
130 weak pointer but it would have to be converted to a shared pointer when
131 func is executed (because the Future returned by func may possibly
132 persist beyond the callback, if it gets moved), and so it is an
133 optimization to just make it shared from the get-go.
135 We have to move in the Promise and func using the MoveWrapper
136 hack. (func could be copied but it's a big drag on perf).
138 Two subtle but important points about this design. detail::Core has no
139 back pointers to Future or Promise, so if Future or Promise get moved
140 (and they will be moved in performant code) we don't have to do
141 anything fancy. And because we store the continuation in the
142 detail::Core, not in the Future, we can execute the continuation even
143 after the Future has gone out of scope. This is an intentional design
144 decision. It is likely we will want to be able to cancel a continuation
145 in some circumstances, but I think it should be explicit not implicit
146 in the destruction of the Future used to create it.
149 [p, funcm](Try<T>&& t) mutable {
150 if (!isTry && t.hasException()) {
151 p->setException(std::move(t.exception()));
154 return (*funcm)(t.template get<isTry, Args>()...);
162 // Variant: returns a Future
163 // e.g. f.then([](T&& t){ return makeFuture<T>(t); });
165 template <typename F, typename R, bool isTry, typename... Args>
166 typename std::enable_if<R::ReturnsFuture::value, typename R::Return>::type
167 Future<T>::thenImplementation(F func, detail::argResult<isTry, F, Args...>) {
168 static_assert(sizeof...(Args) <= 1, "Then must take zero/one argument");
169 typedef typename R::ReturnsFuture::Inner B;
173 // wrap these so we can move them into the lambda
174 folly::MoveWrapper<Promise<B>> p;
175 p->core_->setInterruptHandlerNoLock(core_->getInterruptHandler());
176 folly::MoveWrapper<F> funcm(std::forward<F>(func));
178 // grab the Future now before we lose our handle on the Promise
179 auto f = p->getFuture();
180 f.core_->setExecutorNoLock(getExecutor());
183 [p, funcm](Try<T>&& t) mutable {
184 if (!isTry && t.hasException()) {
185 p->setException(std::move(t.exception()));
188 auto f2 = (*funcm)(t.template get<isTry, Args>()...);
189 // that didn't throw, now we can steal p
190 f2.setCallback_([p](Try<B>&& b) mutable {
191 p->setTry(std::move(b));
193 } catch (const std::exception& e) {
194 p->setException(exception_wrapper(std::current_exception(), e));
196 p->setException(exception_wrapper(std::current_exception()));
204 template <typename T>
205 template <typename R, typename Caller, typename... Args>
206 Future<typename isFuture<R>::Inner>
207 Future<T>::then(R(Caller::*func)(Args...), Caller *instance) {
208 typedef typename std::remove_cv<
209 typename std::remove_reference<
210 typename detail::ArgType<Args...>::FirstArg>::type>::type FirstArg;
211 return then([instance, func](Try<T>&& t){
212 return (instance->*func)(t.template get<isTry<FirstArg>::value, Args>()...);
217 template <class Executor, class Arg, class... Args>
218 auto Future<T>::then(Executor* x, Arg&& arg, Args&&... args)
219 -> decltype(this->then(std::forward<Arg>(arg),
220 std::forward<Args>(args)...))
222 auto oldX = getExecutor();
224 return this->then(std::forward<Arg>(arg), std::forward<Args>(args)...).
229 Future<Unit> Future<T>::then() {
230 return then([] () {});
233 // onError where the callback returns T
236 typename std::enable_if<
237 !detail::callableWith<F, exception_wrapper>::value &&
238 !detail::Extract<F>::ReturnsFuture::value,
240 Future<T>::onError(F&& func) {
241 typedef typename detail::Extract<F>::FirstArg Exn;
243 std::is_same<typename detail::Extract<F>::RawReturn, T>::value,
244 "Return type of onError callback must be T or Future<T>");
247 auto f = p.getFuture();
248 auto pm = folly::makeMoveWrapper(std::move(p));
249 auto funcm = folly::makeMoveWrapper(std::move(func));
250 setCallback_([pm, funcm](Try<T>&& t) mutable {
251 if (!t.template withException<Exn>([&] (Exn& e) {
256 pm->setTry(std::move(t));
263 // onError where the callback returns Future<T>
266 typename std::enable_if<
267 !detail::callableWith<F, exception_wrapper>::value &&
268 detail::Extract<F>::ReturnsFuture::value,
270 Future<T>::onError(F&& func) {
272 std::is_same<typename detail::Extract<F>::Return, Future<T>>::value,
273 "Return type of onError callback must be T or Future<T>");
274 typedef typename detail::Extract<F>::FirstArg Exn;
277 auto f = p.getFuture();
278 auto pm = folly::makeMoveWrapper(std::move(p));
279 auto funcm = folly::makeMoveWrapper(std::move(func));
280 setCallback_([pm, funcm](Try<T>&& t) mutable {
281 if (!t.template withException<Exn>([&] (Exn& e) {
283 auto f2 = (*funcm)(e);
284 f2.setCallback_([pm](Try<T>&& t2) mutable {
285 pm->setTry(std::move(t2));
287 } catch (const std::exception& e2) {
288 pm->setException(exception_wrapper(std::current_exception(), e2));
290 pm->setException(exception_wrapper(std::current_exception()));
293 pm->setTry(std::move(t));
302 Future<T> Future<T>::ensure(F func) {
303 MoveWrapper<F> funcw(std::move(func));
304 return this->then([funcw](Try<T>&& t) {
306 return makeFuture(std::move(t));
312 Future<T> Future<T>::onTimeout(Duration dur, F&& func, Timekeeper* tk) {
313 auto funcw = folly::makeMoveWrapper(std::forward<F>(func));
314 return within(dur, tk)
315 .onError([funcw](TimedOut const&) { return (*funcw)(); });
320 typename std::enable_if<
321 detail::callableWith<F, exception_wrapper>::value &&
322 detail::Extract<F>::ReturnsFuture::value,
324 Future<T>::onError(F&& func) {
326 std::is_same<typename detail::Extract<F>::Return, Future<T>>::value,
327 "Return type of onError callback must be T or Future<T>");
330 auto f = p.getFuture();
331 auto pm = folly::makeMoveWrapper(std::move(p));
332 auto funcm = folly::makeMoveWrapper(std::move(func));
333 setCallback_([pm, funcm](Try<T> t) mutable {
334 if (t.hasException()) {
336 auto f2 = (*funcm)(std::move(t.exception()));
337 f2.setCallback_([pm](Try<T> t2) mutable {
338 pm->setTry(std::move(t2));
340 } catch (const std::exception& e2) {
341 pm->setException(exception_wrapper(std::current_exception(), e2));
343 pm->setException(exception_wrapper(std::current_exception()));
346 pm->setTry(std::move(t));
353 // onError(exception_wrapper) that returns T
356 typename std::enable_if<
357 detail::callableWith<F, exception_wrapper>::value &&
358 !detail::Extract<F>::ReturnsFuture::value,
360 Future<T>::onError(F&& func) {
362 std::is_same<typename detail::Extract<F>::Return, Future<T>>::value,
363 "Return type of onError callback must be T or Future<T>");
366 auto f = p.getFuture();
367 auto pm = folly::makeMoveWrapper(std::move(p));
368 auto funcm = folly::makeMoveWrapper(std::move(func));
369 setCallback_([pm, funcm](Try<T> t) mutable {
370 if (t.hasException()) {
372 return (*funcm)(std::move(t.exception()));
375 pm->setTry(std::move(t));
383 typename std::add_lvalue_reference<T>::type Future<T>::value() {
386 return core_->getTry().value();
390 typename std::add_lvalue_reference<const T>::type Future<T>::value() const {
393 return core_->getTry().value();
397 Try<T>& Future<T>::getTry() {
400 return core_->getTry();
404 Optional<Try<T>> Future<T>::poll() {
406 if (core_->ready()) {
407 o = std::move(core_->getTry());
413 inline Future<T> Future<T>::via(Executor* executor, int8_t priority) && {
416 setExecutor(executor, priority);
418 return std::move(*this);
422 inline Future<T> Future<T>::via(Executor* executor, int8_t priority) & {
425 MoveWrapper<Promise<T>> p;
426 auto f = p->getFuture();
427 then([p](Try<T>&& t) mutable { p->setTry(std::move(t)); });
428 return std::move(f).via(executor, priority);
432 template <class Func>
433 auto via(Executor* x, Func func)
434 -> Future<typename isFuture<decltype(func())>::Inner>
436 // TODO make this actually more performant. :-P #7260175
437 return via(x).then(func);
441 bool Future<T>::isReady() const {
443 return core_->ready();
447 bool Future<T>::hasValue() {
448 return getTry().hasValue();
452 bool Future<T>::hasException() {
453 return getTry().hasException();
457 void Future<T>::raise(exception_wrapper exception) {
458 core_->raise(std::move(exception));
464 Future<typename std::decay<T>::type> makeFuture(T&& t) {
465 return makeFuture(Try<typename std::decay<T>::type>(std::forward<T>(t)));
468 inline // for multiple translation units
469 Future<Unit> makeFuture() {
470 return makeFuture(Unit{});
474 auto makeFutureWith(F&& func)
475 -> Future<typename Unit::Lift<decltype(func())>::type> {
476 using LiftedResult = typename Unit::Lift<decltype(func())>::type;
477 return makeFuture<LiftedResult>(makeTryWith([&func]() mutable {
483 Future<T> makeFuture(std::exception_ptr const& e) {
484 return makeFuture(Try<T>(e));
488 Future<T> makeFuture(exception_wrapper ew) {
489 return makeFuture(Try<T>(std::move(ew)));
492 template <class T, class E>
493 typename std::enable_if<std::is_base_of<std::exception, E>::value,
495 makeFuture(E const& e) {
496 return makeFuture(Try<T>(make_exception_wrapper<E>(e)));
500 Future<T> makeFuture(Try<T>&& t) {
501 return Future<T>(new detail::Core<T>(std::move(t)));
505 Future<Unit> via(Executor* executor, int8_t priority) {
506 return makeFuture().via(executor, priority);
509 // mapSetCallback calls func(i, Try<T>) when every future completes
511 template <class T, class InputIterator, class F>
512 void mapSetCallback(InputIterator first, InputIterator last, F func) {
513 for (size_t i = 0; first != last; ++first, ++i) {
514 first->setCallback_([func, i](Try<T>&& t) {
515 func(i, std::move(t));
520 // collectAll (variadic)
522 template <typename... Fs>
523 typename detail::CollectAllVariadicContext<
524 typename std::decay<Fs>::type::value_type...>::type
525 collectAll(Fs&&... fs) {
526 auto ctx = std::make_shared<detail::CollectAllVariadicContext<
527 typename std::decay<Fs>::type::value_type...>>();
528 detail::collectVariadicHelper<detail::CollectAllVariadicContext>(
529 ctx, std::forward<typename std::decay<Fs>::type>(fs)...);
530 return ctx->p.getFuture();
533 // collectAll (iterator)
535 template <class InputIterator>
538 Try<typename std::iterator_traits<InputIterator>::value_type::value_type>>>
539 collectAll(InputIterator first, InputIterator last) {
541 typename std::iterator_traits<InputIterator>::value_type::value_type T;
543 struct CollectAllContext {
544 CollectAllContext(int n) : results(n) {}
545 ~CollectAllContext() {
546 p.setValue(std::move(results));
548 Promise<std::vector<Try<T>>> p;
549 std::vector<Try<T>> results;
552 auto ctx = std::make_shared<CollectAllContext>(std::distance(first, last));
553 mapSetCallback<T>(first, last, [ctx](size_t i, Try<T>&& t) {
554 ctx->results[i] = std::move(t);
556 return ctx->p.getFuture();
559 // collect (iterator)
563 template <typename T>
564 struct CollectContext {
565 struct Nothing { explicit Nothing(int n) {} };
567 using Result = typename std::conditional<
568 std::is_void<T>::value,
570 std::vector<T>>::type;
572 using InternalResult = typename std::conditional<
573 std::is_void<T>::value,
575 std::vector<Optional<T>>>::type;
577 explicit CollectContext(int n) : result(n) {}
579 if (!threw.exchange(true)) {
580 // map Optional<T> -> T
581 std::vector<T> finalResult;
582 finalResult.reserve(result.size());
583 std::transform(result.begin(), result.end(),
584 std::back_inserter(finalResult),
585 [](Optional<T>& o) { return std::move(o.value()); });
586 p.setValue(std::move(finalResult));
589 inline void setPartialResult(size_t i, Try<T>& t) {
590 result[i] = std::move(t.value());
593 InternalResult result;
594 std::atomic<bool> threw {false};
599 template <class InputIterator>
600 Future<typename detail::CollectContext<
601 typename std::iterator_traits<InputIterator>::value_type::value_type>::Result>
602 collect(InputIterator first, InputIterator last) {
604 typename std::iterator_traits<InputIterator>::value_type::value_type T;
606 auto ctx = std::make_shared<detail::CollectContext<T>>(
607 std::distance(first, last));
608 mapSetCallback<T>(first, last, [ctx](size_t i, Try<T>&& t) {
609 if (t.hasException()) {
610 if (!ctx->threw.exchange(true)) {
611 ctx->p.setException(std::move(t.exception()));
613 } else if (!ctx->threw) {
614 ctx->setPartialResult(i, t);
617 return ctx->p.getFuture();
620 // collect (variadic)
622 template <typename... Fs>
623 typename detail::CollectVariadicContext<
624 typename std::decay<Fs>::type::value_type...>::type
625 collect(Fs&&... fs) {
626 auto ctx = std::make_shared<detail::CollectVariadicContext<
627 typename std::decay<Fs>::type::value_type...>>();
628 detail::collectVariadicHelper<detail::CollectVariadicContext>(
629 ctx, std::forward<typename std::decay<Fs>::type>(fs)...);
630 return ctx->p.getFuture();
633 // collectAny (iterator)
635 template <class InputIterator>
640 std::iterator_traits<InputIterator>::value_type::value_type>>>
641 collectAny(InputIterator first, InputIterator last) {
643 typename std::iterator_traits<InputIterator>::value_type::value_type T;
645 struct CollectAnyContext {
646 CollectAnyContext() {};
647 Promise<std::pair<size_t, Try<T>>> p;
648 std::atomic<bool> done {false};
651 auto ctx = std::make_shared<CollectAnyContext>();
652 mapSetCallback<T>(first, last, [ctx](size_t i, Try<T>&& t) {
653 if (!ctx->done.exchange(true)) {
654 ctx->p.setValue(std::make_pair(i, std::move(t)));
657 return ctx->p.getFuture();
660 // collectN (iterator)
662 template <class InputIterator>
663 Future<std::vector<std::pair<size_t, Try<typename
664 std::iterator_traits<InputIterator>::value_type::value_type>>>>
665 collectN(InputIterator first, InputIterator last, size_t n) {
667 std::iterator_traits<InputIterator>::value_type::value_type T;
668 typedef std::vector<std::pair<size_t, Try<T>>> V;
670 struct CollectNContext {
672 std::atomic<size_t> completed = {0};
675 auto ctx = std::make_shared<CollectNContext>();
677 if (size_t(std::distance(first, last)) < n) {
678 ctx->p.setException(std::runtime_error("Not enough futures"));
680 // for each completed Future, increase count and add to vector, until we
681 // have n completed futures at which point we fulfil our Promise with the
683 mapSetCallback<T>(first, last, [ctx, n](size_t i, Try<T>&& t) {
684 auto c = ++ctx->completed;
686 assert(ctx->v.size() < n);
687 ctx->v.emplace_back(i, std::move(t));
689 ctx->p.setTry(Try<V>(std::move(ctx->v)));
695 return ctx->p.getFuture();
700 template <class It, class T, class F>
701 Future<T> reduce(It first, It last, T&& initial, F&& func) {
703 return makeFuture(std::move(initial));
706 typedef typename std::iterator_traits<It>::value_type::value_type ItT;
707 typedef typename std::conditional<
708 detail::callableWith<F, T&&, Try<ItT>&&>::value, Try<ItT>, ItT>::type Arg;
709 typedef isTry<Arg> IsTry;
711 folly::MoveWrapper<T> minitial(std::move(initial));
712 auto sfunc = std::make_shared<F>(std::move(func));
714 auto f = first->then([minitial, sfunc](Try<ItT>& head) mutable {
715 return (*sfunc)(std::move(*minitial),
716 head.template get<IsTry::value, Arg&&>());
719 for (++first; first != last; ++first) {
720 f = collectAll(f, *first).then([sfunc](std::tuple<Try<T>, Try<ItT>>& t) {
721 return (*sfunc)(std::move(std::get<0>(t).value()),
722 // Either return a ItT&& or a Try<ItT>&& depending
723 // on the type of the argument of func.
724 std::get<1>(t).template get<IsTry::value, Arg&&>());
731 // window (collection)
733 template <class Collection, class F, class ItT, class Result>
734 std::vector<Future<Result>>
735 window(Collection input, F func, size_t n) {
736 struct WindowContext {
737 WindowContext(Collection&& i, F&& fn)
738 : input_(std::move(i)), promises_(input_.size()),
741 std::atomic<size_t> i_ {0};
743 std::vector<Promise<Result>> promises_;
746 static inline void spawn(const std::shared_ptr<WindowContext>& ctx) {
747 size_t i = ctx->i_++;
748 if (i < ctx->input_.size()) {
749 // Using setCallback_ directly since we don't need the Future
750 ctx->func_(std::move(ctx->input_[i])).setCallback_(
751 // ctx is captured by value
752 [ctx, i](Try<Result>&& t) {
753 ctx->promises_[i].setTry(std::move(t));
754 // Chain another future onto this one
755 spawn(std::move(ctx));
761 auto max = std::min(n, input.size());
763 auto ctx = std::make_shared<WindowContext>(
764 std::move(input), std::move(func));
766 for (size_t i = 0; i < max; ++i) {
767 // Start the first n Futures
768 WindowContext::spawn(ctx);
771 std::vector<Future<Result>> futures;
772 futures.reserve(ctx->promises_.size());
773 for (auto& promise : ctx->promises_) {
774 futures.emplace_back(promise.getFuture());
783 template <class I, class F>
784 Future<I> Future<T>::reduce(I&& initial, F&& func) {
785 folly::MoveWrapper<I> minitial(std::move(initial));
786 folly::MoveWrapper<F> mfunc(std::move(func));
787 return then([minitial, mfunc](T& vals) mutable {
788 auto ret = std::move(*minitial);
789 for (auto& val : vals) {
790 ret = (*mfunc)(std::move(ret), std::move(val));
796 // unorderedReduce (iterator)
798 template <class It, class T, class F, class ItT, class Arg>
799 Future<T> unorderedReduce(It first, It last, T initial, F func) {
801 return makeFuture(std::move(initial));
804 typedef isTry<Arg> IsTry;
806 struct UnorderedReduceContext {
807 UnorderedReduceContext(T&& memo, F&& fn, size_t n)
808 : lock_(), memo_(makeFuture<T>(std::move(memo))),
809 func_(std::move(fn)), numThens_(0), numFutures_(n), promise_()
811 folly::MicroSpinLock lock_; // protects memo_ and numThens_
814 size_t numThens_; // how many Futures completed and called .then()
815 size_t numFutures_; // how many Futures in total
819 auto ctx = std::make_shared<UnorderedReduceContext>(
820 std::move(initial), std::move(func), std::distance(first, last));
822 mapSetCallback<ItT>(first, last, [ctx](size_t i, Try<ItT>&& t) {
823 folly::MoveWrapper<Try<ItT>> mt(std::move(t));
824 // Futures can be completed in any order, simultaneously.
825 // To make this non-blocking, we create a new Future chain in
826 // the order of completion to reduce the values.
827 // The spinlock just protects chaining a new Future, not actually
828 // executing the reduce, which should be really fast.
829 folly::MSLGuard lock(ctx->lock_);
830 ctx->memo_ = ctx->memo_.then([ctx, mt](T&& v) mutable {
831 // Either return a ItT&& or a Try<ItT>&& depending
832 // on the type of the argument of func.
833 return ctx->func_(std::move(v), mt->template get<IsTry::value, Arg&&>());
835 if (++ctx->numThens_ == ctx->numFutures_) {
836 // After reducing the value of the last Future, fulfill the Promise
837 ctx->memo_.setCallback_([ctx](Try<T>&& t2) {
838 ctx->promise_.setValue(std::move(t2));
843 return ctx->promise_.getFuture();
849 Future<T> Future<T>::within(Duration dur, Timekeeper* tk) {
850 return within(dur, TimedOut(), tk);
855 Future<T> Future<T>::within(Duration dur, E e, Timekeeper* tk) {
858 Context(E ex) : exception(std::move(ex)), promise() {}
861 std::atomic<bool> token {false};
863 auto ctx = std::make_shared<Context>(std::move(e));
866 tk = folly::detail::getTimekeeperSingleton();
870 .then([ctx](Try<Unit> const& t) {
871 if (ctx->token.exchange(true) == false) {
872 if (t.hasException()) {
873 ctx->promise.setException(std::move(t.exception()));
875 ctx->promise.setException(std::move(ctx->exception));
880 this->then([ctx](Try<T>&& t) {
881 if (ctx->token.exchange(true) == false) {
882 ctx->promise.setTry(std::move(t));
886 return ctx->promise.getFuture().via(getExecutor());
892 Future<T> Future<T>::delayed(Duration dur, Timekeeper* tk) {
893 return collectAll(*this, futures::sleep(dur, tk))
894 .then([](std::tuple<Try<T>, Try<Unit>> tup) {
895 Try<T>& t = std::get<0>(tup);
896 return makeFuture<T>(std::move(t));
903 void waitImpl(Future<T>& f) {
904 // short-circuit if there's nothing to do
905 if (f.isReady()) return;
907 folly::fibers::Baton baton;
908 f = f.then([&](Try<T> t) {
910 return makeFuture(std::move(t));
914 // There's a race here between the return here and the actual finishing of
915 // the future. f is completed, but the setup may not have finished on done
916 // after the baton has posted.
917 while (!f.isReady()) {
918 std::this_thread::yield();
923 void waitImpl(Future<T>& f, Duration dur) {
924 // short-circuit if there's nothing to do
925 if (f.isReady()) return;
927 auto baton = std::make_shared<folly::fibers::Baton>();
928 f = f.then([baton](Try<T> t) {
930 return makeFuture(std::move(t));
933 // Let's preserve the invariant that if we did not timeout (timed_wait returns
934 // true), then the returned Future is complete when it is returned to the
935 // caller. We need to wait out the race for that Future to complete.
936 if (baton->timed_wait(dur)) {
937 while (!f.isReady()) {
938 std::this_thread::yield();
944 void waitViaImpl(Future<T>& f, DrivableExecutor* e) {
945 while (!f.isReady()) {
953 Future<T>& Future<T>::wait() & {
954 detail::waitImpl(*this);
959 Future<T>&& Future<T>::wait() && {
960 detail::waitImpl(*this);
961 return std::move(*this);
965 Future<T>& Future<T>::wait(Duration dur) & {
966 detail::waitImpl(*this, dur);
971 Future<T>&& Future<T>::wait(Duration dur) && {
972 detail::waitImpl(*this, dur);
973 return std::move(*this);
977 Future<T>& Future<T>::waitVia(DrivableExecutor* e) & {
978 detail::waitViaImpl(*this, e);
983 Future<T>&& Future<T>::waitVia(DrivableExecutor* e) && {
984 detail::waitViaImpl(*this, e);
985 return std::move(*this);
990 return std::move(wait().value());
994 T Future<T>::get(Duration dur) {
997 return std::move(value());
1004 T Future<T>::getVia(DrivableExecutor* e) {
1005 return std::move(waitVia(e).value());
1011 static bool equals(const Try<T>& t1, const Try<T>& t2) {
1012 return t1.value() == t2.value();
1018 Future<bool> Future<T>::willEqual(Future<T>& f) {
1019 return collectAll(*this, f).then([](const std::tuple<Try<T>, Try<T>>& t) {
1020 if (std::get<0>(t).hasValue() && std::get<1>(t).hasValue()) {
1021 return detail::TryEquals<T>::equals(std::get<0>(t), std::get<1>(t));
1030 Future<T> Future<T>::filter(F predicate) {
1031 auto p = folly::makeMoveWrapper(std::move(predicate));
1032 return this->then([p](T val) {
1033 T const& valConstRef = val;
1034 if (!(*p)(valConstRef)) {
1035 throw PredicateDoesNotObtain();
1042 template <class Callback>
1043 auto Future<T>::thenMulti(Callback&& fn)
1044 -> decltype(this->then(std::forward<Callback>(fn))) {
1045 // thenMulti with one callback is just a then
1046 return then(std::forward<Callback>(fn));
1050 template <class Callback, class... Callbacks>
1051 auto Future<T>::thenMulti(Callback&& fn, Callbacks&&... fns)
1052 -> decltype(this->then(std::forward<Callback>(fn)).
1053 thenMulti(std::forward<Callbacks>(fns)...)) {
1054 // thenMulti with two callbacks is just then(a).thenMulti(b, ...)
1055 return then(std::forward<Callback>(fn)).
1056 thenMulti(std::forward<Callbacks>(fns)...);
1060 template <class Callback, class... Callbacks>
1061 auto Future<T>::thenMultiWithExecutor(Executor* x, Callback&& fn,
1063 -> decltype(this->then(std::forward<Callback>(fn)).
1064 thenMulti(std::forward<Callbacks>(fns)...)) {
1065 // thenMultiExecutor with two callbacks is
1066 // via(x).then(a).thenMulti(b, ...).via(oldX)
1067 auto oldX = getExecutor();
1069 return then(std::forward<Callback>(fn)).
1070 thenMulti(std::forward<Callbacks>(fns)...).via(oldX);
1074 template <class Callback>
1075 auto Future<T>::thenMultiWithExecutor(Executor* x, Callback&& fn)
1076 -> decltype(this->then(std::forward<Callback>(fn))) {
1077 // thenMulti with one callback is just a then with an executor
1078 return then(x, std::forward<Callback>(fn));
1082 template <class It, class F, class ItT, class Result>
1083 std::vector<Future<Result>> map(It first, It last, F func) {
1084 std::vector<Future<Result>> results;
1085 for (auto it = first; it != last; it++) {
1086 results.push_back(it->then(func));
1092 // Instantiate the most common Future types to save compile time
1093 extern template class Future<Unit>;
1094 extern template class Future<bool>;
1095 extern template class Future<int>;
1096 extern template class Future<int64_t>;
1097 extern template class Future<std::string>;
1098 extern template class Future<double>;
1100 } // namespace folly