csgo-2018-source/public/vstdlib/ieventsystem.h
2021-07-24 21:11:47 -07:00

274 lines
17 KiB
C++

//========== Copyright (c) Valve Corporation, All rights reserved. ==========//
//
// Purpose:
//
// $NoKeywords: $
//
//===========================================================================//
#ifndef IEVENTSYSTEM_H
#define IEVENTSYSTEM_H
#ifdef _WIN32
#pragma once
#endif
#include "appframework/iappsystem.h"
#include "tier0/basetypes.h"
#include "tier1/functors.h"
//-----------------------------------------------------------------------------
// Event queues are used to allow listeners to decide at what point they
// want to deal with event processing
//-----------------------------------------------------------------------------
DECLARE_POINTER_HANDLE( EventQueue_t );
#define EVENT_QUEUE_HANDLE_INVALID ( (EventQueue_t)0 )
DECLARE_POINTER_HANDLE( EventId_t );
#define EVENT_ID_INVALID ( (EventId_t)0 )
//-----------------------------------------------------------------------------
// Global interface for posting/listening to events
//
// Usage for registering/unregistering listeners and posting events:
// DEFINE_EVENT2_WITHNAMES( TestEvent, int, x, int, y );
// void OnTestEvent( const int &x, const int &y );
// void f()
// {
// hTest = g_pEventSystem->CreateEventQueue();
// TestEvent::RegisterFunc( hTest, OnTestEvent );
// or TestEvent::RegisterFunc( hTest, myClassPtr, &CMyClass::OnTestEvent );
// TestEvent::Post( 100, 200 );
// TestEvent::PostToListener( myClassPtr, 100, 200 );
// g_pEventSystem->ProcessEvents( hTest );
// TestEvent::UnregisterFunc( hTest, OnTestEvent );
// g_pEventSystem->DestroyEventQueue( hTest );
// }
//
// Note that the arguments of the event handlers are always const references
// to the arguments specified in the event declaration to avoid extra copies
// of the data.
//
// Also note that it's possible to post an event to a specific listener
// using PostToListener. Just specify the class name as the first argument.
//
// Shit gets funky when you pass pointers to events. You need to be very careful
// that the pointer is guaranteed to be valid until the messages are being posted.
// Also, because everything is a const reference, the function prototypes
// for stuff that accepts pointers looks like this strangeness:
//
// DEFINE_EVENT2_WITHNAMES( TestEvent, int, x, char *, pName );
// void OnTestEvent( const int &x, char * const & pName );
//
// Also note: You cannot register or unregister while in the middle of processing events
//
// NOTE: We use EventClass::RegisterMemberFunc / EventClass:RegisterFunc
// instead of overloading EventClass::Register to get more sane-looking
// error message from the compiler if it happens to be passed an invalid
// event handler.
//
// From a perf standpoint, registering + unregistering listeners, and
// destroying event queues all can cause thread stalls. Do them with
// low frequency.
//-----------------------------------------------------------------------------
abstract_class IEventSystem : public IAppSystem
{
public:
// Creates an event queue.
// Creation can occur at any time. Destruction can happen at any time
// provided you're not simultaneously processing events or registering/unregistering
// listeners on the same thread
virtual EventQueue_t CreateEventQueue() = 0;
virtual void DestroyEventQueue( EventQueue_t hQueue ) = 0;
// Processess queued events for a event queue
virtual void ProcessEvents( EventQueue_t hQueue ) = 0;
// Ignore that macro magic! It allows us to call PostEvent on an arbitrary event id
// with arbitrary arguments. Useful to allow systems to post event ids told to
// it by external systems
inline void PostEvent( EventId_t nEventId )
{
CFunctorData *pData = CreateFunctorData( );
PostEventInternal( nEventId, EVENT_QUEUE_HANDLE_INVALID, NULL, pData );
}
inline void PostEvent( EventId_t nEventId, EventQueue_t hQueue )
{
CFunctorData *pData = CreateFunctorData( );
PostEventInternal( nEventId, hQueue, NULL, pData );
}
inline void PostEventToListener( EventId_t nEventId, const void *pListener )
{
CFunctorData *pData = CreateFunctorData( );
PostEventInternal( nEventId, EVENT_QUEUE_HANDLE_INVALID, pListener, pData );
}
inline void PostEventToListener( EventId_t nEventId, EventQueue_t hQueue, const void *pListener )
{
CFunctorData *pData = CreateFunctorData( );
PostEventInternal( nEventId, hQueue, pListener, pData );
}
#define DEFINE_POST_EVENT(N) \
template < FUNC_SOLO_TEMPLATE_ARG_PARAMS_##N > \
inline void PostEvent( EventId_t nEventId FUNC_ARG_FORMAL_PARAMS_##N ) \
{ \
CFunctorData *pData = CreateFunctorData( FUNC_CALL_ARGS_##N ); \
PostEventInternal( nEventId, EVENT_QUEUE_HANDLE_INVALID, NULL, pData ); \
} \
template < FUNC_SOLO_TEMPLATE_ARG_PARAMS_##N > \
inline void PostEvent( EventId_t nEventId, EventQueue_t hQueue FUNC_ARG_FORMAL_PARAMS_##N ) \
{ \
CFunctorData *pData = CreateFunctorData( FUNC_CALL_ARGS_##N ); \
PostEventInternal( nEventId, hQueue, NULL, pData ); \
} \
template < FUNC_SOLO_TEMPLATE_ARG_PARAMS_##N > \
inline void PostEventToListener( EventId_t nEventId, const void *pListener FUNC_ARG_FORMAL_PARAMS_##N ) \
{ \
CFunctorData *pData = CreateFunctorData( FUNC_CALL_ARGS_##N ); \
PostEventInternal( nEventId, EVENT_QUEUE_HANDLE_INVALID, pListener, pData ); \
} \
template < FUNC_SOLO_TEMPLATE_ARG_PARAMS_##N > \
inline void PostEventToListener( EventId_t nEventId, EventQueue_t hQueue, const void *pListener FUNC_ARG_FORMAL_PARAMS_##N ) \
{ \
CFunctorData *pData = CreateFunctorData( FUNC_CALL_ARGS_##N ); \
PostEventInternal( nEventId, hQueue, pListener, pData ); \
}
FUNC_GENERATE_ALL_BUT0( DEFINE_POST_EVENT );
#undef DEFINE_POST_EVENT
private:
// NOTE: These are not meant to be called directly. See the comment above
// the IEventSystem class definition for how to post/register/unregister events
virtual EventId_t RegisterEvent( const char *pEventName ) = 0;
virtual void PostEventInternal( EventId_t nEventId, EventQueue_t hQueue, const void *pListener, CFunctorData *pData ) = 0;
virtual void RegisterListener( EventId_t nEventId, EventQueue_t hQueue, CFunctorCallback *pCallback ) = 0;
virtual void UnregisterListener( EventId_t nEventId, EventQueue_t hQueue, CFunctorCallback *pCallback ) = 0;
#define DEFINE_FRIEND_CLASSES(N) \
template < typename Event_t FUNC_TEMPLATE_ARG_PARAMS_##N > friend class CEventSignature##N
FUNC_GENERATE_ALL( DEFINE_FRIEND_CLASSES );
#undef DEFINE_FRIEND_CLASSES
};
//-----------------------------------------------------------------------------
// Ignore that man behind the curtain!
//-----------------------------------------------------------------------------
#define DEFINE_EVENT_INTERNAL(N) \
template < typename Event_t FUNC_TEMPLATE_ARG_PARAMS_##N > \
class CEventSignature##N \
{ \
public: \
static inline void Post( FUNC_PROXY_ARG_FORMAL_PARAMS_##N ) \
{ \
CFunctorData *pData = CreateFunctorData( FUNC_CALL_ARGS_##N ); \
g_pEventSystem->PostEventInternal( Event_t::GetEventId(), EVENT_QUEUE_HANDLE_INVALID, NULL, pData ); \
} \
static inline void Post( EventQueue_t hQueue FUNC_ARG_FORMAL_PARAMS_##N ) \
{ \
CFunctorData *pData = CreateFunctorData( FUNC_CALL_ARGS_##N ); \
g_pEventSystem->PostEventInternal( Event_t::GetEventId(), hQueue, NULL, pData ); \
} \
static inline void PostToListener( const void *pListener FUNC_ARG_FORMAL_PARAMS_##N ) \
{ \
CFunctorData *pData = CreateFunctorData( FUNC_CALL_ARGS_##N ); \
g_pEventSystem->PostEventInternal( Event_t::GetEventId(), EVENT_QUEUE_HANDLE_INVALID, pListener, pData ); \
} \
static inline void PostToListener( EventQueue_t hQueue, const void *pListener FUNC_ARG_FORMAL_PARAMS_##N ) \
{ \
CFunctorData *pData = CreateFunctorData( FUNC_CALL_ARGS_##N ); \
g_pEventSystem->PostEventInternal( Event_t::GetEventId(), hQueue, pListener, pData ); \
} \
static inline void RegisterFunc( EventQueue_t hQueue, void (*pfnProxied)( FUNC_PROXY_ARG_FORMAL_PARAMS_##N ) ) \
{ \
CFunctorCallback *pCallback = CreateFunctorCallback( pfnProxied ); \
g_pEventSystem->RegisterListener( Event_t::GetEventId(), hQueue, pCallback ); \
} \
static inline void UnregisterFunc( EventQueue_t hQueue, void (*pfnProxied)( FUNC_PROXY_ARG_FORMAL_PARAMS_##N ) ) \
{ \
CFunctorCallback *pCallback = CreateFunctorCallback( pfnProxied ); \
g_pEventSystem->UnregisterListener( Event_t::GetEventId(), hQueue, pCallback ); \
} \
template < class OBJECT_TYPE_PTR > \
static inline void RegisterMemberFunc( EventQueue_t hQueue, OBJECT_TYPE_PTR *pClass, void (OBJECT_TYPE_PTR::*pfnProxied)( FUNC_PROXY_ARG_FORMAL_PARAMS_##N ) ) \
{ \
CFunctorCallback *pCallback = CreateFunctorCallback( pClass, pfnProxied ); \
g_pEventSystem->RegisterListener( Event_t::GetEventId(), hQueue, pCallback ); \
} \
template < class OBJECT_TYPE_PTR > \
static inline void UnregisterMemberFunc( EventQueue_t hQueue, OBJECT_TYPE_PTR *pClass, void (OBJECT_TYPE_PTR::*pfnProxied)( FUNC_PROXY_ARG_FORMAL_PARAMS_##N ) ) \
{ \
CFunctorCallback *pCallback = CreateFunctorCallback( pClass, pfnProxied ); \
g_pEventSystem->UnregisterListener( Event_t::GetEventId(), hQueue, pCallback ); \
} \
static EventId_t RegisterEvent( const char *pEventName ) \
{ \
return g_pEventSystem->RegisterEvent( pEventName ); \
} \
};
FUNC_GENERATE_ALL( DEFINE_EVENT_INTERNAL )
#define DEFINE_EVENTID_INTERNAL( _eventName ) \
public: \
static EventId_t GetEventId() \
{ \
static EventId_t s_nEventId = EVENT_ID_INVALID; \
if ( s_nEventId == EVENT_ID_INVALID ) \
{ \
s_nEventId = RegisterEvent( #_eventName ); \
} \
return s_nEventId; \
}
#define DEFINE_EVENT( _eventName ) class _eventName : public CEventSignature0< _eventName > { DEFINE_EVENTID_INTERNAL( _eventName ); }
#define DEFINE_EVENT1( _eventName, _arg1 ) class _eventName : public CEventSignature1< _eventName, _arg1 > { DEFINE_EVENTID_INTERNAL( _eventName ); }
#define DEFINE_EVENT2( _eventName, _arg1, _arg2 ) class _eventName : public CEventSignature2< _eventName, _arg1, _arg2 > { DEFINE_EVENTID_INTERNAL( _eventName ); }
#define DEFINE_EVENT3( _eventName, _arg1, _arg2, _arg3 ) class _eventName : public CEventSignature3< _eventName, _arg1, _arg2, _arg3 > { DEFINE_EVENTID_INTERNAL( _eventName ); }
#define DEFINE_EVENT4( _eventName, _arg1, _arg2, _arg3, _arg4 ) class _eventName : public CEventSignature4< _eventName, _arg1, _arg2, _arg3, _arg4 > { DEFINE_EVENTID_INTERNAL( _eventName ); }
#define DEFINE_EVENT5( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5 ) class _eventName : public CEventSignature5< _eventName, _arg1, _arg2, _arg3, _arg4, _arg5 > { DEFINE_EVENTID_INTERNAL( _eventName ); }
#define DEFINE_EVENT6( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6 ) class _eventName : public CEventSignature6< _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6 > { DEFINE_EVENTID_INTERNAL( _eventName ); }
#define DEFINE_EVENT7( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7 ) class _eventName : public CEventSignature7< _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7 > { DEFINE_EVENTID_INTERNAL( _eventName ); }
#define DEFINE_EVENT8( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8 ) class _eventName : public CEventSignature8< _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8 > { DEFINE_EVENTID_INTERNAL( _eventName ); }
#define DEFINE_EVENT9( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9 ) class _eventName : public CEventSignature9< _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9 > { DEFINE_EVENTID_INTERNAL( _eventName ); }
#define DEFINE_EVENT10( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9, _arg10 ) class _eventName : public CEventSignature10< _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9, _arg10 > { DEFINE_EVENTID_INTERNAL( _eventName ); }
#define DEFINE_EVENT11( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9, _arg10, _arg11 ) class _eventName : public CEventSignature11< _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9, _arg10, _arg11 > { DEFINE_EVENTID_INTERNAL( _eventName ); }
#define DEFINE_EVENT12( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9, _arg10, _arg11, _arg12 ) class _eventName : public CEventSignature12< _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9, _arg10, _arg11, _arg12 > { DEFINE_EVENTID_INTERNAL( _eventName ); }
#define DEFINE_EVENT13( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9, _arg10, _arg11, _arg12, _arg13 ) class _eventName : public CEventSignature13< _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9, _arg10, _arg11, _arg12, _arg13 > { DEFINE_EVENTID_INTERNAL( _eventName ); }
#define DEFINE_EVENT14( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9, _arg10, _arg11, _arg12, _arg13, _arg14 ) class _eventName : public CEventSignature14< _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9, _arg10, _arg11, _arg12, _arg13, _arg14 > { DEFINE_EVENTID_INTERNAL( _eventName ); }
#define DEFINE_EVENT1_WITHNAMES( _eventName, _arg1, _arg1Name ) \
DEFINE_EVENT1( _eventName, _arg1 )
#define DEFINE_EVENT2_WITHNAMES( _eventName, _arg1, _arg1Name, _arg2, _arg2Name ) \
DEFINE_EVENT2( _eventName, _arg1, _arg2 )
#define DEFINE_EVENT3_WITHNAMES( _eventName, _arg1, _arg1Name, _arg2, _arg2Name, _arg3, _arg3Name ) \
DEFINE_EVENT3( _eventName, _arg1, _arg2, _arg3 )
#define DEFINE_EVENT4_WITHNAMES( _eventName, _arg1, _arg1Name, _arg2, _arg2Name, _arg3, _arg3Name, _arg4, _arg4Name ) \
DEFINE_EVENT4( _eventName, _arg1, _arg2, _arg3, _arg4 )
#define DEFINE_EVENT5_WITHNAMES( _eventName, _arg1, _arg1Name, _arg2, _arg2Name, _arg3, _arg3Name, _arg4, _arg4Name, _arg5, _arg5Name ) \
DEFINE_EVENT5( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5 )
#define DEFINE_EVENT6_WITHNAMES( _eventName, _arg1, _arg1Name, _arg2, _arg2Name, _arg3, _arg3Name, _arg4, _arg4Name, _arg5, _arg5Name, _arg6, _arg6Name ) \
DEFINE_EVENT6( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6 )
#define DEFINE_EVENT7_WITHNAMES( _eventName, _arg1, _arg1Name, _arg2, _arg2Name, _arg3, _arg3Name, _arg4, _arg4Name, _arg5, _arg5Name, _arg6, _arg6Name, _arg7, _arg7Name ) \
DEFINE_EVENT7( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7 )
#define DEFINE_EVENT8_WITHNAMES( _eventName, _arg1, _arg1Name, _arg2, _arg2Name, _arg3, _arg3Name, _arg4, _arg4Name, _arg5, _arg5Name, _arg6, _arg6Name, _arg7, _arg7Name, _arg8, _arg8Name ) \
DEFINE_EVENT8( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8 )
#define DEFINE_EVENT9_WITHNAMES( _eventName, _arg1, _arg1Name, _arg2, _arg2Name, _arg3, _arg3Name, _arg4, _arg4Name, _arg5, _arg5Name, _arg6, _arg6Name, _arg7, _arg7Name, _arg8, _arg8Name, _arg9, _arg9Name ) \
DEFINE_EVENT9( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9 )
#define DEFINE_EVENT10_WITHNAMES( _eventName, _arg1, _arg1Name, _arg2, _arg2Name, _arg3, _arg3Name, _arg4, _arg4Name, _arg5, _arg5Name, _arg6, _arg6Name, _arg7, _arg7Name, _arg8, _arg8Name, _arg9, _arg9Name, _arg10, _arg10Name ) \
DEFINE_EVENT10( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9, _arg10 )
#define DEFINE_EVENT11_WITHNAMES( _eventName, _arg1, _arg1Name, _arg2, _arg2Name, _arg3, _arg3Name, _arg4, _arg4Name, _arg5, _arg5Name, _arg6, _arg6Name, _arg7, _arg7Name, _arg8, _arg8Name, _arg9, _arg9Name, _arg10, _arg10Name, _arg11, _arg11Name ) \
DEFINE_EVENT11( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9, _arg10, _arg11 )
#define DEFINE_EVENT12_WITHNAMES( _eventName, _arg1, _arg1Name, _arg2, _arg2Name, _arg3, _arg3Name, _arg4, _arg4Name, _arg5, _arg5Name, _arg6, _arg6Name, _arg7, _arg7Name, _arg8, _arg8Name, _arg9, _arg9Name, _arg10, _arg10Name, _arg11, _arg11Name, _arg12, _arg12Name ) \
DEFINE_EVENT12( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9, _arg10, _arg11, _arg12 )
#define DEFINE_EVENT13_WITHNAMES( _eventName, _arg1, _arg1Name, _arg2, _arg2Name, _arg3, _arg3Name, _arg4, _arg4Name, _arg5, _arg5Name, _arg6, _arg6Name, _arg7, _arg7Name, _arg8, _arg8Name, _arg9, _arg9Name, _arg10, _arg10Name, _arg11, _arg11Name, _arg12, _arg12Name, _arg13, _arg13Name ) \
DEFINE_EVENT13( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9, _arg10, _arg11, _arg12, _arg13 )
#define DEFINE_EVENT14_WITHNAMES( _eventName, _arg1, _arg1Name, _arg2, _arg2Name, _arg3, _arg3Name, _arg4, _arg4Name, _arg5, _arg5Name, _arg6, _arg6Name, _arg7, _arg7Name, _arg8, _arg8Name, _arg9, _arg9Name, _arg10, _arg10Name, _arg11, _arg11Name, _arg12, _arg12Name, _arg13, _arg13Name, _arg14, _arg14Name ) \
DEFINE_EVENT14( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9, _arg10, _arg11, _arg12, _arg13, _arg14 )
#endif // IEVENTSYSTEM_H