--- /dev/null
+
+/*******************************************************************************
+
+ Copyright (c) 2009, Charles McGarvey
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#include <map>
+
+#include "Dispatch.hh"
+
+
+namespace Mf {
+
+
+class Dispatch::Impl
+{
+public:
+
+ Impl() :
+ mId(0) {}
+
+ Dispatch::Handler getNewHandler()
+ {
+ ++mId;
+ //return Dispatch::Handler(this, mId);
+ Dispatch::Handler handler(this, mId);
+ return handler;
+ }
+
+ typedef std::pair<unsigned,Dispatch::Function> Callback;
+ typedef std::multimap<std::string,Callback> CallbackLookup;
+ typedef CallbackLookup::iterator CallbackIter;
+
+ typedef std::multimap<unsigned,std::string> HandlerLookup;
+ typedef HandlerLookup::iterator HandlerIter;
+
+
+ inline Handler addHandler(const std::string& event,
+ const Function& callback, Handler handler)
+ {
+ mCallbacks.insert(std::make_pair(event,
+ std::make_pair(handler.getId(), callback)));
+ mHandlers.insert(std::make_pair(handler.getId(), event));
+
+ return handler;
+ }
+
+ inline void removeHandler(unsigned id)
+ {
+ std::pair<HandlerIter,HandlerIter> matching(mHandlers.equal_range(id));
+
+ for (HandlerIter it = matching.first; it != matching.second; ++it)
+ {
+ CallbackIter first = mCallbacks.find((*it).second);
+ CallbackIter last = mCallbacks.end();
+
+ for (CallbackIter jt = first; jt != last; ++jt)
+ {
+ if ((*jt).second.first == id)
+ {
+ mCallbacks.erase(jt);
+ break;
+ }
+ }
+ }
+
+ mHandlers.erase(id);
+ }
+
+ void dispatch(const std::string& event, const Message* message)
+ {
+ std::pair<CallbackIter,CallbackIter>
+ callbacks(mCallbacks.equal_range(event));
+
+ for (CallbackIter it = callbacks.first; it != callbacks.second; ++it)
+ {
+ Function callback = (*it).second.second;
+ callback(message);
+ }
+ }
+
+
+ unsigned mId;
+
+ CallbackLookup mCallbacks;
+ HandlerLookup mHandlers;
+};
+
+
+Dispatch::Handler::~Handler()
+{
+ if (mId)
+ {
+ mDispatch->removeHandler(mId);
+ }
+}
+
+
+Dispatch::Dispatch() :
+ mImpl(new Dispatch::Impl) {}
+
+Dispatch::~Dispatch() {}
+
+
+Dispatch& Dispatch::getInstance()
+{
+ static Dispatch dispatch;
+ return dispatch;
+}
+
+
+Dispatch::Handler Dispatch::addHandler(const std::string& event,
+ const Function& callback)
+{
+ return addHandler(event, callback, mImpl->getNewHandler());
+}
+
+Dispatch::Handler Dispatch::addHandler(const std::string& event,
+ const Function& callback, Handler handler)
+{
+ // pass through
+ return mImpl->addHandler(event, callback, handler);
+}
+
+
+void Dispatch::removeHandler(unsigned id)
+{
+ // pass through
+ return mImpl->removeHandler(id);
+}
+
+
+void Dispatch::dispatch(const std::string& event, const Message* message)
+{
+ // pass through
+ mImpl->dispatch(event, message);
+}
+
+
+} // namespace Mf
+
+/** vim: set ts=4 sw=4 tw=80: *************************************************/
+