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.
21 #include <folly/wangle/detail/State.h>
22 #include <folly/Baton.h>
24 namespace folly { namespace wangle {
28 static const bool value = false;
32 struct isFuture<Future<T> > {
33 static const bool value = true;
37 Future<T>::Future(Future<T>&& other) noexcept : state_(nullptr) {
38 *this = std::move(other);
42 Future<T>& Future<T>::operator=(Future<T>&& other) {
43 std::swap(state_, other.state_);
48 Future<T>::~Future() {
53 void Future<T>::detach() {
55 state_->detachFuture();
61 void Future<T>::throwIfInvalid() const {
68 void Future<T>::setCallback_(F&& func) {
70 state_->setCallback(std::move(func));
75 typename std::enable_if<
76 !isFuture<typename std::result_of<F(Try<T>&&)>::type>::value,
77 Future<typename std::result_of<F(Try<T>&&)>::type> >::type
78 Future<T>::then(F&& func) {
79 typedef typename std::result_of<F(Try<T>&&)>::type B;
83 // wrap these so we can move them into the lambda
84 folly::MoveWrapper<Promise<B>> p;
85 folly::MoveWrapper<F> funcm(std::forward<F>(func));
87 // grab the Future now before we lose our handle on the Promise
88 auto f = p->getFuture();
90 /* This is a bit tricky.
92 We can't just close over *this in case this Future gets moved. So we
93 make a new dummy Future. We could figure out something more
94 sophisticated that avoids making a new Future object when it can, as an
95 optimization. But this is correct.
97 state_ can't be moved, it is explicitly disallowed (as is copying). But
98 if there's ever a reason to allow it, this is one place that makes that
99 assumption and would need to be fixed. We use a standard shared pointer
100 for state_ (by copying it in), which means in essence obj holds a shared
101 pointer to itself. But this shouldn't leak because Promise will not
102 outlive the continuation, because Promise will setException() with a
103 broken Promise if it is destructed before completed. We could use a
104 weak pointer but it would have to be converted to a shared pointer when
105 func is executed (because the Future returned by func may possibly
106 persist beyond the callback, if it gets moved), and so it is an
107 optimization to just make it shared from the get-go.
109 We have to move in the Promise and func using the MoveWrapper
110 hack. (func could be copied but it's a big drag on perf).
112 Two subtle but important points about this design. detail::State has no
113 back pointers to Future or Promise, so if Future or Promise get moved
114 (and they will be moved in performant code) we don't have to do
115 anything fancy. And because we store the continuation in the
116 detail::State, not in the Future, we can execute the continuation even
117 after the Future has gone out of scope. This is an intentional design
118 decision. It is likely we will want to be able to cancel a continuation
119 in some circumstances, but I think it should be explicit not implicit
120 in the destruction of the Future used to create it.
123 [p, funcm](Try<T>&& t) mutable {
125 return (*funcm)(std::move(t));
134 typename std::enable_if<
135 isFuture<typename std::result_of<F(Try<T>&&)>::type>::value,
136 Future<typename std::result_of<F(Try<T>&&)>::type::value_type> >::type
137 Future<T>::then(F&& func) {
138 typedef typename std::result_of<F(Try<T>&&)>::type::value_type B;
142 // wrap these so we can move them into the lambda
143 folly::MoveWrapper<Promise<B>> p;
144 folly::MoveWrapper<F> funcm(std::forward<F>(func));
146 // grab the Future now before we lose our handle on the Promise
147 auto f = p->getFuture();
150 [p, funcm](Try<T>&& t) mutable {
152 auto f2 = (*funcm)(std::move(t));
153 // that didn't throw, now we can steal p
154 f2.setCallback_([p](Try<B>&& b) mutable {
155 p->fulfilTry(std::move(b));
158 p->setException(std::current_exception());
166 Future<void> Future<T>::then() {
167 return then([] (Try<T>&& t) {});
171 typename std::add_lvalue_reference<T>::type Future<T>::value() {
174 return state_->value();
178 typename std::add_lvalue_reference<const T>::type Future<T>::value() const {
181 return state_->value();
185 Try<T>& Future<T>::getTry() {
188 return state_->getTry();
192 template <typename Executor>
193 inline Future<T> Future<T>::via(Executor* executor) {
195 auto f = then([=](Try<T>&& t) {
196 MoveWrapper<Promise<T>> promise;
197 MoveWrapper<Try<T>> tw(std::move(t));
198 auto f2 = promise->getFuture();
199 executor->add([=]() mutable { promise->fulfilTry(std::move(*tw)); });
207 bool Future<T>::isReady() const {
209 return state_->ready();
215 Future<typename std::decay<T>::type> makeFuture(T&& t) {
216 Promise<typename std::decay<T>::type> p;
217 auto f = p.getFuture();
218 p.setValue(std::forward<T>(t));
222 inline // for multiple translation units
223 Future<void> makeFuture() {
225 auto f = p.getFuture();
233 typename std::enable_if<!std::is_reference<F>::value, bool>::type sdf)
234 -> Future<decltype(func())> {
235 Promise<decltype(func())> p;
236 auto f = p.getFuture();
245 auto makeFutureTry(F const& func) -> Future<decltype(func())> {
247 return makeFutureTry(std::move(copy));
251 Future<T> makeFuture(std::exception_ptr const& e) {
253 auto f = p.getFuture();
258 template <class T, class E>
259 typename std::enable_if<std::is_base_of<std::exception, E>::value, Future<T>>::type
260 makeFuture(E const& e) {
262 auto f = p.getFuture();
263 p.fulfil([&]() -> T { throw e; });
268 Future<T> makeFuture(Try<T>&& t) {
270 return makeFuture<T>(std::move(t.value()));
272 return makeFuture<T>(std::current_exception());
277 inline Future<void> makeFuture(Try<void>&& t) {
282 return makeFuture<void>(std::current_exception());
288 template <typename... Fs>
289 typename detail::VariadicContext<
290 typename std::decay<Fs>::type::value_type...>::type
294 new detail::VariadicContext<typename std::decay<Fs>::type::value_type...>();
295 ctx->total = sizeof...(fs);
296 auto f_saved = ctx->p.getFuture();
297 detail::whenAllVariadicHelper(ctx,
298 std::forward<typename std::decay<Fs>::type>(fs)...);
299 return std::move(f_saved);
304 template <class InputIterator>
307 Try<typename std::iterator_traits<InputIterator>::value_type::value_type>>>
308 whenAll(InputIterator first, InputIterator last)
311 typename std::iterator_traits<InputIterator>::value_type::value_type T;
313 auto n = std::distance(first, last);
315 return makeFuture(std::vector<Try<T>>());
318 auto ctx = new detail::WhenAllContext<T>();
321 ctx->results.resize(ctx->total);
323 auto f_saved = ctx->p.getFuture();
325 for (size_t i = 0; first != last; ++first, ++i) {
327 f.setCallback_([ctx, i](Try<T>&& t) {
328 ctx->results[i] = std::move(t);
329 if (++ctx->count == ctx->total) {
330 ctx->p.setValue(std::move(ctx->results));
336 return std::move(f_saved);
339 template <class InputIterator>
344 std::iterator_traits<InputIterator>::value_type::value_type> > >
345 whenAny(InputIterator first, InputIterator last) {
347 typename std::iterator_traits<InputIterator>::value_type::value_type T;
349 auto ctx = new detail::WhenAnyContext<T>(std::distance(first, last));
350 auto f_saved = ctx->p.getFuture();
352 for (size_t i = 0; first != last; first++, i++) {
354 f.setCallback_([i, ctx](Try<T>&& t) {
355 if (!ctx->done.exchange(true)) {
356 ctx->p.setValue(std::make_pair(i, std::move(t)));
362 return std::move(f_saved);
365 template <class InputIterator>
366 Future<std::vector<std::pair<size_t, Try<typename
367 std::iterator_traits<InputIterator>::value_type::value_type>>>>
368 whenN(InputIterator first, InputIterator last, size_t n) {
370 std::iterator_traits<InputIterator>::value_type::value_type T;
371 typedef std::vector<std::pair<size_t, Try<T>>> V;
378 auto ctx = std::make_shared<ctx_t>();
381 // for each completed Future, increase count and add to vector, until we
382 // have n completed futures at which point we fulfil our Promise with the
387 it->then([ctx, n, i](Try<T>&& t) {
389 auto c = ++ctx->completed;
391 assert(ctx->v.size() < n);
392 v.push_back(std::make_pair(i, std::move(t)));
394 ctx->p.fulfilTry(Try<V>(std::move(v)));
404 ctx->p.setException(std::runtime_error("Not enough futures"));
407 return ctx->p.getFuture();
410 template <typename T>
412 waitWithSemaphore(Future<T>&& f) {
414 auto done = f.then([&](Try<T> &&t) {
416 return std::move(t.value());
423 inline Future<void> waitWithSemaphore<void>(Future<void>&& f) {
425 auto done = f.then([&](Try<void> &&t) {
433 template <typename T, class Duration>
435 waitWithSemaphore(Future<T>&& f, Duration timeout) {
436 auto baton = std::make_shared<Baton<>>();
437 auto done = f.then([baton](Try<T> &&t) {
439 return std::move(t.value());
441 baton->timed_wait(std::chrono::system_clock::now() + timeout);
445 template <class Duration>
447 waitWithSemaphore(Future<void>&& f, Duration timeout) {
448 auto baton = std::make_shared<Baton<>>();
449 auto done = f.then([baton](Try<void> &&t) {
453 baton->timed_wait(std::chrono::system_clock::now() + timeout);
459 // I haven't included a Future<T&> specialization because I don't forsee us
460 // using it, however it is not difficult to add when needed. Refer to
461 // Future<void> for guidance. std::future and boost::future code would also be