Last active
May 16, 2024 08:58
-
-
Save jslee02/8215aa9424210357eed7 to your computer and use it in GitHub Desktop.
Event
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <algorithm> | |
#include <cassert> | |
#include <functional> | |
#include <iostream> | |
#include <limits> | |
#include <map> | |
#define LISTENER_COUNT_MAX 256 | |
/// class Event | |
template<typename T> | |
class Event | |
{ | |
public: | |
/// Constructor | |
Event() | |
: mKeyHint(0), | |
mListenerCountMax(LISTENER_COUNT_MAX) | |
{} | |
/// Destructor | |
virtual ~Event() | |
{ | |
mListenerMap.clear(); | |
} | |
/// Type definition of listener function | |
typedef std::function<void(const T& _arg)> ListenerType; | |
/// Connect call back function | |
/// | |
/// \return Return nonnegative integer if the event connect the listener, | |
/// otherwise return -1 | |
/// \remarks It is possible to connect same function object multiple times | |
int connect(const ListenerType& _listener) | |
{ | |
// Check capacity | |
if (mListenerMap.size() == getListenerCountMax()) | |
{ | |
// std::cout << "Warning: Listener is full." << std::endl; | |
return -1; | |
} | |
// Get unique key for the new listener | |
int key = getUniqueKey(); | |
// Add | |
mListenerMap[key] = _listener; | |
// Return the key | |
return key; | |
} | |
/// Connect another event | |
/// \remarks It is possible to connect same function object multiple times | |
int connect(Event<T>* _event) | |
{ | |
using std::placeholders::_1; | |
return connect(std::bind(std::mem_fn(&Event<T>::raise), _event, _1)); | |
} | |
/// Disconnect | |
void disconnect(int _id) | |
{ | |
assert(mListenerMap.find(_id) != mListenerMap.end()); | |
mListenerMap.erase(_id); | |
} | |
/// Return true if there exist a listener with the ID | |
bool containId(int _id) const | |
{ | |
if (mListenerMap.find(_id) != mListenerMap.end()) | |
return true; | |
else | |
return false; | |
} | |
/// Return the number of listeners | |
int getListenerCount() const | |
{ | |
return (int)mListenerMap.size(); | |
} | |
/// Set the maximum number of listeners | |
void setListenerCountMax(int _max) | |
{ | |
assert(_max >= 0); | |
mListenerCountMax = _max; | |
} | |
/// Return the maximum number of listeners | |
int getListenerCountMax() const | |
{ | |
return mListenerCountMax; | |
} | |
/// Raise event | |
void raise(const T& _arg) | |
{ | |
for (typename ListenerMap::iterator i = mListenerMap.begin(); | |
i != mListenerMap.end(); ++i) | |
{ | |
(*i).second(_arg); | |
} | |
} | |
private: | |
/// Return unique key of the listener | |
int getUniqueKey() | |
{ | |
assert(getListenerCount() != getListenerCountMax()); | |
assert(getListenerCount() <= getListenerCountMax()); | |
// Find unique key using the hint | |
while (mListenerMap.find(mKeyHint) != mListenerMap.end()) | |
{ | |
if (mKeyHint == std::numeric_limits<int>::max()) | |
mKeyHint = 0; | |
else | |
mKeyHint++; | |
} | |
int uniqueKey = mKeyHint; | |
// Update the hint | |
if (mKeyHint == std::numeric_limits<int>::max()) | |
mKeyHint = 0; | |
else | |
mKeyHint++; | |
return uniqueKey; | |
} | |
private: | |
/// Typedef of listener function map | |
typedef std::map<int, ListenerType> ListenerMap; | |
/// Listener function map | |
ListenerMap mListenerMap; | |
/// Unique key hint for the new listener | |
int mKeyHint; | |
/// Maximum number of listeners | |
int mListenerCountMax; | |
}; | |
//---------------------------------------------------- | |
// Possible usage | |
//---------------------------------------------------- | |
struct EngineStartArg | |
{ | |
Time startedTime; | |
} | |
void receiver(const EngineStartArg& _arg) | |
{ | |
cout << "The engine started at " << _arg.startedTime << endl; | |
} | |
class Engine | |
{ | |
public: | |
void start() | |
{ | |
EngineStartArg arg; | |
arg.startedTime = getCurrentTime(); | |
mEngineStartEvent.raise(arg); | |
} | |
protected: | |
Event<EngineStartArg> mEngineStartEvent; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment