1 | /* |
2 | * Copyright 2014-present 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/Portability.h> |
20 | #include <folly/executors/InlineExecutor.h> |
21 | #include <folly/futures/Promise.h> |
22 | #include <folly/lang/Exception.h> |
23 | |
24 | namespace folly { |
25 | |
26 | /* |
27 | * SharedPromise provides the same interface as Promise, but you can extract |
28 | * multiple Futures from it, i.e. you can call getFuture() as many times as |
29 | * you'd like. When the SharedPromise is fulfilled, all of the Futures are |
30 | * completed. Calls to getFuture() after the SharedPromise is fulfilled return |
31 | * a completed Future. If you find yourself constructing collections of Promises |
32 | * and fulfilling them simultaneously with the same value, consider this |
33 | * utility instead. Likewise, if you find yourself in need of setting multiple |
34 | * callbacks on the same Future (which is indefinitely unsupported), consider |
35 | * refactoring to use SharedPromise to "split" the Future. |
36 | * |
37 | * The ShardPromise must be kept alive manually. Consider FutureSplitter for |
38 | * automatic lifetime management. |
39 | */ |
40 | template <class T> |
41 | class SharedPromise { |
42 | public: |
43 | /** |
44 | * Return a Future tied to the shared core state. Unlike Promise::getFuture, |
45 | * this can be called an unlimited number of times per SharedPromise. |
46 | */ |
47 | SemiFuture<T> getSemiFuture(); |
48 | |
49 | /** |
50 | * Return a Future tied to the shared core state. Unlike Promise::getFuture, |
51 | * this can be called an unlimited number of times per SharedPromise. |
52 | * NOTE: This function is deprecated. Please use getSemiFuture and pass the |
53 | * appropriate executor to .via on the returned SemiFuture to get a |
54 | * valid Future where necessary. |
55 | */ |
56 | Future<T> getFuture(); |
57 | |
58 | /** Return the number of Futures associated with this SharedPromise */ |
59 | size_t size(); |
60 | |
61 | /** Fulfill the SharedPromise with an exception_wrapper */ |
62 | void setException(exception_wrapper ew); |
63 | |
64 | /** Fulfill the SharedPromise with an exception type E, which can be passed to |
65 | make_exception_wrapper(). Useful for originating exceptions. If you |
66 | caught an exception the exception_wrapper form is more appropriate. |
67 | */ |
68 | template <class E> |
69 | typename std::enable_if<std::is_base_of<std::exception, E>::value>::type |
70 | setException(E const&); |
71 | |
72 | /// Set an interrupt handler to handle interrupts. See the documentation for |
73 | /// Future::raise(). Your handler can do whatever it wants, but if you |
74 | /// bother to set one then you probably will want to fulfill the SharedPromise |
75 | /// with an exception (or special value) indicating how the interrupt was |
76 | /// handled. |
77 | void setInterruptHandler(std::function<void(exception_wrapper const&)>); |
78 | |
79 | /// Sugar to fulfill this SharedPromise<Unit> |
80 | template <class B = T> |
81 | typename std::enable_if<std::is_same<Unit, B>::value, void>::type setValue() { |
82 | setTry(Try<T>(T())); |
83 | } |
84 | |
85 | /** Set the value (use perfect forwarding for both move and copy) */ |
86 | template <class M> |
87 | void setValue(M&& value); |
88 | |
89 | void setTry(Try<T>&& t); |
90 | |
91 | /** Fulfill this SharedPromise with the result of a function that takes no |
92 | arguments and returns something implicitly convertible to T. |
93 | Captures exceptions. e.g. |
94 | |
95 | p.setWith([] { do something that may throw; return a T; }); |
96 | */ |
97 | template <class F> |
98 | void setWith(F&& func); |
99 | |
100 | bool isFulfilled(); |
101 | |
102 | private: |
103 | // this allows SharedPromise move-ctor/move-assign to be defaulted |
104 | struct Mutex : std::mutex { |
105 | Mutex() = default; |
106 | Mutex(Mutex&&) noexcept {} |
107 | Mutex& operator=(Mutex&&) noexcept { |
108 | return *this; |
109 | } |
110 | }; |
111 | |
112 | template <typename V> |
113 | struct Defaulted { |
114 | using Noexcept = StrictConjunction< |
115 | std::is_nothrow_default_constructible<V>, |
116 | std::is_nothrow_move_constructible<V>, |
117 | std::is_nothrow_move_assignable<V>>; |
118 | V value{V()}; |
119 | Defaulted() = default; |
120 | Defaulted(Defaulted&& that) noexcept(Noexcept::value) |
121 | : value(std::exchange(that.value, V())) {} |
122 | Defaulted& operator=(Defaulted&& that) noexcept(Noexcept::value) { |
123 | value = std::exchange(that.value, V()); |
124 | return *this; |
125 | } |
126 | }; |
127 | |
128 | bool hasResult() { |
129 | return try_.value.hasValue() || try_.value.hasException(); |
130 | } |
131 | |
132 | Mutex mutex_; |
133 | Defaulted<size_t> size_; |
134 | Defaulted<Try<T>> try_; |
135 | std::vector<Promise<T>> promises_; |
136 | std::function<void(exception_wrapper const&)> interruptHandler_; |
137 | }; |
138 | |
139 | } // namespace folly |
140 | |
141 | #include <folly/futures/Future.h> |
142 | #include <folly/futures/SharedPromise-inl.h> |
143 | |