xref: /aosp_15_r20/external/federated-compute/fcp/base/future.h (revision 14675a029014e728ec732f129a32e299b2da0601)
1*14675a02SAndroid Build Coastguard Worker /*
2*14675a02SAndroid Build Coastguard Worker  * Copyright 2019 Google LLC
3*14675a02SAndroid Build Coastguard Worker  *
4*14675a02SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*14675a02SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*14675a02SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*14675a02SAndroid Build Coastguard Worker  *
8*14675a02SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*14675a02SAndroid Build Coastguard Worker  *
10*14675a02SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*14675a02SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*14675a02SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*14675a02SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*14675a02SAndroid Build Coastguard Worker  * limitations under the License.
15*14675a02SAndroid Build Coastguard Worker  */
16*14675a02SAndroid Build Coastguard Worker 
17*14675a02SAndroid Build Coastguard Worker /**
18*14675a02SAndroid Build Coastguard Worker  * This file provides a pair of types Future<T> (a value to wait for) and
19*14675a02SAndroid Build Coastguard Worker  * Promise<T> (allows providing the value for an associated future).
20*14675a02SAndroid Build Coastguard Worker  *
21*14675a02SAndroid Build Coastguard Worker  * These serve the same purpose as std::future and std::promise, but with a few
22*14675a02SAndroid Build Coastguard Worker  * differences:
23*14675a02SAndroid Build Coastguard Worker  *  - They do not represent exceptions (i.e. std::promise::set_exception).
24*14675a02SAndroid Build Coastguard Worker  *    Consider representing failure conditions with StatusOr or std::variant
25*14675a02SAndroid Build Coastguard Worker  *  - They do not throw future-related exceptions (e.g. std::future::get throws
26*14675a02SAndroid Build Coastguard Worker  *    if the promise was 'abandoned'; this one indicates that with a value).
27*14675a02SAndroid Build Coastguard Worker  *  - There is no integration with std::async etc.
28*14675a02SAndroid Build Coastguard Worker  *  - They use absl::Duration / absl::Time for waiting with a timeout.
29*14675a02SAndroid Build Coastguard Worker  *  - They are created as a pair (vs. std::promise::get_future(), which throws
30*14675a02SAndroid Build Coastguard Worker  *    an exception if called twice).
31*14675a02SAndroid Build Coastguard Worker  *  - Setting (promise) and taking (future) require rvalues (you might need to
32*14675a02SAndroid Build Coastguard Worker  *    use std::move). This is to indicate that these are 'consuming' operations
33*14675a02SAndroid Build Coastguard Worker  *    (to humans and static analysis tools).
34*14675a02SAndroid Build Coastguard Worker  */
35*14675a02SAndroid Build Coastguard Worker 
36*14675a02SAndroid Build Coastguard Worker #ifndef FCP_BASE_FUTURE_H_
37*14675a02SAndroid Build Coastguard Worker #define FCP_BASE_FUTURE_H_
38*14675a02SAndroid Build Coastguard Worker 
39*14675a02SAndroid Build Coastguard Worker #include <memory>
40*14675a02SAndroid Build Coastguard Worker #include <optional>
41*14675a02SAndroid Build Coastguard Worker #include <tuple>
42*14675a02SAndroid Build Coastguard Worker #include <variant>
43*14675a02SAndroid Build Coastguard Worker 
44*14675a02SAndroid Build Coastguard Worker #include "absl/base/macros.h"
45*14675a02SAndroid Build Coastguard Worker #include "absl/synchronization/notification.h"
46*14675a02SAndroid Build Coastguard Worker #include "fcp/base/meta.h"
47*14675a02SAndroid Build Coastguard Worker #include "fcp/base/monitoring.h"
48*14675a02SAndroid Build Coastguard Worker #include "fcp/base/move_to_lambda.h"
49*14675a02SAndroid Build Coastguard Worker #include "fcp/base/scheduler.h"
50*14675a02SAndroid Build Coastguard Worker #include "fcp/base/unique_value.h"
51*14675a02SAndroid Build Coastguard Worker 
52*14675a02SAndroid Build Coastguard Worker namespace fcp {
53*14675a02SAndroid Build Coastguard Worker 
54*14675a02SAndroid Build Coastguard Worker // Since fcp::Promise is already defined by the reactive streams library
55*14675a02SAndroid Build Coastguard Worker // (fcp/reactive/), we'll define fcp::thread::{Promise, Future}.
56*14675a02SAndroid Build Coastguard Worker namespace thread {
57*14675a02SAndroid Build Coastguard Worker 
58*14675a02SAndroid Build Coastguard Worker // Forward declarations; see doc comments below
59*14675a02SAndroid Build Coastguard Worker template <typename T>
60*14675a02SAndroid Build Coastguard Worker class Future;
61*14675a02SAndroid Build Coastguard Worker template <typename T>
62*14675a02SAndroid Build Coastguard Worker class Promise;
63*14675a02SAndroid Build Coastguard Worker 
64*14675a02SAndroid Build Coastguard Worker template <typename T>
65*14675a02SAndroid Build Coastguard Worker struct FuturePair {
66*14675a02SAndroid Build Coastguard Worker   Promise<T> promise;
67*14675a02SAndroid Build Coastguard Worker   Future<T> future;
68*14675a02SAndroid Build Coastguard Worker };
69*14675a02SAndroid Build Coastguard Worker 
70*14675a02SAndroid Build Coastguard Worker namespace future_internal {
71*14675a02SAndroid Build Coastguard Worker // We want Promise and Future to be created only as a pair, with MakeFuture.
72*14675a02SAndroid Build Coastguard Worker // This type is given permission to construct them.
73*14675a02SAndroid Build Coastguard Worker struct Maker {
74*14675a02SAndroid Build Coastguard Worker   template <typename T>
75*14675a02SAndroid Build Coastguard Worker   static FuturePair<T> Make();
76*14675a02SAndroid Build Coastguard Worker };
77*14675a02SAndroid Build Coastguard Worker 
78*14675a02SAndroid Build Coastguard Worker // Common state of a Promise / Future pair. Destructed when *both* the promise
79*14675a02SAndroid Build Coastguard Worker // and future are gone.
80*14675a02SAndroid Build Coastguard Worker //
81*14675a02SAndroid Build Coastguard Worker // States: NotSet, Set, Taken
82*14675a02SAndroid Build Coastguard Worker // Transitions:
83*14675a02SAndroid Build Coastguard Worker //   NotSet -> Set: When a value is provided (std::nullopt indicates an
84*14675a02SAndroid Build Coastguard Worker //                  abandoned promise). *Before* ready_ is signalled.
85*14675a02SAndroid Build Coastguard Worker //   Set -> Taken: When a future takes a value. *After* ready_ is signalled.
86*14675a02SAndroid Build Coastguard Worker template <typename T>
87*14675a02SAndroid Build Coastguard Worker class FutureState {
88*14675a02SAndroid Build Coastguard Worker  public:
89*14675a02SAndroid Build Coastguard Worker   bool Wait(absl::Duration timeout) const;
90*14675a02SAndroid Build Coastguard Worker   std::optional<T> Take();
91*14675a02SAndroid Build Coastguard Worker   void Set(std::optional<T> val);
92*14675a02SAndroid Build Coastguard Worker 
93*14675a02SAndroid Build Coastguard Worker  private:
94*14675a02SAndroid Build Coastguard Worker   enum class State { kNotSet, kSet, kTaken };
95*14675a02SAndroid Build Coastguard Worker 
96*14675a02SAndroid Build Coastguard Worker   absl::Notification ready_;
97*14675a02SAndroid Build Coastguard Worker   State state_ = State::kNotSet;
98*14675a02SAndroid Build Coastguard Worker   std::optional<T> value_;
99*14675a02SAndroid Build Coastguard Worker };
100*14675a02SAndroid Build Coastguard Worker 
101*14675a02SAndroid Build Coastguard Worker // A Future and Promise share a single FutureState. That is, FutureState
102*14675a02SAndroid Build Coastguard Worker // is ref-counted, with two initial refs (no additional refs can be created,
103*14675a02SAndroid Build Coastguard Worker // since Future and Promise are move-only). So, we define FutureStateRef as a
104*14675a02SAndroid Build Coastguard Worker // move-only std::shared_ptr.
105*14675a02SAndroid Build Coastguard Worker template <typename T>
106*14675a02SAndroid Build Coastguard Worker using FutureStateRef = UniqueValue<std::shared_ptr<FutureState<T>>>;
107*14675a02SAndroid Build Coastguard Worker }  // namespace future_internal
108*14675a02SAndroid Build Coastguard Worker 
109*14675a02SAndroid Build Coastguard Worker /**
110*14675a02SAndroid Build Coastguard Worker  * Allows waiting for and retrieving a value (provided eventually by a paired
111*14675a02SAndroid Build Coastguard Worker  * Promise).
112*14675a02SAndroid Build Coastguard Worker  *
113*14675a02SAndroid Build Coastguard Worker  * If the paired Promise is 'abandoned' (destructed without having a value set),
114*14675a02SAndroid Build Coastguard Worker  * then the Future's value is std::nullopt.
115*14675a02SAndroid Build Coastguard Worker  */
116*14675a02SAndroid Build Coastguard Worker template <typename T>
117*14675a02SAndroid Build Coastguard Worker class Future {
118*14675a02SAndroid Build Coastguard Worker  public:
119*14675a02SAndroid Build Coastguard Worker   Future(Future&&) = default;
120*14675a02SAndroid Build Coastguard Worker   Future& operator=(Future&&) = default;
121*14675a02SAndroid Build Coastguard Worker 
122*14675a02SAndroid Build Coastguard Worker   /**
123*14675a02SAndroid Build Coastguard Worker    * Retrieves the future value, waiting until it is available.
124*14675a02SAndroid Build Coastguard Worker    * Taking from a future *consumes* it, and so requires an rvalue. To take
125*14675a02SAndroid Build Coastguard Worker    * from a Future<T> f:
126*14675a02SAndroid Build Coastguard Worker    *   std::move(f).Take()
127*14675a02SAndroid Build Coastguard Worker    *
128*14675a02SAndroid Build Coastguard Worker    * If the paired promise is 'abandoned' (destructed before a real value is
129*14675a02SAndroid Build Coastguard Worker    * provided), the value is std::nullopt.
130*14675a02SAndroid Build Coastguard Worker    */
131*14675a02SAndroid Build Coastguard Worker   ABSL_MUST_USE_RESULT
Take()132*14675a02SAndroid Build Coastguard Worker   std::optional<T> Take() && {
133*14675a02SAndroid Build Coastguard Worker     future_internal::FutureStateRef<T> state = std::move(state_);
134*14675a02SAndroid Build Coastguard Worker     FCP_CHECK(state.has_value());
135*14675a02SAndroid Build Coastguard Worker     return (*state)->Take();
136*14675a02SAndroid Build Coastguard Worker   }
137*14675a02SAndroid Build Coastguard Worker 
138*14675a02SAndroid Build Coastguard Worker   /**
139*14675a02SAndroid Build Coastguard Worker    * Waits for the value to become available, with a timeout. Unlike Take(),
140*14675a02SAndroid Build Coastguard Worker    * this does *not* consume the value.
141*14675a02SAndroid Build Coastguard Worker    *
142*14675a02SAndroid Build Coastguard Worker    * Returns a bool indicating if the value is available (if so, Take() will
143*14675a02SAndroid Build Coastguard Worker    * return immediately).
144*14675a02SAndroid Build Coastguard Worker    */
145*14675a02SAndroid Build Coastguard Worker   ABSL_MUST_USE_RESULT
Wait(absl::Duration timeout)146*14675a02SAndroid Build Coastguard Worker   bool Wait(absl::Duration timeout) const {
147*14675a02SAndroid Build Coastguard Worker     FCP_CHECK(state_.has_value());
148*14675a02SAndroid Build Coastguard Worker     return (*state_)->Wait(timeout);
149*14675a02SAndroid Build Coastguard Worker   }
150*14675a02SAndroid Build Coastguard Worker 
151*14675a02SAndroid Build Coastguard Worker  private:
152*14675a02SAndroid Build Coastguard Worker   friend struct future_internal::Maker;
153*14675a02SAndroid Build Coastguard Worker 
Future(future_internal::FutureStateRef<T> state)154*14675a02SAndroid Build Coastguard Worker   explicit Future(future_internal::FutureStateRef<T> state)
155*14675a02SAndroid Build Coastguard Worker       : state_(std::move(state)) {}
156*14675a02SAndroid Build Coastguard Worker 
157*14675a02SAndroid Build Coastguard Worker   future_internal::FutureStateRef<T> state_;
158*14675a02SAndroid Build Coastguard Worker };
159*14675a02SAndroid Build Coastguard Worker 
160*14675a02SAndroid Build Coastguard Worker /**
161*14675a02SAndroid Build Coastguard Worker  * Allows providing a value to satisfy a paired Future.
162*14675a02SAndroid Build Coastguard Worker  *
163*14675a02SAndroid Build Coastguard Worker  * If this Promise is 'abandoned' (destructed without having a value set),
164*14675a02SAndroid Build Coastguard Worker  * then the Future gets the value std::nullopt.
165*14675a02SAndroid Build Coastguard Worker  */
166*14675a02SAndroid Build Coastguard Worker template <typename T>
167*14675a02SAndroid Build Coastguard Worker class Promise {
168*14675a02SAndroid Build Coastguard Worker  public:
169*14675a02SAndroid Build Coastguard Worker   Promise(Promise&&) = default;
170*14675a02SAndroid Build Coastguard Worker   Promise& operator=(Promise&&) = default;
171*14675a02SAndroid Build Coastguard Worker 
~Promise()172*14675a02SAndroid Build Coastguard Worker   ~Promise() {
173*14675a02SAndroid Build Coastguard Worker     if (state_.has_value()) {
174*14675a02SAndroid Build Coastguard Worker       // Abandoned
175*14675a02SAndroid Build Coastguard Worker       (*state_)->Set(std::nullopt);
176*14675a02SAndroid Build Coastguard Worker     }
177*14675a02SAndroid Build Coastguard Worker   }
178*14675a02SAndroid Build Coastguard Worker 
179*14675a02SAndroid Build Coastguard Worker   /**
180*14675a02SAndroid Build Coastguard Worker    * Provides a value to the paired Future. Setting a promise *consumes* it,
181*14675a02SAndroid Build Coastguard Worker    * and so requires an rvalue. To set a Promise<T> p:
182*14675a02SAndroid Build Coastguard Worker    *   std::move(p).Set(...)
183*14675a02SAndroid Build Coastguard Worker    */
Set(T value)184*14675a02SAndroid Build Coastguard Worker   void Set(T value) && {
185*14675a02SAndroid Build Coastguard Worker     future_internal::FutureStateRef<T> state = std::move(state_);
186*14675a02SAndroid Build Coastguard Worker     FCP_CHECK(state.has_value());
187*14675a02SAndroid Build Coastguard Worker     (*state)->Set(std::move(value));
188*14675a02SAndroid Build Coastguard Worker   }
189*14675a02SAndroid Build Coastguard Worker 
190*14675a02SAndroid Build Coastguard Worker  private:
191*14675a02SAndroid Build Coastguard Worker   friend struct future_internal::Maker;
192*14675a02SAndroid Build Coastguard Worker 
Promise(future_internal::FutureStateRef<T> state)193*14675a02SAndroid Build Coastguard Worker   explicit Promise(future_internal::FutureStateRef<T> state)
194*14675a02SAndroid Build Coastguard Worker       : state_(std::move(state)) {}
195*14675a02SAndroid Build Coastguard Worker 
196*14675a02SAndroid Build Coastguard Worker   future_internal::FutureStateRef<T> state_;
197*14675a02SAndroid Build Coastguard Worker };
198*14675a02SAndroid Build Coastguard Worker 
199*14675a02SAndroid Build Coastguard Worker /** Creates a paired Future and Promise. */
200*14675a02SAndroid Build Coastguard Worker template <typename T>
MakeFuture()201*14675a02SAndroid Build Coastguard Worker FuturePair<T> MakeFuture() {
202*14675a02SAndroid Build Coastguard Worker   return future_internal::Maker::Make<T>();
203*14675a02SAndroid Build Coastguard Worker }
204*14675a02SAndroid Build Coastguard Worker 
205*14675a02SAndroid Build Coastguard Worker /**
206*14675a02SAndroid Build Coastguard Worker  * Schedules a task which calls a function computing a value. Returns a future
207*14675a02SAndroid Build Coastguard Worker  * to wait for and access the value once it is computed.
208*14675a02SAndroid Build Coastguard Worker  */
209*14675a02SAndroid Build Coastguard Worker template <typename T>
ScheduleFuture(Scheduler * scheduler,std::function<T ()> func)210*14675a02SAndroid Build Coastguard Worker Future<T> ScheduleFuture(Scheduler* scheduler, std::function<T()> func) {
211*14675a02SAndroid Build Coastguard Worker   thread::FuturePair<T> p = thread::MakeFuture<T>();
212*14675a02SAndroid Build Coastguard Worker   MoveToLambdaWrapper<thread::Promise<T>> promise_capture =
213*14675a02SAndroid Build Coastguard Worker       MoveToLambda(std::move(p.promise));
214*14675a02SAndroid Build Coastguard Worker   // Lambda is stateful (since the promise is consumed). This is okay, since
215*14675a02SAndroid Build Coastguard Worker   // it should only be called once.
216*14675a02SAndroid Build Coastguard Worker   scheduler->Schedule([promise_capture, func]() mutable {
217*14675a02SAndroid Build Coastguard Worker     std::move(*promise_capture).Set(func());
218*14675a02SAndroid Build Coastguard Worker   });
219*14675a02SAndroid Build Coastguard Worker 
220*14675a02SAndroid Build Coastguard Worker   return std::move(p.future);
221*14675a02SAndroid Build Coastguard Worker }
222*14675a02SAndroid Build Coastguard Worker 
223*14675a02SAndroid Build Coastguard Worker namespace future_internal {
224*14675a02SAndroid Build Coastguard Worker 
225*14675a02SAndroid Build Coastguard Worker template <typename T>
Make()226*14675a02SAndroid Build Coastguard Worker FuturePair<T> Maker::Make() {
227*14675a02SAndroid Build Coastguard Worker   std::shared_ptr<FutureState<T>> state = std::make_shared<FutureState<T>>();
228*14675a02SAndroid Build Coastguard Worker 
229*14675a02SAndroid Build Coastguard Worker   auto promise_ref = FutureStateRef<T>(state);
230*14675a02SAndroid Build Coastguard Worker   // Note that we use std::move this time, to avoid ref-count churn.
231*14675a02SAndroid Build Coastguard Worker   auto future_ref = FutureStateRef<T>(std::move(state));
232*14675a02SAndroid Build Coastguard Worker   return {Promise<T>(std::move(promise_ref)), Future<T>(std::move(future_ref))};
233*14675a02SAndroid Build Coastguard Worker }
234*14675a02SAndroid Build Coastguard Worker 
235*14675a02SAndroid Build Coastguard Worker template <typename T>
Wait(absl::Duration timeout)236*14675a02SAndroid Build Coastguard Worker bool FutureState<T>::Wait(absl::Duration timeout) const {
237*14675a02SAndroid Build Coastguard Worker   return ready_.WaitForNotificationWithTimeout(timeout);
238*14675a02SAndroid Build Coastguard Worker }
239*14675a02SAndroid Build Coastguard Worker 
240*14675a02SAndroid Build Coastguard Worker template <typename T>
Set(std::optional<T> val)241*14675a02SAndroid Build Coastguard Worker void FutureState<T>::Set(std::optional<T> val) {
242*14675a02SAndroid Build Coastguard Worker   FCP_CHECK(!ready_.HasBeenNotified())
243*14675a02SAndroid Build Coastguard Worker       << "Attempted to set a FutureState which has already been notified";
244*14675a02SAndroid Build Coastguard Worker   // Not notified => value_ has *not* been set, and the Promise has exclusive
245*14675a02SAndroid Build Coastguard Worker   // access (no atomics or locks needed below).
246*14675a02SAndroid Build Coastguard Worker   switch (state_) {
247*14675a02SAndroid Build Coastguard Worker     case State::kNotSet:
248*14675a02SAndroid Build Coastguard Worker       state_ = State::kSet;
249*14675a02SAndroid Build Coastguard Worker       value_ = std::move(val);
250*14675a02SAndroid Build Coastguard Worker       // This has release semantics; stores to state_ and value_ will be visible
251*14675a02SAndroid Build Coastguard Worker       // to whomever sees that the notification.
252*14675a02SAndroid Build Coastguard Worker       ready_.Notify();
253*14675a02SAndroid Build Coastguard Worker       return;
254*14675a02SAndroid Build Coastguard Worker     case State::kSet:
255*14675a02SAndroid Build Coastguard Worker       FCP_CHECK(false) << "FutureState has been notified, so state_ should be "
256*14675a02SAndroid Build Coastguard Worker                           "kTaken or kSet";
257*14675a02SAndroid Build Coastguard Worker       abort();  // Compiler thinks FCP_CHECK(false) might return
258*14675a02SAndroid Build Coastguard Worker     case State::kTaken:
259*14675a02SAndroid Build Coastguard Worker       FCP_CHECK(false) << "FutureState has already been taken from";
260*14675a02SAndroid Build Coastguard Worker       abort();  // Compiler thinks FCP_CHECK(false) might return
261*14675a02SAndroid Build Coastguard Worker   }
262*14675a02SAndroid Build Coastguard Worker }
263*14675a02SAndroid Build Coastguard Worker 
264*14675a02SAndroid Build Coastguard Worker template <typename T>
Take()265*14675a02SAndroid Build Coastguard Worker std::optional<T> FutureState<T>::Take() {
266*14675a02SAndroid Build Coastguard Worker   ready_.WaitForNotification();
267*14675a02SAndroid Build Coastguard Worker   // Notified => value_ has been set, and exclusive access has been transferred
268*14675a02SAndroid Build Coastguard Worker   // from the Promise to the Future (no atomics or locks needed below).
269*14675a02SAndroid Build Coastguard Worker   switch (state_) {
270*14675a02SAndroid Build Coastguard Worker     case State::kSet:
271*14675a02SAndroid Build Coastguard Worker       state_ = State::kTaken;
272*14675a02SAndroid Build Coastguard Worker       // value_.has_value() will still be set, but we won't read it again
273*14675a02SAndroid Build Coastguard Worker       // in the kTaken state.
274*14675a02SAndroid Build Coastguard Worker       return std::move(value_);
275*14675a02SAndroid Build Coastguard Worker     case State::kNotSet:
276*14675a02SAndroid Build Coastguard Worker       FCP_CHECK(false) << "FutureState has been notified, so state_ should be "
277*14675a02SAndroid Build Coastguard Worker                           "kTaken or kSet";
278*14675a02SAndroid Build Coastguard Worker       abort();  // Compiler thinks FCP_CHECK(false) might return
279*14675a02SAndroid Build Coastguard Worker     case State::kTaken:
280*14675a02SAndroid Build Coastguard Worker       FCP_CHECK(false) << "FutureState has already been taken from";
281*14675a02SAndroid Build Coastguard Worker       abort();  // Compiler thinks FCP_CHECK(false) might return
282*14675a02SAndroid Build Coastguard Worker   }
283*14675a02SAndroid Build Coastguard Worker }
284*14675a02SAndroid Build Coastguard Worker 
285*14675a02SAndroid Build Coastguard Worker }  // namespace future_internal
286*14675a02SAndroid Build Coastguard Worker 
287*14675a02SAndroid Build Coastguard Worker }  // namespace thread
288*14675a02SAndroid Build Coastguard Worker }  // namespace fcp
289*14675a02SAndroid Build Coastguard Worker 
290*14675a02SAndroid Build Coastguard Worker #endif  // FCP_BASE_FUTURE_H_
291