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_);
48 typename std::enable_if<!isFuture<T2>::value, void*>::type>
49 Future<T>::Future(T2&& val) : core_(nullptr) {
51 p.setValue(std::forward<T2>(val));
52 *this = p.getFuture();
57 typename std::enable_if<
58 folly::is_void_or_unit<T2>::value,
60 Future<T>::Future() : core_(nullptr) {
63 *this = p.getFuture();
68 Future<T>::~Future() {
73 void Future<T>::detach() {
75 core_->detachFuture();
81 void Future<T>::throwIfInvalid() const {
88 void Future<T>::setCallback_(F&& func) {
90 core_->setCallback(std::move(func));
97 typename std::enable_if<isFuture<F>::value,
98 Future<typename isFuture<T>::Inner>>::type
100 return then([](Future<typename isFuture<T>::Inner> internal_future) {
101 return internal_future;
107 // Variant: returns a value
108 // e.g. f.then([](Try<T>&& t){ return t.value(); });
110 template <typename F, typename R, bool isTry, typename... Args>
111 typename std::enable_if<!R::ReturnsFuture::value, typename R::Return>::type
112 Future<T>::thenImplementation(F func, detail::argResult<isTry, F, Args...>) {
113 static_assert(sizeof...(Args) <= 1, "Then must take zero/one argument");
114 typedef typename R::ReturnsFuture::Inner B;
118 // wrap these so we can move them into the lambda
119 folly::MoveWrapper<Promise<B>> p;
120 folly::MoveWrapper<F> funcm(std::forward<F>(func));
122 // grab the Future now before we lose our handle on the Promise
123 auto f = p->getFuture();
125 f.setExecutor(getExecutor());
128 /* This is a bit tricky.
130 We can't just close over *this in case this Future gets moved. So we
131 make a new dummy Future. We could figure out something more
132 sophisticated that avoids making a new Future object when it can, as an
133 optimization. But this is correct.
135 core_ can't be moved, it is explicitly disallowed (as is copying). But
136 if there's ever a reason to allow it, this is one place that makes that
137 assumption and would need to be fixed. We use a standard shared pointer
138 for core_ (by copying it in), which means in essence obj holds a shared
139 pointer to itself. But this shouldn't leak because Promise will not
140 outlive the continuation, because Promise will setException() with a
141 broken Promise if it is destructed before completed. We could use a
142 weak pointer but it would have to be converted to a shared pointer when
143 func is executed (because the Future returned by func may possibly
144 persist beyond the callback, if it gets moved), and so it is an
145 optimization to just make it shared from the get-go.
147 We have to move in the Promise and func using the MoveWrapper
148 hack. (func could be copied but it's a big drag on perf).
150 Two subtle but important points about this design. detail::Core has no
151 back pointers to Future or Promise, so if Future or Promise get moved
152 (and they will be moved in performant code) we don't have to do
153 anything fancy. And because we store the continuation in the
154 detail::Core, not in the Future, we can execute the continuation even
155 after the Future has gone out of scope. This is an intentional design
156 decision. It is likely we will want to be able to cancel a continuation
157 in some circumstances, but I think it should be explicit not implicit
158 in the destruction of the Future used to create it.
161 [p, funcm](Try<T>&& t) mutable {
162 if (!isTry && t.hasException()) {
163 p->setException(std::move(t.exception()));
166 return (*funcm)(t.template get<isTry, Args>()...);
174 // Variant: returns a Future
175 // e.g. f.then([](T&& t){ return makeFuture<T>(t); });
177 template <typename F, typename R, bool isTry, typename... Args>
178 typename std::enable_if<R::ReturnsFuture::value, typename R::Return>::type
179 Future<T>::thenImplementation(F func, detail::argResult<isTry, F, Args...>) {
180 static_assert(sizeof...(Args) <= 1, "Then must take zero/one argument");
181 typedef typename R::ReturnsFuture::Inner B;
185 // wrap these so we can move them into the lambda
186 folly::MoveWrapper<Promise<B>> p;
187 folly::MoveWrapper<F> funcm(std::forward<F>(func));
189 // grab the Future now before we lose our handle on the Promise
190 auto f = p->getFuture();
192 f.setExecutor(getExecutor());
196 [p, funcm](Try<T>&& t) mutable {
197 if (!isTry && t.hasException()) {
198 p->setException(std::move(t.exception()));
201 auto f2 = (*funcm)(t.template get<isTry, Args>()...);
202 // that didn't throw, now we can steal p
203 f2.setCallback_([p](Try<B>&& b) mutable {
204 p->setTry(std::move(b));
206 } catch (const std::exception& e) {
207 p->setException(exception_wrapper(std::current_exception(), e));
209 p->setException(exception_wrapper(std::current_exception()));
217 template <typename T>
218 template <typename R, typename Caller, typename... Args>
219 Future<typename isFuture<R>::Inner>
220 Future<T>::then(R(Caller::*func)(Args...), Caller *instance) {
221 typedef typename std::remove_cv<
222 typename std::remove_reference<
223 typename detail::ArgType<Args...>::FirstArg>::type>::type FirstArg;
224 return then([instance, func](Try<T>&& t){
225 return (instance->*func)(t.template get<isTry<FirstArg>::value, Args>()...);
230 template <class Executor, class Arg, class... Args>
231 auto Future<T>::then(Executor* x, Arg&& arg, Args&&... args)
232 -> decltype(this->then(std::forward<Arg>(arg),
233 std::forward<Args>(args)...))
235 auto oldX = getExecutor();
237 return this->then(std::forward<Arg>(arg), std::forward<Args>(args)...).
242 Future<void> Future<T>::then() {
243 return then([] (Try<T>&& t) {});
246 // onError where the callback returns T
249 typename std::enable_if<
250 !detail::callableWith<F, exception_wrapper>::value &&
251 !detail::Extract<F>::ReturnsFuture::value,
253 Future<T>::onError(F&& func) {
254 typedef typename detail::Extract<F>::FirstArg Exn;
256 std::is_same<typename detail::Extract<F>::RawReturn, T>::value,
257 "Return type of onError callback must be T or Future<T>");
260 auto f = p.getFuture();
261 auto pm = folly::makeMoveWrapper(std::move(p));
262 auto funcm = folly::makeMoveWrapper(std::move(func));
263 setCallback_([pm, funcm](Try<T>&& t) mutable {
264 if (!t.template withException<Exn>([&] (Exn& e) {
269 pm->setTry(std::move(t));
276 // onError where the callback returns Future<T>
279 typename std::enable_if<
280 !detail::callableWith<F, exception_wrapper>::value &&
281 detail::Extract<F>::ReturnsFuture::value,
283 Future<T>::onError(F&& func) {
285 std::is_same<typename detail::Extract<F>::Return, Future<T>>::value,
286 "Return type of onError callback must be T or Future<T>");
287 typedef typename detail::Extract<F>::FirstArg Exn;
290 auto f = p.getFuture();
291 auto pm = folly::makeMoveWrapper(std::move(p));
292 auto funcm = folly::makeMoveWrapper(std::move(func));
293 setCallback_([pm, funcm](Try<T>&& t) mutable {
294 if (!t.template withException<Exn>([&] (Exn& e) {
296 auto f2 = (*funcm)(e);
297 f2.setCallback_([pm](Try<T>&& t2) mutable {
298 pm->setTry(std::move(t2));
300 } catch (const std::exception& e2) {
301 pm->setException(exception_wrapper(std::current_exception(), e2));
303 pm->setException(exception_wrapper(std::current_exception()));
306 pm->setTry(std::move(t));
315 Future<T> Future<T>::ensure(F func) {
316 MoveWrapper<F> funcw(std::move(func));
317 return this->then([funcw](Try<T>&& t) {
319 return makeFuture(std::move(t));
325 Future<T> Future<T>::onTimeout(Duration dur, F&& func, Timekeeper* tk) {
326 auto funcw = folly::makeMoveWrapper(std::forward<F>(func));
327 return within(dur, tk)
328 .onError([funcw](TimedOut const&) { return (*funcw)(); });
333 typename std::enable_if<
334 detail::callableWith<F, exception_wrapper>::value &&
335 detail::Extract<F>::ReturnsFuture::value,
337 Future<T>::onError(F&& func) {
339 std::is_same<typename detail::Extract<F>::Return, Future<T>>::value,
340 "Return type of onError callback must be T or Future<T>");
343 auto f = p.getFuture();
344 auto pm = folly::makeMoveWrapper(std::move(p));
345 auto funcm = folly::makeMoveWrapper(std::move(func));
346 setCallback_([pm, funcm](Try<T> t) mutable {
347 if (t.hasException()) {
349 auto f2 = (*funcm)(std::move(t.exception()));
350 f2.setCallback_([pm](Try<T> t2) mutable {
351 pm->setTry(std::move(t2));
353 } catch (const std::exception& e2) {
354 pm->setException(exception_wrapper(std::current_exception(), e2));
356 pm->setException(exception_wrapper(std::current_exception()));
359 pm->setTry(std::move(t));
366 // onError(exception_wrapper) that returns T
369 typename std::enable_if<
370 detail::callableWith<F, exception_wrapper>::value &&
371 !detail::Extract<F>::ReturnsFuture::value,
373 Future<T>::onError(F&& func) {
375 std::is_same<typename detail::Extract<F>::Return, Future<T>>::value,
376 "Return type of onError callback must be T or Future<T>");
379 auto f = p.getFuture();
380 auto pm = folly::makeMoveWrapper(std::move(p));
381 auto funcm = folly::makeMoveWrapper(std::move(func));
382 setCallback_([pm, funcm](Try<T> t) mutable {
383 if (t.hasException()) {
385 return (*funcm)(std::move(t.exception()));
388 pm->setTry(std::move(t));
396 typename std::add_lvalue_reference<T>::type Future<T>::value() {
399 return core_->getTry().value();
403 typename std::add_lvalue_reference<const T>::type Future<T>::value() const {
406 return core_->getTry().value();
410 Try<T>& Future<T>::getTry() {
413 return core_->getTry();
417 Optional<Try<T>> Future<T>::poll() {
419 if (core_->ready()) {
420 o = std::move(core_->getTry());
426 inline Future<T> Future<T>::via(Executor* executor) && {
429 setExecutor(executor);
431 return std::move(*this);
435 inline Future<T> Future<T>::via(Executor* executor) & {
438 MoveWrapper<Promise<T>> p;
439 auto f = p->getFuture();
440 then([p](Try<T>&& t) mutable { p->setTry(std::move(t)); });
441 return std::move(f).via(executor);
445 bool Future<T>::isReady() const {
447 return core_->ready();
451 void Future<T>::raise(exception_wrapper exception) {
452 core_->raise(std::move(exception));
458 Future<typename std::decay<T>::type> makeFuture(T&& t) {
459 Promise<typename std::decay<T>::type> p;
460 p.setValue(std::forward<T>(t));
461 return p.getFuture();
464 inline // for multiple translation units
465 Future<void> makeFuture() {
468 return p.getFuture();
474 typename std::enable_if<!std::is_reference<F>::value, bool>::type sdf)
475 -> Future<decltype(func())> {
476 Promise<decltype(func())> p;
481 return p.getFuture();
485 auto makeFutureWith(F const& func) -> Future<decltype(func())> {
487 return makeFutureWith(std::move(copy));
491 Future<T> makeFuture(std::exception_ptr const& e) {
494 return p.getFuture();
498 Future<T> makeFuture(exception_wrapper ew) {
500 p.setException(std::move(ew));
501 return p.getFuture();
504 template <class T, class E>
505 typename std::enable_if<std::is_base_of<std::exception, E>::value,
507 makeFuture(E const& e) {
509 p.setException(make_exception_wrapper<E>(e));
510 return p.getFuture();
514 Future<T> makeFuture(Try<T>&& t) {
515 Promise<typename std::decay<T>::type> p;
516 p.setTry(std::move(t));
517 return p.getFuture();
521 inline Future<void> makeFuture(Try<void>&& t) {
522 if (t.hasException()) {
523 return makeFuture<void>(std::move(t.exception()));
530 inline Future<void> via(Executor* executor) {
531 return makeFuture().via(executor);
536 template <typename... Fs>
537 typename detail::VariadicContext<
538 typename std::decay<Fs>::type::value_type...>::type
539 collectAll(Fs&&... fs) {
541 new detail::VariadicContext<typename std::decay<Fs>::type::value_type...>();
542 ctx->total = sizeof...(fs);
543 auto f_saved = ctx->p.getFuture();
544 detail::collectAllVariadicHelper(ctx,
545 std::forward<typename std::decay<Fs>::type>(fs)...);
551 template <class InputIterator>
554 Try<typename std::iterator_traits<InputIterator>::value_type::value_type>>>
555 collectAll(InputIterator first, InputIterator last) {
557 typename std::iterator_traits<InputIterator>::value_type::value_type T;
560 return makeFuture(std::vector<Try<T>>());
562 size_t n = std::distance(first, last);
564 auto ctx = new detail::WhenAllContext<T>();
566 ctx->results.resize(n);
568 auto f_saved = ctx->p.getFuture();
570 for (size_t i = 0; first != last; ++first, ++i) {
573 f.setCallback_([ctx, i, n](Try<T> t) {
574 ctx->results[i] = std::move(t);
575 if (++ctx->count == n) {
576 ctx->p.setValue(std::move(ctx->results));
587 template <class, class, typename = void> struct CollectContextHelper;
589 template <class T, class VecT>
590 struct CollectContextHelper<T, VecT,
591 typename std::enable_if<std::is_same<T, VecT>::value>::type> {
592 static inline std::vector<T>&& getResults(std::vector<VecT>& results) {
593 return std::move(results);
597 template <class T, class VecT>
598 struct CollectContextHelper<T, VecT,
599 typename std::enable_if<!std::is_same<T, VecT>::value>::type> {
600 static inline std::vector<T> getResults(std::vector<VecT>& results) {
601 std::vector<T> finalResults;
602 finalResults.reserve(results.size());
603 for (auto& opt : results) {
604 finalResults.push_back(std::move(opt.value()));
610 template <typename T>
611 struct CollectContext {
613 typedef typename std::conditional<
614 std::is_default_constructible<T>::value,
619 explicit CollectContext(int n) : count(0), success_count(0), threw(false) {
623 Promise<std::vector<T>> p;
624 std::vector<VecT> results;
625 std::atomic<size_t> count, success_count;
626 std::atomic_bool threw;
628 typedef std::vector<T> result_type;
630 static inline Future<std::vector<T>> makeEmptyFuture() {
631 return makeFuture(std::vector<T>());
634 inline void setValue() {
635 p.setValue(CollectContextHelper<T, VecT>::getResults(results));
638 inline void addResult(int i, Try<T>& t) {
639 results[i] = std::move(t.value());
644 struct CollectContext<void> {
646 explicit CollectContext(int n) : count(0), success_count(0), threw(false) {}
649 std::atomic<size_t> count, success_count;
650 std::atomic_bool threw;
652 typedef void result_type;
654 static inline Future<void> makeEmptyFuture() {
658 inline void setValue() {
662 inline void addResult(int i, Try<void>& t) {
669 template <class InputIterator>
670 Future<typename detail::CollectContext<
671 typename std::iterator_traits<InputIterator>::value_type::value_type
673 collect(InputIterator first, InputIterator last) {
675 typename std::iterator_traits<InputIterator>::value_type::value_type T;
678 return detail::CollectContext<T>::makeEmptyFuture();
681 size_t n = std::distance(first, last);
682 auto ctx = new detail::CollectContext<T>(n);
683 auto f_saved = ctx->p.getFuture();
685 for (size_t i = 0; first != last; ++first, ++i) {
688 f.setCallback_([ctx, i, n](Try<T> t) {
690 if (t.hasException()) {
691 if (!ctx->threw.exchange(true)) {
692 ctx->p.setException(std::move(t.exception()));
694 } else if (!ctx->threw) {
695 ctx->addResult(i, t);
696 if (++ctx->success_count == n) {
701 if (++ctx->count == n) {
710 template <class InputIterator>
715 std::iterator_traits<InputIterator>::value_type::value_type> > >
716 collectAny(InputIterator first, InputIterator last) {
718 typename std::iterator_traits<InputIterator>::value_type::value_type T;
720 auto ctx = new detail::WhenAnyContext<T>(std::distance(first, last));
721 auto f_saved = ctx->p.getFuture();
723 for (size_t i = 0; first != last; first++, i++) {
725 f.setCallback_([i, ctx](Try<T>&& t) {
726 if (!ctx->done.exchange(true)) {
727 ctx->p.setValue(std::make_pair(i, std::move(t)));
736 template <class InputIterator>
737 Future<std::vector<std::pair<size_t, Try<typename
738 std::iterator_traits<InputIterator>::value_type::value_type>>>>
739 collectN(InputIterator first, InputIterator last, size_t n) {
741 std::iterator_traits<InputIterator>::value_type::value_type T;
742 typedef std::vector<std::pair<size_t, Try<T>>> V;
749 auto ctx = std::make_shared<ctx_t>();
752 // for each completed Future, increase count and add to vector, until we
753 // have n completed futures at which point we fulfill our Promise with the
758 it->then([ctx, n, i](Try<T>&& t) {
760 auto c = ++ctx->completed;
762 assert(ctx->v.size() < n);
763 v.push_back(std::make_pair(i, std::move(t)));
765 ctx->p.setTry(Try<V>(std::move(v)));
775 ctx->p.setException(std::runtime_error("Not enough futures"));
778 return ctx->p.getFuture();
781 template <class It, class T, class F>
782 Future<T> reduce(It first, It last, T&& initial, F&& func) {
784 return makeFuture(std::move(initial));
787 typedef typename std::iterator_traits<It>::value_type::value_type ItT;
788 typedef typename std::conditional<
789 detail::callableWith<F, T&&, Try<ItT>&&>::value, Try<ItT>, ItT>::type Arg;
790 typedef isTry<Arg> IsTry;
792 folly::MoveWrapper<T> minitial(std::move(initial));
793 auto sfunc = std::make_shared<F>(std::move(func));
795 auto f = first->then([minitial, sfunc](Try<ItT>& head) mutable {
796 return (*sfunc)(std::move(*minitial),
797 head.template get<IsTry::value, Arg&&>());
800 for (++first; first != last; ++first) {
801 f = collectAll(f, *first).then([sfunc](std::tuple<Try<T>, Try<ItT>>& t) {
802 return (*sfunc)(std::move(std::get<0>(t).value()),
803 // Either return a ItT&& or a Try<ItT>&& depending
804 // on the type of the argument of func.
805 std::get<1>(t).template get<IsTry::value, Arg&&>());
813 template <class I, class F>
814 Future<I> Future<T>::reduce(I&& initial, F&& func) {
815 folly::MoveWrapper<I> minitial(std::move(initial));
816 folly::MoveWrapper<F> mfunc(std::move(func));
817 return then([minitial, mfunc](T& vals) mutable {
818 auto ret = std::move(*minitial);
819 for (auto& val : vals) {
820 ret = (*mfunc)(std::move(ret), std::move(val));
827 Future<T> Future<T>::within(Duration dur, Timekeeper* tk) {
828 return within(dur, TimedOut(), tk);
833 Future<T> Future<T>::within(Duration dur, E e, Timekeeper* tk) {
836 Context(E ex) : exception(std::move(ex)), promise(), token(false) {}
839 std::atomic<bool> token;
841 auto ctx = std::make_shared<Context>(std::move(e));
844 tk = folly::detail::getTimekeeperSingleton();
848 .then([ctx](Try<void> const& t) {
849 if (ctx->token.exchange(true) == false) {
850 if (t.hasException()) {
851 ctx->promise.setException(std::move(t.exception()));
853 ctx->promise.setException(std::move(ctx->exception));
858 this->then([ctx](Try<T>&& t) {
859 if (ctx->token.exchange(true) == false) {
860 ctx->promise.setTry(std::move(t));
864 return ctx->promise.getFuture();
868 Future<T> Future<T>::delayed(Duration dur, Timekeeper* tk) {
869 return collectAll(*this, futures::sleep(dur, tk))
870 .then([](std::tuple<Try<T>, Try<void>> tup) {
871 Try<T>& t = std::get<0>(tup);
872 return makeFuture<T>(std::move(t));
879 void waitImpl(Future<T>& f) {
880 // short-circuit if there's nothing to do
881 if (f.isReady()) return;
883 folly::fibers::Baton baton;
884 f = f.then([&](Try<T> t) {
886 return makeFuture(std::move(t));
890 // There's a race here between the return here and the actual finishing of
891 // the future. f is completed, but the setup may not have finished on done
892 // after the baton has posted.
893 while (!f.isReady()) {
894 std::this_thread::yield();
899 void waitImpl(Future<T>& f, Duration dur) {
900 // short-circuit if there's nothing to do
901 if (f.isReady()) return;
903 auto baton = std::make_shared<folly::fibers::Baton>();
904 f = f.then([baton](Try<T> t) {
906 return makeFuture(std::move(t));
909 // Let's preserve the invariant that if we did not timeout (timed_wait returns
910 // true), then the returned Future is complete when it is returned to the
911 // caller. We need to wait out the race for that Future to complete.
912 if (baton->timed_wait(dur)) {
913 while (!f.isReady()) {
914 std::this_thread::yield();
920 void waitViaImpl(Future<T>& f, DrivableExecutor* e) {
921 while (!f.isReady()) {
929 Future<T>& Future<T>::wait() & {
930 detail::waitImpl(*this);
935 Future<T>&& Future<T>::wait() && {
936 detail::waitImpl(*this);
937 return std::move(*this);
941 Future<T>& Future<T>::wait(Duration dur) & {
942 detail::waitImpl(*this, dur);
947 Future<T>&& Future<T>::wait(Duration dur) && {
948 detail::waitImpl(*this, dur);
949 return std::move(*this);
953 Future<T>& Future<T>::waitVia(DrivableExecutor* e) & {
954 detail::waitViaImpl(*this, e);
959 Future<T>&& Future<T>::waitVia(DrivableExecutor* e) && {
960 detail::waitViaImpl(*this, e);
961 return std::move(*this);
966 return std::move(wait().value());
970 inline void Future<void>::get() {
975 T Future<T>::get(Duration dur) {
978 return std::move(value());
985 inline void Future<void>::get(Duration dur) {
995 T Future<T>::getVia(DrivableExecutor* e) {
996 return std::move(waitVia(e).value());
1000 inline void Future<void>::getVia(DrivableExecutor* e) {
1005 Future<bool> Future<T>::willEqual(Future<T>& f) {
1006 return collectAll(*this, f).then([](const std::tuple<Try<T>, Try<T>>& t) {
1007 if (std::get<0>(t).hasValue() && std::get<1>(t).hasValue()) {
1008 return std::get<0>(t).value() == std::get<1>(t).value();
1017 Future<T> Future<T>::filter(F predicate) {
1018 auto p = folly::makeMoveWrapper(std::move(predicate));
1019 return this->then([p](T val) {
1020 T const& valConstRef = val;
1021 if (!(*p)(valConstRef)) {
1022 throw PredicateDoesNotObtain();
1031 Future<Z> chainHelper(Future<Z> f) {
1035 template <class Z, class F, class Fn, class... Callbacks>
1036 Future<Z> chainHelper(F f, Fn fn, Callbacks... fns) {
1037 return chainHelper<Z>(f.then(fn), fns...);
1041 template <class A, class Z, class... Callbacks>
1042 std::function<Future<Z>(Try<A>)>
1043 chain(Callbacks... fns) {
1044 MoveWrapper<Promise<A>> pw;
1045 MoveWrapper<Future<Z>> fw(chainHelper<Z>(pw->getFuture(), fns...));
1046 return [=](Try<A> t) mutable {
1047 pw->setTry(std::move(t));
1048 return std::move(*fw);
1052 template <class It, class F, class ItT, class Result>
1053 std::vector<Future<Result>> map(It first, It last, F func) {
1054 std::vector<Future<Result>> results;
1055 for (auto it = first; it != last; it++) {
1056 results.push_back(it->then(func));
1062 } // namespace folly
1064 // I haven't included a Future<T&> specialization because I don't forsee us
1065 // using it, however it is not difficult to add when needed. Refer to
1066 // Future<void> for guidance. std::future and boost::future code would also be