Squid::Tasks 1.0.0
C++14 coroutine-based task library for games
TokenList.h
1#pragma once
2
60
61#include <algorithm>
62#include <numeric>
63#include <vector>
64#include <string>
65
66//--- User configuration header ---//
67#include "TasksConfig.h"
68
69NAMESPACE_SQUID_BEGIN
70
71template <typename T = void>
72class TokenList;
73
76struct Token
77{
78 Token(std::string in_name)
79 : name(std::move(in_name))
80 {
81 }
82 std::string name; // Used for debug only
83};
84
87template <typename tData>
89{
90 DataToken(std::string in_name, tData in_data)
91 : name(std::move(in_name))
92 , data(std::move(in_data))
93 {
94 }
95 std::string name; // Used for debug only
96 tData data;
97};
98
100inline std::shared_ptr<Token> MakeToken(std::string in_name)
101{
102 return std::make_shared<Token>(std::move(in_name));
103}
104
106template <typename tData>
107std::shared_ptr<DataToken<tData>> MakeToken(std::string in_name, tData in_data)
108{
109 return std::make_shared<DataToken<tData>>(std::move(in_name), std::move(in_data));
110}
111
114template <typename T>
116{
117public:
119 using Token = typename std::conditional_t<std::is_void<T>::value, Token, DataToken<T>>;
120
122 template <typename U = T, typename std::enable_if_t<std::is_void<U>::value>* = nullptr>
123 static std::shared_ptr<Token> MakeToken(std::string in_name)
124 {
125 return std::make_shared<Token>(std::move(in_name));
126 }
127
129 template <typename U = T, typename std::enable_if_t<!std::is_void<U>::value>* = nullptr>
130 static std::shared_ptr<Token> MakeToken(std::string in_name, U in_data)
131 {
132 return std::make_shared<Token>(std::move(in_name), std::move(in_data));
133 }
134
136 template <typename U = T, typename std::enable_if_t<std::is_void<U>::value>* = nullptr>
137 SQUID_NODISCARD std::shared_ptr<Token> TakeToken(std::string in_name)
138 {
139 return AddTokenInternal(MakeToken(std::move(in_name)));
140 }
141
143 template <typename U = T, typename std::enable_if_t<!std::is_void<U>::value>* = nullptr>
144 SQUID_NODISCARD std::shared_ptr<Token> TakeToken(std::string in_name, U in_data)
145 {
146 return AddTokenInternal(MakeToken(std::move(in_name), std::move(in_data)));
147 }
148
150 std::shared_ptr<Token> AddToken(std::shared_ptr<Token> in_token)
151 {
152 SQUID_RUNTIME_CHECK(in_token, "Cannot add null token");
153 auto foundIter = std::find_if(m_tokens.begin(), m_tokens.end(), [&in_token](const std::weak_ptr<Token> in_iterToken){
154 return in_iterToken.lock() == in_token;
155 });
156
157 if(foundIter == m_tokens.end()) // Prevent duplicate tokens
158 {
159 return AddTokenInternal(in_token);
160 }
161 return in_token;
162 }
163
165 void RemoveToken(std::shared_ptr<Token> in_token)
166 {
167 // Find and remove the token
168 if(m_tokens.size())
169 {
170 m_tokens.erase(std::remove_if(m_tokens.begin(), m_tokens.end(), [&in_token](const std::weak_ptr<Token>& in_otherToken) {
171 return !in_otherToken.owner_before(in_token) && !in_token.owner_before(in_otherToken);
172 }), m_tokens.end());
173 }
174 }
175
177 operator bool() const
178 {
179 return HasTokens();
180 }
181
183 bool HasTokens() const
184 {
185 // Return true when holding any unexpired tokens
186 for(auto i = (int32_t)(m_tokens.size() - 1); i >= 0; --i)
187 {
188 const auto& token = m_tokens[i];
189 if(!token.expired())
190 {
191 return true;
192 }
193 m_tokens.pop_back(); // Because the token is expired, we can safely remove it from the back
194 }
195 return false;
196 }
197
199 std::vector<T> GetTokenData() const
200 {
201 std::vector<T> tokenData;
202 for(const auto& tokenWeak : m_tokens)
203 {
204 if(auto token = tokenWeak.lock())
205 {
206 tokenData.push_back(token->data);
207 }
208 }
209 return tokenData;
210 }
211
215
217 std::optional<T> GetLeastRecent() const
218 {
219 Sanitize();
220 return m_tokens.size() ? m_tokens.front().lock()->data : std::optional<T>{};
221 }
222
224 std::optional<T> GetMostRecent() const
225 {
226 Sanitize();
227 return m_tokens.size() ? m_tokens.back().lock()->data : std::optional<T>{};
228 }
229
231 std::optional<T> GetMin() const
232 {
233 std::optional<T> ret;
234 SanitizeAndProcessData([&ret](const T& in_data) {
235 if(!ret || in_data < ret.value())
236 {
237 ret = in_data;
238 }
239 });
240 return ret;
241 }
242
244 std::optional<T> GetMax() const
245 {
246 std::optional<T> ret;
247 SanitizeAndProcessData([&ret](const T& in_data) {
248 if(!ret || in_data > ret.value())
249 {
250 ret = in_data;
251 }
252 });
253 return ret;
254 }
255
257 std::optional<double> GetMean() const
258 {
259 std::optional<double> ret;
260 std::optional<double> total;
261 SanitizeAndProcessData([&total](const T& in_data) {
262 total = total.value_or(0.0) + (double)in_data;
263 });
264 if(total)
265 {
266 ret = total.value() / m_tokens.size();
267 }
268 return ret;
269 }
270
272 template <typename U = T, typename std::enable_if_t<!std::is_void<U>::value>* = nullptr>
273 bool Contains(const U& in_searchData) const
274 {
275 bool containsData = false;
276 SanitizeAndProcessData([&in_searchData, &containsData](const T& in_data) {
277 if(in_searchData == in_data)
278 {
279 containsData = true;
280 }
281 });
282 return containsData;
283 }
285
287 std::string GetDebugString() const
288 {
289 std::vector<std::string> tokenStrings;
290 std::string debugStr;
291 for(const auto& token : m_tokens)
292 {
293 if(!token.expired())
294 {
295 if(debugStr.size() > 0)
296 {
297 debugStr += "\n";
298 }
299 debugStr += token.lock()->name;
300 }
301 }
302 if(debugStr.size() == 0)
303 {
304 debugStr = "[no tokens]";
305 }
306 return debugStr;
307 }
308
309private:
310 // Shared internal implementation for adding tokens
311 std::shared_ptr<Token> AddTokenInternal(std::shared_ptr<Token> in_token)
312 {
313 Sanitize();
314 m_tokens.push_back(in_token);
315 return in_token;
316 }
317
318 // Sanitation
319 void Sanitize() const
320 {
321 // Remove all invalid tokens
322 if(m_tokens.size())
323 {
324 m_tokens.erase(std::remove_if(m_tokens.begin(), m_tokens.end(), [](const std::weak_ptr<Token>& in_token) {
325 return in_token.expired();
326 }), m_tokens.end());
327 }
328 }
329 template <typename tFn>
330 void SanitizeAndProcessData(tFn in_dataFn) const
331 {
332 // Remove all invalid tokens while applying a processing function on each valid token
333 if(m_tokens.size())
334 {
335 m_tokens.erase(std::remove_if(m_tokens.begin(), m_tokens.end(), [&in_dataFn](const std::weak_ptr<Token>& in_token) {
336 if(in_token.expired())
337 {
338 return true;
339 }
340 if(auto token = in_token.lock())
341 {
342 in_dataFn(token->data);
343 }
344 return false;
345 }), m_tokens.end());
346 }
347 }
348
349 // Token data
350 mutable std::vector<std::weak_ptr<Token>> m_tokens; // Mutable so we can remove expired tokens while converting bool
351};
352
353NAMESPACE_SQUID_END
354
Container for tracking decentralized state across multiple tasks. (See Token List for more info....
Definition: TokenList.h:116
std::optional< double > GetMean() const
Returns arithmetic mean of all associated data from the set of live tokens.
Definition: TokenList.h:257
typename std::conditional_t< std::is_void< T >::value, Token, DataToken< T > > Token
Type of Token tracked by this container.
Definition: TokenList.h:119
std::shared_ptr< Token > TakeToken(std::string in_name, U in_data)
Create and add a token with the specified debug name and associated data.
Definition: TokenList.h:144
std::optional< T > GetMax() const
Returns largest associated data from the set of live tokens.
Definition: TokenList.h:244
std::shared_ptr< Token > AddToken(std::shared_ptr< Token > in_token)
Add an existing token to this container.
Definition: TokenList.h:150
std::optional< T > GetLeastRecent() const
Returns associated data from the least-recently-added live token.
Definition: TokenList.h:217
bool HasTokens() const
Returns whether this container holds any live tokens.
Definition: TokenList.h:183
bool Contains(const U &in_searchData) const
Returns whether the set of live tokens contains at least one token associated with the specified data...
Definition: TokenList.h:273
std::shared_ptr< Token > TakeToken(std::string in_name)
Create and add a token with the specified debug name.
Definition: TokenList.h:137
std::optional< T > GetMostRecent() const
Returns associated data from the most-recently-added live token.
Definition: TokenList.h:224
std::vector< T > GetTokenData() const
Returns an array of all live token data.
Definition: TokenList.h:199
std::optional< T > GetMin() const
Returns smallest associated data from the set of live tokens.
Definition: TokenList.h:231
static std::shared_ptr< Token > MakeToken(std::string in_name, U in_data)
Create a token with the specified debug name and associated data.
Definition: TokenList.h:130
void RemoveToken(std::shared_ptr< Token > in_token)
Explicitly remove a token from this container.
Definition: TokenList.h:165
static std::shared_ptr< Token > MakeToken(std::string in_name)
Create a token with the specified debug name.
Definition: TokenList.h:123
std::string GetDebugString() const
Returns a debug string containing a list of the debug names of all live tokens.
Definition: TokenList.h:287
std::shared_ptr< Token > MakeToken(std::string in_name)
Create a token with the specified debug name.
Definition: TokenList.h:100
Handle to a TokenList element that stores both a debug name and associated data.
Definition: TokenList.h:89
Handle to a TokenList element that stores a debug name.
Definition: TokenList.h:77