mirror of
https://github.com/SWG-Source/src.git
synced 2026-07-29 23:15:56 -04:00
Added sharedLog and sharedMessageDispatch libraries
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
project(sharedMessageDispatch)
|
||||
|
||||
if(WIN32)
|
||||
add_definitions(/D_CRT_SECURE_NO_WARNINGS)
|
||||
endif()
|
||||
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/public)
|
||||
|
||||
add_subdirectory(src)
|
||||
+1
@@ -0,0 +1 @@
|
||||
#include "../../src/shared/Emitter.h"
|
||||
+1
@@ -0,0 +1 @@
|
||||
#include "../../src/shared/FirstSharedMessageDispatch.h"
|
||||
+1
@@ -0,0 +1 @@
|
||||
#include "../../src/shared/Message.h"
|
||||
+1
@@ -0,0 +1 @@
|
||||
#include "../../src/shared/MessageManager.h"
|
||||
+1
@@ -0,0 +1 @@
|
||||
#include "../../src/shared/Receiver.h"
|
||||
+1
@@ -0,0 +1 @@
|
||||
#include "../../src/shared/Transceiver.h"
|
||||
@@ -0,0 +1,37 @@
|
||||
|
||||
set(SHARED_SOURCES
|
||||
shared/Emitter.cpp
|
||||
shared/Emitter.h
|
||||
shared/FirstSharedMessageDispatch.h
|
||||
shared/Message.cpp
|
||||
shared/Message.h
|
||||
shared/MessageManager.cpp
|
||||
shared/MessageManager.h
|
||||
shared/Receiver.cpp
|
||||
shared/Receiver.h
|
||||
shared/Transceiver.cpp
|
||||
shared/Transceiver.h
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
set(PLATFORM_SOURCES
|
||||
win32/FirstSharedMessageDispatch.cpp
|
||||
)
|
||||
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/win32)
|
||||
else()
|
||||
set(PLATFORM_SOURCES "")
|
||||
endif()
|
||||
|
||||
include_directories(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/shared
|
||||
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedDebug/include/public
|
||||
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFoundation/include/public
|
||||
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFoundationTypes/include/public
|
||||
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMemoryManager/include/public
|
||||
)
|
||||
|
||||
add_library(sharedMessageDispatch STATIC
|
||||
${SHARED_SOURCES}
|
||||
${PLATFORM_SOURCES}
|
||||
)
|
||||
@@ -0,0 +1,268 @@
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
#include "sharedMessageDispatch/FirstSharedMessageDispatch.h"
|
||||
|
||||
#include "sharedDebug/Profiler.h"
|
||||
#include "sharedMessageDispatch/Emitter.h"
|
||||
#include "sharedMessageDispatch/MessageManager.h"
|
||||
#include "sharedMessageDispatch/Receiver.h"
|
||||
#include "sharedMessageDispatch/Message.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
||||
namespace MessageDispatch {
|
||||
struct Emitter::ReceiverList
|
||||
{
|
||||
typedef std::set<Receiver *> ReceiverSet;
|
||||
typedef std::map<unsigned long int, ReceiverSet> Container;
|
||||
mutable Container c;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief Construct an emitter
|
||||
|
||||
An Emitter is an abstract base. This is never directly invoked.
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
Emitter::Emitter() :
|
||||
receiverList(new ReceiverList)
|
||||
{
|
||||
assert (receiverList != NULL);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief pure virtual destructor
|
||||
|
||||
The Emitter destructor cleans up message dispatch relationships
|
||||
*/
|
||||
Emitter::~Emitter()
|
||||
{
|
||||
for(ReceiverList::Container::iterator i = receiverList->c.begin(); i != receiverList->c.end(); ++i)
|
||||
{
|
||||
ReceiverList::ReceiverSet & targets = (*i).second;
|
||||
for(ReceiverList::ReceiverSet::iterator j = targets.begin(); j != targets.end(); ++j)
|
||||
{
|
||||
Receiver * r = (*j);
|
||||
r->emitterDestroyed(*this);
|
||||
}
|
||||
}
|
||||
|
||||
delete receiverList;
|
||||
receiverList = 0;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief Attach a Receiver object directly to this Emitter
|
||||
|
||||
When a Receiver needs to specifically target a particular emitter,
|
||||
it should invoke addReceiver and specify the message type it is
|
||||
subscribing to.
|
||||
|
||||
@param target The Receiver object that will receive the
|
||||
specified message when the Emitter emits.
|
||||
@param messageTypeName The message type that the Emitter should
|
||||
deliver to the target Receiver.
|
||||
|
||||
@see Receiver
|
||||
@see MessageManager::addReceiver
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
void Emitter::addReceiver(Receiver & target, const char * const messageTypeName) const
|
||||
{
|
||||
const unsigned long int messageType = MessageBase::makeMessageTypeFromString(messageTypeName);
|
||||
addReceiver(target, messageType);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void Emitter::addReceiver(Receiver & target, const MessageBase & source) const
|
||||
{
|
||||
const unsigned long int messageType = source.getType();
|
||||
addReceiver(target, messageType);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void Emitter::addReceiver(Receiver & target, const unsigned long int messageType) const
|
||||
{
|
||||
ReceiverList::Container::iterator i = receiverList->c.find(messageType);
|
||||
|
||||
if(i == receiverList->c.end())
|
||||
{
|
||||
ReceiverList::ReceiverSet newSet;
|
||||
newSet.insert(&target); //lint !e534 // ignoring iterator returned from insert
|
||||
receiverList->c.insert (std::make_pair (messageType, newSet));
|
||||
}
|
||||
else
|
||||
{
|
||||
ReceiverList::ReceiverSet & s = (*i).second;
|
||||
s.insert(&target); //lint !e534 // ignoring iterator returned from insert
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief emit a message
|
||||
|
||||
All targeted Receivers will receive the Message that is emitted by
|
||||
this Emitter object. The Message is forwarded to the MessageManager
|
||||
to be dispatched to objects that are interested in receiving ALL
|
||||
messages of a specific type, regardless of who emits it. Those
|
||||
Receiver objects will only receive the Message via the MessageManager
|
||||
if they did NOT receive the message from this Emitter object as a
|
||||
targetted message.
|
||||
|
||||
@param message A const reference to a MessageBase object that will
|
||||
be delivered to registered Receivers.
|
||||
|
||||
@see addReceiver
|
||||
@see MessageManager::addReceiver
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
void Emitter::emitMessage(const MessageBase & message) const
|
||||
{
|
||||
NOT_NULL(receiverList);
|
||||
|
||||
ReceiverList::Container::iterator i = receiverList->c.find(message.getType());
|
||||
if(i != receiverList->c.end())
|
||||
{
|
||||
//-- make copy
|
||||
const ReceiverList::ReceiverSet targets = (*i).second;
|
||||
for(ReceiverList::ReceiverSet::const_iterator j = targets.begin(); j != targets.end(); ++j)
|
||||
{
|
||||
Receiver * r = (*j);
|
||||
NOT_NULL(r);
|
||||
r->receiveMessage(*this, message);
|
||||
}
|
||||
}
|
||||
MessageManager::getInstance().emitMessage(*this, message);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief helper to determine if an Emitter has a Receiver in it's target
|
||||
list
|
||||
|
||||
This helper is invoked by the MessageManager to determine if a
|
||||
Receiver is registered as a target for a message type. When the
|
||||
Emitter emits a message, all Receiver objects registered with the
|
||||
Emitter will receive the message. If a Receiver object is ALSO registered
|
||||
with the MessageManager to receive ALL messages of the requested type,
|
||||
the MessageManager invokes this method on the source Emitter object
|
||||
to ensure that the Receiver target is not delivered the same message
|
||||
twice.
|
||||
|
||||
@param target The receiver to search for
|
||||
@param messageType The MessageBase typeID of the message that the
|
||||
receiver is interested in.
|
||||
|
||||
@return true if this Emitter object has the Receiver mapped to the
|
||||
messageType in it's target list.
|
||||
|
||||
@see MessageManager
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
const bool Emitter::hasReceiver(const Receiver & target, const unsigned long int messageType) const
|
||||
{
|
||||
bool result = false;
|
||||
ReceiverList::Container::const_iterator i = receiverList->c.find(messageType);
|
||||
if(i != receiverList->c.end())
|
||||
{
|
||||
const ReceiverList::ReceiverSet & targets = (*i).second;
|
||||
const ReceiverList::ReceiverSet::const_iterator j = targets.find(const_cast<Receiver *>(&target)); //stl is broken
|
||||
result = (j != targets.end());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief helper to determine if an Emitter has a Receiver in it's target
|
||||
list
|
||||
|
||||
This helper is invoked to determine if a Receiver is registered as a
|
||||
target for any message type.
|
||||
|
||||
@param target The receiver to search for
|
||||
|
||||
@return true if this Emitter object has the Receiver mapped to any messageType
|
||||
|
||||
@see MessageManager
|
||||
|
||||
@author John Watson
|
||||
*/
|
||||
const bool Emitter::hasReceiver(const Receiver & target) const
|
||||
{
|
||||
for (ReceiverList::Container::const_iterator i = receiverList->c.begin (); i != receiverList->c.end (); ++i)
|
||||
{
|
||||
const ReceiverList::ReceiverSet & targets = (*i).second;
|
||||
const ReceiverList::ReceiverSet::const_iterator j = targets.find(const_cast<Receiver *>(&target)); //stl is broken
|
||||
if (j != targets.end())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief remove a receiver from target lists
|
||||
|
||||
This is most often invoked from a Receiver object's destructor. It
|
||||
removes the receiver from all Message mappings.
|
||||
|
||||
@param target The receiver that is being destroyed
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
void Emitter::receiverDestroyed(const Receiver & target) const
|
||||
{
|
||||
// find the receiver
|
||||
for(ReceiverList::Container::iterator i = receiverList->c.begin(); i != receiverList->c.end(); ++i)
|
||||
{
|
||||
ReceiverList::ReceiverSet & targets = (*i).second;
|
||||
const ReceiverList::ReceiverSet::iterator j = targets.find(const_cast<Receiver *>(&target)); //stl is broken
|
||||
|
||||
if(j != targets.end())
|
||||
{
|
||||
targets.erase(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief Remove a Receiver object from a specific message in the target map
|
||||
|
||||
@param target The Receiver object that will break the
|
||||
Target->message relationship.
|
||||
@param messageTypeName A message type describing the message type the
|
||||
Receiver will disassociate itself from
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
void Emitter::removeReceiver(const Receiver & target, const char * const messageTypeName) const
|
||||
{
|
||||
unsigned long int messageType = MessageBase::makeMessageTypeFromString(messageTypeName);
|
||||
|
||||
const ReceiverList::Container::iterator i = receiverList->c.find(messageType);
|
||||
if(i != receiverList->c.end())
|
||||
{
|
||||
ReceiverList::ReceiverSet & rset = (*i).second;
|
||||
//const cast for broken stl
|
||||
rset.erase(const_cast<Receiver *>(&target)); //lint !e534 // ignoring iterator returned from insert
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
}//namespace MessageDispatch
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// Emitter.h
|
||||
// copyright 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_Emitter_H
|
||||
#define INCLUDED_Emitter_H
|
||||
|
||||
// ======================================================================
|
||||
|
||||
namespace MessageDispatch
|
||||
{
|
||||
|
||||
class MessageBase;
|
||||
class Receiver;
|
||||
|
||||
/**
|
||||
@brief Class that can emit messages
|
||||
|
||||
Emitter objects can transmit Message objects, which are dispatched
|
||||
to receivers either directly, or via the MessageManager.
|
||||
|
||||
@see Message
|
||||
@see MessageBase
|
||||
@see Receiver
|
||||
@see MessageManager
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
class Emitter
|
||||
{
|
||||
public:
|
||||
Emitter();
|
||||
virtual ~Emitter();
|
||||
void addReceiver(Receiver & target, const char * const messageTypeName) const;
|
||||
void addReceiver(Receiver & target, const MessageBase & source) const;
|
||||
void addReceiver(Receiver & target, const unsigned long int messageType) const;
|
||||
void emitMessage(const MessageBase & message) const;
|
||||
|
||||
const bool hasReceiver(const Receiver & target, const unsigned long int messageType) const;
|
||||
const bool hasReceiver(const Receiver & target) const;
|
||||
|
||||
void receiverDestroyed(const Receiver & target) const;
|
||||
void removeReceiver(const Receiver & target, const char * const messageTypeName) const;
|
||||
|
||||
private:
|
||||
|
||||
struct ReceiverList;
|
||||
ReceiverList * receiverList;
|
||||
};
|
||||
|
||||
|
||||
}// namespace MessageDispatch
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// FirstMessageDispatch.h
|
||||
// copyright (c) 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_FirstMessageDispatch_H
|
||||
#define INCLUDED_FirstMessageDispatch_H
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedFoundation/FirstSharedFoundation.h"
|
||||
#include "sharedMessageDispatch/Emitter.h"
|
||||
#include "sharedMessageDispatch/MessageManager.h"
|
||||
#include "sharedMessageDispatch/Message.h"
|
||||
#include "sharedMessageDispatch/Receiver.h"
|
||||
#include <set>
|
||||
#include <hash_map>
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,81 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// FirstMessageDispatch.h
|
||||
// copyright (c) 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedMessageDispatch/FirstSharedMessageDispatch.h"
|
||||
#include "sharedMessageDispatch/Message.h"
|
||||
|
||||
#include "sharedFoundation/LabelHash.h"
|
||||
#include "sharedFoundation/Crc.h"
|
||||
#include "sharedFoundation/Production.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace MessageDispatch
|
||||
{
|
||||
|
||||
// ======================================================================
|
||||
|
||||
/**
|
||||
@brief build a message type to identify a message
|
||||
|
||||
Returns an STL hash of the type name.
|
||||
*/
|
||||
const unsigned long int MessageBase::makeMessageTypeFromString(const char * const idString)
|
||||
{
|
||||
unsigned long int result = 0;
|
||||
#if PRODUCTION == 0
|
||||
result = LabelHash::hashLabel("MessageDispatch", idString);
|
||||
#else
|
||||
result = Crc::calculate(idString);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief construct a named message object
|
||||
|
||||
The MessageBase is an abstract base class. Initializes the type
|
||||
member to the STL hash of the name string.
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
MessageBase::MessageBase(const char * const typeName) :
|
||||
type(0)
|
||||
{
|
||||
type = makeMessageTypeFromString(typeName);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief construct a named message object
|
||||
|
||||
The MessageBase is an abstract base class. Initializes the type
|
||||
the supplied type. Useful when the hash is cached.
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
MessageBase::MessageBase(const unsigned long int newType) :
|
||||
type(newType)
|
||||
{
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief destroy the MessageBase object
|
||||
|
||||
Doesn't do anything special.
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
MessageBase::~MessageBase()
|
||||
{
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
} // namespace MessageDispatch
|
||||
@@ -0,0 +1,210 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// Message.h
|
||||
// copyright 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_Message_H
|
||||
#define INCLUDED_Message_H
|
||||
|
||||
// ======================================================================
|
||||
|
||||
namespace MessageDispatch
|
||||
{
|
||||
/**
|
||||
@brief A base class defining a common interface for Message object
|
||||
handling.
|
||||
|
||||
The MessageBase is a pure virtual class. All Message objects
|
||||
handled by Emitter and Receiver objects derive from the MessageBase.
|
||||
|
||||
@see Message
|
||||
@author Justin Randall
|
||||
*/
|
||||
class MessageBase
|
||||
{
|
||||
public:
|
||||
explicit MessageBase(const char * const typeName);
|
||||
explicit MessageBase(const unsigned long int type);
|
||||
virtual ~MessageBase();
|
||||
static const unsigned long int makeMessageTypeFromString(const char * const id);
|
||||
const unsigned long int getType() const;
|
||||
const bool isType(const char * const typeName) const;
|
||||
void setType(const unsigned long int newType);
|
||||
void setType(const char * const typeName);
|
||||
private:
|
||||
MessageBase();
|
||||
unsigned long int type;
|
||||
};
|
||||
|
||||
/**
|
||||
@brief Message template
|
||||
|
||||
Builds a message from some user supplied class.
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
template<class ValueType>
|
||||
class Message : public MessageBase
|
||||
{
|
||||
public:
|
||||
explicit Message(const char * const typeName="");
|
||||
explicit Message(const unsigned long int type);
|
||||
Message(const char * const typeName, const ValueType & value);
|
||||
Message(const unsigned long int type, const ValueType & value);
|
||||
explicit Message(const Message & source);
|
||||
virtual ~Message();
|
||||
Message & operator = (const Message & rhs);
|
||||
const ValueType & getValue() const;
|
||||
void setValue(const ValueType & rhs);
|
||||
private:
|
||||
ValueType value;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief get the type of Message
|
||||
|
||||
@return the type of the Message. The type is an STL hash of the
|
||||
type name.
|
||||
*/
|
||||
inline const unsigned long int MessageBase::getType() const
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
inline const bool MessageBase::isType(const char * const typeName) const
|
||||
{
|
||||
return (makeMessageTypeFromString(typeName) == type);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
@brief set or reset the type identifier
|
||||
*/
|
||||
inline void MessageBase::setType(const unsigned long newType)
|
||||
{
|
||||
type = newType;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
@brief set or reset the type identifier
|
||||
*/
|
||||
inline void MessageBase::setType(const char * const typeName)
|
||||
{
|
||||
setType(makeMessageTypeFromString(typeName));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
@brief construct a named message
|
||||
|
||||
@param typeName A string describing the type of message. This
|
||||
value is hashed (using the STL hash function)
|
||||
the result is used for the MessageBase type name.
|
||||
@author Justin Randall
|
||||
*/
|
||||
template<class ValueType>
|
||||
inline Message<ValueType>::Message(const char * const typeName) :
|
||||
MessageBase(typeName),
|
||||
value()
|
||||
{
|
||||
}
|
||||
|
||||
template<class ValueType>
|
||||
inline Message<ValueType>::Message(const unsigned long int type) :
|
||||
MessageBase(type),
|
||||
value()
|
||||
{
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief Construct a named message and initialize it to the
|
||||
supplied ValueType value.
|
||||
|
||||
@param typeName A string describing the type of message. This
|
||||
value is hashed (using the STL hash function)
|
||||
the result is used for the MessageBase type name.
|
||||
@newValue Some value to initialize the message object to.
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
template<class ValueType>
|
||||
inline Message<ValueType>::Message(const char * const typeName, const ValueType & newValue) :
|
||||
MessageBase(typeName),
|
||||
value(newValue)
|
||||
{
|
||||
}
|
||||
|
||||
template<class ValueType>
|
||||
inline Message<ValueType>::Message(const unsigned long int type, const ValueType & newValue) :
|
||||
MessageBase(type),
|
||||
value(newValue)
|
||||
{
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief Message copy constructor
|
||||
|
||||
Performs a copy of the message type and value members.
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
template<class ValueType>
|
||||
inline Message<ValueType>::Message(const Message<ValueType> & source) :
|
||||
MessageBase(source.getType()),
|
||||
value(source.getValue())
|
||||
{
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief destroy the Message object
|
||||
|
||||
Doesn't do anything special.
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
template<class ValueType>
|
||||
inline Message<ValueType>::~Message()
|
||||
{
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief Assign the souce ValueType to the value member
|
||||
|
||||
@param source the new value for the Message::value member
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
template<class ValueType>
|
||||
inline void Message<ValueType>::setValue(const ValueType & source)
|
||||
{
|
||||
value = source;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief return the Message::value member
|
||||
|
||||
@return the value of the value member
|
||||
*/
|
||||
template<class ValueType>
|
||||
inline const ValueType & Message<ValueType>::getValue() const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
}//namespace MessageDispatch
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif // _Message_H
|
||||
@@ -0,0 +1,225 @@
|
||||
#include "sharedMessageDispatch/FirstSharedMessageDispatch.h"
|
||||
|
||||
#include "sharedDebug/Profiler.h"
|
||||
#include "sharedMessageDispatch/Emitter.h"
|
||||
#include "sharedMessageDispatch/Message.h"
|
||||
#include "sharedMessageDispatch/MessageManager.h"
|
||||
#include "sharedMessageDispatch/Receiver.h"
|
||||
|
||||
#include <set>
|
||||
#include <hash_map>
|
||||
|
||||
namespace MessageDispatch {
|
||||
|
||||
MessageManager MessageManager::ms_instance;
|
||||
|
||||
struct MessageManager::Data
|
||||
{
|
||||
std::hash_map<unsigned long int, std::set<Receiver *> > receivers;
|
||||
std::hash_map<unsigned long int, std::set<void (*)(const Emitter &, const MessageBase &)> > staticCallbacks;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief Do NOT construct Singleton objects directly!
|
||||
*/
|
||||
MessageManager::MessageManager()
|
||||
: data (new Data)
|
||||
{
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief Do NOT destroy Singleton objects directly!
|
||||
*/
|
||||
MessageManager::~MessageManager()
|
||||
{
|
||||
delete data;
|
||||
data = 0;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief add a Receiver object to a map of Receiver objects that will
|
||||
receive all messages of a certain type.
|
||||
|
||||
Some Receiver objects may wish to receive a message of a certain
|
||||
type regardless of the Emitter object that originates the message.
|
||||
|
||||
@param target The Receiver object that will listen for all
|
||||
messages of the requested type
|
||||
@param messageTypeName The message type to listen for
|
||||
|
||||
@see Emitter::addReceiver
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
void MessageManager::addReceiver(Receiver & target, const char * const messageTypeName)
|
||||
{
|
||||
const unsigned long int messageType = MessageBase::makeMessageTypeFromString(messageTypeName);
|
||||
addReceiver(target, messageType);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void MessageManager::addReceiver(Receiver & target, const MessageBase & source)
|
||||
{
|
||||
const unsigned long int messageType = source.getType();
|
||||
addReceiver(target, messageType);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void MessageManager::addReceiver(Receiver & target, const unsigned long int messageType)
|
||||
{
|
||||
std::hash_map<unsigned long int, std::set<Receiver *> >::iterator i = data->receivers.find(messageType);
|
||||
if(i != data->receivers.end())
|
||||
{
|
||||
target.setHasTargets(true);
|
||||
std::set<Receiver *> & targets = (*i).second;
|
||||
targets.insert(&target);//lint !e534 // ignoring iterator returned from insert
|
||||
}
|
||||
else
|
||||
{
|
||||
target.setHasTargets(true);
|
||||
std::set<Receiver *> newTargets;
|
||||
newTargets.insert(&target);//lint !e534 // ignoring iterator returned from insert
|
||||
data->receivers[messageType] = newTargets;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void MessageManager::addStaticCallback(void (*callback)(const Emitter &, const MessageBase &), const unsigned long int messageType)
|
||||
{
|
||||
std::hash_map<unsigned long int, std::set<void (*)(const Emitter &, const MessageBase &)> >::iterator f = data->staticCallbacks.find(messageType);
|
||||
if(f != data->staticCallbacks.end())
|
||||
{
|
||||
std::set<void (*)(const Emitter &, const MessageBase &)> & targets = f->second;
|
||||
targets.insert(callback);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::set<void (*)(const Emitter &, const MessageBase &)> newTargets;
|
||||
newTargets.insert(callback);
|
||||
data->staticCallbacks[messageType] = newTargets;
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief Invoked by Emitter objects when a message is broadcast
|
||||
|
||||
@param emitter The source of the MessageBase object being broadcast
|
||||
@param message The message being broadcast
|
||||
|
||||
@see Emitter::emit
|
||||
@see Receiver::onReceive
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
void MessageManager::emitMessage(const Emitter & emitter, const MessageBase & message) const
|
||||
{
|
||||
const unsigned long int messageType = message.getType();
|
||||
std::hash_map<unsigned long int, std::set<Receiver *> >::const_iterator i = data->receivers.find(messageType);
|
||||
if(i != data->receivers.end())
|
||||
{
|
||||
const std::set<Receiver *> targets = (*i).second;
|
||||
std::set<Receiver *>::const_iterator j;
|
||||
for(j = targets.begin(); j != targets.end(); ++j)
|
||||
{
|
||||
Receiver * r = (*j);
|
||||
if(! emitter.hasReceiver(*r, messageType))
|
||||
{
|
||||
r->receiveMessage(emitter, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::hash_map<unsigned long int, std::set<void (*)(const Emitter &, const MessageBase &)> >::iterator f = data->staticCallbacks.find(messageType);
|
||||
if(f != data->staticCallbacks.end())
|
||||
{
|
||||
const std::set<void (*)(const Emitter &, const MessageBase &)> targets = f->second;
|
||||
std::set<void (*)(const Emitter &, const MessageBase &)>::const_iterator c;
|
||||
for(c = targets.begin(); c != targets.end(); ++c)
|
||||
{
|
||||
void (*callback)(const Emitter &, const MessageBase &) = *c;
|
||||
callback(emitter, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief Invoked by a Receiver during it's destructor
|
||||
*/
|
||||
void MessageManager::receiverDestroyed(const Receiver & target)
|
||||
{
|
||||
if (!target.getHasTargets())
|
||||
{
|
||||
return;
|
||||
}
|
||||
// find receiver
|
||||
std::hash_map<unsigned long int, std::set<Receiver *> >::iterator i;
|
||||
for(i = data->receivers.begin(); i != data->receivers.end(); ++i)
|
||||
{
|
||||
std::set<Receiver *> & targets = (*i).second;
|
||||
// const cast to satisfy STL semantics, target remains unchanged
|
||||
std::set<Receiver *>::iterator j = targets.find(const_cast<Receiver *>(&target));
|
||||
if(j != targets.end())
|
||||
{
|
||||
targets.erase(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief break a Receiver->Message relationship
|
||||
|
||||
When a Receiver no longer wants to receive all messages of a certain
|
||||
type, it invokes MessageManager::removeReceiver to irradicate
|
||||
any relationship with the message in the MessageManager target map.
|
||||
|
||||
@param target The Receiver object that is breaking the
|
||||
connection.
|
||||
@param messageTypeName Identifies the source MessageBase objects
|
||||
that the Receiver object will now ignore.
|
||||
|
||||
@see Emitter::removeReceiver
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
void MessageManager::removeReceiver(const Receiver & target, const char * const messageTypeName)
|
||||
{
|
||||
const unsigned long int messageType = MessageBase::makeMessageTypeFromString(messageTypeName);
|
||||
removeReceiver(target, messageType);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void MessageManager::removeReceiver(const Receiver & target, const unsigned long int messageType)
|
||||
{
|
||||
std::hash_map<unsigned long int, std::set<Receiver *> >::iterator i = data->receivers.find(messageType);
|
||||
if(i != data->receivers.end())
|
||||
{
|
||||
std::set<Receiver *> & targets = (*i).second;
|
||||
std::set<Receiver *>::iterator j = targets.find(const_cast<Receiver *>(&target));
|
||||
if(j != targets.end())
|
||||
{
|
||||
targets.erase(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void connectToMessage(const char * const messageTypeName, void (*callback)(const Emitter &, const MessageBase &))
|
||||
{
|
||||
const unsigned long int messageType = MessageBase::makeMessageTypeFromString(messageTypeName);
|
||||
MessageManager::getInstance().addStaticCallback(callback, messageType);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
}//namespace MessageDispatch
|
||||
@@ -0,0 +1,57 @@
|
||||
#ifndef INCLUDED_MessageManager_H
|
||||
#define INCLUDED_MessageManager_H
|
||||
|
||||
namespace MessageDispatch
|
||||
{
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
class Emitter;
|
||||
class MessageBase;
|
||||
class Receiver;
|
||||
|
||||
void connectToMessage(const char * const messageTypeName, void (*)(const Emitter &, const MessageBase &));
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief A Singleton class responsible for broadcasting and tracking
|
||||
Receiver, Emitter and Message objects
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
class MessageManager
|
||||
{
|
||||
public:
|
||||
MessageManager();
|
||||
~MessageManager();
|
||||
void addReceiver(Receiver & target, const char * const messageTypeName);
|
||||
void addReceiver(Receiver & target, const MessageBase & source);
|
||||
void addReceiver(Receiver & target, const unsigned long int messageType);
|
||||
void addStaticCallback(void (*)(const Emitter &, const MessageBase &), const unsigned long int messageTypeName);
|
||||
void emitMessage(const Emitter & emitter, const MessageBase & message) const;
|
||||
void receiverDestroyed(const Receiver & target);
|
||||
void removeReceiver(const Receiver & target, const char * const messageTypeName);
|
||||
void removeReceiver(const Receiver & target, const unsigned long int messageType);
|
||||
|
||||
static MessageManager & getInstance ();
|
||||
|
||||
|
||||
private:
|
||||
struct Data;
|
||||
Data *data;
|
||||
|
||||
static MessageManager ms_instance;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
inline MessageManager & MessageManager::getInstance ()
|
||||
{
|
||||
return ms_instance;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
}//namespace MessageDispatch
|
||||
|
||||
#endif // _MessageManager_H
|
||||
@@ -0,0 +1,215 @@
|
||||
//---------------------------------------------------------------------
|
||||
#include "sharedMessageDispatch/FirstSharedMessageDispatch.h"
|
||||
|
||||
#include "sharedDebug/Profiler.h"
|
||||
#include "sharedMessageDispatch/Emitter.h"
|
||||
#include "sharedMessageDispatch/MessageManager.h"
|
||||
#include "sharedMessageDispatch/Message.h"
|
||||
#include "sharedMessageDispatch/Receiver.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
||||
namespace MessageDispatch {
|
||||
|
||||
struct Receiver::EmitterTargets
|
||||
{
|
||||
typedef std::set<const Emitter *> Container;
|
||||
Container c;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief construct a Receiver object
|
||||
|
||||
Receiver objects are abstract base classes. Do NOT instantiate
|
||||
a Receiver directly!
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
Receiver::Receiver() :
|
||||
emitterTargets(new EmitterTargets),
|
||||
hasTargets(false)
|
||||
{
|
||||
assert(emitterTargets != NULL);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void Receiver::setHasTargets(bool targets)
|
||||
{
|
||||
hasTargets = targets;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
bool Receiver::getHasTargets() const
|
||||
{
|
||||
return hasTargets;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief destroy the Receiver object
|
||||
|
||||
Finds all Emitter objects that this Receiver is connected to and
|
||||
invokes Emitter::receiveMessagerDestroyed
|
||||
|
||||
It then advises the MessageManager that the Receiver object is
|
||||
being destroyed.
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
Receiver::~Receiver()
|
||||
{
|
||||
disconnectAll();
|
||||
delete emitterTargets;
|
||||
emitterTargets = 0;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief connect to an Emitter to receive a message that it emits
|
||||
|
||||
When an Emitter object emits a message, it dispatches the message
|
||||
to all subscribed receivers before sending it to the MessageManager
|
||||
for broadcasting.
|
||||
|
||||
Receiver objects are inserted into the Emitter target map by way of
|
||||
this function (which wraps Emitter::addReceiver)
|
||||
|
||||
@param target The Emitter object to connect to
|
||||
@param messageTypeName The message type to listen for
|
||||
|
||||
@see Emitter::addReceiver
|
||||
@see MessageManager::addReceiver
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
void Receiver::connectToEmitter(const Emitter & target, const char * const messageTypeName)
|
||||
{
|
||||
target.addReceiver(*this, messageTypeName);
|
||||
emitterTargets->c.insert (&target);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
@brief advise the MessageManager that this Reciever object is
|
||||
interested in ALL messages of the requested type.
|
||||
|
||||
@param messageTypeName A string describing the type of message
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
void Receiver::connectToMessage(const char * const messageTypeName)
|
||||
{
|
||||
MessageManager::getInstance().addReceiver(*this, messageTypeName);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void Receiver::connectToMessage(const MessageBase & source)
|
||||
{
|
||||
MessageManager::getInstance().addReceiver(*this, source);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void Receiver::disconnectAll()
|
||||
{
|
||||
EmitterTargets::Container::iterator i;
|
||||
for(i = emitterTargets->c.begin(); i != emitterTargets->c.end(); ++i)
|
||||
{
|
||||
const Emitter * e = (*i);
|
||||
e->receiverDestroyed(*this);
|
||||
}
|
||||
emitterTargets->c.clear();
|
||||
MessageManager::getInstance().receiverDestroyed(*this);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void Receiver::disconnectFromMessage(const char * const messageTypeName)
|
||||
{
|
||||
disconnectFromMessage(MessageBase::makeMessageTypeFromString(messageTypeName));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void Receiver::disconnectFromMessage(const unsigned long int messageType)
|
||||
{
|
||||
MessageManager::getInstance().removeReceiver(*this, messageType);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void Receiver::disconnectFromMessage(const MessageBase & source)
|
||||
{
|
||||
disconnectFromMessage(source.getType());
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief helper to clean up destroyed emitter objects
|
||||
|
||||
If an Emitter is destroyed, but is not removed from it's target
|
||||
Receiver objects emitterTargets, the Receiver objects could
|
||||
attempt to invoke methods on an Emitter that no longer exists (e.g.
|
||||
during destruction, when the Reciever attempts to notify the
|
||||
Emitter that it is going away).
|
||||
|
||||
@param target The Emitter that is being destroyed
|
||||
|
||||
@see Emitter::receiverDestroyed
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
void Receiver::emitterDestroyed(Emitter & target)
|
||||
{
|
||||
emitterTargets->c.erase (&target);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
/**
|
||||
@brief stop receiving a specific message type from an emitter
|
||||
|
||||
@param target The Emitter that we want to stop listening for messagetype from
|
||||
@param messageType The messagetype we want to stop listening to on the target
|
||||
|
||||
@see Emitter::connectToEmitter
|
||||
|
||||
@author John Watson
|
||||
*/
|
||||
void Receiver::disconnectFromEmitter(const Emitter & target, const char * const messageType)
|
||||
{
|
||||
target.removeReceiver (*this, messageType);
|
||||
if (!target.hasReceiver (*this))
|
||||
emitterTargets->c.erase (&target);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
GlobalFunctionReceiver::GlobalFunctionReceiver(Function function)
|
||||
: Receiver(),
|
||||
m_function(function)
|
||||
{
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
GlobalFunctionReceiver::~GlobalFunctionReceiver()
|
||||
{
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void GlobalFunctionReceiver::receiveMessage(const Emitter &source, const MessageBase &message)
|
||||
{
|
||||
m_function(source, message);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
}//namespace MessageDispatch
|
||||
@@ -0,0 +1,116 @@
|
||||
#ifndef INCLUDED_Receiver_H
|
||||
#define INCLUDED_Receiver_H
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
#pragma warning ( disable : 4786 ) // symbol truncated to 255 characters in debug info
|
||||
|
||||
namespace MessageDispatch
|
||||
{
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
class MessageBase;
|
||||
class Emitter;
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief Abstract base class describing an object that can receive
|
||||
messages emitted by Emitter objects.
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
class Receiver
|
||||
{
|
||||
public:
|
||||
Receiver();
|
||||
virtual ~Receiver();
|
||||
|
||||
void connectToEmitter(const Emitter & target, const char * const messageTypeName);
|
||||
void connectToEmitter(const Emitter & target, const MessageBase & source);
|
||||
void connectToMessage(const char * const messageTypeName);
|
||||
void connectToMessage(const MessageBase & source);
|
||||
void disconnectFromEmitter(const Emitter & target, const char * const messageType);
|
||||
void disconnectFromEmitter(const Emitter & target, const MessageBase & source);
|
||||
void disconnectFromEmitter(const Emitter & target, const unsigned long int messageType);
|
||||
void disconnectFromMessage(const char * const messageTypeName);
|
||||
void disconnectFromMessage(const MessageBase & source);
|
||||
void disconnectFromMessage(const unsigned long int messageType);
|
||||
void disconnectAll();
|
||||
void emitterDestroyed(Emitter & target);
|
||||
void setHasTargets(bool targets);
|
||||
bool getHasTargets() const;
|
||||
|
||||
/** Pure virtual */
|
||||
virtual void receiveMessage(const Emitter & source, const MessageBase & message) = 0;
|
||||
private:
|
||||
|
||||
struct EmitterTargets;
|
||||
EmitterTargets * emitterTargets;
|
||||
bool hasTargets;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
class GlobalFunctionReceiver : public Receiver
|
||||
{
|
||||
public:
|
||||
|
||||
typedef void (*Function)(const Emitter &, const MessageBase &);
|
||||
|
||||
public:
|
||||
|
||||
GlobalFunctionReceiver(Function function);
|
||||
virtual ~GlobalFunctionReceiver();
|
||||
virtual void receiveMessage(const Emitter &source, const MessageBase &message);
|
||||
|
||||
private:
|
||||
|
||||
Function m_function;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
template <typename T>
|
||||
class MemberFunctionReceiver : public Receiver
|
||||
{
|
||||
public:
|
||||
|
||||
typedef void (T::*TMemberFunction)(const Emitter &, const MessageBase &);
|
||||
|
||||
public:
|
||||
|
||||
MemberFunctionReceiver(T &object, TMemberFunction memberFunction);
|
||||
virtual ~MemberFunctionReceiver();
|
||||
virtual void receiveMessage(const Emitter &source, const MessageBase &message);
|
||||
|
||||
private:
|
||||
T *m_object;
|
||||
TMemberFunction m_memberFunction;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
template <typename T>
|
||||
MemberFunctionReceiver<T>::MemberFunctionReceiver(T &object, TMemberFunction memberFunction)
|
||||
: Receiver(),
|
||||
m_object(&object),
|
||||
m_memberFunction(memberFunction)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
MemberFunctionReceiver<T>::~MemberFunctionReceiver()
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void MemberFunctionReceiver<T>::receiveMessage(const Emitter &source, const MessageBase &message)
|
||||
{
|
||||
(m_object->*m_memberFunction)(source, message);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
}//namespace MessageDispatch
|
||||
|
||||
#endif // _Receiver_H
|
||||
@@ -0,0 +1,69 @@
|
||||
// Transceiver.cpp
|
||||
// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved.
|
||||
// Author: Justin Randall
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#include "sharedMessageDispatch/FirstSharedMessageDispatch.h"
|
||||
#include "sharedMessageDispatch/Transceiver.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace MessageDispatch {
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
TransceiverBase::GlobalReceiverInfo::GlobalReceiverInfo() :
|
||||
receivers(),
|
||||
pendingAdds(),
|
||||
pendingRemoves(),
|
||||
locked(false)
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
TransceiverBase::TransceiverBase() :
|
||||
locked(false)
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
TransceiverBase::~TransceiverBase()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
TransceiverBase::GlobalReceiverInfo & TransceiverBase::getGlobalReceiverInfo(const type_info & typeId)
|
||||
{
|
||||
static std::map<const char * const, GlobalReceiverInfo> receiverSets;
|
||||
GlobalReceiverInfo & result = receiverSets[typeId.name()];
|
||||
return result;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
Callback::Callback() :
|
||||
receivers()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
Callback::~Callback()
|
||||
{
|
||||
std::vector<TransceiverBase *>::iterator i;
|
||||
TransceiverBase * t;
|
||||
for(i = receivers.begin(); i != receivers.end(); ++i)
|
||||
{
|
||||
t = (*i);
|
||||
delete t;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
}//namespace MessageDispatch
|
||||
|
||||
@@ -0,0 +1,670 @@
|
||||
// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved.
|
||||
// Author: Justin Randall
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#ifndef _Transceiver_H
|
||||
#define _Transceiver_H
|
||||
|
||||
/**
|
||||
Transceiver.h
|
||||
|
||||
Message dispatch to non-static object member functions
|
||||
|
||||
|
||||
<----- Messages from Transceivers
|
||||
deliver to OBJECT::foo(Type)
|
||||
which is a non-static member
|
||||
function.
|
||||
<-----------------------
|
||||
+----------------------+ +-------------------+
|
||||
| OBJECT | +---+ Transceiver<Type> |
|
||||
+-+--------------------+ | +-------------------+
|
||||
| |Callback m_callback | |
|
||||
| +-+------------------+ | +-------------------+
|
||||
| |OwnedTransceiver |------+---+ Transceiver<Type> |
|
||||
| +------------------+ | +-------------------+
|
||||
| |ptr to member func| |
|
||||
| +------------------+ | +-------------------+
|
||||
+ | +---+ Transceiver<Type> +
|
||||
| +--------------------+ +-------------------+
|
||||
+-|void foo(Type) |
|
||||
| +--------------------+
|
||||
| |
|
||||
+----------------------+
|
||||
|
||||
Transceivers may be used as anonymous "broadcast" sources
|
||||
delivering messages to anyone listing for a particular *type*
|
||||
of message, or they may have direct relationships with other
|
||||
transceivers. The relationship is defined by the receiving
|
||||
object, not the transceiver. The receiver will connect() to
|
||||
either another transceiver, or to a type of message. It specifies
|
||||
the address of a member function that is capable of receiving
|
||||
the type of message emitted from another transceiver.
|
||||
|
||||
When the emitting transceiver dispatches a message, it looks
|
||||
through a vector of receivers for direct message dispatch, then
|
||||
delivers messages to each receiver in the list. It also maintains
|
||||
a list of pending removes, and skips transceivers (really
|
||||
OwnedTransceiver objects) that have been deleted to prevent
|
||||
dispatch to a destroyed object.
|
||||
|
||||
After direct dispatches are delievered, the transceiver finds
|
||||
a "gobal" dispatch list that contains receivers that are connected
|
||||
to the *type* of message this transceiver emits, rahter than this
|
||||
transceiver specifically. The message is delivered to all recepients
|
||||
in that global list. Like the local dispatch, the global dispatch also
|
||||
checks for destroyed objects and skips delivery if they are no
|
||||
longer valid.
|
||||
|
||||
Clients of dispatch code use to interfaces: Callback objects, which
|
||||
are responsible for connecting object member functions to transceivers,
|
||||
and Transceiver objects themselves. Client code may either implement
|
||||
directed dispatch from object to object using a has-a relationship. The
|
||||
emitting object will have a Transceiver, the receiving object will
|
||||
have a Callback. It is the responsibility of the client to ensure
|
||||
that their Transceiver or Callback objects are destroyed when their
|
||||
owning objects are destroyed.
|
||||
|
||||
Client code may also emit messages by simply declaring a Transceiver
|
||||
on the stack and invoking emitMessage() with the correct parameter type
|
||||
for the message. Any objects that connect() to a message type rather
|
||||
than a specific transceiver will receive the message.
|
||||
|
||||
Usage:
|
||||
|
||||
// anonymous dispatch example
|
||||
class MyClass
|
||||
{
|
||||
public:
|
||||
MyClass()
|
||||
{
|
||||
m_callback = new Callback;
|
||||
// connect to any transceiver emitting a bool
|
||||
m_callback->connect(*this, &MyClass::foo);
|
||||
}
|
||||
~MyClass()
|
||||
{
|
||||
// ensure transceivers don't deliver to this
|
||||
// object anymore
|
||||
delete m_callback;
|
||||
}
|
||||
|
||||
protected:
|
||||
void foo(bool);
|
||||
private:
|
||||
Callback * m_callback;
|
||||
};
|
||||
|
||||
// code somewhere else (could be anywhere)
|
||||
void bar()
|
||||
{
|
||||
Transceiver<bool> t;
|
||||
bool msg = true;
|
||||
t.emitMessage(msg);
|
||||
}
|
||||
|
||||
// directed dispatch example
|
||||
class MyEmitter
|
||||
{
|
||||
public:
|
||||
//...
|
||||
|
||||
Transceiver<bool> & getEmitter()
|
||||
{
|
||||
return m_emitter;
|
||||
}
|
||||
|
||||
void bar()
|
||||
{
|
||||
bool msg = true;
|
||||
m_emitter.emitMessage(msg);
|
||||
}
|
||||
|
||||
private:
|
||||
Transceiver<bool> m_emitter;
|
||||
};
|
||||
|
||||
class MyReceiver
|
||||
{
|
||||
public:
|
||||
explicit MyReceiver(MyEmitter & source)
|
||||
{
|
||||
m_callback = new Callback;
|
||||
m_callback->connect(source, *this, &MyReceiver::foo);
|
||||
}
|
||||
~MyReceiver()
|
||||
{
|
||||
delete m_callback;
|
||||
}
|
||||
protected:
|
||||
void foo(bool)
|
||||
{
|
||||
// I received a bool message from one of
|
||||
// the transceivers I am connected too!
|
||||
}
|
||||
};
|
||||
|
||||
// anywhere else in the application
|
||||
void doStuff()
|
||||
{
|
||||
MyEmitter emitter;
|
||||
MyReceiver receiver(emitter);
|
||||
|
||||
// receiver.foo(true) is called by way of emitter.bar()
|
||||
emitter.bar();
|
||||
}
|
||||
*/
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#include <set>
|
||||
#include <typeinfo>
|
||||
#include <vector>
|
||||
|
||||
#if _MSC_VER < 1300
|
||||
using std::type_info;
|
||||
#endif
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
namespace MessageDispatch {
|
||||
|
||||
class TransceiverBase
|
||||
{
|
||||
public:
|
||||
TransceiverBase();
|
||||
virtual ~TransceiverBase();
|
||||
|
||||
|
||||
protected:
|
||||
struct GlobalReceiverInfo
|
||||
{
|
||||
GlobalReceiverInfo();
|
||||
std::vector<TransceiverBase *> receivers;
|
||||
std::vector<TransceiverBase *> pendingAdds;
|
||||
std::vector<TransceiverBase *> pendingRemoves;
|
||||
|
||||
bool locked;
|
||||
};
|
||||
|
||||
protected:
|
||||
static GlobalReceiverInfo & getGlobalReceiverInfo(const type_info & typeId);
|
||||
|
||||
protected:
|
||||
mutable bool locked;
|
||||
};
|
||||
|
||||
template<typename MessageType, typename IdentifierType = void *>
|
||||
class Transceiver : public TransceiverBase
|
||||
{
|
||||
public:
|
||||
Transceiver();
|
||||
virtual ~Transceiver();
|
||||
void emitMessage(MessageType source) const;
|
||||
protected:
|
||||
friend class Callback;
|
||||
void listenForAny();
|
||||
//void listenTo(Transceiver<MessageType, IdentifierType> & source);
|
||||
virtual void receiveMessage(MessageType) {};
|
||||
|
||||
private:
|
||||
Transceiver(const Transceiver & source);
|
||||
Transceiver & operator = (const Transceiver & rhs);
|
||||
|
||||
void addReceiver(Transceiver * target);
|
||||
void removeReceiver(Transceiver * target);
|
||||
|
||||
private:
|
||||
std::vector<Transceiver<MessageType, IdentifierType> *> localReceivers;
|
||||
std::set<Transceiver<MessageType, IdentifierType> *> listenSet;
|
||||
|
||||
// bookkeeping containers and flags to permit safe usage during
|
||||
// message emission
|
||||
mutable std::vector<Transceiver<MessageType, IdentifierType> *> pendingAdds;
|
||||
mutable std::vector<Transceiver<MessageType, IdentifierType> *> pendingRemoves;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
template<typename MessageType, typename IdentifierType>
|
||||
inline Transceiver<MessageType, IdentifierType>::Transceiver() :
|
||||
TransceiverBase(),
|
||||
localReceivers(),
|
||||
listenSet(),
|
||||
pendingAdds(),
|
||||
pendingRemoves()
|
||||
{
|
||||
// ensure the global receiver for this type of transceiver
|
||||
// is fully constructed before this object (which may be the
|
||||
// first transceiver) is fully constructed. The global
|
||||
// receiver info is a static with linkage in Transceiver.cpp,
|
||||
// and should be destroyed only after ALL transceivers of this
|
||||
// type have been destroyed.
|
||||
getGlobalReceiverInfo(typeid(this));
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
template<typename MessageType, typename IdentifierType>
|
||||
inline Transceiver<MessageType, IdentifierType>::~Transceiver()
|
||||
{
|
||||
typename std::vector<Transceiver<MessageType, IdentifierType> *>::iterator i;
|
||||
typename std::set<Transceiver<MessageType, IdentifierType> *>::iterator f;
|
||||
|
||||
// advise anyone that this transceiver is connected to that
|
||||
// they should NOT call removeReceiver in their destructor
|
||||
// because THIS transceiver is being destroyed
|
||||
for(i = localReceivers.begin(); i != localReceivers.end(); ++i)
|
||||
{
|
||||
// find this receiver on the other transceiver's
|
||||
// listen set
|
||||
f = (*i)->listenSet.find(this);
|
||||
|
||||
// if it's found, remove this receiver from the listenSet
|
||||
if(f != (*i)->listenSet.end())
|
||||
(*i)->listenSet.erase(f);
|
||||
}
|
||||
|
||||
// for every transceiver that this object receives messages
|
||||
// from, remove thiis object from their distribution
|
||||
// list, so that they will not attempt to deliver
|
||||
// messages to this object after it has been destroyed
|
||||
for(f = listenSet.begin(); f != listenSet.end(); ++f)
|
||||
{
|
||||
(*f)->removeReceiver(this);
|
||||
}
|
||||
|
||||
|
||||
// remove this transceiver from the global receiver list
|
||||
// to prevent anonymous distribution to this delieted
|
||||
// transceiver
|
||||
GlobalReceiverInfo & info = getGlobalReceiverInfo(typeid(this));
|
||||
std::vector<TransceiverBase *>::iterator g;
|
||||
if(info.locked == false)
|
||||
{
|
||||
g = std::find(info.receivers.begin(), info.receivers.end(), this);
|
||||
if(g != info.receivers.end())
|
||||
info.receivers.erase(g);
|
||||
}
|
||||
else
|
||||
{
|
||||
// the global transceiver list is busy dispatching
|
||||
// a message that this transceiver may receive, put
|
||||
// it on the global pending remove list, which is
|
||||
// checked during message dispatch
|
||||
info.pendingRemoves.push_back(this);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
template<typename MessageType, typename IdentifierType>
|
||||
inline void Transceiver<MessageType, IdentifierType>::addReceiver(Transceiver<MessageType, IdentifierType> * target)
|
||||
{
|
||||
// do not add a transceiver to the receiver list if this transceiver
|
||||
// is busy dispatching a message.
|
||||
if(locked)
|
||||
{
|
||||
pendingAdds.push_back(target);
|
||||
}
|
||||
else
|
||||
{
|
||||
typename std::vector<Transceiver<MessageType, IdentifierType> *>::const_iterator f = std::find(localReceivers.begin(), localReceivers.end(), target);
|
||||
if(f == localReceivers.end())
|
||||
{
|
||||
localReceivers.push_back(target);
|
||||
target->listenSet.insert(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
template<typename MessageType, typename IdentifierType>
|
||||
inline void Transceiver<MessageType, IdentifierType>::emitMessage(MessageType message) const
|
||||
{
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// set our status to locked so that adds to this receiver do not touch
|
||||
// the localReceiverSet and put it in an undefined state.
|
||||
// See Transceiver::addReceiver for information on the locked flag
|
||||
locked = true;
|
||||
|
||||
// iterate through direct connections to this Transceiver
|
||||
typename std::vector<Transceiver<MessageType, IdentifierType> *>::const_iterator i;
|
||||
|
||||
// which dispatch loop will we run?
|
||||
// fast dispatch
|
||||
for(i = localReceivers.begin(); i != localReceivers.end(); ++i)
|
||||
{
|
||||
// quick and easy check.
|
||||
// if no removes have been posted as a result of the
|
||||
// last dispatch, simply deliver the message
|
||||
if(pendingRemoves.empty())
|
||||
{
|
||||
(*i)->receiveMessage(message);
|
||||
}
|
||||
else
|
||||
{
|
||||
// it might not be safe, because a transceiver requested a removal. This
|
||||
// can happen when the owner object of the transceiver has
|
||||
// deleted itself. Just skip this target and clean up the
|
||||
// removal at the end of emitMessage.
|
||||
if(std::find(pendingRemoves.begin(), pendingRemoves.end(), (*i)) != pendingRemoves.end())
|
||||
continue;
|
||||
|
||||
(*i)->receiveMessage(message);
|
||||
}
|
||||
}
|
||||
locked = false;
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// lock the global receiver set to prevent
|
||||
// unsafe add/remove calls to it while dispatching this message.
|
||||
GlobalReceiverInfo & info = getGlobalReceiverInfo(typeid(const_cast<Transceiver<MessageType, IdentifierType> *>(this)));
|
||||
info.locked = true;
|
||||
std::vector<TransceiverBase *>::iterator g;
|
||||
for(g = info.receivers.begin(); g != info.receivers.end(); ++g)
|
||||
{
|
||||
// quick and easy check.
|
||||
// if no removes have been posted as a result of the
|
||||
// last dispatch, simply deliver the message
|
||||
if(pendingRemoves.empty())
|
||||
{
|
||||
Transceiver<MessageType, IdentifierType> * t = static_cast<Transceiver<MessageType, IdentifierType> *>((*g));
|
||||
t->receiveMessage(message);
|
||||
}
|
||||
else
|
||||
{
|
||||
// it might not be safe, because a transceiver requested a removal. This
|
||||
// can happen when the owner object of the transceiver has
|
||||
// deleted itself. Just skip this target and clean up the
|
||||
// removal at the end of emitMessage.
|
||||
if(std::find(info.pendingRemoves.begin(), info.pendingRemoves.end(), (*g)) != info.pendingRemoves.end())
|
||||
continue;
|
||||
|
||||
Transceiver<MessageType, IdentifierType> * t = static_cast<Transceiver<MessageType, IdentifierType> *>((*g));
|
||||
t->receiveMessage(message);
|
||||
}
|
||||
}
|
||||
info.locked = false;
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
// process local connections to this transceiver
|
||||
if(! pendingAdds.empty())
|
||||
{
|
||||
for(i = pendingAdds.begin(); i != pendingAdds.end(); ++i)
|
||||
{
|
||||
// place the pending transceive ron the receiver list
|
||||
const_cast<Transceiver<MessageType, IdentifierType> *>(this)->addReceiver(*i);
|
||||
}
|
||||
pendingAdds.clear();
|
||||
}
|
||||
|
||||
// a transceiver directly connected to this object was destroyed or
|
||||
// disconnected during the message dispatch. Remove it from the
|
||||
// list of receivers to ensure messages aren't delivered to the target
|
||||
// and that it will not receive a notification during the destruction
|
||||
// of THIS transceiver
|
||||
if(! pendingRemoves.empty())
|
||||
{
|
||||
typename std::vector<Transceiver<MessageType, IdentifierType> *>::const_iterator a;;
|
||||
for(a = pendingRemoves.begin(); a != pendingRemoves.end(); ++a)
|
||||
{
|
||||
const_cast<Transceiver<MessageType, IdentifierType> *>(this)->removeReceiver(*a);
|
||||
}
|
||||
pendingRemoves.clear();
|
||||
}
|
||||
|
||||
// perform the same add/remove logic for the global receiver info
|
||||
if(! info.pendingAdds.empty())
|
||||
{
|
||||
std::vector<TransceiverBase *>::const_iterator addIter;
|
||||
for(addIter = info.pendingAdds.begin(); addIter != info.pendingAdds.end(); ++addIter)
|
||||
{
|
||||
Transceiver<MessageType, IdentifierType> * t = static_cast<Transceiver<MessageType, IdentifierType> *>((*addIter));
|
||||
t->listenForAny();
|
||||
}
|
||||
info.pendingAdds.clear();
|
||||
}
|
||||
|
||||
if(! info.pendingRemoves.empty())
|
||||
{
|
||||
std::vector<TransceiverBase *>::const_iterator removeIter;
|
||||
for(removeIter = info.pendingRemoves.begin(); removeIter != info.pendingRemoves.end(); ++removeIter)
|
||||
{
|
||||
std::vector<TransceiverBase *>::iterator r = std::find(info.receivers.begin(), info.receivers.end(), *removeIter);
|
||||
if(r != info.receivers.end())
|
||||
info.receivers.erase(r);
|
||||
}
|
||||
info.pendingRemoves.clear();
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
template<typename MessageType, typename IdentifierType>
|
||||
inline void Transceiver<MessageType, IdentifierType>::listenForAny()
|
||||
{
|
||||
GlobalReceiverInfo & info = getGlobalReceiverInfo(typeid(this));
|
||||
|
||||
// if the global receiver info is not locked, then it is not
|
||||
// busy dispatching an anonymous message and it is safe to
|
||||
// add this transceiver directly to the list of listeners
|
||||
if(! info.locked)
|
||||
{
|
||||
std::vector<TransceiverBase *>::const_iterator f = std::find(info.receivers.begin(), info.receivers.end(), this);
|
||||
if(f == info.receivers.end())
|
||||
info.receivers.push_back(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
// another transceiver of this type is performing
|
||||
// operations on the global receiver set. Adds will
|
||||
// be processed by that transceiver when it is done
|
||||
// working with the global receiver list
|
||||
info.pendingAdds.push_back(this);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
template<typename MessageType, typename IdentifierType>
|
||||
inline void Transceiver<MessageType, IdentifierType>::removeReceiver(Transceiver<MessageType, IdentifierType> * target)
|
||||
{
|
||||
if(locked)
|
||||
{
|
||||
// this transceiver is busy dispatching messages. Do not invalidate
|
||||
// the receiver list by erasing a member while this object is
|
||||
// iterating through it to dispatch. The remove list, if it is
|
||||
// not empty, will be checked to see if the target transceiver
|
||||
// is listed, and messages will not be dispatched to it.
|
||||
pendingRemoves.push_back(target);
|
||||
}
|
||||
else
|
||||
{
|
||||
// it is safe to directly remove the target transceiver from the
|
||||
// receiver list.
|
||||
typename std::vector<Transceiver<MessageType, IdentifierType> *>::iterator f = std::find(localReceivers.begin(), localReceivers.end(), target);
|
||||
if(f != localReceivers.end())
|
||||
localReceivers.erase(f);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
An OwnedTransceiver is a helper/interface class that links end-point
|
||||
objects, Callback objects and transceivers. The abstraction is
|
||||
present to make message dispatch safe when emitting messages to objects
|
||||
that may be deleted. Callbacks and OwnedTransceivers notify other
|
||||
transceivers if an object is being destroyed. Objects that receive
|
||||
messages have Callback members, and when those callback members
|
||||
are destroyed, they clean up transceiver receive lists to prevent
|
||||
operations on the deleted object.
|
||||
*/
|
||||
template<typename MessageType, typename ObjectType, typename IdentifierType = void *>
|
||||
class OwnedTransceiver : public Transceiver<MessageType, IdentifierType>
|
||||
{
|
||||
public:
|
||||
OwnedTransceiver(Transceiver<MessageType, IdentifierType> * source, ObjectType & o);
|
||||
~OwnedTransceiver();
|
||||
|
||||
// this where all messages are routed before finally being
|
||||
// delivered to the object member function specified in the
|
||||
// callback. receiveMessage overrides the base Transceiver method.
|
||||
virtual void receiveMessage(MessageType msg)
|
||||
{
|
||||
(owner.*callback)(msg);
|
||||
};
|
||||
|
||||
void setCallback(void (ObjectType::*cb)(MessageType) )
|
||||
{
|
||||
callback = cb;
|
||||
};
|
||||
|
||||
private:
|
||||
friend class Callback;
|
||||
OwnedTransceiver<MessageType, ObjectType, IdentifierType> & operator = (const OwnedTransceiver<MessageType, ObjectType, IdentifierType> &);
|
||||
OwnedTransceiver(const OwnedTransceiver<MessageType, ObjectType, IdentifierType> &);
|
||||
Transceiver<MessageType, IdentifierType> * source;
|
||||
ObjectType & owner;
|
||||
void (ObjectType::*callback)(MessageType);
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
template<typename MessageType, typename ObjectType, typename IdentifierType>
|
||||
inline OwnedTransceiver<MessageType, ObjectType, IdentifierType>::OwnedTransceiver(Transceiver<MessageType, IdentifierType> * s, ObjectType & o) :
|
||||
source(s),
|
||||
owner(o),
|
||||
callback(0)
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
template<typename MessageType, typename ObjectType, typename IdentifierType>
|
||||
inline OwnedTransceiver<MessageType, ObjectType, IdentifierType>::~OwnedTransceiver()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
class Callback
|
||||
{
|
||||
public:
|
||||
Callback();
|
||||
virtual ~Callback();
|
||||
|
||||
template<typename MessageType, typename ObjectType, typename IdentifierType>
|
||||
void connect(
|
||||
Transceiver<MessageType, IdentifierType> & source,
|
||||
ObjectType & object,
|
||||
void (ObjectType::*callback)(MessageType)
|
||||
)
|
||||
{
|
||||
OwnedTransceiver<MessageType, ObjectType, IdentifierType> * target = new OwnedTransceiver<MessageType, ObjectType, IdentifierType>(&source, object);
|
||||
receivers.push_back(target);
|
||||
|
||||
target->setCallback(callback);
|
||||
source.addReceiver(target);
|
||||
//target->listenTo(source);
|
||||
}
|
||||
|
||||
template<typename MessageType, typename ObjectType>
|
||||
inline void connect(ObjectType & object, void (ObjectType::*callback)(MessageType))
|
||||
{
|
||||
OwnedTransceiver<MessageType, ObjectType> * target = new OwnedTransceiver<MessageType, ObjectType>(0, object);
|
||||
receivers.push_back(target);
|
||||
|
||||
target->setCallback(callback);
|
||||
target->listenForAny();
|
||||
}
|
||||
|
||||
template<typename MessageType, typename ObjectType, typename IdentifierType>
|
||||
inline void connect(ObjectType & object, void (ObjectType::*callback)(MessageType), IdentifierType *)
|
||||
{
|
||||
OwnedTransceiver<MessageType, ObjectType, IdentifierType> * target = new OwnedTransceiver<MessageType, ObjectType, IdentifierType>(0, object);
|
||||
receivers.push_back(target);
|
||||
|
||||
target->setCallback(callback);
|
||||
target->listenForAny();
|
||||
}
|
||||
|
||||
template<typename MessageType, typename ObjectType, typename IdentifierType>
|
||||
void disconnect(
|
||||
Transceiver<MessageType, IdentifierType> & source,
|
||||
ObjectType & object,
|
||||
void (ObjectType::*callback)(MessageType)
|
||||
)
|
||||
{
|
||||
removeTarget(&source, object, callback);
|
||||
}
|
||||
|
||||
template<typename MessageType, typename ObjectType, typename IdentifierType>
|
||||
void disconnectByType(
|
||||
Transceiver<MessageType, IdentifierType> & source,
|
||||
ObjectType & object,
|
||||
void (ObjectType::*callback)(MessageType),
|
||||
IdentifierType *
|
||||
)
|
||||
{
|
||||
removeTarget(&source, object, callback);
|
||||
}
|
||||
|
||||
template<typename MessageType, typename ObjectType>
|
||||
void disconnect(ObjectType & object, void (ObjectType::*callback)(MessageType) )
|
||||
{
|
||||
removeTarget(static_cast<Transceiver<MessageType> *>(0), object, callback);
|
||||
}
|
||||
|
||||
template<typename MessageType, typename ObjectType, typename IdentifierType>
|
||||
void disconnect(ObjectType & object, void (ObjectType::*callback)(MessageType), IdentifierType *)
|
||||
{
|
||||
removeTarget(static_cast<Transceiver<MessageType, IdentifierType> *>(0), object, callback);
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename MessageType, typename ObjectType, typename IdentifierType>
|
||||
void removeTarget(
|
||||
Transceiver<MessageType, IdentifierType> * source,
|
||||
ObjectType & object,
|
||||
void (ObjectType::*callback)(MessageType)
|
||||
)
|
||||
{
|
||||
std::vector<TransceiverBase *>::iterator i;
|
||||
OwnedTransceiver<MessageType, ObjectType, IdentifierType> * target;
|
||||
|
||||
for(i = receivers.begin(); i != receivers.end(); ++i)
|
||||
{
|
||||
target = dynamic_cast<OwnedTransceiver<MessageType, ObjectType, IdentifierType> *>((*i));
|
||||
if(target)
|
||||
{
|
||||
if(&target->owner == &object && target->callback == callback && target->source == source)
|
||||
{
|
||||
delete target;
|
||||
receivers.erase(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<TransceiverBase *> receivers;
|
||||
};
|
||||
|
||||
template<typename MessageType>
|
||||
void emitMessage(MessageType m)
|
||||
{
|
||||
static Transceiver<MessageType> t;
|
||||
t.emitMessage(m);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
}//namespace MessageDispatch
|
||||
|
||||
#endif // _Transceiver_H
|
||||
@@ -0,0 +1,8 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// FirstMessageDispatch.cpp
|
||||
// copyright (c) 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedMessageDispatch/FirstSharedMessageDispatch.h"
|
||||
Reference in New Issue
Block a user