8d8af26718359f9e9d290410791f242640eba08c
[folly.git] / folly / wangle / Future-inl.h
1 /*
2  * Copyright 2014 Facebook, Inc.
3  *
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
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #pragma once
18
19 #include "detail.h"
20
21 namespace folly { namespace wangle {
22
23 template <typename T>
24 struct isFuture {
25   static const bool value = false;
26 };
27
28 template <typename T>
29 struct isFuture<Future<T> > {
30   static const bool value = true;
31 };
32
33 template <class T>
34 Future<T>::Future(Future<T>&& other) : obj_(other.obj_) {
35   other.obj_ = nullptr;
36 }
37
38 template <class T>
39 Future<T>& Future<T>::operator=(Future<T>&& other) {
40   std::swap(obj_, other.obj_);
41   return *this;
42 }
43
44 template <class T>
45 Future<T>::~Future() {
46   if (obj_) {
47     setContinuation([](Try<T>&&) {}); // detach
48   }
49 }
50
51 template <class T>
52 void Future<T>::throwIfInvalid() const {
53   if (!obj_)
54     throw NoState();
55 }
56
57 template <class T>
58 template <class F>
59 void Future<T>::setContinuation(F&& func) {
60   throwIfInvalid();
61   obj_->setContinuation(std::move(func));
62   obj_ = nullptr;
63 }
64
65 template <class T>
66 template <class F>
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;
72
73   throwIfInvalid();
74
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));
78
79   // grab the Future now before we lose our handle on the Promise
80   auto f = p->getFuture();
81
82   /* This is a bit tricky.
83
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.
88
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.
100
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).
103
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.
113      */
114   setContinuation(
115     [p, funcm](Try<T>&& t) mutable {
116       p->fulfil([&]() {
117           return (*funcm)(std::move(t));
118         });
119     });
120
121   return std::move(f);
122 }
123
124 template <class T>
125 template <class F>
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;
131
132   throwIfInvalid();
133
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));
137
138   // grab the Future now before we lose our handle on the Promise
139   auto f = p->getFuture();
140
141   setContinuation(
142     [p, funcm](Try<T>&& t) mutable {
143       try {
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));
148           });
149       } catch (...) {
150         p->setException(std::current_exception());
151       }
152     });
153
154   return std::move(f);
155 }
156
157 template <class T>
158 Future<void> Future<T>::then() {
159   return then([] (Try<T>&& t) {});
160 }
161
162 template <class T>
163 typename std::add_lvalue_reference<T>::type Future<T>::value() {
164   throwIfInvalid();
165
166   return obj_->value();
167 }
168
169 template <class T>
170 typename std::add_lvalue_reference<const T>::type Future<T>::value() const {
171   throwIfInvalid();
172
173   return obj_->value();
174 }
175
176 template <class T>
177 Try<T>& Future<T>::getTry() {
178   throwIfInvalid();
179
180   return obj_->getTry();
181 }
182
183 template <class T>
184 template <typename Executor>
185 inline Future<T> Future<T>::via(Executor* executor) {
186   throwIfInvalid();
187
188   folly::MoveWrapper<Promise<T>> p;
189   auto f = p->getFuture();
190
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));
195         });
196     });
197
198   return f;
199 }
200
201 template <class T>
202 template <typename Executor>
203 inline void Future<T>::executeWith(
204     Executor* executor, Promise<T>&& cont_promise) {
205   throwIfInvalid();
206
207   folly::MoveWrapper<Promise<T>> p(std::move(cont_promise));
208
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));
213         });
214     });
215 }
216
217 template <class T>
218 bool Future<T>::isReady() const {
219   throwIfInvalid();
220   return obj_->ready();
221 }
222
223 // makeFuture
224
225 template <class T>
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));
230   return std::move(f);
231 }
232
233 inline // for multiple translation units
234 Future<void> makeFuture() {
235   Promise<void> p;
236   auto f = p.getFuture();
237   p.setValue();
238   return std::move(f);
239 }
240
241 template <class F>
242 auto makeFutureTry(
243     F&& func,
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();
248   p.fulfil(
249     [&func]() {
250       return (func)();
251     });
252   return std::move(f);
253 }
254
255 template <class F>
256 auto makeFutureTry(F const& func) -> Future<decltype(func())> {
257   F copy = func;
258   return makeFutureTry(std::move(copy));
259 }
260
261 template <class T>
262 Future<T> makeFuture(std::exception_ptr const& e) {
263   Promise<T> p;
264   auto f = p.getFuture();
265   p.setException(e);
266   return std::move(f);
267 }
268
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) {
272   Promise<T> p;
273   auto f = p.getFuture();
274   p.fulfil([&]() -> T { throw e; });
275   return std::move(f);
276 }
277
278 template <class T>
279 Future<T> makeFuture(Try<T>&& t) {
280   try {
281     return makeFuture<T>(std::move(t.value()));
282   } catch (...) {
283     return makeFuture<T>(std::current_exception());
284   }
285 }
286
287 template <>
288 inline Future<void> makeFuture(Try<void>&& t) {
289   try {
290     t.throwIfFailed();
291     return makeFuture();
292   } catch (...) {
293     return makeFuture<void>(std::current_exception());
294   }
295 }
296
297 // when (variadic)
298
299 template <typename... Fs>
300 typename detail::VariadicContext<
301   typename std::decay<Fs>::type::value_type...>::type
302 whenAll(Fs&&... fs)
303 {
304   auto ctx =
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);
311 }
312
313 // when (iterator)
314
315 template <class InputIterator>
316 Future<
317   std::vector<
318   Try<typename std::iterator_traits<InputIterator>::value_type::value_type>>>
319 whenAll(InputIterator first, InputIterator last)
320 {
321   typedef
322     typename std::iterator_traits<InputIterator>::value_type::value_type T;
323
324   auto n = std::distance(first, last);
325   if (n == 0) {
326     return makeFuture(std::vector<Try<T>>());
327   }
328
329   auto ctx = new detail::WhenAllContext<T>();
330
331   ctx->total = n;
332   ctx->results.resize(ctx->total);
333
334   auto f_saved = ctx->p.getFuture();
335
336   for (size_t i = 0; first != last; ++first, ++i) {
337      auto& f = *first;
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));
342            delete ctx;
343          }
344        });
345   }
346
347   return std::move(f_saved);
348 }
349
350 template <class InputIterator>
351 Future<
352   std::pair<size_t,
353             Try<
354               typename
355               std::iterator_traits<InputIterator>::value_type::value_type> > >
356 whenAny(InputIterator first, InputIterator last) {
357   typedef
358     typename std::iterator_traits<InputIterator>::value_type::value_type T;
359
360   auto ctx = new detail::WhenAnyContext<T>(std::distance(first, last));
361   auto f_saved = ctx->p.getFuture();
362
363   for (size_t i = 0; first != last; first++, i++) {
364     auto& f = *first;
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)));
368       }
369       ctx->decref();
370     });
371   }
372
373   return std::move(f_saved);
374 }
375
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) {
380   typedef typename
381     std::iterator_traits<InputIterator>::value_type::value_type T;
382   typedef std::vector<std::pair<size_t, Try<T>>> V;
383
384   struct ctx_t {
385     V v;
386     size_t completed;
387     Promise<V> p;
388   };
389   auto ctx = std::make_shared<ctx_t>();
390   ctx->completed = 0;
391
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
394   // vector
395   auto it = first;
396   size_t i = 0;
397   while (it != last) {
398     it->then([ctx, n, i](Try<T>&& t) {
399       auto& v = ctx->v;
400       auto c = ++ctx->completed;
401       if (c <= n) {
402         assert(ctx->v.size() < n);
403         v.push_back(std::make_pair(i, std::move(t)));
404         if (c == n) {
405           ctx->p.fulfilTry(Try<V>(std::move(v)));
406         }
407       }
408     });
409
410     it++;
411     i++;
412   }
413
414   if (i < n) {
415     ctx->p.setException(std::runtime_error("Not enough futures"));
416   }
417
418   return ctx->p.getFuture();
419 }
420
421 }}
422
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
426 // instructive.