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() {
50 setContinuation([](Try<T>&&) {}); // detach
56 void Future<T>::throwIfInvalid() const {
63 void Future<T>::setContinuation(F&& func) {
65 obj_->setContinuation(std::move(func));
71 typename std::enable_if<
72 !isFuture<typename std::result_of<F(Try<T>&&)>::type>::value,
73 Future<typename std::result_of<F(Try<T>&&)>::type> >::type
74 Future<T>::then(F&& func) {
75 typedef typename std::result_of<F(Try<T>&&)>::type B;
79 // wrap these so we can move them into the lambda
80 folly::MoveWrapper<Promise<B>> p;
81 folly::MoveWrapper<F> funcm(std::forward<F>(func));
83 // grab the Future now before we lose our handle on the Promise
84 auto f = p->getFuture();
86 /* This is a bit tricky.
88 We can't just close over *this in case this Future gets moved. So we
89 make a new dummy Future. We could figure out something more
90 sophisticated that avoids making a new Future object when it can, as an
91 optimization. But this is correct.
93 obj_ can't be moved, it is explicitly disallowed (as is copying). But
94 if there's ever a reason to allow it, this is one place that makes that
95 assumption and would need to be fixed. We use a standard shared pointer
96 for obj_ (by copying it in), which means in essence obj holds a shared
97 pointer to itself. But this shouldn't leak because Promise will not
98 outlive the continuation, because Promise will setException() with a
99 broken Promise if it is destructed before completed. We could use a
100 weak pointer but it would have to be converted to a shared pointer when
101 func is executed (because the Future returned by func may possibly
102 persist beyond the callback, if it gets moved), and so it is an
103 optimization to just make it shared from the get-go.
105 We have to move in the Promise and func using the MoveWrapper
106 hack. (func could be copied but it's a big drag on perf).
108 Two subtle but important points about this design. FutureObject has no
109 back pointers to Future or Promise, so if Future or Promise get moved
110 (and they will be moved in performant code) we don't have to do
111 anything fancy. And because we store the continuation in the
112 FutureObject, not in the Future, we can execute the continuation even
113 after the Future has gone out of scope. This is an intentional design
114 decision. It is likely we will want to be able to cancel a continuation
115 in some circumstances, but I think it should be explicit not implicit
116 in the destruction of the Future used to create it.
119 [p, funcm](Try<T>&& t) mutable {
121 return (*funcm)(std::move(t));
130 typename std::enable_if<
131 isFuture<typename std::result_of<F(Try<T>&&)>::type>::value,
132 Future<typename std::result_of<F(Try<T>&&)>::type::value_type> >::type
133 Future<T>::then(F&& func) {
134 typedef typename std::result_of<F(Try<T>&&)>::type::value_type B;
138 // wrap these so we can move them into the lambda
139 folly::MoveWrapper<Promise<B>> p;
140 folly::MoveWrapper<F> funcm(std::forward<F>(func));
142 // grab the Future now before we lose our handle on the Promise
143 auto f = p->getFuture();
146 [p, funcm](Try<T>&& t) mutable {
148 auto f2 = (*funcm)(std::move(t));
149 // that didn't throw, now we can steal p
150 f2.setContinuation([p](Try<B>&& b) mutable {
151 p->fulfilTry(std::move(b));
154 p->setException(std::current_exception());
162 Future<void> Future<T>::then() {
163 return then([] (Try<T>&& t) {});
167 typename std::add_lvalue_reference<T>::type Future<T>::value() {
170 return obj_->value();
174 typename std::add_lvalue_reference<const T>::type Future<T>::value() const {
177 return obj_->value();
181 Try<T>& Future<T>::getTry() {
184 return obj_->getTry();
188 template <typename Executor>
189 inline Future<T> Future<T>::executeWithSameThread(Executor* executor) {
192 folly::MoveWrapper<Promise<T>> p;
193 auto f = p->getFuture();
195 setContinuation([executor, p](Try<T>&& t) mutable {
196 folly::MoveWrapper<Try<T>> tt(std::move(t));
197 executor->add([p, tt]() mutable {
198 p->fulfilTry(std::move(*tt));
206 template <typename Executor>
207 inline void Future<T>::executeWith(
208 Executor* executor, Promise<T>&& cont_promise) {
211 folly::MoveWrapper<Promise<T>> p(std::move(cont_promise));
213 setContinuation([executor, p](Try<T>&& t) mutable {
214 folly::MoveWrapper<Try<T>> tt(std::move(t));
215 executor->add([p, tt]() mutable {
216 p->fulfilTry(std::move(*tt));
222 bool Future<T>::isReady() const {
224 return obj_->ready();
230 Future<typename std::decay<T>::type> makeFuture(T&& t) {
231 Promise<typename std::decay<T>::type> p;
232 auto f = p.getFuture();
233 p.setValue(std::forward<T>(t));
237 inline // for multiple translation units
238 Future<void> makeFuture() {
240 auto f = p.getFuture();
248 typename std::enable_if<!std::is_reference<F>::value, bool>::type sdf)
249 -> Future<decltype(func())> {
250 Promise<decltype(func())> p;
251 auto f = p.getFuture();
260 auto makeFutureTry(F const& func) -> Future<decltype(func())> {
262 return makeFutureTry(std::move(copy));
266 Future<T> makeFuture(std::exception_ptr const& e) {
268 auto f = p.getFuture();
273 template <class T, class E>
274 typename std::enable_if<std::is_base_of<std::exception, E>::value, Future<T>>::type
275 makeFuture(E const& e) {
277 auto f = p.getFuture();
278 p.fulfil([&]() -> T { throw e; });
284 template <typename... Fs>
285 typename detail::VariadicContext<
286 typename std::decay<Fs>::type::value_type...>::type
290 new detail::VariadicContext<typename std::decay<Fs>::type::value_type...>();
291 ctx->total = sizeof...(fs);
292 auto f_saved = ctx->p.getFuture();
293 detail::whenAllVariadicHelper(ctx,
294 std::forward<typename std::decay<Fs>::type>(fs)...);
295 return std::move(f_saved);
300 template <class InputIterator>
303 Try<typename std::iterator_traits<InputIterator>::value_type::value_type>>>
304 whenAll(InputIterator first, InputIterator last)
307 typename std::iterator_traits<InputIterator>::value_type::value_type T;
309 auto n = std::distance(first, last);
311 return makeFuture<std::vector<Try<T>>>({});
313 auto ctx = new detail::WhenAllContext<T>();
316 ctx->results.resize(ctx->total);
318 auto f_saved = ctx->p.getFuture();
320 for (size_t i = 0; first != last; ++first, ++i) {
322 f.setContinuation([ctx, i](Try<T>&& t) {
323 ctx->results[i] = std::move(t);
324 if (++ctx->count == ctx->total) {
325 ctx->p.setValue(std::move(ctx->results));
331 return std::move(f_saved);
334 template <class InputIterator>
339 std::iterator_traits<InputIterator>::value_type::value_type> > >
340 whenAny(InputIterator first, InputIterator last) {
342 typename std::iterator_traits<InputIterator>::value_type::value_type T;
344 auto ctx = new detail::WhenAnyContext<T>(std::distance(first, last));
345 auto f_saved = ctx->p.getFuture();
347 for (size_t i = 0; first != last; first++, i++) {
349 f.setContinuation([i, ctx](Try<T>&& t) {
350 if (!ctx->done.exchange(true)) {
351 ctx->p.setValue(std::make_pair(i, std::move(t)));
357 return std::move(f_saved);
360 template <class InputIterator>
361 Future<std::vector<std::pair<size_t, Try<typename
362 std::iterator_traits<InputIterator>::value_type::value_type>>>>
363 whenN(InputIterator first, InputIterator last, size_t n) {
365 std::iterator_traits<InputIterator>::value_type::value_type T;
366 typedef std::vector<std::pair<size_t, Try<T>>> V;
373 auto ctx = std::make_shared<ctx_t>();
376 // for each completed Future, increase count and add to vector, until we
377 // have n completed futures at which point we fulfil our Promise with the
382 it->then([ctx, n, i](Try<T>&& t) {
384 auto c = ++ctx->completed;
386 assert(ctx->v.size() < n);
387 v.push_back(std::make_pair(i, std::move(t)));
389 ctx->p.fulfilTry(Try<V>(std::move(v)));
399 ctx->p.setException(std::runtime_error("Not enough futures"));
402 return ctx->p.getFuture();
407 // I haven't included a Future<T&> specialization because I don't forsee us
408 // using it, however it is not difficult to add when needed. Refer to
409 // Future<void> for guidance. std::future and boost::future code would also be