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; });
280 template <typename... Fs>
281 typename detail::VariadicContext<
282 typename std::decay<Fs>::type::value_type...>::type
286 new detail::VariadicContext<typename std::decay<Fs>::type::value_type...>();
287 ctx->total = sizeof...(fs);
288 auto f_saved = ctx->p.getFuture();
289 detail::whenAllVariadicHelper(ctx,
290 std::forward<typename std::decay<Fs>::type>(fs)...);
291 return std::move(f_saved);
296 template <class InputIterator>
299 Try<typename std::iterator_traits<InputIterator>::value_type::value_type>>>
300 whenAll(InputIterator first, InputIterator last)
303 typename std::iterator_traits<InputIterator>::value_type::value_type T;
305 auto n = std::distance(first, last);
307 return makeFuture<std::vector<Try<T>>>({});
309 auto ctx = new detail::WhenAllContext<T>();
312 ctx->results.resize(ctx->total);
314 auto f_saved = ctx->p.getFuture();
316 for (size_t i = 0; first != last; ++first, ++i) {
318 f.setContinuation([ctx, i](Try<T>&& t) {
319 ctx->results[i] = std::move(t);
320 if (++ctx->count == ctx->total) {
321 ctx->p.setValue(std::move(ctx->results));
327 return std::move(f_saved);
330 template <class InputIterator>
335 std::iterator_traits<InputIterator>::value_type::value_type> > >
336 whenAny(InputIterator first, InputIterator last) {
338 typename std::iterator_traits<InputIterator>::value_type::value_type T;
340 auto ctx = new detail::WhenAnyContext<T>(std::distance(first, last));
341 auto f_saved = ctx->p.getFuture();
343 for (size_t i = 0; first != last; first++, i++) {
345 f.setContinuation([i, ctx](Try<T>&& t) {
346 if (!ctx->done.exchange(true)) {
347 ctx->p.setValue(std::make_pair(i, std::move(t)));
353 return std::move(f_saved);
356 template <class InputIterator>
357 Future<std::vector<std::pair<size_t, Try<typename
358 std::iterator_traits<InputIterator>::value_type::value_type>>>>
359 whenN(InputIterator first, InputIterator last, size_t n) {
361 std::iterator_traits<InputIterator>::value_type::value_type T;
362 typedef std::vector<std::pair<size_t, Try<T>>> V;
369 auto ctx = std::make_shared<ctx_t>();
372 // for each completed Future, increase count and add to vector, until we
373 // have n completed futures at which point we fulfil our Promise with the
378 it->then([ctx, n, i](Try<T>&& t) {
380 auto c = ++ctx->completed;
382 assert(ctx->v.size() < n);
383 v.push_back(std::make_pair(i, std::move(t)));
385 ctx->p.fulfilTry(Try<V>(std::move(v)));
395 ctx->p.setException(std::runtime_error("Not enough futures"));
398 return ctx->p.getFuture();
403 // I haven't included a Future<T&> specialization because I don't forsee us
404 // using it, however it is not difficult to add when needed. Refer to
405 // Future<void> for guidance. std::future and boost::future code would also be