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 namespace folly { namespace wangle {
25 static const bool value = false;
29 struct isFuture<Future<T> > {
30 static const bool value = true;
34 Future<T>::Future(Future<T>&& other) : obj_(other.obj_) {
39 Future<T>& Future<T>::operator=(Future<T>&& other) {
40 std::swap(obj_, other.obj_);
45 Future<T>::~Future() {
47 setContinuation([](Try<T>&&) {}); // detach
52 void Future<T>::throwIfInvalid() const {
59 void Future<T>::setContinuation(F&& func) {
61 obj_->setContinuation(std::move(func));
67 typename std::enable_if<
68 !isFuture<typename std::result_of<F(Try<T>&&)>::type>::value,
69 Future<typename std::result_of<F(Try<T>&&)>::type> >::type
70 Future<T>::then(F&& func) {
71 typedef typename std::result_of<F(Try<T>&&)>::type B;
75 // wrap these so we can move them into the lambda
76 folly::MoveWrapper<Promise<B>> p;
77 folly::MoveWrapper<F> funcm(std::forward<F>(func));
79 // grab the Future now before we lose our handle on the Promise
80 auto f = p->getFuture();
82 /* This is a bit tricky.
84 We can't just close over *this in case this Future gets moved. So we
85 make a new dummy Future. We could figure out something more
86 sophisticated that avoids making a new Future object when it can, as an
87 optimization. But this is correct.
89 obj_ can't be moved, it is explicitly disallowed (as is copying). But
90 if there's ever a reason to allow it, this is one place that makes that
91 assumption and would need to be fixed. We use a standard shared pointer
92 for obj_ (by copying it in), which means in essence obj holds a shared
93 pointer to itself. But this shouldn't leak because Promise will not
94 outlive the continuation, because Promise will setException() with a
95 broken Promise if it is destructed before completed. We could use a
96 weak pointer but it would have to be converted to a shared pointer when
97 func is executed (because the Future returned by func may possibly
98 persist beyond the callback, if it gets moved), and so it is an
99 optimization to just make it shared from the get-go.
101 We have to move in the Promise and func using the MoveWrapper
102 hack. (func could be copied but it's a big drag on perf).
104 Two subtle but important points about this design. FutureObject has no
105 back pointers to Future or Promise, so if Future or Promise get moved
106 (and they will be moved in performant code) we don't have to do
107 anything fancy. And because we store the continuation in the
108 FutureObject, not in the Future, we can execute the continuation even
109 after the Future has gone out of scope. This is an intentional design
110 decision. It is likely we will want to be able to cancel a continuation
111 in some circumstances, but I think it should be explicit not implicit
112 in the destruction of the Future used to create it.
115 [p, funcm](Try<T>&& t) mutable {
117 return (*funcm)(std::move(t));
126 typename std::enable_if<
127 isFuture<typename std::result_of<F(Try<T>&&)>::type>::value,
128 Future<typename std::result_of<F(Try<T>&&)>::type::value_type> >::type
129 Future<T>::then(F&& func) {
130 typedef typename std::result_of<F(Try<T>&&)>::type::value_type B;
134 // wrap these so we can move them into the lambda
135 folly::MoveWrapper<Promise<B>> p;
136 folly::MoveWrapper<F> funcm(std::forward<F>(func));
138 // grab the Future now before we lose our handle on the Promise
139 auto f = p->getFuture();
142 [p, funcm](Try<T>&& t) mutable {
144 auto f2 = (*funcm)(std::move(t));
145 // that didn't throw, now we can steal p
146 f2.setContinuation([p](Try<B>&& b) mutable {
147 p->fulfilTry(std::move(b));
150 p->setException(std::current_exception());
158 Future<void> Future<T>::then() {
159 return then([] (Try<T>&& t) {});
163 typename std::add_lvalue_reference<T>::type Future<T>::value() {
166 return obj_->value();
170 typename std::add_lvalue_reference<const T>::type Future<T>::value() const {
173 return obj_->value();
177 Try<T>& Future<T>::getTry() {
180 return obj_->getTry();
184 template <typename Executor>
185 inline Future<T> Future<T>::via(Executor* executor) {
188 folly::MoveWrapper<Promise<T>> p;
189 auto f = p->getFuture();
191 setContinuation([executor, p](Try<T>&& t) mutable {
192 folly::MoveWrapper<Try<T>> tt(std::move(t));
193 executor->add([p, tt]() mutable {
194 p->fulfilTry(std::move(*tt));
202 template <typename Executor>
203 inline void Future<T>::executeWith(
204 Executor* executor, Promise<T>&& cont_promise) {
207 folly::MoveWrapper<Promise<T>> p(std::move(cont_promise));
209 setContinuation([executor, p](Try<T>&& t) mutable {
210 folly::MoveWrapper<Try<T>> tt(std::move(t));
211 executor->add([p, tt]() mutable {
212 p->fulfilTry(std::move(*tt));
218 bool Future<T>::isReady() const {
220 return obj_->ready();
226 Future<typename std::decay<T>::type> makeFuture(T&& t) {
227 Promise<typename std::decay<T>::type> p;
228 auto f = p.getFuture();
229 p.setValue(std::forward<T>(t));
233 inline // for multiple translation units
234 Future<void> makeFuture() {
236 auto f = p.getFuture();
244 typename std::enable_if<!std::is_reference<F>::value, bool>::type sdf)
245 -> Future<decltype(func())> {
246 Promise<decltype(func())> p;
247 auto f = p.getFuture();
256 auto makeFutureTry(F const& func) -> Future<decltype(func())> {
258 return makeFutureTry(std::move(copy));
262 Future<T> makeFuture(std::exception_ptr const& e) {
264 auto f = p.getFuture();
269 template <class T, class E>
270 typename std::enable_if<std::is_base_of<std::exception, E>::value, Future<T>>::type
271 makeFuture(E const& e) {
273 auto f = p.getFuture();
274 p.fulfil([&]() -> T { throw e; });
279 Future<T> makeFuture(Try<T>&& t) {
281 return makeFuture<T>(std::move(t.value()));
283 return makeFuture<T>(std::current_exception());
288 inline Future<void> makeFuture(Try<void>&& t) {
293 return makeFuture<void>(std::current_exception());
299 template <typename... Fs>
300 typename detail::VariadicContext<
301 typename std::decay<Fs>::type::value_type...>::type
305 new detail::VariadicContext<typename std::decay<Fs>::type::value_type...>();
306 ctx->total = sizeof...(fs);
307 auto f_saved = ctx->p.getFuture();
308 detail::whenAllVariadicHelper(ctx,
309 std::forward<typename std::decay<Fs>::type>(fs)...);
310 return std::move(f_saved);
315 template <class InputIterator>
318 Try<typename std::iterator_traits<InputIterator>::value_type::value_type>>>
319 whenAll(InputIterator first, InputIterator last)
322 typename std::iterator_traits<InputIterator>::value_type::value_type T;
324 auto n = std::distance(first, last);
326 return makeFuture(std::vector<Try<T>>());
329 auto ctx = new detail::WhenAllContext<T>();
332 ctx->results.resize(ctx->total);
334 auto f_saved = ctx->p.getFuture();
336 for (size_t i = 0; first != last; ++first, ++i) {
338 f.setContinuation([ctx, i](Try<T>&& t) {
339 ctx->results[i] = std::move(t);
340 if (++ctx->count == ctx->total) {
341 ctx->p.setValue(std::move(ctx->results));
347 return std::move(f_saved);
350 template <class InputIterator>
355 std::iterator_traits<InputIterator>::value_type::value_type> > >
356 whenAny(InputIterator first, InputIterator last) {
358 typename std::iterator_traits<InputIterator>::value_type::value_type T;
360 auto ctx = new detail::WhenAnyContext<T>(std::distance(first, last));
361 auto f_saved = ctx->p.getFuture();
363 for (size_t i = 0; first != last; first++, i++) {
365 f.setContinuation([i, ctx](Try<T>&& t) {
366 if (!ctx->done.exchange(true)) {
367 ctx->p.setValue(std::make_pair(i, std::move(t)));
373 return std::move(f_saved);
376 template <class InputIterator>
377 Future<std::vector<std::pair<size_t, Try<typename
378 std::iterator_traits<InputIterator>::value_type::value_type>>>>
379 whenN(InputIterator first, InputIterator last, size_t n) {
381 std::iterator_traits<InputIterator>::value_type::value_type T;
382 typedef std::vector<std::pair<size_t, Try<T>>> V;
389 auto ctx = std::make_shared<ctx_t>();
392 // for each completed Future, increase count and add to vector, until we
393 // have n completed futures at which point we fulfil our Promise with the
398 it->then([ctx, n, i](Try<T>&& t) {
400 auto c = ++ctx->completed;
402 assert(ctx->v.size() < n);
403 v.push_back(std::make_pair(i, std::move(t)));
405 ctx->p.fulfilTry(Try<V>(std::move(v)));
415 ctx->p.setException(std::runtime_error("Not enough futures"));
418 return ctx->p.getFuture();
423 // I haven't included a Future<T&> specialization because I don't forsee us
424 // using it, however it is not difficult to add when needed. Refer to
425 // Future<void> for guidance. std::future and boost::future code would also be