#ifndef STEAMNETWORKINGSOCKETS_THINKER_H
#define STEAMNETWORKINGSOCKETS_THINKER_H
#pragma once
#include "steamnetworkingsockets_internal.h"
namespace SteamNetworkingSocketsLib {
const SteamNetworkingMicroseconds k_nThinkTime_Never = INT64_MAX;
const SteamNetworkingMicroseconds k_nThinkTime_ASAP = 1; class ThinkerSetIndex;
class IThinker
{
public:
STEAMNETWORKINGSOCKETS_DECLARE_CLASS_OPERATOR_NEW
virtual ~IThinker();
void SetNextThinkTime( SteamNetworkingMicroseconds usecTargetThinkTime );
void EnsureMinThinkTime( SteamNetworkingMicroseconds usecTargetThinkTime );
void ClearNextThinkTime() { SetNextThinkTime( k_nThinkTime_Never ); }
void SetNextThinkTimeASAP() { EnsureMinThinkTime( k_nThinkTime_ASAP ); }
inline SteamNetworkingMicroseconds GetNextThinkTime() const { return m_usecNextThinkTime; }
inline bool IsScheduled() const { return m_usecNextThinkTime != k_nThinkTime_Never; }
virtual bool TryLock() const;
static void Thinker_ProcessThinkers();
static SteamNetworkingMicroseconds Thinker_GetNextScheduledThinkTime();
protected:
IThinker();
virtual void Think( SteamNetworkingMicroseconds usecNow ) = 0;
private:
SteamNetworkingMicroseconds m_usecNextThinkTime;
int m_queueIndex;
friend class ThinkerSetIndex;
void InternalSetNextThinkTime( SteamNetworkingMicroseconds usecTargetThinkTime );
void InternalEnsureMinThinkTime( SteamNetworkingMicroseconds usecTargetThinkTime );
public:
#ifdef DBGFLAG_VALIDATE
virtual void Validate( CValidator &validator, const char *pchName );
#endif
};
template <typename L>
class ILockableThinker : public IThinker
{
public:
virtual bool TryLock() const override final { return m_pLock->try_lock(); }
inline void Unlock() { m_pLock->unlock(); }
L *m_pLock;
protected:
ILockableThinker( L &lock ) : IThinker(), m_pLock( &lock ) {}
};
#ifdef DBGFLAG_VALIDATE
extern void Thinker_ValidateStatics( CValidator &validator );
#endif
template<typename TOuter>
class ScheduledMethodThinker : private IThinker
{
public:
typedef void (TOuter::*TMethod)( SteamNetworkingMicroseconds );
ScheduledMethodThinker() : m_pOuter( nullptr ), m_method( nullptr ) {}
ScheduledMethodThinker( TOuter *pOuter, TMethod method ) : m_pOuter( pOuter ), m_method( method ) {}
inline void Schedule( SteamNetworkingMicroseconds usecWhen ) { Assert( m_pOuter && m_method ); IThinker::SetNextThinkTime( usecWhen ); }
inline void ScheduleASAP() { Schedule( k_nThinkTime_ASAP ); }
inline void Schedule( TOuter *pOuter, TMethod method, SteamNetworkingMicroseconds usecWhen )
{
Cancel(); m_pOuter = pOuter;
m_method = method;
Schedule( usecWhen );
}
inline void ScheduleASAP( TOuter *pOuter, TMethod method ) { Schedule( pOuter, method, k_nThinkTime_ASAP ); }
inline void EnsureMinScheduleTime( SteamNetworkingMicroseconds usecWhen ) { Assert( m_pOuter && m_method ); EnsureMinThinkTime( usecWhen ); }
inline void EnsureMinScheduleTime( TOuter *pOuter, TMethod method, SteamNetworkingMicroseconds usecWhen )
{
if ( usecWhen >= IThinker::GetNextThinkTime() )
{
Assert( m_pOuter == pOuter );
Assert( m_method == method );
}
else
{
Schedule( pOuter, method, usecWhen );
}
}
inline void Cancel() { IThinker::SetNextThinkTime( k_nThinkTime_Never ); }
using IThinker::IsScheduled;
inline SteamNetworkingMicroseconds GetScheduleTime() const { return IThinker::GetNextThinkTime(); }
protected:
TOuter *m_pOuter;
TMethod m_method;
virtual void Think( SteamNetworkingMicroseconds usecNow )
{
if ( m_pOuter )
(m_pOuter->*m_method)( usecNow );
}
};
template<typename TOuter>
class ScheduledMethodThinkerLockable final : public ScheduledMethodThinker<TOuter>
{
public:
using super=ScheduledMethodThinker<TOuter>;
using super::ScheduledMethodThinker;
virtual bool TryLock() const override
{
return !super::m_pOuter || super::m_pOuter->TryLock();
}
virtual void Think( SteamNetworkingMicroseconds usecNow ) override
{
if ( super::m_pOuter )
{
(super::m_pOuter->*super::m_method)( usecNow );
super::m_pOuter->Unlock();
}
}
};
}
#endif