diff --git a/esignal/Base.cpp b/esignal/Base.cpp index 8a245bd..d079d45 100644 --- a/esignal/Base.cpp +++ b/esignal/Base.cpp @@ -11,10 +11,12 @@ #include #include -size_t esignal::Base::s_uid = 0; +size_t esignal::Base::s_uid = 1; +int64_t esignal::Base::s_uidSignalEmit = 1; -esignal::Base::Base() : - m_shared(this) { +esignal::Base::Base(ObserverConnection _countObs) : + m_shared(this), + m_connectionObserver(_countObs) { } esignal::Base::~Base() { @@ -38,14 +40,12 @@ std::ostream& esignal::operator <<(std::ostream& _os, const esignal::Base& _obj) return _os; } -void esignal::Base::disconnectShared(const std::shared_ptr& _obj) { - -} - -const char* esignal::logIndent(int32_t _iii) { - static const char g_val[] = " "; - if (_iii > 5) { - return g_val; +#ifdef DEBUG + const char* esignal::logIndent(int32_t _iii) { + static const char g_val[] = " "; + if (_iii > 15) { + return g_val; + } + return g_val + (15-_iii)*4; } - return g_val + (5-_iii)*4; -} +#endif diff --git a/esignal/Base.h b/esignal/Base.h index 60fbd5e..7945ade 100644 --- a/esignal/Base.h +++ b/esignal/Base.h @@ -19,12 +19,16 @@ namespace esignal { class Base { + public: + using ObserverConnection = std::function; //!< Define an Observer of the number of observer protected: esignal::LockSharedPtrRef m_shared; //!< Reference counter on itself. - static size_t s_uid; //!< blobal id of the signal (STATIC) + static size_t s_uid; //!< global id of the signal (STATIC) + static int64_t s_uidSignalEmit; //!< global id to emit counting + ObserverConnection m_connectionObserver; public: //! @brief Basic constructor: - Base(); + Base(ObserverConnection _countObs = nullptr); //! @brief Copy constructor: Base(const Base&) = delete; //! @brief Move constructor @@ -34,7 +38,7 @@ namespace esignal { /** * @brief get name of the signal */ - virtual void disconnectShared(const std::shared_ptr& _obj); + virtual void disconnectShared(const std::shared_ptr& _obj) = 0; virtual void disconnect(std::size_t _uid) = 0; /** * @brief Get name of the signal. @@ -48,5 +52,7 @@ namespace esignal { virtual const std::string& getDescription() const; }; std::ostream& operator <<(std::ostream& _os, const esignal::Base& _obj); - const char* logIndent(int32_t _iii); + #ifdef DEBUG + const char* logIndent(int32_t _iii); + #endif } diff --git a/esignal/ISignal.h b/esignal/ISignal.h index 5d200df..e037aa7 100644 --- a/esignal/ISignal.h +++ b/esignal/ISignal.h @@ -18,8 +18,8 @@ namespace esignal { /** * @brief Sigla same as @ref esignal::Signal withe a name and a description to manage a list of signals. */ - template - class ISignal : public Signal { + template + class ISignal : public Signal { protected: esignal::Interface& m_signalInterfaceLink; //!< interface of the signal manager. std::string m_name; //!< name of the signal. @@ -28,9 +28,15 @@ namespace esignal { /** * @brief Create a signal with a specific type. * @param[in] _signalInterfaceLink reference on the signal lister. + * @param[in] _countObs (optionnal) Local observer to know the count of connection on the signal. * @param[in] _name Static name of the signal. * @param[in] _description Description of the signal. */ + template + ISignal(CLASS_TYPE* _signalInterfaceLink, + FUNC_TYPE _func, + const std::string& _name, + const std::string& _description = ""); ISignal(esignal::Interface& _signalInterfaceLink, const std::string& _name, const std::string& _description = ""); @@ -43,3 +49,17 @@ namespace esignal { }; } +template +template +esignal::ISignal::ISignal(CLASS_TYPE* _class, + FUNC_TYPE _func, + const std::string& _name, + const std::string& _description) : + esignal::Signal(_class, _func), + m_signalInterfaceLink(*_class), + m_name(_name), + m_description(_description) { + // add a reference on the current signal ... + m_signalInterfaceLink.signalAdd(this); +} + diff --git a/esignal/Interface.cpp b/esignal/Interface.cpp index 4e6c88f..80e30e5 100644 --- a/esignal/Interface.cpp +++ b/esignal/Interface.cpp @@ -62,12 +62,3 @@ void esignal::Interface::signalDisconnect(const std::shared_ptr& _object) it->disconnectShared(_object); } } - -void esignal::Interface::signalDisconnect(size_t _uid) { - for(auto &it : m_list) { - if (it == nullptr) { - continue; - } - it->disconnect(_uid); - } -} diff --git a/esignal/Interface.h b/esignal/Interface.h index 08a6025..82907b0 100644 --- a/esignal/Interface.h +++ b/esignal/Interface.h @@ -42,7 +42,6 @@ namespace esignal { * @param[in] _sharedPtr sharedPtr to unlink (no type needed ...). */ void signalDisconnect(const std::shared_ptr& _sharedPtr); - void signalDisconnect(size_t _uid); }; } diff --git a/esignal/LockSharedPtrRef.h b/esignal/LockSharedPtrRef.h index a3e5f16..d3ef1d5 100644 --- a/esignal/LockSharedPtrRef.h +++ b/esignal/LockSharedPtrRef.h @@ -18,6 +18,9 @@ namespace esignal { template class LockSharedPtrRef { public: + // TODO : Remove data from refcounter ...==> + // esignal::RefCount* m_counter; //!< Access on the reference counter + // TYPE* m_data; //!< Pointer on the data esignal::RefCount* m_counter; //!< Access on the reference counter public: /** @@ -64,6 +67,11 @@ namespace esignal { * @return false The data has been removed */ bool isAlive(); + private: + /** + * @remove reference on the refcounter... + */ + void rmShared(); }; } diff --git a/esignal/Signal.h b/esignal/Signal.h index ea4b51e..8799f28 100644 --- a/esignal/Signal.h +++ b/esignal/Signal.h @@ -31,8 +31,13 @@ namespace esignal { protected: int32_t m_callInProgress; //!< know if we are in a recursive loop public: - //! @brief Basic constructor - Signal(); + /** + * @brief Basic constructor + * @param[in] _countObs Local observer to know the count of connection on the signal. + */ + Signal(ObserverConnection _countObs=nullptr); + template + Signal(CLASS_TYPE* _class, FUNC_TYPE _func); //! @brief Copy constructor (REMOVED) Signal(const Signal&) = delete; //! @brief Copy operator (REMOVED) @@ -167,7 +172,10 @@ esignal::Connection esignal::Signal::connect(OBSERVER_TYPE&& _observe std::unique_ptr executer(new Executor(std::forward(_observer))); std::size_t uid = executer->m_uid; m_executors.push_back(std::move(executer)); - return Connection(Base::m_shared, uid); + if (m_connectionObserver!=nullptr) { + m_connectionObserver(m_executors.size()); + } + return esignal::Connection(Base::m_shared, uid); } template @@ -175,11 +183,18 @@ template esignal::Connection esignal::Signal::connect(CLASS_TYPE* _class, FUNC_TYPE _func, FUNC_ARGS_TYPE... _arg) { + if (_class == nullptr) { + // ERROR + return esignal::Connection(); + } std::unique_ptr executer(new Executor([=](const T_ARGS& ... _argBase){ (*_class.*_func)(_argBase..., _arg... ); })); std::size_t uid = executer->m_uid; m_executors.push_back(std::move(executer)); + if (m_connectionObserver!=nullptr) { + m_connectionObserver(m_executors.size()); + } return Connection(Base::m_shared, uid); } @@ -188,6 +203,10 @@ template void esignal::Signal::connect(const std::shared_ptr& _class, void (CLASS_TYPE::*_func)(const T_ARGS&..., FUNC_ARGS_TYPE...), FUNC_ARGS_TYPE... _args) { + if (_class == nullptr) { + // ERROR + return; + } std::shared_ptr obj2 = std::dynamic_pointer_cast(_class); if (obj2 == nullptr) { ESIGNAL_ERROR("Can not bind signal ..."); @@ -199,4 +218,17 @@ void esignal::Signal::connect(const std::shared_ptr +template +esignal::Signal::Signal(CLASS_TYPE* _class, + FUNC_TYPE _func): + esignal::Base([=](size_t _val){(*_class.*_func)(_val);}), + m_callInProgress(0) { + // nothing to do +} + diff --git a/esignal/details/ISignal.hxx b/esignal/details/ISignal.hxx index 2e85d66..02026a9 100644 --- a/esignal/details/ISignal.hxx +++ b/esignal/details/ISignal.hxx @@ -10,8 +10,8 @@ #include #include -template -esignal::ISignal::ISignal(esignal::Interface& _signalInterfaceLink, +template +esignal::ISignal::ISignal(esignal::Interface& _signalInterfaceLink, const std::string& _name, const std::string& _description): m_signalInterfaceLink(_signalInterfaceLink), @@ -21,18 +21,18 @@ esignal::ISignal::ISignal(esignal::Interface& _signalInterfaceLink, m_signalInterfaceLink.signalAdd(this); } -template -esignal::ISignal::~ISignal() { +template +esignal::ISignal::~ISignal() { m_signalInterfaceLink.signalRemove(this); } -template -const std::string& esignal::ISignal::getName() const { +template +const std::string& esignal::ISignal::getName() const { return m_name; } -template -const std::string& esignal::ISignal::getDescription() const { +template +const std::string& esignal::ISignal::getDescription() const { return m_description; } diff --git a/esignal/details/LockSharedPtrRef.hxx b/esignal/details/LockSharedPtrRef.hxx index 186bfbc..40eddeb 100644 --- a/esignal/details/LockSharedPtrRef.hxx +++ b/esignal/details/LockSharedPtrRef.hxx @@ -7,28 +7,35 @@ */ #include +#include template esignal::LockSharedPtrRef::LockSharedPtrRef(TYPE* _pointer) : m_counter(nullptr) { + ESIGNAL_VERBOSE("LockSharedPtrRef new [START] " << int64_t(_pointer)); if (_pointer != nullptr) { m_counter = new RefCount(_pointer); m_counter->inc(); } + ESIGNAL_VERBOSE("LockSharedPtrRef new [STOP]"); } template esignal::LockSharedPtrRef::LockSharedPtrRef(const LockSharedPtrRef& _obj) : m_counter(_obj.m_counter) { + ESIGNAL_VERBOSE("LockSharedPtrRef new [START] ref ..."); if (m_counter == nullptr) { return; } m_counter->inc(); + ESIGNAL_VERBOSE("LockSharedPtrRef new [STOP]"); } template esignal::LockSharedPtrRef& esignal::LockSharedPtrRef::operator=(const esignal::LockSharedPtrRef& _obj) { + ESIGNAL_VERBOSE("LockSharedPtrRef copy [START]"); if (&_obj == this) { + ESIGNAL_VERBOSE("LockSharedPtrRef copy [STOP] auto-copy"); return *this; } if (m_counter != nullptr) { @@ -37,41 +44,57 @@ esignal::LockSharedPtrRef& esignal::LockSharedPtrRef::operator=(cons } m_counter = _obj.m_counter; if (m_counter == nullptr) { + ESIGNAL_VERBOSE("LockSharedPtrRef copy [STOP] no counter"); return *this; } m_counter->inc(); + ESIGNAL_VERBOSE("LockSharedPtrRef copy [STOP]"); return *this; } template esignal::LockSharedPtrRef::LockSharedPtrRef(LockSharedPtrRef&& _obj) : m_counter(std::move(_obj.m_counter)) { - + ESIGNAL_VERBOSE("LockSharedPtrRef move [DONE]"); } template esignal::LockSharedPtrRef::~LockSharedPtrRef() { + ESIGNAL_VERBOSE("LockSharedPtrRef delete [START]"); + rmShared(); + ESIGNAL_VERBOSE("LockSharedPtrRef delete [STOP]"); +} + +template +void esignal::LockSharedPtrRef::rmShared() { + ESIGNAL_VERBOSE("LockSharedPtrRef rmShared [START]"); if (m_counter == nullptr) { return; } int64_t count = m_counter->dec(); if (count > 0) { + m_counter = nullptr; return; } delete m_counter; m_counter = nullptr; + ESIGNAL_VERBOSE("LockSharedPtrRef rmShared [STOP]"); } template void esignal::LockSharedPtrRef::removeData() { + ESIGNAL_VERBOSE("LockSharedPtrRef removeData [START]"); if (m_counter != nullptr) { m_counter->remove(); } + ESIGNAL_VERBOSE("LockSharedPtrRef removeData [STOP]"); } template void esignal::LockSharedPtrRef::disconnect(std::size_t _uid) { + ESIGNAL_VERBOSE("LockSharedPtrRef disconnect [START] " << _uid); if (m_counter == nullptr) { + ESIGNAL_VERBOSE("LockSharedPtrRef disconnect [STOP] No counter"); return; } m_counter->lock(); @@ -80,10 +103,13 @@ void esignal::LockSharedPtrRef::disconnect(std::size_t _uid) { val->disconnect(_uid); } m_counter->unlock(); + rmShared(); + ESIGNAL_VERBOSE("LockSharedPtrRef disconnect [STOP]"); } template bool esignal::LockSharedPtrRef::isAlive() { + ESIGNAL_VERBOSE("LockSharedPtrRef isAlive [DONE] "); return m_counter != nullptr; } diff --git a/esignal/details/RefCount.hxx b/esignal/details/RefCount.hxx index e3f970e..ffccccc 100644 --- a/esignal/details/RefCount.hxx +++ b/esignal/details/RefCount.hxx @@ -8,56 +8,70 @@ #pragma once #include +#include template esignal::RefCount::RefCount(TYPE* _data) : m_count(0), m_data(_data) { + ESIGNAL_VERBOSE(int64_t(this) << " RefCount New : " << int64_t(_data)); // nothing to do. } template esignal::RefCount::~RefCount() { + ESIGNAL_VERBOSE(int64_t(this) << " RefCount delete"); m_data = nullptr; } template void esignal::RefCount::lock() { + ESIGNAL_VERBOSE(int64_t(this) << " RefCount LOCK [START]"); m_lock.lock(); + ESIGNAL_VERBOSE(int64_t(this) << " RefCount LOCK [STOP]"); } template void esignal::RefCount::unlock() { + ESIGNAL_VERBOSE(int64_t(this) << " RefCount UN-LOCK [START]"); m_lock.unlock(); + ESIGNAL_VERBOSE(int64_t(this) << " RefCount UN-LOCK [STOP]"); } template void esignal::RefCount::inc() { + ESIGNAL_VERBOSE(int64_t(this) << " RefCount INC [START] " << m_count); lock(); m_count++; unlock(); + ESIGNAL_VERBOSE(int64_t(this) << " RefCount INC [STOP] " << m_count); } template int64_t esignal::RefCount::dec() { + ESIGNAL_VERBOSE(int64_t(this) << " RefCount DEC [START] " << m_count); int64_t val; lock(); m_count--; val = m_count; unlock(); + ESIGNAL_VERBOSE(int64_t(this) << " RefCount DEC [STOP] " << m_count); return val; } template int64_t esignal::RefCount::getCount() const { + ESIGNAL_VERBOSE(int64_t(this) << " RefCount get count " << m_count); return m_count; } template void esignal::RefCount::remove() { + ESIGNAL_VERBOSE(int64_t(this) << " RefCount remove [START]"); lock(); m_data = nullptr; unlock(); + ESIGNAL_VERBOSE(int64_t(this) << " RefCount remove [STOP]"); } template diff --git a/esignal/details/Signal.hxx b/esignal/details/Signal.hxx index 8fd7ca4..e811783 100644 --- a/esignal/details/Signal.hxx +++ b/esignal/details/Signal.hxx @@ -13,43 +13,67 @@ #define __class__ "Signal" template -esignal::Signal::Signal(): +esignal::Signal::Signal(ObserverConnection _countObs): + esignal::Base(_countObs), m_callInProgress(0) { // nothing to do } + + template void esignal::Signal::emit(const T_ARGS&... _args) { + #ifdef DEBUG + int32_t tmpID = s_uidSignalEmit++; + #endif // TODO : Add protection ... but how ... m_callInProgress++; + ESIGNAL_DEBUG(esignal::logIndent(m_callInProgress-1) << " signal{" << tmpID << "} :"); for (size_t iii=0; iii < m_executors.size(); ++iii) { m_executors[iii]->emit(_args...); } if (m_callInProgress == 1) { + bool haveRemove = false; auto it = m_executors.begin(); while (it != m_executors.end()) { if ( *it == nullptr || (*it)->m_removed == true) { it = m_executors.erase(it); + haveRemove = true; continue; } ++it; } + if (haveRemove == true) { + if (m_connectionObserver!=nullptr) { + m_connectionObserver(m_executors.size()); + } + } } m_callInProgress--; } template void esignal::Signal::removeIfPossible() { + if (m_callInProgress != 0) { + return; + } + bool haveRemove = false; auto it = m_executors.begin(); while (it != m_executors.end()) { if ( *it == nullptr || (*it)->m_removed == true) { it = m_executors.erase(it); + haveRemove = true; continue; } ++it; } + if (haveRemove == true) { + if (m_connectionObserver!=nullptr) { + m_connectionObserver(m_executors.size()); + } + } } template @@ -85,7 +109,10 @@ bool esignal::Signal::empty() const { template void esignal::Signal::clear() { - m_executors.clear(); + for (size_t iii=0; iii < m_executors.size(); ++iii) { + m_executors[iii]->m_removed = true; + } + removeIfPossible(); } @@ -157,170 +184,3 @@ bool esignal::Signal::ExecutorShared::isSharedPtr(const std::shared_p } - - - - - -#if 0 -template esignal::Signal::Signal() : - m_callInProgress(0), - m_someOneRemoveInCall(false) { - -} - -template esignal::Signal::~Signal() { - -} - - void esignal::Signal::connect(std::shared_ptr _obj, std::function _function ) { - if (m_callInProgress == 0) { - m_callerList.push_back(std::make_pair(std::weak_ptr(_obj), _function)); - } else { - m_callerListInCallback.push_back(std::make_pair(std::weak_ptr(_obj), _function)); - } -} - -template void esignal::Signal::connect(std::function _function ) { - if (m_callInProgress == 0) { - m_callerListDirect.push_back(_function); - } else { - m_callerListDirectInCallback.push_back(_function); - } -} - -template bool esignal::Signal::isRegistered(std::shared_ptr _obj) { - if (_obj == nullptr) { - return false; - } - for (auto &it : m_callerList) { - std::shared_ptr obj = it.first.lock(); - if (obj == _obj) { - return true; - } - } - for (auto &it : m_callerListInCallback) { - std::shared_ptr obj = it.first.lock(); - if (obj == _obj) { - return true; - } - } - return false; -} - -template void esignal::Signal::release(std::shared_ptr _obj) { - if (m_callInProgress == 0) { - // Remove from the list : - auto it(m_callerList.begin()); - while(it != m_callerList.end()) { - if (it->first.lock() == _obj) { - it = m_callerList.erase(it); - } else { - ++it; - } - } - } else { - // just remove weak poointer - auto it(m_callerList.begin()); - while(it != m_callerList.end()) { - if (it->first.lock() == _obj) { - it->first.reset(); - } else { - ++it; - } - } - m_someOneRemoveInCall = true; - } - // remove from add list in callback progress - auto it = m_callerListInCallback.begin(); - while(it != m_callerListInCallback.end()) { - if (it->first.lock() == _obj) { - it = m_callerListInCallback.erase(it); - } else { - ++it; - } - } -} - -template void esignal::Signal::emit(const T&... _data) { - #ifdef DEBUG - m_signalCallLevel++; - int32_t tmpID = m_uidSignal++; - #endif - m_callInProgress++; - if (m_periodic == true) { - ESIGNAL_VERBOSE(esignal::logIndent(m_signalCallLevel-1) << "emit signal{" << tmpID << "} : signal='" << m_name << "' data='" << /*etk::to_string(_data) <<*/ "' to: " << m_callerList.size() << " element(s)"); - } else { - ESIGNAL_DEBUG(esignal::logIndent(m_signalCallLevel-1) << "emit signal{" << tmpID << "} : signal='" << m_name << "' data='" << /*etk::to_string(_data) <<*/ "' to: " << m_callerList.size() << " element(s)"); - } - { - auto it(m_callerList.begin()); - while (it != m_callerList.end()) { - std::shared_ptr destObject = it->first.lock(); - if (destObject == nullptr) { - it = m_callerList.erase(it); - ESIGNAL_DEBUG(esignal::logIndent(m_signalCallLevel-1) << " nullptr dest"); - continue; - } - if (m_periodic == true) { - ESIGNAL_VERBOSE(esignal::logIndent(m_signalCallLevel-1) << " signal{" << tmpID << "} :");// [" << destObject->getId() << "]" << destObject->getObjectType()); - } else { - ESIGNAL_DEBUG(esignal::logIndent(m_signalCallLevel-1) << " signal{" << tmpID << "} :");// [" << destObject->getId() << "]" << destObject->getObjectType()); - } - it->second(_data...); - ++it; - } - } - { - auto it(m_callerListDirect.begin()); - while (it != m_callerListDirect.end()) { - if (m_periodic == true) { - ESIGNAL_VERBOSE(esignal::logIndent(m_signalCallLevel-1) << "X signal{" << tmpID << "} :");// [" << destObject->getId() << "]" << destObject->getObjectType()); - } else { - ESIGNAL_DEBUG(esignal::logIndent(m_signalCallLevel-1) << "X signal{" << tmpID << "} :");// [" << destObject->getId() << "]" << destObject->getObjectType()); - } - (*it)(_data...); - ++it; - } - } - m_callInProgress--; - #ifdef DEBUG - m_signalCallLevel--; - #endif - // Remove element in call phase: - if (m_someOneRemoveInCall == true) { - m_someOneRemoveInCall = false; - // Remove from the list : - auto it(m_callerList.begin()); - while(it != m_callerList.end()) { - if (it->first.expired() == true) { - it = m_callerList.erase(it); - } else { - ++it; - } - } - } - // add element in call phase: - if (m_callerListInCallback.size() > 0) { - for (auto &it : m_callerListInCallback) { - m_callerList.push_back(it); - } - m_callerListInCallback.clear(); - } - if (m_callerListDirectInCallback.size() > 0) { - for (auto &it : m_callerListDirectInCallback) { - m_callerListDirect.push_back(it); - } - m_callerListDirectInCallback.clear(); - } -} - -template size_t esignal::Signal::getNumberConnected() { - return m_callerList.size() + m_callerListDirect.size(); -} -#endif - - - - - diff --git a/lutin_esignal-test.py b/lutin_esignal-test.py index 87294f0..40d4690 100644 --- a/lutin_esignal-test.py +++ b/lutin_esignal-test.py @@ -30,6 +30,7 @@ def create(target, module_name): my_module.add_src_file([ 'test/main.cpp', 'test/declareSignals.cpp', + 'test/test_signal_counter.cpp', 'test/test_signal_class_func.cpp', 'test/test_signal_recursive.cpp', 'test/test_signal_shared_ptr_func.cpp', diff --git a/test/test_isignal.cpp b/test/test_isignal.cpp index f16559b..388d0de 100644 --- a/test/test_isignal.cpp +++ b/test/test_isignal.cpp @@ -8,7 +8,7 @@ #define NAME "SingleArg" #include -#include +#include #include #include #include @@ -17,4 +17,111 @@ #undef __class__ #define __class__ "test_isignal" +class testISignal : public esignal::Interface { + public: + esignal::ISignal m_signalInt; + esignal::ISignal m_signalString; + esignal::ISignal m_signalFloat; + public: + size_t m_count; + testISignal(): + m_signalInt(this, &testISignal::changeCount, "int", "desc int"), + m_signalString(*this, "string", "desc string"), + m_signalFloat(*this, "float", "desc float") { + m_count = 0; + } + void changeCount(size_t _a) { + TEST_VERBOSE("connection number : " << _a); + m_count = _a; + } +}; +TEST(test_isignal_counter, localbasicCounter1) { + testISignal localClass; + EXPECT_EQ(localClass.m_signalString.size(), 0); + EXPECT_EQ(localClass.m_signalString.empty(), true); + esignal::Connection connection1 = localClass.m_signalString.connect([=](std::string){}); + EXPECT_EQ(localClass.m_signalString.size(), 1); + EXPECT_EQ(localClass.m_signalString.empty(), false); + esignal::Connection connection2 = localClass.m_signalString.connect([=](std::string){}); + EXPECT_EQ(localClass.m_signalString.size(), 2); + EXPECT_EQ(localClass.m_signalString.empty(), false); + connection1.disconnect(); + EXPECT_EQ(localClass.m_signalString.size(), 1); + EXPECT_EQ(localClass.m_signalString.empty(), false); + connection2.disconnect(); + EXPECT_EQ(localClass.m_signalString.size(), 0); + EXPECT_EQ(localClass.m_signalString.empty(), true); +} + +TEST(test_isignal_counter, localbasicCounter2) { + testISignal localClass; + EXPECT_EQ(localClass.m_signalInt.size(), 0); + EXPECT_EQ(localClass.m_signalInt.empty(), true); + EXPECT_EQ(localClass.m_count, 0); + esignal::Connection connection1 = localClass.m_signalInt.connect([=](int32_t){}); + EXPECT_EQ(localClass.m_signalInt.size(), 1); + EXPECT_EQ(localClass.m_signalInt.empty(), false); + EXPECT_EQ(localClass.m_count, 1); + esignal::Connection connection2 = localClass.m_signalInt.connect([=](int32_t){}); + EXPECT_EQ(localClass.m_signalInt.size(), 2); + EXPECT_EQ(localClass.m_signalInt.empty(), false); + EXPECT_EQ(localClass.m_count, 2); + connection1.disconnect(); + EXPECT_EQ(localClass.m_signalInt.size(), 1); + EXPECT_EQ(localClass.m_signalInt.empty(), false); + EXPECT_EQ(localClass.m_count, 1); + connection2.disconnect(); + EXPECT_EQ(localClass.m_signalInt.size(), 0); + EXPECT_EQ(localClass.m_signalInt.empty(), true); + EXPECT_EQ(localClass.m_count, 0); +} + + +TEST(test_isignal_counter, localbasicNameDesc) { + testISignal localClass; + EXPECT_EQ(localClass.m_signalFloat.getName(), "float"); + EXPECT_EQ(localClass.m_signalInt.getName(), "int"); + EXPECT_EQ(localClass.m_signalString.getName(), "string"); + EXPECT_EQ(localClass.m_signalFloat.getDescription(), "desc float"); + EXPECT_EQ(localClass.m_signalInt.getDescription(), "desc int"); + EXPECT_EQ(localClass.m_signalString.getDescription(), "desc string"); +} + +class testCallbackIShared : public std::enable_shared_from_this { + public: + testCallbackIShared() { + } + void callbackConstInt(const int32_t& _a) { + TEST_VERBOSE("event a=" << _a); + } +}; + +TEST(test_isignal_counter, localbasicInterfaceGetListSignal) { + testISignal localClass; + std::vector list; + list.push_back("int"); + list.push_back("string"); + list.push_back("float"); + EXPECT_EQ(localClass.signalGetAll(), list); +} + +TEST(test_isignal_counter, localbasicInterfaceDisconnectNullPtr) { + testISignal localClass; + localClass.signalDisconnect(nullptr); +} + +TEST(test_isignal_counter, localbasicInterfaceDisconnectSharedPtr) { + testISignal localClass; + std::shared_ptr tmp = std::make_shared(); + localClass.signalDisconnect(tmp); + EXPECT_EQ(localClass.m_signalInt.size(), 0); + EXPECT_EQ(localClass.m_signalInt.empty(), true); + localClass.m_signalInt.connect(tmp, &testCallbackIShared::callbackConstInt); + EXPECT_EQ(localClass.m_signalInt.size(), 1); + EXPECT_EQ(localClass.m_signalInt.empty(), false); + localClass.m_signalInt.emit(34567); + localClass.signalDisconnect(tmp); + EXPECT_EQ(localClass.m_signalInt.size(), 0); + EXPECT_EQ(localClass.m_signalInt.empty(), true); +} diff --git a/test/test_signal_class_func.cpp b/test/test_signal_class_func.cpp index 6d419fd..8cd9cc5 100644 --- a/test/test_signal_class_func.cpp +++ b/test/test_signal_class_func.cpp @@ -22,46 +22,117 @@ class testCallback { std::string m_string; bool m_void; testCallback() { + m_emptyFunctor = nullptr; m_void = false; m_int32 = 0; m_string = ""; } + using stupidFunctor = std::function; + + stupidFunctor m_emptyFunctor; + void callbackVoid(){ + TEST_VERBOSE("event void"); m_void = true; } void callbackInt(int32_t _a){ + TEST_VERBOSE("event a=" << _a); m_int32 = _a; } void callbackConstInt(const int32_t& _a){ + TEST_VERBOSE("event a=" << _a); m_int32 = _a; } void callbackString(std::string _b){ + TEST_VERBOSE("event b=" << _b); m_string = _b; } void callbackConstString(const std::string& _b){ + TEST_VERBOSE("event b=" << _b); m_string = _b; } void callbackIntString(int32_t _a, std::string _b){ + TEST_VERBOSE("event a=" << _a << " b=" << _b); m_int32 = _a; m_string = _b; } void callbackConstIntString(const int32_t& _a, const std::string& _b){ + TEST_VERBOSE("event a=" << _a << " b=" << _b); m_int32 = _a; m_string = _b; } void callbackMixedIntString(int32_t _a, const std::string& _b){ + TEST_VERBOSE("event a=" << _a << " b=" << _b); m_int32 = _a; m_string = _b; } void callbackPolyargs(const int32_t& _a, const std::string& _b, char _char, int _int) { + TEST_VERBOSE("event a=" << _a << " b=" << _b << " _char=" << _char << " _int=" << _int); m_int32 = _a + _int; m_string = _b + _char; } void callbackDisconnect(esignal::Connection* _connection) { + TEST_VERBOSE("Disconnect ..."); _connection->disconnect(); } }; +TEST(test_signal_class_func, localLog) { + esignal::Signal<> signal; + TEST_INFO("dtrem log : " << signal); +} + +TEST(test_signal_class_func, force_clear_all_connection) { + testCallback localClass; + esignal::Signal<> signal; + signal.clear(); + EXPECT_EQ(signal.size(), 0); + EXPECT_EQ(signal.empty(), true); + esignal::Connection connection1 = signal.connect(&localClass, &testCallback::callbackVoid); + EXPECT_EQ(signal.size(), 1); + EXPECT_EQ(signal.empty(), false); + signal.clear(); + EXPECT_EQ(signal.size(), 0); + EXPECT_EQ(signal.empty(), true); + connection1.disconnect(); + EXPECT_EQ(signal.size(), 0); + EXPECT_EQ(signal.empty(), true); + signal.emit(); + EXPECT_EQ(localClass.m_void, false); +} + +TEST(test_signal_class_func, localbasicNameDesc) { + esignal::Signal<> signal; + EXPECT_EQ(signal.getName(), ""); + EXPECT_EQ(signal.getDescription(), ""); +} + +TEST(test_signal_class_func, localNullClass) { + testCallback* localClass = nullptr; + esignal::Signal<> signal; + EXPECT_EQ(signal.size(), 0); + EXPECT_EQ(signal.empty(), true); + esignal::Connection connection1 = signal.connect(localClass, &testCallback::callbackVoid); + EXPECT_EQ(signal.size(), 0); + EXPECT_EQ(signal.empty(), true); + signal.emit(); +} + +/* +BAD case ... +TEST(test_signal_class_func, localNullFunc) { + testCallback localClass; + esignal::Signal<> signal; + EXPECT_EQ(signal.size(), 0); + EXPECT_EQ(signal.empty(), true); + esignal::Connection connection1 = signal.connect(&localClass, &testCallback::m_emptyFunctor); + EXPECT_EQ(signal.size(), 0); + EXPECT_EQ(signal.empty(), true); + signal.emit(); + EXPECT_EQ(localClass.m_void, false); +} +*/ + TEST(test_signal_class_func, localFunctionVoid) { testCallback localClass; esignal::Signal<> signal; diff --git a/test/test_signal_counter.cpp b/test/test_signal_counter.cpp new file mode 100644 index 0000000..47bacfa --- /dev/null +++ b/test/test_signal_counter.cpp @@ -0,0 +1,94 @@ +/** + * @author Edouard DUPIN + * + * @copyright 2016, Edouard DUPIN, all right reserved + * + * @license APACHE v2.0 (see license file) + */ + +#define NAME "SingleArg" +#include +#include +#include +#include +#include + + +#undef __class__ +#define __class__ "test_signal_counter" +class testCounter { + public: + esignal::Signal m_signal; + public: + size_t m_int32; + testCounter(): + m_signal(this, &testCounter::changeCount) { + m_int32 = 0; + } + void changeCount(size_t _a){ + TEST_VERBOSE("connection number : " << _a); + m_int32 = _a; + } +}; + +TEST(test_signal_counter, localbasicCounter) { + testCounter localClass; + EXPECT_EQ(localClass.m_signal.size(), 0); + EXPECT_EQ(localClass.m_signal.empty(), true); + EXPECT_EQ(localClass.m_int32, 0); + esignal::Connection connection1 = localClass.m_signal.connect([=](std::string){}); + EXPECT_EQ(localClass.m_signal.size(), 1); + EXPECT_EQ(localClass.m_signal.empty(), false); + EXPECT_EQ(localClass.m_int32, 1); + esignal::Connection connection2 = localClass.m_signal.connect([=](std::string){}); + EXPECT_EQ(localClass.m_signal.size(), 2); + EXPECT_EQ(localClass.m_signal.empty(), false); + EXPECT_EQ(localClass.m_int32, 2); + connection1.disconnect(); + EXPECT_EQ(localClass.m_signal.size(), 1); + EXPECT_EQ(localClass.m_signal.empty(), false); + EXPECT_EQ(localClass.m_int32, 1); + connection2.disconnect(); + EXPECT_EQ(localClass.m_signal.size(), 0); + EXPECT_EQ(localClass.m_signal.empty(), true); + EXPECT_EQ(localClass.m_int32, 0); +} + + +TEST(test_signal_counter, localbasicCopy) { + testCounter localClass; + EXPECT_EQ(localClass.m_signal.size(), 0); + EXPECT_EQ(localClass.m_signal.empty(), true); + EXPECT_EQ(localClass.m_int32, 0); + esignal::Connection connection1 = localClass.m_signal.connect([=](std::string){}); + EXPECT_EQ(localClass.m_signal.size(), 1); + EXPECT_EQ(localClass.m_signal.empty(), false); + EXPECT_EQ(localClass.m_int32, 1); + esignal::Connection connection2 = std::move(connection1); + EXPECT_EQ(localClass.m_signal.size(), 1); + EXPECT_EQ(localClass.m_signal.empty(), false); + EXPECT_EQ(localClass.m_int32, 1); + connection1.disconnect(); + EXPECT_EQ(localClass.m_signal.size(), 1); + EXPECT_EQ(localClass.m_signal.empty(), false); + EXPECT_EQ(localClass.m_int32, 1); + connection2.disconnect(); + EXPECT_EQ(localClass.m_signal.size(), 0); + EXPECT_EQ(localClass.m_signal.empty(), true); + EXPECT_EQ(localClass.m_int32, 0); +} + + +TEST(test_signal_counter, localbasicCheckConnection) { + testCounter localClass; + EXPECT_EQ(localClass.m_signal.size(), 0); + EXPECT_EQ(localClass.m_signal.empty(), true); + EXPECT_EQ(localClass.m_int32, 0); + esignal::Connection connection1 = localClass.m_signal.connect([=](std::string){}); + EXPECT_EQ(connection1.isConnected(), true); + connection1.disconnect(); + EXPECT_EQ(connection1.isConnected(), false); + EXPECT_EQ(localClass.m_signal.size(), 0); + EXPECT_EQ(localClass.m_signal.empty(), true); + EXPECT_EQ(localClass.m_int32, 0); +} diff --git a/test/test_signal_recursive.cpp b/test/test_signal_recursive.cpp index 9eb5357..26270fb 100644 --- a/test/test_signal_recursive.cpp +++ b/test/test_signal_recursive.cpp @@ -22,7 +22,9 @@ static int32_t tmpRetInt32 = 0; static auto callbackInt = [](int32_t _a){ tmpRetInt32 = _a; + TEST_VERBOSE("event a=" << _a); if (tmpRetInt32 != 0) { + TEST_VERBOSE("emit a=" << _a-1); signalll->emit(_a - 1); } }; diff --git a/test/test_signal_shared_ptr_func.cpp b/test/test_signal_shared_ptr_func.cpp index f47c9c9..c4cf0e9 100644 --- a/test/test_signal_shared_ptr_func.cpp +++ b/test/test_signal_shared_ptr_func.cpp @@ -22,6 +22,7 @@ class testCallbackShared : public std::enable_shared_from_this; + + using stupidFunctor = void(); + + stupidFunctor* m_emptyFunctor; + void callbackVoid() { + TEST_VERBOSE("event void"); m_void = true; } void callbackInt(int32_t _a) { + TEST_VERBOSE("event a=" << _a); m_int32 = _a; } void callbackConstInt(const int32_t& _a) { + TEST_VERBOSE("event a=" << _a); m_int32 = _a; } void callbackString(std::string _b) { + TEST_VERBOSE("event b=" << _b); m_string = _b; } void callbackConstString(const std::string& _b) { + TEST_VERBOSE("event b=" << _b); m_string = _b; } void callbackIntString(int32_t _a, std::string _b) { + TEST_VERBOSE("event a=" << _a << " b=" << _b); m_int32 = _a; m_string = _b; } void callbackConstIntString(const int32_t& _a, const std::string& _b) { + TEST_VERBOSE("event a=" << _a << " b=" << _b); m_int32 = _a; m_string = _b; } void callbackMixedIntString(int32_t _a, const std::string& _b) { + TEST_VERBOSE("event a=" << _a << " b=" << _b); m_int32 = _a; m_string = _b; } void callbackPolyargs(const int32_t& _a, const std::string& _b, char _char, int _int) { + TEST_VERBOSE("event a=" << _a << " b=" << _b << " _char=" << _char << " _int=" << _int); m_int32 = _a + _int; m_string = _b + _char; } @@ -66,6 +82,34 @@ class testCallbackShared : public std::enable_shared_from_this localClassA = std::make_shared(); + std::shared_ptr localClassB = std::make_shared(); + esignal::Signal<> signal(&removeObserver); + EXPECT_EQ(signal.size(), 0); + EXPECT_EQ(signal.empty(), true); + signal.connect(localClassA, &testCallbackShared::callbackVoid); + signal.connect(localClassB, &testCallbackShared::callbackVoid); + esignal::Connection ccc1 = signal.connect(&callbackVoid); + esignal::Connection ccc2 = signal.connect(&callbackVoid); + EXPECT_EQ(signal.size(), 4); + EXPECT_EQ(signal.empty(), false); + signal.emit(); + EXPECT_EQ(signal.size(), 4); + EXPECT_EQ(signal.empty(), false); + localClassB.reset(); + EXPECT_EQ(signal.size(), 4); + EXPECT_EQ(signal.empty(), false); + signal.emit(); + EXPECT_EQ(signal.size(), 3); + EXPECT_EQ(signal.empty(), false); + localClassB = std::make_shared(); + signal.connect(localClassB, &testCallbackShared::callbackVoid); + EXPECT_EQ(signal.size(), 4); + EXPECT_EQ(signal.empty(), false); + signal.emit(); + EXPECT_EQ(signal.size(), 4); + EXPECT_EQ(signal.empty(), false); + localClassA.reset(); + signal.disconnectShared(localClassB); + signal.disconnectShared(localClassA); + EXPECT_EQ(signal.size(), 2); + EXPECT_EQ(signal.empty(), false); + ccc1.disconnect(); + ccc2.disconnect(); + EXPECT_EQ(signal.size(), 0); + EXPECT_EQ(signal.empty(), true); + +} diff --git a/test/test_signal_static_func.cpp b/test/test_signal_static_func.cpp index 75677b9..257d3d1 100644 --- a/test/test_signal_static_func.cpp +++ b/test/test_signal_static_func.cpp @@ -28,41 +28,50 @@ static void clear() { } static void callbackVoid(){ + TEST_VERBOSE("event void"); tmpRetVoid = true; }; static void callbackInt(int32_t _a){ + TEST_VERBOSE("event a=" << _a); tmpRetInt32 = _a; }; static void callbackConstInt(const int32_t& _a){ + TEST_VERBOSE("event a=" << _a); tmpRetInt32 = _a; }; static void callbackString(std::string _b){ + TEST_VERBOSE("event b=" << _b); tmpRetString = _b; }; static void callbackConstString(const std::string& _b){ + TEST_VERBOSE("event b=" << _b); tmpRetString = _b; }; static void callbackIntString(int32_t _a, std::string _b){ + TEST_VERBOSE("event a=" << _a << " b=" << _b); tmpRetInt32 = _a; tmpRetString = _b; }; static void callbackConstIntString(const int32_t& _a, const std::string& _b){ + TEST_VERBOSE("event a=" << _a << " b=" << _b); tmpRetInt32 = _a; tmpRetString = _b; }; static void callbackMixedIntString(int32_t _a, const std::string& _b){ + TEST_VERBOSE("event a=" << _a << " b=" << _b); tmpRetInt32 = _a; tmpRetString = _b; }; static void callbackPolyargs(const int32_t& _a, const std::string& _b, char _char, int _int) { + TEST_VERBOSE("event a=" << _a << " b=" << _b << " _char=" << _char << " _int=" << _int); tmpRetInt32 = _a + _int; tmpRetString = _b + _char; }