/* 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 );
}