From: Eugene Kurzberg Date: Fri, 23 Dec 2016 12:51:50 +0000 (+0200) Subject: Refactored CallbackManager to support std::function callbacks X-Git-Tag: submit/tizen_3.0/20170110.135457^2~7 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F57%2F106457%2F3;p=profile%2Fmobile%2Fapps%2Fnative%2Fphone-contacts.git Refactored CallbackManager to support std::function callbacks and unsubscribing during notification. Change-Id: I84aa88271fd898c91427baeb27dea1a3a17a248a Signed-off-by: Eugene Kurzberg --- diff --git a/lib-apps-common/inc/System/Settings.h b/lib-apps-common/inc/System/Settings.h index 2feab1a..f73d089 100644 --- a/lib-apps-common/inc/System/Settings.h +++ b/lib-apps-common/inc/System/Settings.h @@ -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); }; } diff --git a/lib-apps-common/inc/Utils/CallbackManager.h b/lib-apps-common/inc/Utils/CallbackManager.h index 137b0ea..eaa11fa 100644 --- a/lib-apps-common/inc/Utils/CallbackManager.h +++ b/lib-apps-common/inc/Utils/CallbackManager.h @@ -17,6 +17,7 @@ #ifndef UTILS_CALLBACK_MANAGER_H #define UTILS_CALLBACK_MANAGER_H +#include #include namespace Utils @@ -32,38 +33,44 @@ namespace Utils /** * @brief Callback prototype. */ - typedef void(*CallbackType)(void *, Args...); + typedef std::function CallbackType; /** - * @brief Callback and data pair. + * @brief Callback and subscriber pair. */ typedef std::pair 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 Callbacks; Callbacks m_Callbacks; + int m_Index; }; } diff --git a/lib-apps-common/inc/Utils/CallbackManagerImpl.h b/lib-apps-common/inc/Utils/CallbackManagerImpl.h index 9986734..70af5d4 100644 --- a/lib-apps-common/inc/Utils/CallbackManagerImpl.h +++ b/lib-apps-common/inc/Utils/CallbackManagerImpl.h @@ -18,38 +18,57 @@ #define UTILS_CALLBACK_MANAGER_IMPL_H #include "Utils/CallbackManager.h" -#include + +/* -1 is a possible index if the first callback is removed during notification */ +#define INVALID_CALLBACK_INDEX -2 namespace Utils { template - bool CallbackManager::isEmpty() const + CallbackManager::CallbackManager() + : m_Index(INVALID_CALLBACK_INDEX) + { } + + template + CallbackManager::operator bool() const { - return m_Callbacks.empty(); + return !m_Callbacks.empty(); } template - void CallbackManager::addCallback(Callback callback) + void CallbackManager::operator+=(Callback callback) { - m_Callbacks.push_back(callback); + m_Callbacks.push_back(std::move(callback)); } template - void CallbackManager::removeCallback(Callback callback) + void CallbackManager::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 - void CallbackManager::invokeCallbacks(Args... args) + void CallbackManager::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; } } diff --git a/lib-apps-common/src/System/Settings.cpp b/lib-apps-common/src/System/Settings.cpp index cbd2ba5..7ecdd8f 100644 --- a/lib-apps-common/src/System/Settings.cpp +++ b/lib-apps-common/src/System/Settings.cpp @@ -17,6 +17,7 @@ #include "System/Settings.h" #include "Utils/Callback.h" +#include #include 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); } } diff --git a/lib-logs/src/Logs/Details/DetailsView.cpp b/lib-logs/src/Logs/Details/DetailsView.cpp index 01823a3..42ed8b4 100644 --- a/lib-logs/src/Logs/Details/DetailsView.cpp +++ b/lib-logs/src/Logs/Details/DetailsView.cpp @@ -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) diff --git a/lib-logs/src/Logs/List/LogsView.cpp b/lib-logs/src/Logs/List/LogsView.cpp index 6f369fa..69ad35e 100644 --- a/lib-logs/src/Logs/List/LogsView.cpp +++ b/lib-logs/src/Logs/List/LogsView.cpp @@ -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