Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Kitware
GitHub Repository: Kitware/CMake
Path: blob/master/Utilities/cmcppdap/include/dap/future.h
3158 views
1
// Copyright 2019 Google LLC
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// https://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
#ifndef dap_future_h
16
#define dap_future_h
17
18
#include <condition_variable>
19
#include <memory>
20
#include <mutex>
21
22
namespace dap {
23
24
// internal functionality
25
namespace detail {
26
template <typename T>
27
struct promise_state {
28
T val;
29
std::mutex mutex;
30
std::condition_variable cv;
31
bool hasVal = false;
32
};
33
} // namespace detail
34
35
// forward declaration
36
template <typename T>
37
class promise;
38
39
// future_status is the enumeration returned by future::wait_for and
40
// future::wait_until.
41
enum class future_status {
42
ready,
43
timeout,
44
};
45
46
// future is a minimal reimplementation of std::future, that does not suffer
47
// from TSAN false positives. See:
48
// https://gcc.gnu.org/bugzilla//show_bug.cgi?id=69204
49
template <typename T>
50
class future {
51
public:
52
using State = detail::promise_state<T>;
53
54
// constructors
55
inline future() = default;
56
inline future(future&&) = default;
57
58
// valid() returns true if the future has an internal state.
59
bool valid() const;
60
61
// get() blocks until the future has a valid result, and returns it.
62
// The future must have a valid internal state to call this method.
63
inline T get();
64
65
// wait() blocks until the future has a valid result.
66
// The future must have a valid internal state to call this method.
67
void wait() const;
68
69
// wait_for() blocks until the future has a valid result, or the timeout is
70
// reached.
71
// The future must have a valid internal state to call this method.
72
template <class Rep, class Period>
73
future_status wait_for(
74
const std::chrono::duration<Rep, Period>& timeout) const;
75
76
// wait_until() blocks until the future has a valid result, or the timeout is
77
// reached.
78
// The future must have a valid internal state to call this method.
79
template <class Clock, class Duration>
80
future_status wait_until(
81
const std::chrono::time_point<Clock, Duration>& timeout) const;
82
83
private:
84
friend promise<T>;
85
future(const future&) = delete;
86
inline future(const std::shared_ptr<State>& state);
87
88
std::shared_ptr<State> state = std::make_shared<State>();
89
};
90
91
template <typename T>
92
future<T>::future(const std::shared_ptr<State>& s) : state(s) {}
93
94
template <typename T>
95
bool future<T>::valid() const {
96
return static_cast<bool>(state);
97
}
98
99
template <typename T>
100
T future<T>::get() {
101
std::unique_lock<std::mutex> lock(state->mutex);
102
state->cv.wait(lock, [&] { return state->hasVal; });
103
return state->val;
104
}
105
106
template <typename T>
107
void future<T>::wait() const {
108
std::unique_lock<std::mutex> lock(state->mutex);
109
state->cv.wait(lock, [&] { return state->hasVal; });
110
}
111
112
template <typename T>
113
template <class Rep, class Period>
114
future_status future<T>::wait_for(
115
const std::chrono::duration<Rep, Period>& timeout) const {
116
std::unique_lock<std::mutex> lock(state->mutex);
117
return state->cv.wait_for(lock, timeout, [&] { return state->hasVal; })
118
? future_status::ready
119
: future_status::timeout;
120
}
121
122
template <typename T>
123
template <class Clock, class Duration>
124
future_status future<T>::wait_until(
125
const std::chrono::time_point<Clock, Duration>& timeout) const {
126
std::unique_lock<std::mutex> lock(state->mutex);
127
return state->cv.wait_until(lock, timeout, [&] { return state->hasVal; })
128
? future_status::ready
129
: future_status::timeout;
130
}
131
132
// promise is a minimal reimplementation of std::promise, that does not suffer
133
// from TSAN false positives. See:
134
// https://gcc.gnu.org/bugzilla//show_bug.cgi?id=69204
135
template <typename T>
136
class promise {
137
public:
138
// constructors
139
inline promise() = default;
140
inline promise(promise&& other) = default;
141
inline promise(const promise& other) = default;
142
143
// set_value() stores value to the shared state.
144
// set_value() must only be called once.
145
inline void set_value(const T& value) const;
146
inline void set_value(T&& value) const;
147
148
// get_future() returns a future sharing this promise's state.
149
future<T> get_future();
150
151
private:
152
using State = detail::promise_state<T>;
153
std::shared_ptr<State> state = std::make_shared<State>();
154
};
155
156
template <typename T>
157
future<T> promise<T>::get_future() {
158
return future<T>(state);
159
}
160
161
template <typename T>
162
void promise<T>::set_value(const T& value) const {
163
std::unique_lock<std::mutex> lock(state->mutex);
164
state->val = value;
165
state->hasVal = true;
166
state->cv.notify_all();
167
}
168
169
template <typename T>
170
void promise<T>::set_value(T&& value) const {
171
std::unique_lock<std::mutex> lock(state->mutex);
172
state->val = std::move(value);
173
state->hasVal = true;
174
state->cv.notify_all();
175
}
176
177
} // namespace dap
178
179
#endif // dap_future_h
180
181