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>::valueTry() {
184 return obj_->valueTry();
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<typename Fs::value_type...>::type
288 auto ctx = new detail::VariadicContext<typename Fs::value_type...>();
289 ctx->total = sizeof...(fs);
290 auto f_saved = ctx->p.getFuture();
291 detail::whenAllVariadicHelper(ctx, fs...);
292 return std::move(f_saved);
297 template <class InputIterator>
300 Try<typename std::iterator_traits<InputIterator>::value_type::value_type>>>
301 whenAll(InputIterator first, InputIterator last)
304 typename std::iterator_traits<InputIterator>::value_type::value_type T;
306 auto n = std::distance(first, last);
308 return makeFuture<std::vector<Try<T>>>({});
310 auto ctx = new detail::WhenAllContext<T>();
313 ctx->results.resize(ctx->total);
315 auto f_saved = ctx->p.getFuture();
317 for (size_t i = 0; first != last; ++first, ++i) {
319 f.setContinuation([ctx, i](Try<T>&& t) {
320 ctx->results[i] = std::move(t);
321 if (++ctx->count == ctx->total) {
322 ctx->p.setValue(std::move(ctx->results));
328 return std::move(f_saved);
331 template <class InputIterator>
336 std::iterator_traits<InputIterator>::value_type::value_type> > >
337 whenAny(InputIterator first, InputIterator last) {
339 typename std::iterator_traits<InputIterator>::value_type::value_type T;
341 auto ctx = new detail::WhenAnyContext<T>(std::distance(first, last));
342 auto f_saved = ctx->p.getFuture();
344 for (size_t i = 0; first != last; first++, i++) {
346 f.setContinuation([i, ctx](Try<T>&& t) {
347 if (!ctx->done.exchange(true)) {
348 ctx->p.setValue(std::make_pair(i, std::move(t)));
354 return std::move(f_saved);
357 template <class InputIterator>
358 Future<std::vector<std::pair<size_t, Try<typename
359 std::iterator_traits<InputIterator>::value_type::value_type>>>>
360 whenN(InputIterator first, InputIterator last, size_t n) {
362 std::iterator_traits<InputIterator>::value_type::value_type T;
363 typedef std::vector<std::pair<size_t, Try<T>>> V;
370 auto ctx = std::make_shared<ctx_t>();
373 // for each completed Future, increase count and add to vector, until we
374 // have n completed futures at which point we fulfil our Promise with the
379 it->then([ctx, n, i](Try<T>&& t) {
381 auto c = ++ctx->completed;
383 assert(ctx->v.size() < n);
384 v.push_back(std::make_pair(i, std::move(t)));
386 ctx->p.fulfilTry(Try<V>(std::move(v)));
396 ctx->p.setException(std::runtime_error("Not enough futures"));
399 return ctx->p.getFuture();