Refactored CallbackManager to support std::function callbacks 57/106457/3
authorEugene Kurzberg <i.kurtsberg@samsung.com>
Fri, 23 Dec 2016 12:51:50 +0000 (14:51 +0200)
committerEugene Kurzberg <i.kurtsberg@samsung.com>
Fri, 23 Dec 2016 12:51:50 +0000 (14:51 +0200)
and unsubscribing during notification.

Change-Id: I84aa88271fd898c91427baeb27dea1a3a17a248a
Signed-off-by: Eugene Kurzberg <i.kurtsberg@samsung.com>
lib-apps-common/inc/System/Settings.h
lib-apps-common/inc/Utils/CallbackManager.h
lib-apps-common/inc/Utils/CallbackManagerImpl.h
lib-apps-common/src/System/Settings.cpp
lib-logs/src/Logs/Details/DetailsView.cpp
lib-logs/src/Logs/List/LogsView.cpp

index 2feab1a..f73d089 100644 (file)
@@ -34,7 +34,7 @@ namespace System
                /**
                 * @see system_settings_unset_changed_cb()
                 */
-               EXPORT_API void removeCallback(system_settings_key_e key, CallbackManager::Callback callback);
+               EXPORT_API void removeCallback(system_settings_key_e key, void *subscriber);
        };
 }
 
index 137b0ea..eaa11fa 100644 (file)
@@ -17,6 +17,7 @@
 #ifndef UTILS_CALLBACK_MANAGER_H
 #define UTILS_CALLBACK_MANAGER_H
 
+#include <functional>
 #include <vector>
 
 namespace Utils
@@ -32,38 +33,44 @@ namespace Utils
                /**
                 * @brief Callback prototype.
                 */
-               typedef void(*CallbackType)(void *, Args...);
+               typedef std::function<void(Args...)> CallbackType;
 
                /**
-                * @brief Callback and data pair.
+                * @brief Callback and subscriber pair.
                 */
                typedef std::pair<CallbackType, void *> Callback;
 
+               CallbackManager();
+
                /**
-                * @return Whether there is no added callbacks.
+                * @return Whether there are any added callbacks.
                 */
-               bool isEmpty() const;
+               explicit operator bool() const;
 
                /**
                 * @brief Add new callback.
-                * @param[in]   callback    Callback and data pair.
+                * @param[in]   callback    Callback and subscriber pair.
+                * @remark Subscriber can be any value by which the callback can be
+                *         identified when removing it. However it is most convenient
+                *         to identify it by the pointer to the object that receives it.
                 */
-               void addCallback(Callback callback);
+               void operator+=(Callback callback);
 
                /**
                 * @brief Remove added callback.
-                * @param[in]   callback    Callback and data pair.
+                * @param[in]   subscriber  Callback subscriber.
                 */
-               void removeCallback(Callback callback);
+               void operator-=(void *subscriber);
 
                /**
                 * @brief Invoke all added callbacks.
                 */
-               void invokeCallbacks(Args... args);
+               void operator()(Args... args);
 
        private:
                typedef std::vector<Callback> Callbacks;
                Callbacks m_Callbacks;
+               int m_Index;
        };
 }
 
index 9986734..70af5d4 100644 (file)
 #define UTILS_CALLBACK_MANAGER_IMPL_H
 
 #include "Utils/CallbackManager.h"
-#include <algorithm>
+
+/* -1 is a possible index if the first callback is removed during notification */
+#define INVALID_CALLBACK_INDEX -2
 
 namespace Utils
 {
        template <typename... Args>
-       bool CallbackManager<Args...>::isEmpty() const
+       CallbackManager<Args...>::CallbackManager()
+               : m_Index(INVALID_CALLBACK_INDEX)
+       { }
+
+       template <typename... Args>
+       CallbackManager<Args...>::operator bool() const
        {
-               return m_Callbacks.empty();
+               return !m_Callbacks.empty();
        }
 
        template <typename... Args>
-       void CallbackManager<Args...>::addCallback(Callback callback)
+       void CallbackManager<Args...>::operator+=(Callback callback)
        {
-               m_Callbacks.push_back(callback);
+               m_Callbacks.push_back(std::move(callback));
        }
 
        template <typename... Args>
-       void CallbackManager<Args...>::removeCallback(Callback callback)
+       void CallbackManager<Args...>::operator-=(void *subscriber)
        {
-               auto it = std::find(m_Callbacks.begin(), m_Callbacks.end(), callback);
-               if (it != m_Callbacks.end()) {
-                       m_Callbacks.erase(it);
+               for (int i = 0; i < (int) m_Callbacks.size(); ++i) {
+                       if (m_Callbacks[i].second == subscriber) {
+                               if (i <= m_Index) {
+                                       --m_Index;
+                               }
+                               m_Callbacks.erase(m_Callbacks.begin() + i);
+                               break;
+                       }
                }
        }
 
        template <typename... Args>
-       void CallbackManager<Args...>::invokeCallbacks(Args... args)
+       void CallbackManager<Args...>::operator()(Args... args)
        {
-               /* FIXME: This might fail if removeCallback() or addCallback() is called during invocation */
-               for (auto &&callback : m_Callbacks) {
-                       callback.first(callback.second, args...);
+               if (m_Index > INVALID_CALLBACK_INDEX) {
+                       return;
+               }
+
+               for (m_Index = 0; m_Index < (int) m_Callbacks.size(); ++m_Index) {
+                       Callback &callback = m_Callbacks[m_Index];
+                       if (callback.first) {
+                               callback.first(args...);
+                       }
                }
+               m_Index = INVALID_CALLBACK_INDEX;
        }
 }
 
index cbd2ba5..7ecdd8f 100644 (file)
@@ -17,6 +17,7 @@
 #include "System/Settings.h"
 #include "Utils/Callback.h"
 
+#include <algorithm>
 #include <list>
 
 using namespace System::Settings;
@@ -30,7 +31,7 @@ namespace
                        : m_Key(key)
                {
                        system_settings_set_changed_cb(m_Key,
-                                       makeCallbackWithLastParam(&KeyManager::invokeCallbacks), this);
+                                       makeCallbackWithLastParam(&KeyManager::operator()), this);
                }
 
                ~KeyManager()
@@ -58,18 +59,18 @@ void System::Settings::addCallback(system_settings_key_e key, KeyManager::Callba
                manager = --keyManagers.end();
        }
 
-       manager->addCallback(callback);
+       (*manager) += (callback);
 }
 
-void System::Settings::removeCallback(system_settings_key_e key, KeyManager::Callback callback)
+void System::Settings::removeCallback(system_settings_key_e key, void *subscriber)
 {
        auto manager = std::find(keyManagers.begin(), keyManagers.end(), key);
        if (manager == keyManagers.end()) {
                return;
        }
 
-       manager->removeCallback(callback);
-       if (manager->isEmpty()) {
+       (*manager) -= subscriber;
+       if (!*manager) {
                keyManagers.erase(manager);
        }
 }
index 01823a3..42ed8b4 100644 (file)
@@ -57,17 +57,15 @@ DetailsView::DetailsView(const char *number)
        setCancelCallback(std::bind(&DetailsView::onCanceled, this));
 
        Settings::addCallback(SYSTEM_SETTINGS_KEY_LOCALE_TIMEFORMAT_24HOUR,
-                       { makeCallback(&DetailsView::onTimeFormatChanged), this });
+                       { std::bind(&DetailsView::onTimeFormatChanged, this, _1), this });
        Settings::addCallback(SYSTEM_SETTINGS_KEY_LOCALE_COUNTRY,
-                       { makeCallback(&DetailsView::onTimeFormatChanged), this });
+                       { std::bind(&DetailsView::onTimeFormatChanged, this, _1), this });
 }
 
 DetailsView::~DetailsView()
 {
-       Settings::removeCallback(SYSTEM_SETTINGS_KEY_LOCALE_TIMEFORMAT_24HOUR,
-                       { makeCallback(&DetailsView::onTimeFormatChanged), this });
-       Settings::removeCallback(SYSTEM_SETTINGS_KEY_LOCALE_COUNTRY,
-                       { makeCallback(&DetailsView::onTimeFormatChanged), this });
+       Settings::removeCallback(SYSTEM_SETTINGS_KEY_LOCALE_TIMEFORMAT_24HOUR, this);
+       Settings::removeCallback(SYSTEM_SETTINGS_KEY_LOCALE_COUNTRY, this);
 }
 
 Evas_Object *DetailsView::onCreate(Evas_Object *parent)
index 6f369fa..69ad35e 100644 (file)
@@ -50,21 +50,18 @@ LogsView::LogsView(FilterType filterType)
        setStrings(strings);
 
        Settings::addCallback(SYSTEM_SETTINGS_KEY_LOCALE_TIMEFORMAT_24HOUR,
-                       { makeCallback(&LogsView::onSettingsChanged), this });
+                       { std::bind(&LogsView::onSettingsChanged, this, _1), this });
        Settings::addCallback(SYSTEM_SETTINGS_KEY_LOCALE_COUNTRY,
-                       { makeCallback(&LogsView::onSettingsChanged), this });
+                       { std::bind(&LogsView::onSettingsChanged, this, _1), this });
        Settings::addCallback(SYSTEM_SETTINGS_KEY_TIME_CHANGED,
-                       { makeCallback(&LogsView::onSettingsChanged), this });
+                       { std::bind(&LogsView::onSettingsChanged, this, _1), this });
 }
 
 LogsView::~LogsView()
 {
-       Settings::removeCallback(SYSTEM_SETTINGS_KEY_LOCALE_TIMEFORMAT_24HOUR,
-                       { makeCallback(&LogsView::onSettingsChanged), this });
-       Settings::removeCallback(SYSTEM_SETTINGS_KEY_LOCALE_COUNTRY,
-                       { makeCallback(&LogsView::onSettingsChanged), this });
-       Settings::removeCallback(SYSTEM_SETTINGS_KEY_TIME_CHANGED,
-                       { makeCallback(&LogsView::onSettingsChanged), this });
+       Settings::removeCallback(SYSTEM_SETTINGS_KEY_LOCALE_TIMEFORMAT_24HOUR, this);
+       Settings::removeCallback(SYSTEM_SETTINGS_KEY_LOCALE_COUNTRY, this);
+       Settings::removeCallback(SYSTEM_SETTINGS_KEY_TIME_CHANGED, this);
 }
 
 LogsView::FilterType LogsView::getFilterType() const