|
19 | 19 | #ifndef LIB_FUTURE_H_ |
20 | 20 | #define LIB_FUTURE_H_ |
21 | 21 |
|
22 | | -#include <condition_variable> |
| 22 | +#include <atomic> |
23 | 23 | #include <functional> |
| 24 | +#include <future> |
24 | 25 | #include <list> |
25 | 26 | #include <memory> |
26 | 27 | #include <mutex> |
27 | | - |
28 | | -using Lock = std::unique_lock<std::mutex>; |
| 28 | +#include <utility> |
29 | 29 |
|
30 | 30 | namespace pulsar { |
31 | 31 |
|
32 | 32 | template <typename Result, typename Type> |
33 | | -struct InternalState { |
34 | | - std::mutex mutex; |
35 | | - std::condition_variable condition; |
36 | | - Result result; |
37 | | - Type value; |
38 | | - bool complete; |
39 | | - |
40 | | - std::list<typename std::function<void(Result, const Type&)> > listeners; |
41 | | -}; |
42 | | - |
43 | | -template <typename Result, typename Type> |
44 | | -class Future { |
| 33 | +class InternalState { |
45 | 34 | public: |
46 | | - typedef std::function<void(Result, const Type&)> ListenerCallback; |
47 | | - |
48 | | - Future& addListener(ListenerCallback callback) { |
49 | | - InternalState<Result, Type>* state = state_.get(); |
50 | | - Lock lock(state->mutex); |
| 35 | + using Listener = std::function<void(Result, const Type &)>; |
51 | 36 |
|
52 | | - if (state->complete) { |
53 | | - lock.unlock(); |
54 | | - callback(state->result, state->value); |
| 37 | + void addListener(Listener listener) { |
| 38 | + if (completed()) { |
| 39 | + listener(future_.get().first, future_.get().second); |
55 | 40 | } else { |
56 | | - state->listeners.push_back(callback); |
| 41 | + std::lock_guard<std::mutex> lock{mutex_}; |
| 42 | + listeners_.emplace_back(listener); |
57 | 43 | } |
58 | | - |
59 | | - return *this; |
60 | 44 | } |
61 | 45 |
|
62 | | - Result get(Type& result) { |
63 | | - InternalState<Result, Type>* state = state_.get(); |
64 | | - Lock lock(state->mutex); |
65 | | - |
66 | | - if (!state->complete) { |
67 | | - // Wait for result |
68 | | - while (!state->complete) { |
69 | | - state->condition.wait(lock); |
70 | | - } |
| 46 | + bool complete(Result result, const Type &value) { |
| 47 | + std::unique_lock<std::mutex> lock{mutex_}; |
| 48 | + if (completed_) { |
| 49 | + return false; |
71 | 50 | } |
72 | | - |
73 | | - result = state->value; |
74 | | - return state->result; |
75 | | - } |
76 | | - |
77 | | - template <typename Duration> |
78 | | - bool get(Result& res, Type& value, Duration d) { |
79 | | - InternalState<Result, Type>* state = state_.get(); |
80 | | - Lock lock(state->mutex); |
81 | | - |
82 | | - if (!state->complete) { |
83 | | - // Wait for result |
84 | | - while (!state->complete) { |
85 | | - if (!state->condition.wait_for(lock, d, [&state] { return state->complete; })) { |
86 | | - // Timeout while waiting for the future to complete |
87 | | - return false; |
88 | | - } |
89 | | - } |
| 51 | + decltype(listeners_) listeners; |
| 52 | + listeners.swap(listeners_); |
| 53 | + for (auto &&listener : listeners) { |
| 54 | + listener(result, value); |
90 | 55 | } |
91 | | - |
92 | | - value = state->value; |
93 | | - res = state->result; |
| 56 | + // Set completed_ with true after all listeners are called to ensure the order that any listener that |
| 57 | + // is added after complete() is called after all existing listeners. |
| 58 | + completed_.store(true, std::memory_order_release); |
| 59 | + listeners_.clear(); |
| 60 | + lock.unlock(); |
| 61 | + promise_.set_value(std::make_pair(result, value)); |
94 | 62 | return true; |
95 | 63 | } |
96 | 64 |
|
97 | | - private: |
98 | | - typedef std::shared_ptr<InternalState<Result, Type> > InternalStatePtr; |
99 | | - Future(InternalStatePtr state) : state_(state) {} |
| 65 | + bool completed() const noexcept { return completed_.load(std::memory_order_acquire); } |
100 | 66 |
|
101 | | - std::shared_ptr<InternalState<Result, Type> > state_; |
| 67 | + Result get(Type &result) { |
| 68 | + auto pair = future_.get(); |
| 69 | + result = std::move(pair.second); |
| 70 | + return pair.first; |
| 71 | + } |
102 | 72 |
|
103 | | - template <typename U, typename V> |
104 | | - friend class Promise; |
| 73 | + private: |
| 74 | + std::atomic_bool completed_{false}; |
| 75 | + std::promise<std::pair<Result, Type>> promise_; |
| 76 | + std::shared_future<std::pair<Result, Type>> future_{promise_.get_future()}; |
| 77 | + std::list<Listener> listeners_; |
| 78 | + mutable std::mutex mutex_; |
105 | 79 | }; |
106 | 80 |
|
107 | 81 | template <typename Result, typename Type> |
108 | | -class Promise { |
109 | | - public: |
110 | | - Promise() : state_(std::make_shared<InternalState<Result, Type> >()) {} |
111 | | - |
112 | | - bool setValue(const Type& value) const { |
113 | | - static Result DEFAULT_RESULT; |
114 | | - InternalState<Result, Type>* state = state_.get(); |
115 | | - Lock lock(state->mutex); |
116 | | - |
117 | | - if (state->complete) { |
118 | | - return false; |
119 | | - } |
| 82 | +using InternalStatePtr = std::shared_ptr<InternalState<Result, Type>>; |
120 | 83 |
|
121 | | - state->value = value; |
122 | | - state->result = DEFAULT_RESULT; |
123 | | - state->complete = true; |
124 | | - |
125 | | - decltype(state->listeners) listeners; |
126 | | - listeners.swap(state->listeners); |
127 | | - |
128 | | - lock.unlock(); |
129 | | - |
130 | | - for (auto& callback : listeners) { |
131 | | - callback(DEFAULT_RESULT, value); |
132 | | - } |
| 84 | +template <typename Result, typename Type> |
| 85 | +class Future { |
| 86 | + public: |
| 87 | + using Listener = typename InternalState<Result, Type>::Listener; |
133 | 88 |
|
134 | | - state->condition.notify_all(); |
135 | | - return true; |
| 89 | + Future &addListener(Listener listener) { |
| 90 | + state_->addListener(listener); |
| 91 | + return *this; |
136 | 92 | } |
137 | 93 |
|
138 | | - bool setFailed(Result result) const { |
139 | | - static Type DEFAULT_VALUE; |
140 | | - InternalState<Result, Type>* state = state_.get(); |
141 | | - Lock lock(state->mutex); |
| 94 | + Result get(Type &result) { return state_->get(result); } |
142 | 95 |
|
143 | | - if (state->complete) { |
144 | | - return false; |
145 | | - } |
| 96 | + private: |
| 97 | + InternalStatePtr<Result, Type> state_; |
146 | 98 |
|
147 | | - state->result = result; |
148 | | - state->complete = true; |
| 99 | + Future(InternalStatePtr<Result, Type> state) : state_(state) {} |
149 | 100 |
|
150 | | - decltype(state->listeners) listeners; |
151 | | - listeners.swap(state->listeners); |
| 101 | + template <typename U, typename V> |
| 102 | + friend class Promise; |
| 103 | +}; |
152 | 104 |
|
153 | | - lock.unlock(); |
| 105 | +template <typename Result, typename Type> |
| 106 | +class Promise { |
| 107 | + public: |
| 108 | + Promise() : state_(std::make_shared<InternalState<Result, Type>>()) {} |
154 | 109 |
|
155 | | - for (auto& callback : listeners) { |
156 | | - callback(result, DEFAULT_VALUE); |
157 | | - } |
| 110 | + bool setValue(const Type &value) const { return state_->complete({}, value); } |
158 | 111 |
|
159 | | - state->condition.notify_all(); |
160 | | - return true; |
161 | | - } |
| 112 | + bool setFailed(Result result) const { return state_->complete(result, {}); } |
162 | 113 |
|
163 | | - bool isComplete() const { |
164 | | - InternalState<Result, Type>* state = state_.get(); |
165 | | - Lock lock(state->mutex); |
166 | | - return state->complete; |
167 | | - } |
| 114 | + bool isComplete() const { return state_->completed(); } |
168 | 115 |
|
169 | | - Future<Result, Type> getFuture() const { return Future<Result, Type>(state_); } |
| 116 | + Future<Result, Type> getFuture() const { return Future<Result, Type>{state_}; } |
170 | 117 |
|
171 | 118 | private: |
172 | | - typedef std::function<void(Result, const Type&)> ListenerCallback; |
173 | | - std::shared_ptr<InternalState<Result, Type> > state_; |
| 119 | + const InternalStatePtr<Result, Type> state_; |
174 | 120 | }; |
175 | 121 |
|
176 | | -class Void {}; |
177 | | - |
178 | | -} /* namespace pulsar */ |
| 122 | +} // namespace pulsar |
179 | 123 |
|
180 | | -#endif /* LIB_FUTURE_H_ */ |
| 124 | +#endif |
0 commit comments