remove fireAndForget
[folly.git] / folly / wangle / Later-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 <folly/wangle/Executor.h>
20 #include <folly/wangle/Future.h>
21 #include <folly/Optional.h>
22
23 namespace folly { namespace wangle {
24
25 template <typename T>
26 struct isLater {
27   static const bool value = false;
28 };
29
30 template <typename T>
31 struct isLater<Later<T> > {
32   static const bool value = true;
33 };
34
35 template <typename T>
36 struct isLaterOrFuture {
37   static const bool value = false;
38 };
39
40 template <typename T>
41 struct isLaterOrFuture<Later<T>> {
42   static const bool value = true;
43 };
44
45 template <typename T>
46 struct isLaterOrFuture<Future<T>> {
47   static const bool value = true;
48 };
49
50 template <typename T>
51 template <class U, class Unused, class Unused2>
52 Later<T>::Later() {
53   future_ = starter_.getFuture();
54 }
55
56 template <class T>
57 Later<T>::Later(Future<T>&& f) {
58   MoveWrapper<Future<T>> fw(std::move(f));
59   *this = Later<void>()
60     .then([fw](Try<void>&&) mutable {
61       return std::move(*fw);
62     });
63 }
64
65 template <typename T>
66 Later<T>::Later(Promise<void>&& starter)
67   : starter_(std::forward<Promise<void>>(starter)) { }
68
69 template <class T>
70 template <class U, class Unused, class Unused2>
71 Later<T>::Later(U&& input) {
72   folly::MoveWrapper<Promise<U>> promise;
73   folly::MoveWrapper<U> inputm(std::forward<U>(input));
74   future_ = promise->getFuture();
75   starter_.getFuture().then([=](Try<void>&& t) mutable {
76     promise->setValue(std::move(*inputm));
77   });
78 }
79
80 template <typename T>
81 Later<T>::Later(std::exception_ptr const& eptr) {
82   folly::MoveWrapper<Promise<T>> promise;
83   future_ = promise->getFuture();
84   starter_.getFuture().then([=](Try<void>&& t) mutable {
85     promise->setException(eptr);
86   });
87 }
88
89 template <typename T>
90 template <typename E, class Unused>
91 Later<T>::Later(E const& e) :
92     Later<T>::Later(std::make_exception_ptr<E>(e)) {
93 }
94
95 template <class T>
96 template <class U, class Unused, class Unused2>
97 Later<T>::Later(std::function<void(std::function<void(U&&)>&&)>&& fn) {
98   folly::MoveWrapper<Promise<U>> promise;
99   future_ = promise->getFuture();
100   starter_.getFuture().then([=](Try<void>&& t) mutable {
101     fn([=](U&& output) mutable {
102       promise->setValue(std::move(output));
103     });
104   });
105 }
106
107 template <class T>
108 template <class F>
109 typename std::enable_if<
110   !isLaterOrFuture<typename std::result_of<F(Try<T>&&)>::type>::value,
111   Later<typename std::result_of<F(Try<T>&&)>::type> >::type
112 Later<T>::then(F&& fn) {
113   typedef typename std::result_of<F(Try<T>&&)>::type B;
114
115   Later<B> later(std::move(starter_));
116   later.future_ = future_->then(std::forward<F>(fn));
117   return later;
118 }
119
120 template <class T>
121 template <class F>
122 typename std::enable_if<
123   isFuture<typename std::result_of<F(Try<T>&&)>::type>::value,
124   Later<typename std::result_of<F(Try<T>&&)>::type::value_type> >::type
125 Later<T>::then(F&& fn) {
126   typedef typename std::result_of<F(Try<T>&&)>::type::value_type B;
127
128   Later<B> later(std::move(starter_));
129   later.future_ = future_->then(std::move(fn));
130   return later;
131 }
132
133 template <class T>
134 template <class F>
135 typename std::enable_if<
136   isLater<typename std::result_of<F(Try<T>&&)>::type>::value,
137   Later<typename std::result_of<F(Try<T>&&)>::type::value_type> >::type
138 Later<T>::then(F&& fn) {
139   typedef typename std::result_of<F(Try<T>&&)>::type::value_type B;
140
141   folly::MoveWrapper<Promise<B>> promise;
142   folly::MoveWrapper<F> fnm(std::move(fn));
143   Later<B> later(std::move(starter_));
144   later.future_ = promise->getFuture();
145   future_->then([=](Try<T>&& t) mutable {
146     (*fnm)(std::move(t))
147     .then([=](Try<B>&& t2) mutable {
148       promise->fulfilTry(std::move(t2));
149     })
150     .launch();
151   });
152   return later;
153 }
154
155 template <class T>
156 Later<T> Later<T>::via(Executor* executor) {
157   folly::MoveWrapper<Promise<T>> promise;
158   Later<T> later(std::move(starter_));
159   later.future_ = promise->getFuture();
160
161   future_->setCallback_([executor, promise](Try<T>&& t) mutable {
162     folly::MoveWrapper<Try<T>> tt(std::move(t));
163     executor->add([promise, tt]() mutable {
164       promise->fulfilTry(std::move(*tt));
165     });
166   });
167
168   return later;
169 }
170
171 template <class T>
172 Future<T> Later<T>::launch() {
173   starter_.setValue();
174   return std::move(*future_);
175 }
176
177 template <class T>
178 Later<std::vector<Try<T>>> whenAllLater(std::vector<Later<T>>&& laters) {
179   if (laters.size() == 0) {
180     return Later<std::vector<Try<T>>>(std::vector<Try<T>>());
181   }
182
183   auto ctx = new detail::WhenAllLaterContext<T>();
184   ctx->total = laters.size();
185   ctx->results.resize(ctx->total);
186
187   MoveWrapper<std::vector<Later<T>>> mlaters{std::move(laters)};
188
189   std::function<void(std::function<void(std::vector<Try<T>>&&)>&&)> wrapper =
190     [ctx, mlaters](std::function<void(std::vector<Try<T>>&&)>&& fn) mutable {
191       ctx->fn = std::move(fn);
192       size_t i = 0;
193       for (auto& l : *mlaters) {
194         l.then([ctx, i](Try<T>&& t) {
195             ctx->results[i] = std::move(t);
196             if (++ctx->count == ctx->total) {
197               ctx->fn(std::move(ctx->results));
198               delete ctx;
199             }
200           }).launch();
201           ++i;
202       }
203     };
204   return Later<std::vector<Try<T>>>(std::move(wrapper));
205 }
206
207 }}