//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // //============================================================================= #ifndef CALLQUEUE_H #define CALLQUEUE_H #include "functors.h" #include "tier0/tslist.h" #if defined(_WIN32) #pragma once #endif //----------------------------------------------------- // Avert thy eyes! Imagine rather: // // void QueueCall( , [args1, [arg2,]...] // void QueueCall( , , [args1, [arg2,]...] // void QueueRefCall( , <, [args1, [arg2,]...] //----------------------------------------------------- #define DEFINE_CALLQUEUE_NONMEMBER_QUEUE_CALL(N) \ template \ void QueueCall(FUNCTION_RETTYPE (*pfnProxied)( \ FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) FUNC_ARG_FORMAL_PARAMS_##N) { \ QueueFunctorInternal( \ CreateFunctor(pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N)); \ } //------------------------------------- #define DEFINE_CALLQUEUE_MEMBER_QUEUE_CALL(N) \ template \ void QueueCall(OBJECT_TYPE_PTR pObject, \ FUNCTION_RETTYPE (FUNCTION_CLASS::*pfnProxied)( \ FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) \ FUNC_ARG_FORMAL_PARAMS_##N) { \ QueueFunctorInternal( \ CreateFunctor(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N)); \ } //------------------------------------- #define DEFINE_CALLQUEUE_CONST_MEMBER_QUEUE_CALL(N) \ template \ void QueueCall(OBJECT_TYPE_PTR pObject, \ FUNCTION_RETTYPE (FUNCTION_CLASS::*pfnProxied)( \ FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) \ const FUNC_ARG_FORMAL_PARAMS_##N) { \ QueueFunctorInternal( \ CreateFunctor(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N)); \ } //------------------------------------- #define DEFINE_CALLQUEUE_REF_COUNTING_MEMBER_QUEUE_CALL(N) \ template \ void QueueRefCall(OBJECT_TYPE_PTR pObject, \ FUNCTION_RETTYPE (FUNCTION_CLASS::*pfnProxied)( \ FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) \ FUNC_ARG_FORMAL_PARAMS_##N) { \ QueueFunctorInternal(CreateRefCountingFunctor( \ pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N)); \ } //------------------------------------- #define DEFINE_CALLQUEUE_REF_COUNTING_CONST_MEMBER_QUEUE_CALL(N) \ template \ void QueueRefCall(OBJECT_TYPE_PTR pObject, \ FUNCTION_RETTYPE (FUNCTION_CLASS::*pfnProxied)( \ FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) \ const FUNC_ARG_FORMAL_PARAMS_##N) { \ QueueFunctorInternal(CreateRefCountingFunctor( \ pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N)); \ } #define FUNC_GENERATE_QUEUE_METHODS() \ FUNC_GENERATE_ALL(DEFINE_CALLQUEUE_NONMEMBER_QUEUE_CALL); \ FUNC_GENERATE_ALL(DEFINE_CALLQUEUE_MEMBER_QUEUE_CALL); \ FUNC_GENERATE_ALL(DEFINE_CALLQUEUE_CONST_MEMBER_QUEUE_CALL); \ FUNC_GENERATE_ALL(DEFINE_CALLQUEUE_REF_COUNTING_MEMBER_QUEUE_CALL); \ FUNC_GENERATE_ALL(DEFINE_CALLQUEUE_REF_COUNTING_CONST_MEMBER_QUEUE_CALL) //----------------------------------------------------- template > class CCallQueueT { public: CCallQueueT() : m_bNoQueue(false) { #ifdef _DEBUG m_nCurSerialNumber = 0; m_nBreakSerialNumber = (unsigned)-1; #endif } void DisableQueue(bool bDisable) { if (m_bNoQueue == bDisable) { return; } if (!m_bNoQueue) CallQueued(); m_bNoQueue = bDisable; } bool IsDisabled() const { return m_bNoQueue; } int Count() { return m_queue.Count(); } void CallQueued() { if (!m_queue.Count()) { return; } m_queue.PushItem(NULL); CFunctor *pFunctor; while (m_queue.PopItem(&pFunctor) && pFunctor != NULL) { #ifdef _DEBUG if (pFunctor->m_nUserID == m_nBreakSerialNumber) { m_nBreakSerialNumber = (unsigned)-1; } #endif (*pFunctor)(); pFunctor->Release(); } } void QueueFunctor(CFunctor *pFunctor) { Assert(pFunctor); QueueFunctorInternal(RetAddRef(pFunctor)); } void Flush() { m_queue.PushItem(NULL); CFunctor *pFunctor; while (m_queue.PopItem(&pFunctor) && pFunctor != NULL) { pFunctor->Release(); } } FUNC_GENERATE_QUEUE_METHODS(); private: void QueueFunctorInternal(CFunctor *pFunctor) { if (!m_bNoQueue) { #ifdef _DEBUG pFunctor->m_nUserID = m_nCurSerialNumber++; #endif m_queue.PushItem(pFunctor); } else { (*pFunctor)(); pFunctor->Release(); } } QUEUE_TYPE m_queue; bool m_bNoQueue; unsigned m_nCurSerialNumber; unsigned m_nBreakSerialNumber; }; class CCallQueue : public CCallQueueT<> {}; //----------------------------------------------------- // Optional interface that can be bound to concrete CCallQueue //----------------------------------------------------- class ICallQueue { public: void QueueFunctor(CFunctor *pFunctor) { QueueFunctorInternal(RetAddRef(pFunctor)); } FUNC_GENERATE_QUEUE_METHODS(); private: virtual void QueueFunctorInternal(CFunctor *pFunctor) = 0; }; #endif // CALLQUEUE_H