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.
22 #include <folly/wangle/detail/Core.h>
23 #include <folly/Baton.h>
25 namespace folly { namespace wangle {
29 static const bool value = false;
33 struct isFuture<Future<T> > {
34 static const bool value = true;
38 Future<T>::Future(Future<T>&& other) noexcept : core_(nullptr) {
39 *this = std::move(other);
43 Future<T>& Future<T>::operator=(Future<T>&& other) {
44 std::swap(core_, other.core_);
49 Future<T>::~Future() {
54 void Future<T>::detach() {
56 core_->detachFuture();
62 void Future<T>::throwIfInvalid() const {
69 void Future<T>::setCallback_(F&& func) {
71 core_->setCallback(std::move(func));
74 // Variant: f.then([](Try<T>&& t){ return t.value(); });
77 typename std::enable_if<
78 !isFuture<typename std::result_of<F(Try<T>&&)>::type>::value,
79 Future<typename std::result_of<F(Try<T>&&)>::type> >::type
80 Future<T>::then(F&& func) {
81 typedef typename std::result_of<F(Try<T>&&)>::type B;
85 // wrap these so we can move them into the lambda
86 folly::MoveWrapper<Promise<B>> p;
87 folly::MoveWrapper<F> funcm(std::forward<F>(func));
89 // grab the Future now before we lose our handle on the Promise
90 auto f = p->getFuture();
92 /* This is a bit tricky.
94 We can't just close over *this in case this Future gets moved. So we
95 make a new dummy Future. We could figure out something more
96 sophisticated that avoids making a new Future object when it can, as an
97 optimization. But this is correct.
99 core_ can't be moved, it is explicitly disallowed (as is copying). But
100 if there's ever a reason to allow it, this is one place that makes that
101 assumption and would need to be fixed. We use a standard shared pointer
102 for core_ (by copying it in), which means in essence obj holds a shared
103 pointer to itself. But this shouldn't leak because Promise will not
104 outlive the continuation, because Promise will setException() with a
105 broken Promise if it is destructed before completed. We could use a
106 weak pointer but it would have to be converted to a shared pointer when
107 func is executed (because the Future returned by func may possibly
108 persist beyond the callback, if it gets moved), and so it is an
109 optimization to just make it shared from the get-go.
111 We have to move in the Promise and func using the MoveWrapper
112 hack. (func could be copied but it's a big drag on perf).
114 Two subtle but important points about this design. detail::Core has no
115 back pointers to Future or Promise, so if Future or Promise get moved
116 (and they will be moved in performant code) we don't have to do
117 anything fancy. And because we store the continuation in the
118 detail::Core, not in the Future, we can execute the continuation even
119 after the Future has gone out of scope. This is an intentional design
120 decision. It is likely we will want to be able to cancel a continuation
121 in some circumstances, but I think it should be explicit not implicit
122 in the destruction of the Future used to create it.
125 [p, funcm](Try<T>&& t) mutable {
127 return (*funcm)(std::move(t));
134 // Variant: f.then([](T&& t){ return t; });
137 typename std::enable_if<
138 !std::is_same<T, void>::value &&
139 !isFuture<typename std::result_of<
140 F(typename detail::AliasIfVoid<T>::type&&)>::type>::value,
141 Future<typename std::result_of<
142 F(typename detail::AliasIfVoid<T>::type&&)>::type> >::type
143 Future<T>::then(F&& func) {
144 typedef typename std::result_of<F(T&&)>::type B;
148 folly::MoveWrapper<Promise<B>> p;
149 folly::MoveWrapper<F> funcm(std::forward<F>(func));
150 auto f = p->getFuture();
153 [p, funcm](Try<T>&& t) mutable {
154 if (t.hasException()) {
155 p->setException(t.getException());
158 return (*funcm)(std::move(t.value()));
166 // Variant: f.then([](){ return; });
169 typename std::enable_if<
170 std::is_same<T, void>::value &&
171 !isFuture<typename std::result_of<F()>::type>::value,
172 Future<typename std::result_of<F()>::type> >::type
173 Future<T>::then(F&& func) {
174 typedef typename std::result_of<F()>::type B;
178 folly::MoveWrapper<Promise<B>> p;
179 folly::MoveWrapper<F> funcm(std::forward<F>(func));
180 auto f = p->getFuture();
183 [p, funcm](Try<T>&& t) mutable {
184 if (t.hasException()) {
185 p->setException(t.getException());
196 // Variant: f.then([](Try<T>&& t){ return makeFuture<T>(t.value()); });
199 typename std::enable_if<
200 isFuture<typename std::result_of<F(Try<T>&&)>::type>::value,
201 Future<typename std::result_of<F(Try<T>&&)>::type::value_type> >::type
202 Future<T>::then(F&& func) {
203 typedef typename std::result_of<F(Try<T>&&)>::type::value_type B;
207 // wrap these so we can move them into the lambda
208 folly::MoveWrapper<Promise<B>> p;
209 folly::MoveWrapper<F> funcm(std::forward<F>(func));
211 // grab the Future now before we lose our handle on the Promise
212 auto f = p->getFuture();
215 [p, funcm](Try<T>&& t) mutable {
217 auto f2 = (*funcm)(std::move(t));
218 // that didn't throw, now we can steal p
219 f2.setCallback_([p](Try<B>&& b) mutable {
220 p->fulfilTry(std::move(b));
223 p->setException(std::current_exception());
230 // Variant: f.then([](T&& t){ return makeFuture<T>(t); });
233 typename std::enable_if<
234 !std::is_same<T, void>::value &&
235 isFuture<typename std::result_of<
236 F(typename detail::AliasIfVoid<T>::type&&)>::type>::value,
237 Future<typename std::result_of<
238 F(typename detail::AliasIfVoid<T>::type&&)>::type::value_type> >::type
239 Future<T>::then(F&& func) {
240 typedef typename std::result_of<F(T&&)>::type::value_type B;
244 folly::MoveWrapper<Promise<B>> p;
245 folly::MoveWrapper<F> funcm(std::forward<F>(func));
246 auto f = p->getFuture();
249 [p, funcm](Try<T>&& t) mutable {
250 if (t.hasException()) {
251 p->setException(t.getException());
254 auto f2 = (*funcm)(std::move(t.value()));
255 f2.setCallback_([p](Try<B>&& b) mutable {
256 p->fulfilTry(std::move(b));
259 p->setException(std::current_exception());
267 // Variant: f.then([](){ return makeFuture(); });
270 typename std::enable_if<
271 std::is_same<T, void>::value &&
272 isFuture<typename std::result_of<F()>::type>::value,
273 Future<typename std::result_of<F()>::type::value_type> >::type
274 Future<T>::then(F&& func) {
275 typedef typename std::result_of<F()>::type::value_type B;
279 folly::MoveWrapper<Promise<B>> p;
280 folly::MoveWrapper<F> funcm(std::forward<F>(func));
282 auto f = p->getFuture();
285 [p, funcm](Try<T>&& t) mutable {
286 if (t.hasException()) {
287 p->setException(t.getException());
290 auto f2 = (*funcm)();
291 f2.setCallback_([p](Try<B>&& b) mutable {
292 p->fulfilTry(std::move(b));
295 p->setException(std::current_exception());
304 Future<void> Future<T>::then() {
305 return then([] (Try<T>&& t) {});
309 typename std::add_lvalue_reference<T>::type Future<T>::value() {
312 return core_->getTry().value();
316 typename std::add_lvalue_reference<const T>::type Future<T>::value() const {
319 return core_->getTry().value();
323 Try<T>& Future<T>::getTry() {
326 return core_->getTry();
330 template <typename Executor>
331 inline Future<T> Future<T>::via(Executor* executor) {
335 core_->setExecutor(executor);
337 return std::move(*this);
341 bool Future<T>::isReady() const {
343 return core_->ready();
347 void Future<T>::raise(std::exception_ptr exception) {
348 core_->raise(exception);
354 Future<typename std::decay<T>::type> makeFuture(T&& t) {
355 Promise<typename std::decay<T>::type> p;
356 auto f = p.getFuture();
357 p.setValue(std::forward<T>(t));
361 inline // for multiple translation units
362 Future<void> makeFuture() {
364 auto f = p.getFuture();
372 typename std::enable_if<!std::is_reference<F>::value, bool>::type sdf)
373 -> Future<decltype(func())> {
374 Promise<decltype(func())> p;
375 auto f = p.getFuture();
384 auto makeFutureTry(F const& func) -> Future<decltype(func())> {
386 return makeFutureTry(std::move(copy));
390 Future<T> makeFuture(std::exception_ptr const& e) {
392 auto f = p.getFuture();
397 template <class T, class E>
398 typename std::enable_if<std::is_base_of<std::exception, E>::value,
400 makeFuture(E const& e) {
402 auto f = p.getFuture();
403 p.fulfil([&]() -> T { throw e; });
408 Future<T> makeFuture(Try<T>&& t) {
410 return makeFuture<T>(std::move(t.value()));
412 return makeFuture<T>(std::current_exception());
417 inline Future<void> makeFuture(Try<void>&& t) {
422 return makeFuture<void>(std::current_exception());
427 template <typename Executor>
428 Future<void> via(Executor* executor) {
429 return makeFuture().via(executor);
434 template <typename... Fs>
435 typename detail::VariadicContext<
436 typename std::decay<Fs>::type::value_type...>::type
440 new detail::VariadicContext<typename std::decay<Fs>::type::value_type...>();
441 ctx->total = sizeof...(fs);
442 auto f_saved = ctx->p.getFuture();
443 detail::whenAllVariadicHelper(ctx,
444 std::forward<typename std::decay<Fs>::type>(fs)...);
445 return std::move(f_saved);
450 template <class InputIterator>
453 Try<typename std::iterator_traits<InputIterator>::value_type::value_type>>>
454 whenAll(InputIterator first, InputIterator last)
457 typename std::iterator_traits<InputIterator>::value_type::value_type T;
459 auto n = std::distance(first, last);
461 return makeFuture(std::vector<Try<T>>());
464 auto ctx = new detail::WhenAllContext<T>();
466 ctx->results.resize(n);
468 auto f_saved = ctx->p.getFuture();
470 for (size_t i = 0; first != last; ++first, ++i) {
473 f.setCallback_([ctx, i, n](Try<T>&& t) {
474 ctx->results[i] = std::move(t);
475 if (++ctx->count == n) {
476 ctx->p.setValue(std::move(ctx->results));
482 return std::move(f_saved);
485 template <class InputIterator>
490 std::iterator_traits<InputIterator>::value_type::value_type> > >
491 whenAny(InputIterator first, InputIterator last) {
493 typename std::iterator_traits<InputIterator>::value_type::value_type T;
495 auto ctx = new detail::WhenAnyContext<T>(std::distance(first, last));
496 auto f_saved = ctx->p.getFuture();
498 for (size_t i = 0; first != last; first++, i++) {
500 f.setCallback_([i, ctx](Try<T>&& t) {
501 if (!ctx->done.exchange(true)) {
502 ctx->p.setValue(std::make_pair(i, std::move(t)));
508 return std::move(f_saved);
511 template <class InputIterator>
512 Future<std::vector<std::pair<size_t, Try<typename
513 std::iterator_traits<InputIterator>::value_type::value_type>>>>
514 whenN(InputIterator first, InputIterator last, size_t n) {
516 std::iterator_traits<InputIterator>::value_type::value_type T;
517 typedef std::vector<std::pair<size_t, Try<T>>> V;
524 auto ctx = std::make_shared<ctx_t>();
527 // for each completed Future, increase count and add to vector, until we
528 // have n completed futures at which point we fulfil our Promise with the
533 it->then([ctx, n, i](Try<T>&& t) {
535 auto c = ++ctx->completed;
537 assert(ctx->v.size() < n);
538 v.push_back(std::make_pair(i, std::move(t)));
540 ctx->p.fulfilTry(Try<V>(std::move(v)));
550 ctx->p.setException(std::runtime_error("Not enough futures"));
553 return ctx->p.getFuture();
556 template <typename T>
558 waitWithSemaphore(Future<T>&& f) {
560 auto done = f.then([&](Try<T> &&t) {
562 return std::move(t.value());
565 while (!done.isReady()) {
566 // There's a race here between the return here and the actual finishing of
567 // the future. f is completed, but the setup may not have finished on done
568 // after the baton has posted.
569 std::this_thread::yield();
575 inline Future<void> waitWithSemaphore<void>(Future<void>&& f) {
577 auto done = f.then([&](Try<void> &&t) {
582 while (!done.isReady()) {
583 // There's a race here between the return here and the actual finishing of
584 // the future. f is completed, but the setup may not have finished on done
585 // after the baton has posted.
586 std::this_thread::yield();
591 template <typename T, class Duration>
593 waitWithSemaphore(Future<T>&& f, Duration timeout) {
594 auto baton = std::make_shared<Baton<>>();
595 auto done = f.then([baton](Try<T> &&t) {
597 return std::move(t.value());
599 baton->timed_wait(std::chrono::system_clock::now() + timeout);
603 template <class Duration>
605 waitWithSemaphore(Future<void>&& f, Duration timeout) {
606 auto baton = std::make_shared<Baton<>>();
607 auto done = f.then([baton](Try<void> &&t) {
611 baton->timed_wait(std::chrono::system_clock::now() + timeout);
617 // I haven't included a Future<T&> specialization because I don't forsee us
618 // using it, however it is not difficult to add when needed. Refer to
619 // Future<void> for guidance. std::future and boost::future code would also be