--- /dev/null
+
+/*] Copyright (c) 2009-2010, Charles McGarvey [**************************
+**] All rights reserved.
+*
+* vi:ts=4 sw=4 tw=75
+*
+* Distributable under the terms and conditions of the 2-clause BSD license;
+* see the file COPYING for a complete text of the license.
+*
+**************************************************************************/
+
+#include <map>
+
+#include "dispatcher.hh"
+
+
+namespace moof {
+
+
+class dispatcher::impl
+{
+public:
+
+ impl(dispatcher* dispatcher) :
+ dispatcher_(dispatcher),
+ id_(0) {}
+
+ dispatcher::handle getNewHandle()
+ {
+ ++id_;
+ dispatcher::handle handle(dispatcher_->impl_, id_);
+ return handle;
+ }
+
+ typedef std::pair<unsigned,dispatcher::function> callback;
+ typedef std::multimap<std::string,callback> callback_lookup;
+ typedef callback_lookup::iterator callback_it;
+
+ typedef std::multimap<unsigned,std::string> handle_lookup;
+ typedef handle_lookup::iterator handle_it;
+
+
+ handle add_target(const std::string& event,
+ const function& callback,
+ handle handle)
+ {
+ callbacks_.insert(std::make_pair(event, std::make_pair(handle.id(),
+ callback)));
+ handles_.insert(std::make_pair(handle.id(), event));
+
+ return handle;
+ }
+
+ void remove_target(unsigned id)
+ {
+ std::pair<handle_it,handle_it> matching(handles_.equal_range(id));
+
+ for (handle_it it = matching.first; it != matching.second; ++it)
+ {
+ callback_it first = callbacks_.find((*it).second);
+ callback_it last = callbacks_.end();
+
+ for (callback_it jt = first; jt != last; ++jt)
+ {
+ if ((*jt).second.first == id)
+ {
+ callbacks_.erase(jt);
+ break;
+ }
+ }
+ }
+
+ handles_.erase(id);
+ }
+
+ void dispatch(const std::string& event)
+ {
+ std::pair<callback_it,callback_it>
+ callbacks(callbacks_.equal_range(event));
+
+ for (callback_it it = callbacks.first; it != callbacks.second; ++it)
+ {
+ function callback = (*it).second.second;
+ callback();
+ }
+ }
+
+
+ dispatcher* dispatcher_;
+
+ unsigned id_;
+
+ callback_lookup callbacks_;
+ handle_lookup handles_;
+};
+
+
+void dispatcher::handle::clear()
+{
+ boost::shared_ptr<impl> dispatcher;
+ if (id_ && (dispatcher = dispatcher_.lock()))
+ {
+ dispatcher->remove_target(id_);
+ id_ = 0;
+ }
+}
+
+
+dispatcher::dispatcher() :
+ impl_(new dispatcher::impl(this)) {}
+
+
+dispatcher::handle dispatcher::add_target(const std::string& event,
+ const function& callback)
+{
+ return add_target(event, callback, impl_->getNewHandle());
+}
+
+dispatcher::handle dispatcher::add_target(const std::string& event,
+ const function& callback,
+ handle handle)
+{
+ // pass through
+ return impl_->add_target(event, callback, handle);
+}
+
+
+void dispatcher::remove_target(unsigned id)
+{
+ // pass through
+ return impl_->remove_target(id);
+}
+
+
+void dispatcher::dispatch(const std::string& event)
+{
+ // pass through
+ impl_->dispatch(event);
+}
+
+
+dispatcher& dispatcher::global()
+{
+ static dispatcher dispatcher;
+ return dispatcher;
+}
+
+
+} // namespace moof
+