DRDE/AusRegCliever/include/EventSender.h

220 lines
6.5 KiB
C++

#ifndef EVENT_SENDER_H
#define EVENT_SENDER_H
/**
\file
Class template definition file.
\copyright
Copyright (C) 2002, 2003 Oliver Schoenborn
This software is provided 'as-is', without
any express or implied warranty. In no event
will the authors be held liable for any
damages arising from the use of this
software.
You can redistribute it and/or modify it
under the terms found in the LICENSE file that
is included in the library distribution.
\endcopyright
*/
#include <list>
#include <typeinfo>
#include <string>
#include <sstream>
#include "Listener.h" // uses inline
#include "EventFWD.h"
#include "PolymorphEvent.h"
//class PolymorphEvent;
template <typename EvType>
class EventSender
{
public: // types
/// Simpler form of Listener<EvType>
typedef Listener<EvType> TListener;
private: // types
/// So Listener<EvType> can call register etc
friend class Listener<EvType>;
/// Short form of std::list<TListener*>.
typedef std::list<TListener*> Registry;
public: // static methods
class IllegalSendError;
inline static void remove(TListener&);
inline static void add(TListener&);
inline static void send(const EvType&);
inline static bool isSending();
inline static bool hasListeners();
inline static unsigned int getNumListeners();
inline static unsigned int getMinNumIgnored();
private: // construct/destroy singleton
EventSender(): _isBusySending(false), _eventIgnored(0) {}
~EventSender();
private: // methods called by Listener
void registerListener(TListener*);
void removeListener(TListener*);
void incEventIgnored() {_eventIgnored ++;}
static EventSender<EvType>& instance(); // MUST NOT BE INLINE
private: // utility methods
void sendEvent(const EvType&);
void cleanupQueues();
bool removeFrom(Registry&, TListener*);
inline std::string lisnrID(TListener* = NULL) const;
//bool hasListener(TListener*) const;
private: // data
/// Registry of listeners that want to hear events of this type
Registry _registry;
/// True if EvType events are being sent (ie calling listeners)
bool _isBusySending;
/// How many listeners ignored the last event sent (so far)
unsigned int _eventIgnored;
/// The queue for registering listeners when send() is in progress
Registry _registrationQueue;
/// The queue for removing listeners when send() is in progress
Registry _removalQueue;
};
/** Specialization of EventSender for events inheriting
from PolymorphEvent. This provides a natural alternative
to the call on Polymorph::send().
*/
template <>
class EventSender<PolymorphEvent>
{
public:
/** Send the polymorphic event to its listeners. It simply calls
PolymorphEvent::send(), which must be overriden by subclasses
of PolymorphEvent to call EventSender<EvType>::send(const EvType&).
Hence see the latter for more info.
*/
static void send(const PolymorphEvent& event)
{
event.send();
}
};
/* Include IllegalSendError in this header so users don't have
to include manually. It has to be included after class definition
since it is an inner class to EventSender.
*/
#include "IllegalSendError.h"
/** Are there listeners currently registered? If this returns false,
creating and send()ing and event just wastes cpu cycles since no
one will hear event.
\return true if there are listeners in registry
*/
template<typename EvType>
inline bool
EventSender<EvType>::hasListeners()
{
return ! instance()._registry.empty();
}
/** Get how many listeners have ignored the event
that is currently being sent and that they have received.
This number is reset to 0 before every call to send(const EvType&).
This number is a minimum, since a listener is not required to
tell EventSender<EvType> that it is ignoring an event.
*/
template<typename EvType>
inline unsigned int
EventSender<EvType>::getMinNumIgnored()
{
return instance()._eventIgnored;
}
/** Get how many listeners are currently registered. Note that if
isSending() is true, then this number does not take into account
listeners that are queued for registration/removal.
*/
template<typename EvType>
inline unsigned int
EventSender<EvType>::getNumListeners()
{
return instance()._registry.size();
}
/** Send the \a event to its listeners.
- Upon return, getNumIgnored() will have the number of
listeners who have ignored the event.
- If one of the called listeners calls registerListener or
removeListener, the operation will be queued and processed only
after the event has been sent to all listeners. This insures the
integrity of the list of listeners during the send()
process.
- Throws an exception if called while another send() is
taking place, see IllegalSendError. You can use
isSending() to test whether a send is taking place.
- All other exceptions are caught
\exception IllegalSendError
*/
template<typename EvType>
inline void
EventSender<EvType>::send(const EvType& event)
{
instance().sendEvent(event);
}
/** Is this event sender currently sending the event to
its listeners? True if yes, false otherwise.
*/
template<typename EvType>
inline bool
EventSender<EvType>::isSending()
{
return instance()._isBusySending;
}
/** Remove the \a listener from the registry. Does
nothing if the listener is not in the registry.
*/
template<typename EvType>
inline void
EventSender<EvType>::remove(TListener& listener)
{
listener.TListener::ignoreEvents();
}
/** Add the \a listener to the registry. Does nothing
if the listener is already registered.
*/
template<typename EvType>
inline void
EventSender<EvType>::add(TListener& listener)
{
listener.TListener::listenForEvents();
}
/// Shortcut for TypeID of a listener
template<typename EvType>
inline std::string
EventSender<EvType>::lisnrID(TListener* lisnr)
const
{
std::ostringstream lisnrStr;
lisnrStr << typeid(TListener).name();
if (lisnr) lisnrStr << ":" << lisnr;
return lisnrStr.str();
}
//#ifdef __GNUG__
// // because gcc doesn't handle separate template definition
// #include "EventSender.cc"
//#endif
#endif // EVENT_SENDER_H