Skip to content

Instantly share code, notes, and snippets.

@jslee02
Last active May 16, 2024 08:58
Show Gist options
  • Save jslee02/8215aa9424210357eed7 to your computer and use it in GitHub Desktop.
Save jslee02/8215aa9424210357eed7 to your computer and use it in GitHub Desktop.
Event
#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