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.
20 #include <folly/LifoSem.h>
22 namespace folly { namespace wangle {
26 static const bool value = false;
30 struct isFuture<Future<T> > {
31 static const bool value = true;
35 Future<T>::Future(Future<T>&& other) noexcept : obj_(other.obj_) {
40 Future<T>& Future<T>::operator=(Future<T>&& other) {
41 std::swap(obj_, other.obj_);
46 Future<T>::~Future() {
48 setCallback_([](Try<T>&&) {}); // detach
53 void Future<T>::throwIfInvalid() const {
60 void Future<T>::setCallback_(F&& func) {
62 obj_->setCallback_(std::move(func));
68 typename std::enable_if<
69 !isFuture<typename std::result_of<F(Try<T>&&)>::type>::value,
70 Future<typename std::result_of<F(Try<T>&&)>::type> >::type
71 Future<T>::then(F&& func) {
72 typedef typename std::result_of<F(Try<T>&&)>::type B;
76 // wrap these so we can move them into the lambda
77 folly::MoveWrapper<Promise<B>> p;
78 folly::MoveWrapper<F> funcm(std::forward<F>(func));
80 // grab the Future now before we lose our handle on the Promise
81 auto f = p->getFuture();
83 /* This is a bit tricky.
85 We can't just close over *this in case this Future gets moved. So we
86 make a new dummy Future. We could figure out something more
87 sophisticated that avoids making a new Future object when it can, as an
88 optimization. But this is correct.
90 obj_ can't be moved, it is explicitly disallowed (as is copying). But
91 if there's ever a reason to allow it, this is one place that makes that
92 assumption and would need to be fixed. We use a standard shared pointer
93 for obj_ (by copying it in), which means in essence obj holds a shared
94 pointer to itself. But this shouldn't leak because Promise will not
95 outlive the continuation, because Promise will setException() with a
96 broken Promise if it is destructed before completed. We could use a
97 weak pointer but it would have to be converted to a shared pointer when
98 func is executed (because the Future returned by func may possibly
99 persist beyond the callback, if it gets moved), and so it is an
100 optimization to just make it shared from the get-go.
102 We have to move in the Promise and func using the MoveWrapper
103 hack. (func could be copied but it's a big drag on perf).
105 Two subtle but important points about this design. FutureObject has no
106 back pointers to Future or Promise, so if Future or Promise get moved
107 (and they will be moved in performant code) we don't have to do
108 anything fancy. And because we store the continuation in the
109 FutureObject, not in the Future, we can execute the continuation even
110 after the Future has gone out of scope. This is an intentional design
111 decision. It is likely we will want to be able to cancel a continuation
112 in some circumstances, but I think it should be explicit not implicit
113 in the destruction of the Future used to create it.
116 [p, funcm](Try<T>&& t) mutable {
118 return (*funcm)(std::move(t));
127 typename std::enable_if<
128 isFuture<typename std::result_of<F(Try<T>&&)>::type>::value,
129 Future<typename std::result_of<F(Try<T>&&)>::type::value_type> >::type
130 Future<T>::then(F&& func) {
131 typedef typename std::result_of<F(Try<T>&&)>::type::value_type B;
135 // wrap these so we can move them into the lambda
136 folly::MoveWrapper<Promise<B>> p;
137 folly::MoveWrapper<F> funcm(std::forward<F>(func));
139 // grab the Future now before we lose our handle on the Promise
140 auto f = p->getFuture();
143 [p, funcm](Try<T>&& t) mutable {
145 auto f2 = (*funcm)(std::move(t));
146 // that didn't throw, now we can steal p
147 f2.setCallback_([p](Try<B>&& b) mutable {
148 p->fulfilTry(std::move(b));
151 p->setException(std::current_exception());
159 Future<void> Future<T>::then() {
160 return then([] (Try<T>&& t) {});
164 typename std::add_lvalue_reference<T>::type Future<T>::value() {
167 return obj_->value();
171 typename std::add_lvalue_reference<const T>::type Future<T>::value() const {
174 return obj_->value();
178 Try<T>& Future<T>::getTry() {
181 return obj_->getTry();
185 template <typename Executor>
186 inline Future<T> Future<T>::via(Executor* executor) {
189 folly::MoveWrapper<Promise<T>> p;
190 auto f = p->getFuture();
192 setCallback_([executor, p](Try<T>&& t) mutable {
193 folly::MoveWrapper<Try<T>> tt(std::move(t));
194 executor->add([p, tt]() mutable {
195 p->fulfilTry(std::move(*tt));
203 bool Future<T>::isReady() const {
205 return obj_->ready();
211 Future<typename std::decay<T>::type> makeFuture(T&& t) {
212 Promise<typename std::decay<T>::type> p;
213 auto f = p.getFuture();
214 p.setValue(std::forward<T>(t));
218 inline // for multiple translation units
219 Future<void> makeFuture() {
221 auto f = p.getFuture();
229 typename std::enable_if<!std::is_reference<F>::value, bool>::type sdf)
230 -> Future<decltype(func())> {
231 Promise<decltype(func())> p;
232 auto f = p.getFuture();
241 auto makeFutureTry(F const& func) -> Future<decltype(func())> {
243 return makeFutureTry(std::move(copy));
247 Future<T> makeFuture(std::exception_ptr const& e) {
249 auto f = p.getFuture();
254 template <class T, class E>
255 typename std::enable_if<std::is_base_of<std::exception, E>::value, Future<T>>::type
256 makeFuture(E const& e) {
258 auto f = p.getFuture();
259 p.fulfil([&]() -> T { throw e; });
264 Future<T> makeFuture(Try<T>&& t) {
266 return makeFuture<T>(std::move(t.value()));
268 return makeFuture<T>(std::current_exception());
273 inline Future<void> makeFuture(Try<void>&& t) {
278 return makeFuture<void>(std::current_exception());
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>>());
314 auto ctx = new detail::WhenAllContext<T>();
317 ctx->results.resize(ctx->total);
319 auto f_saved = ctx->p.getFuture();
321 for (size_t i = 0; first != last; ++first, ++i) {
323 f.setCallback_([ctx, i](Try<T>&& t) {
324 ctx->results[i] = std::move(t);
325 if (++ctx->count == ctx->total) {
326 ctx->p.setValue(std::move(ctx->results));
332 return std::move(f_saved);
335 template <class InputIterator>
340 std::iterator_traits<InputIterator>::value_type::value_type> > >
341 whenAny(InputIterator first, InputIterator last) {
343 typename std::iterator_traits<InputIterator>::value_type::value_type T;
345 auto ctx = new detail::WhenAnyContext<T>(std::distance(first, last));
346 auto f_saved = ctx->p.getFuture();
348 for (size_t i = 0; first != last; first++, i++) {
350 f.setCallback_([i, ctx](Try<T>&& t) {
351 if (!ctx->done.exchange(true)) {
352 ctx->p.setValue(std::make_pair(i, std::move(t)));
358 return std::move(f_saved);
361 template <class InputIterator>
362 Future<std::vector<std::pair<size_t, Try<typename
363 std::iterator_traits<InputIterator>::value_type::value_type>>>>
364 whenN(InputIterator first, InputIterator last, size_t n) {
366 std::iterator_traits<InputIterator>::value_type::value_type T;
367 typedef std::vector<std::pair<size_t, Try<T>>> V;
374 auto ctx = std::make_shared<ctx_t>();
377 // for each completed Future, increase count and add to vector, until we
378 // have n completed futures at which point we fulfil our Promise with the
383 it->then([ctx, n, i](Try<T>&& t) {
385 auto c = ++ctx->completed;
387 assert(ctx->v.size() < n);
388 v.push_back(std::make_pair(i, std::move(t)));
390 ctx->p.fulfilTry(Try<V>(std::move(v)));
400 ctx->p.setException(std::runtime_error("Not enough futures"));
403 return ctx->p.getFuture();
406 template <typename T>
408 waitWithSemaphore(Future<T>&& f) {
410 auto done = f.then([&](Try<T> &&t) {
412 return std::move(t.value());
419 inline Future<void> waitWithSemaphore<void>(Future<void>&& f) {
421 auto done = f.then([&](Try<void> &&t) {
429 template <typename T, class Duration>
431 waitWithSemaphore(Future<T>&& f, Duration timeout) {
432 auto sem = std::make_shared<LifoSem>();
433 auto done = f.then([sem](Try<T> &&t) {
435 return std::move(t.value());
437 std::thread t([sem, timeout](){
438 std::this_thread::sleep_for(timeout);
444 } catch (ShutdownSemError & ign) { }
448 template <class Duration>
450 waitWithSemaphore(Future<void>&& f, Duration timeout) {
451 auto sem = std::make_shared<LifoSem>();
452 auto done = f.then([sem](Try<void> &&t) {
456 std::thread t([sem, timeout](){
457 std::this_thread::sleep_for(timeout);
463 } catch (ShutdownSemError & ign) { }
469 // I haven't included a Future<T&> specialization because I don't forsee us
470 // using it, however it is not difficult to add when needed. Refer to
471 // Future<void> for guidance. std::future and boost::future code would also be