1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 #ifndef COMMONAPI_DBUS_DBUS_MULTI_EVENT_H_
5 #define COMMONAPI_DBUS_DBUS_MULTI_EVENT_H_
7 #include <CommonAPI/Event.h>
10 #include <unordered_map>
15 template <typename... _Arguments>
16 class DBusMultiEvent {
18 typedef std::function<SubscriptionStatus(const std::string&, const _Arguments&...)> Listener;
19 typedef std::unordered_multimap<std::string, Listener> ListenersMap;
20 typedef typename ListenersMap::iterator Subscription;
22 Subscription subscribeAll(const Listener& listener);
23 Subscription subscribe(const std::string& name, const Listener& listener);
25 void unsubscribe(Subscription listenerSubscription);
27 virtual ~DBusMultiEvent() { }
30 SubscriptionStatus notifyListeners(const std::string& name, const _Arguments&... eventArguments);
32 virtual void onFirstListenerAdded(const std::string& name, const Listener& listener) { }
33 virtual void onListenerAdded(const std::string& name, const Listener& listener) { }
35 virtual void onListenerRemoved(const std::string& name, const Listener& listener) { }
36 virtual void onLastListenerRemoved(const std::string& name, const Listener& listener) { }
39 typedef std::pair<typename ListenersMap::iterator, typename ListenersMap::iterator> IteratorRange;
40 SubscriptionStatus notifyListenersRange(const std::string& name, IteratorRange listenersRange, const _Arguments&... eventArguments);
42 ListenersMap listenersMap_;
45 template <typename... _Arguments>
46 typename DBusMultiEvent<_Arguments...>::Subscription
47 DBusMultiEvent<_Arguments...>::subscribeAll(const Listener& listener) {
48 return subscribe(std::string(), listener);
51 template <typename... _Arguments>
52 typename DBusMultiEvent<_Arguments...>::Subscription
53 DBusMultiEvent<_Arguments...>::subscribe(const std::string& name, const Listener& listener) {
54 const bool firstListenerAdded = listenersMap_.empty();
56 auto listenerSubscription = listenersMap_.insert({name, listener});
58 if (firstListenerAdded)
59 onFirstListenerAdded(name, listener);
61 onListenerAdded(name, listener);
63 return listenerSubscription;
66 template <typename... _Arguments>
67 void DBusMultiEvent<_Arguments...>::unsubscribe(Subscription listenerSubscription) {
68 const std::string name = listenerSubscription->first;
69 const Listener listener = listenerSubscription->second;
71 listenersMap_.erase(listenerSubscription);
73 onListenerRemoved(name, listener);
75 const bool lastListenerRemoved = listenersMap_.empty();
76 if (lastListenerRemoved)
77 onLastListenerRemoved(name, listener);
80 template <typename... _Arguments>
81 SubscriptionStatus DBusMultiEvent<_Arguments...>::notifyListeners(const std::string& name, const _Arguments&... eventArguments) {
82 const SubscriptionStatus subscriptionStatus = notifyListenersRange(name, listenersMap_.equal_range(name), eventArguments...);
84 if (subscriptionStatus == SubscriptionStatus::CANCEL)
85 return SubscriptionStatus::CANCEL;
87 return notifyListenersRange(name, listenersMap_.equal_range(std::string()), eventArguments...);
90 template <typename... _Arguments>
91 SubscriptionStatus DBusMultiEvent<_Arguments...>::notifyListenersRange(
92 const std::string& name,
93 IteratorRange listenersRange,
94 const _Arguments&... eventArguments) {
95 for (auto iterator = listenersRange.first; iterator != listenersRange.second; ) {
96 const Listener& listener = iterator->second;
97 const SubscriptionStatus listenerSubcriptionStatus = listener(name, eventArguments...);
99 if (listenerSubcriptionStatus == SubscriptionStatus::CANCEL) {
100 auto listenerIterator = iterator;
101 listenersMap_.erase(listenerIterator);
107 return listenersMap_.empty() ? SubscriptionStatus::CANCEL : SubscriptionStatus::RETAIN;
111 } // namespace CommonAPI
113 #endif // COMMONAPI_DBUS_DBUS_MULTI_EVENT_H_