Squid::Tasks 1.0.0
C++14 coroutine-based task library for games
Token List

Data structure for tracking decentralized state across multiple tasks. More...

Classes

class  TokenList< T >
 Container for tracking decentralized state across multiple tasks. (See Token List for more info...) More...
 
struct  Token
 Handle to a TokenList element that stores a debug name. More...
 
struct  DataToken< tData >
 Handle to a TokenList element that stores both a debug name and associated data. More...
 

Functions

std::shared_ptr< TokenMakeToken (std::string in_name)
 Create a token with the specified debug name.
 
template<typename tData >
std::shared_ptr< DataToken< tData > > MakeToken (std::string in_name, tData in_data)
 Create a token with the specified debug name and associated data.
 

Detailed Description

Data structure for tracking decentralized state across multiple tasks.

Token objects can be created using TokenList::MakeToken(), returning a shared pointer to a new Token. This new Token can then be added to the TokenList using TokenList::AddToken(). TokenList::TakeToken() can be used to make + add a new token with a single function call.

Because TokenList uses weak pointers to track its elements, Token objects are logically removed from the list once they are destroyed. As such, it is usually unnecessary to explicitly call TokenList::RemoveToken() to remove a Token from the list. Instead, it is idiomatic to consider the Token to be a sort of "scope guard" that will remove itself from all TokenList objects when it leaves scope.

The TokenList class is included as part of Squid::Tasks to provide a simple mechanism for robustly sharing aribtrary state between multiple tasks. Consider this example of a poison damage-over-time system:

class Character : public Actor
{
public:
bool IsPoisoned() const
{
return m_poisonTokens; // Whether there are any live poison tokens
}
void OnPoisoned(float in_dps, float in_duration)
{
m_taskMgr.RunManaged(ManagePoisonInstance(in_dps, in_duration));
}
private:
TokenList<float> m_poisonTokens; // Token list indicating live poison damage
Task<> ManagePoisonInstance(float in_dps, float in_duration)
{
// Take a poison token and hold it for N seconds
auto poisonToken = m_poisonTokens.TakeToken(__FUNCTION__, in_dps);
co_await WaitSeconds(in_duration);
}
Task<> ManageCharacter() // Called once per frame
{
while(true)
{
float poisonDps = m_poisonTokens.GetMax(); // Get highest DPS poison instance
DealDamage(poisonDps * GetDT()); // Deal the actual poison damage
co_await Suspend();
}
}
};
Definition: Task.h:204
Container for tracking decentralized state across multiple tasks. (See Token List for more info....
Definition: TokenList.h:116
std::optional< T > GetMax() const
Returns largest associated data from the set of live tokens.
Definition: TokenList.h:244
std::shared_ptr< Token > TakeToken(std::string in_name)
Create and add a token with the specified debug name.
Definition: TokenList.h:137
Task< tTaskTime > WaitSeconds(tTaskTime in_seconds, tTimeFn in_timeFn)
Awaiter function that waits N seconds in a given time-stream.
Definition: Task.h:850
Awaiter class that suspends unconditionally.
Definition: Task.h:91

As the above example shows, this mechanism is well-suited for coroutines, as they can hold a Token across multiple frames. Also note that Token objects can optionally hold data. The TokenList class has query functions (e.g. GetMin()/GetMax()) that can be used to aggregate the data from the set of live tokens. This is used above to quickly find the highest DPS poison instance.