/* PCSX2 - PS2 Emulator for PCs * Copyright (C) 2002-2009 PCSX2 Dev Team * * PCSX2 is free software: you can redistribute it and/or modify it under the terms * of the GNU Lesser General Public License as published by the Free Software Found- * ation, either version 3 of the License, or (at your option) any later version. * * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with PCSX2. * If not, see . */ #pragma once using Threading::ScopedLock; template< typename EvtType > class PredicatesAreTheThingsOfNightmares { typedef EventListener< EvtType > ListenerType; protected: const void* const m_object_match; public: PredicatesAreTheThingsOfNightmares( const void* objmatch ) : m_object_match( objmatch ) { } bool operator()( const ListenerType& src ) const { return src.object == m_object_match; } }; // Checks for duplicates before adding the event. template< typename EvtType > void EventSource::Add( const ListenerType& listener ) { ScopedLock locker( m_listeners_lock ); if( !pxAssertDev( listener.OnEvent != NULL, "NULL listener callback function." ) ) return; Handle iter = m_listeners.begin(); while( iter != m_listeners.end() ) { if( *iter == listener ) return; ++iter; } _AddFast_without_lock( listener ); } template< typename EvtType > void EventSource::Remove( const ListenerType& listener ) { ScopedLock locker( m_listeners_lock ); m_cache_valid = false; m_listeners.remove( listener ); } template< typename EvtType > void EventSource::Remove( const Handle& listenerHandle ) { ScopedLock locker( m_listeners_lock ); m_cache_valid = false; m_listeners.erase( listenerHandle ); } template< typename EvtType > typename EventSource::Handle EventSource::AddFast( const ListenerType& listener ) { ScopedLock locker( m_listeners_lock ); return _AddFast_without_lock( listener ); } template< typename EvtType > typename EventSource::Handle EventSource::_AddFast_without_lock( const ListenerType& listener ) { m_cache_valid = false; m_listeners.push_front( listener ); return m_listeners.begin(); } template< typename EvtType > void EventSource::Add( void* objhandle, typename ListenerType::FuncType* fnptr ) { Add( ListenerType( objhandle, fnptr ) ); } template< typename EvtType > void EventSource::Remove( void* objhandle, typename ListenerType::FuncType* fnptr ) { Remove( ListenerType( objhandle, fnptr ) ); } // removes all listeners which reference the given object. Use for assuring object deletion. template< typename EvtType > void EventSource::RemoveObject( const void* object ) { m_cache_valid = false; m_listeners.remove_if( PredicatesAreTheThingsOfNightmares( object ) ); } template< typename EvtType > __forceinline void EventSource::_DispatchRaw( ConstIterator iter, const ConstIterator& iend, EvtType& evt ) { while( iter != iend ) { try { iter->OnEvent( iter->object, evt ); } catch( Exception::RuntimeError& ex ) { Console.Error( L"Ignoring runtime error thrown from event listener: " + ex.FormatDiagnosticMessage() ); } catch( Exception::BaseException& ex ) { if( IsDevBuild ) throw; Console.Error( L"Ignoring non-runtime BaseException thrown from event listener: " + ex.FormatDiagnosticMessage() ); } ++iter; } } template< typename EvtType > void EventSource::Dispatch( EvtType& evt ) { if( !m_cache_valid ) { m_cache_copy = m_listeners; m_cache_valid = true; } _DispatchRaw( m_cache_copy.begin(), m_cache_copy.end(), evt ); }