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/State.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 : state_(nullptr) {
39 *this = std::move(other);
43 Future<T>& Future<T>::operator=(Future<T>&& other) {
44 std::swap(state_, other.state_);
49 Future<T>::~Future() {
54 void Future<T>::detach() {
56 state_->detachFuture();
62 void Future<T>::throwIfInvalid() const {
69 void Future<T>::setCallback_(F&& func) {
71 state_->setCallback(std::move(func));
76 typename std::enable_if<
77 !isFuture<typename std::result_of<F(Try<T>&&)>::type>::value,
78 Future<typename std::result_of<F(Try<T>&&)>::type> >::type
79 Future<T>::then(F&& func) {
80 typedef typename std::result_of<F(Try<T>&&)>::type B;
84 // wrap these so we can move them into the lambda
85 folly::MoveWrapper<Promise<B>> p;
86 folly::MoveWrapper<F> funcm(std::forward<F>(func));
88 // grab the Future now before we lose our handle on the Promise
89 auto f = p->getFuture();
91 /* This is a bit tricky.
93 We can't just close over *this in case this Future gets moved. So we
94 make a new dummy Future. We could figure out something more
95 sophisticated that avoids making a new Future object when it can, as an
96 optimization. But this is correct.
98 state_ can't be moved, it is explicitly disallowed (as is copying). But
99 if there's ever a reason to allow it, this is one place that makes that
100 assumption and would need to be fixed. We use a standard shared pointer
101 for state_ (by copying it in), which means in essence obj holds a shared
102 pointer to itself. But this shouldn't leak because Promise will not
103 outlive the continuation, because Promise will setException() with a
104 broken Promise if it is destructed before completed. We could use a
105 weak pointer but it would have to be converted to a shared pointer when
106 func is executed (because the Future returned by func may possibly
107 persist beyond the callback, if it gets moved), and so it is an
108 optimization to just make it shared from the get-go.
110 We have to move in the Promise and func using the MoveWrapper
111 hack. (func could be copied but it's a big drag on perf).
113 Two subtle but important points about this design. detail::State has no
114 back pointers to Future or Promise, so if Future or Promise get moved
115 (and they will be moved in performant code) we don't have to do
116 anything fancy. And because we store the continuation in the
117 detail::State, not in the Future, we can execute the continuation even
118 after the Future has gone out of scope. This is an intentional design
119 decision. It is likely we will want to be able to cancel a continuation
120 in some circumstances, but I think it should be explicit not implicit
121 in the destruction of the Future used to create it.
124 [p, funcm](Try<T>&& t) mutable {
126 return (*funcm)(std::move(t));
135 typename std::enable_if<
136 isFuture<typename std::result_of<F(Try<T>&&)>::type>::value,
137 Future<typename std::result_of<F(Try<T>&&)>::type::value_type> >::type
138 Future<T>::then(F&& func) {
139 typedef typename std::result_of<F(Try<T>&&)>::type::value_type B;
143 // wrap these so we can move them into the lambda
144 folly::MoveWrapper<Promise<B>> p;
145 folly::MoveWrapper<F> funcm(std::forward<F>(func));
147 // grab the Future now before we lose our handle on the Promise
148 auto f = p->getFuture();
151 [p, funcm](Try<T>&& t) mutable {
153 auto f2 = (*funcm)(std::move(t));
154 // that didn't throw, now we can steal p
155 f2.setCallback_([p](Try<B>&& b) mutable {
156 p->fulfilTry(std::move(b));
159 p->setException(std::current_exception());
167 Future<void> Future<T>::then() {
168 return then([] (Try<T>&& t) {});
172 typename std::add_lvalue_reference<T>::type Future<T>::value() {
175 return state_->value();
179 typename std::add_lvalue_reference<const T>::type Future<T>::value() const {
182 return state_->value();
186 Try<T>& Future<T>::getTry() {
189 return state_->getTry();
193 template <typename Executor>
194 inline Future<T> Future<T>::via(Executor* executor) {
196 auto f = then([=](Try<T>&& t) {
197 MoveWrapper<Promise<T>> promise;
198 MoveWrapper<Try<T>> tw(std::move(t));
199 auto f2 = promise->getFuture();
200 executor->add([=]() mutable { promise->fulfilTry(std::move(*tw)); });
208 bool Future<T>::isReady() const {
210 return state_->ready();
216 Future<typename std::decay<T>::type> makeFuture(T&& t) {
217 Promise<typename std::decay<T>::type> p;
218 auto f = p.getFuture();
219 p.setValue(std::forward<T>(t));
223 inline // for multiple translation units
224 Future<void> makeFuture() {
226 auto f = p.getFuture();
234 typename std::enable_if<!std::is_reference<F>::value, bool>::type sdf)
235 -> Future<decltype(func())> {
236 Promise<decltype(func())> p;
237 auto f = p.getFuture();
246 auto makeFutureTry(F const& func) -> Future<decltype(func())> {
248 return makeFutureTry(std::move(copy));
252 Future<T> makeFuture(std::exception_ptr const& e) {
254 auto f = p.getFuture();
259 template <class T, class E>
260 typename std::enable_if<std::is_base_of<std::exception, E>::value, Future<T>>::type
261 makeFuture(E const& e) {
263 auto f = p.getFuture();
264 p.fulfil([&]() -> T { throw e; });
269 Future<T> makeFuture(Try<T>&& t) {
271 return makeFuture<T>(std::move(t.value()));
273 return makeFuture<T>(std::current_exception());
278 inline Future<void> makeFuture(Try<void>&& t) {
283 return makeFuture<void>(std::current_exception());
289 template <typename... Fs>
290 typename detail::VariadicContext<
291 typename std::decay<Fs>::type::value_type...>::type
295 new detail::VariadicContext<typename std::decay<Fs>::type::value_type...>();
296 ctx->total = sizeof...(fs);
297 auto f_saved = ctx->p.getFuture();
298 detail::whenAllVariadicHelper(ctx,
299 std::forward<typename std::decay<Fs>::type>(fs)...);
300 return std::move(f_saved);
305 template <class InputIterator>
308 Try<typename std::iterator_traits<InputIterator>::value_type::value_type>>>
309 whenAll(InputIterator first, InputIterator last)
312 typename std::iterator_traits<InputIterator>::value_type::value_type T;
314 auto n = std::distance(first, last);
316 return makeFuture(std::vector<Try<T>>());
319 auto ctx = new detail::WhenAllContext<T>();
322 ctx->results.resize(ctx->total);
324 auto f_saved = ctx->p.getFuture();
326 for (size_t i = 0; first != last; ++first, ++i) {
328 f.setCallback_([ctx, i](Try<T>&& t) {
329 ctx->results[i] = std::move(t);
330 if (++ctx->count == ctx->total) {
331 ctx->p.setValue(std::move(ctx->results));
337 return std::move(f_saved);
340 template <class InputIterator>
345 std::iterator_traits<InputIterator>::value_type::value_type> > >
346 whenAny(InputIterator first, InputIterator last) {
348 typename std::iterator_traits<InputIterator>::value_type::value_type T;
350 auto ctx = new detail::WhenAnyContext<T>(std::distance(first, last));
351 auto f_saved = ctx->p.getFuture();
353 for (size_t i = 0; first != last; first++, i++) {
355 f.setCallback_([i, ctx](Try<T>&& t) {
356 if (!ctx->done.exchange(true)) {
357 ctx->p.setValue(std::make_pair(i, std::move(t)));
363 return std::move(f_saved);
366 template <class InputIterator>
367 Future<std::vector<std::pair<size_t, Try<typename
368 std::iterator_traits<InputIterator>::value_type::value_type>>>>
369 whenN(InputIterator first, InputIterator last, size_t n) {
371 std::iterator_traits<InputIterator>::value_type::value_type T;
372 typedef std::vector<std::pair<size_t, Try<T>>> V;
379 auto ctx = std::make_shared<ctx_t>();
382 // for each completed Future, increase count and add to vector, until we
383 // have n completed futures at which point we fulfil our Promise with the
388 it->then([ctx, n, i](Try<T>&& t) {
390 auto c = ++ctx->completed;
392 assert(ctx->v.size() < n);
393 v.push_back(std::make_pair(i, std::move(t)));
395 ctx->p.fulfilTry(Try<V>(std::move(v)));
405 ctx->p.setException(std::runtime_error("Not enough futures"));
408 return ctx->p.getFuture();
411 template <typename T>
413 waitWithSemaphore(Future<T>&& f) {
415 auto done = f.then([&](Try<T> &&t) {
417 return std::move(t.value());
420 while (!done.isReady()) {
421 // There's a race here between the return here and the actual finishing of
422 // the future. f is completed, but the setup may not have finished on done
423 // after the baton has posted.
424 std::this_thread::yield();
430 inline Future<void> waitWithSemaphore<void>(Future<void>&& f) {
432 auto done = f.then([&](Try<void> &&t) {
437 while (!done.isReady()) {
438 // There's a race here between the return here and the actual finishing of
439 // the future. f is completed, but the setup may not have finished on done
440 // after the baton has posted.
441 std::this_thread::yield();
446 template <typename T, class Duration>
448 waitWithSemaphore(Future<T>&& f, Duration timeout) {
449 auto baton = std::make_shared<Baton<>>();
450 auto done = f.then([baton](Try<T> &&t) {
452 return std::move(t.value());
454 baton->timed_wait(std::chrono::system_clock::now() + timeout);
458 template <class Duration>
460 waitWithSemaphore(Future<void>&& f, Duration timeout) {
461 auto baton = std::make_shared<Baton<>>();
462 auto done = f.then([baton](Try<void> &&t) {
466 baton->timed_wait(std::chrono::system_clock::now() + timeout);
472 // I haven't included a Future<T&> specialization because I don't forsee us
473 // using it, however it is not difficult to add when needed. Refer to
474 // Future<void> for guidance. std::future and boost::future code would also be