diff --git a/arcane/src/arcane/tests/UtilsUnitTest.cc b/arcane/src/arcane/tests/UtilsUnitTest.cc index 42abcfdb8..2ce4c252f 100644 --- a/arcane/src/arcane/tests/UtilsUnitTest.cc +++ b/arcane/src/arcane/tests/UtilsUnitTest.cc @@ -1,11 +1,11 @@ // -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- //----------------------------------------------------------------------------- -// Copyright 2000-2024 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) // See the top-level COPYRIGHT file for details. // SPDX-License-Identifier: Apache-2.0 //----------------------------------------------------------------------------- /*---------------------------------------------------------------------------*/ -/* UtilsUnitTest.cc (C) 2000-2024 */ +/* UtilsUnitTest.cc (C) 2000-2025 */ /* */ /* Test des fonctions utilitaires de Arcane. */ /*---------------------------------------------------------------------------*/ @@ -16,7 +16,6 @@ #include "arcane/utils/ArgumentException.h" #include "arcane/utils/AutoDestroyUserData.h" #include "arcane/utils/HPReal.h" -#include "arcane/utils/IFunctorWithArgument.h" #include "arcane/utils/IMemoryInfo.h" #include "arcane/utils/ITraceMng.h" #include "arcane/utils/PlatformUtils.h" @@ -33,19 +32,11 @@ #include "arcane/core/FactoryService.h" #include "arcane/core/ServiceBuilder.h" -#include "arcane/tests/ArcaneTestGlobal.h" - #include /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ -namespace Arcane -{ -extern "C++" ARCANE_UTILS_EXPORT void -_internalTestEvent(); -} - namespace ArcaneTest { @@ -119,7 +110,6 @@ class UtilsUnitTest void _testStackTrace(); void _testSetClassConfig(); void _testFloatingException(); - void _testEvents(); void _testConvertFromString(); void _testConvertFromStringToInt32Array(); void _testCommandLine(); @@ -164,7 +154,6 @@ executeTest() _testUserData(); _testHPReal(); _testTruncateReal(); - _testEvents(); info() << Trace::Color::darkRed() << "[TEST_COLOR] DARK_RED"; info() << Trace::Color::darkGreen() << "[TEST_COLOR] DARK_GREEN"; @@ -760,16 +749,6 @@ _printMemoryInfos() /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ -void UtilsUnitTest:: -_testEvents() -{ - info() << "INTERNAL TEST EVENT"; - _internalTestEvent(); -} - -/*---------------------------------------------------------------------------*/ -/*---------------------------------------------------------------------------*/ - void UtilsUnitTest:: _testConvertFromString() { diff --git a/arcane/src/arcane/utils/Event.cc b/arcane/src/arcane/utils/Event.cc index 1baf3dd27..ce368bee5 100644 --- a/arcane/src/arcane/utils/Event.cc +++ b/arcane/src/arcane/utils/Event.cc @@ -1,11 +1,11 @@ // -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- //----------------------------------------------------------------------------- -// Copyright 2000-2023 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) // See the top-level COPYRIGHT file for details. // SPDX-License-Identifier: Apache-2.0 //----------------------------------------------------------------------------- /*---------------------------------------------------------------------------*/ -/* Event.cc (C) 2000-2023 */ +/* Event.cc (C) 2000-2025 */ /* */ /* Gestionnaires d'évènements. */ /*---------------------------------------------------------------------------*/ @@ -37,19 +37,13 @@ namespace Arcane class EventObservableBase::Impl { public: - Impl(){} - public: - void rebuildOberversArray() - { - m_observers_array.clear(); - m_observers_array.reserve(arcaneCheckArraySize(m_observers.size())); - for( auto o : m_observers ) - m_observers_array.add(o); - } + + Impl() {} + public: + std::set m_auto_destroy_observers; std::set m_observers; - UniqueArray m_observers_array; }; /*---------------------------------------------------------------------------*/ @@ -80,14 +74,26 @@ EventObservableBase:: /*---------------------------------------------------------------------------*/ void EventObservableBase:: -_attachObserver(EventObserverBase* obs,bool is_auto_destroy) +_rebuildObserversArray() +{ + m_observers_array.clear(); + m_observers_array.reserve(m_p->m_observers.size()); + for (auto o : m_p->m_observers) + m_observers_array.add(o); +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +void EventObservableBase:: +_attachObserver(EventObserverBase* obs, bool is_auto_destroy) { // Vérifie que l'observeur n'est pas dans la liste. - if (m_p->m_observers.find(obs)!=m_p->m_observers.end()) + if (m_p->m_observers.find(obs) != m_p->m_observers.end()) ARCANE_FATAL("Observer is already attached to this observable"); obs->_notifyAttach(this); m_p->m_observers.insert(obs); - m_p->rebuildOberversArray(); + _rebuildObserversArray(); if (is_auto_destroy) m_p->m_auto_destroy_observers.insert(obs); } @@ -102,8 +108,8 @@ _detachObserver(EventObserverBase* obs) // dynamiquement. Il n'y a donc pas besoin de mettre à jour // m_p->m_auto_destroy_observers. bool is_ok = false; - for( auto o : m_p->m_observers ) - if (o==obs){ + for (auto o : m_p->m_observers) + if (o == obs) { m_p->m_observers.erase(o); is_ok = true; break; @@ -113,16 +119,7 @@ _detachObserver(EventObserverBase* obs) if (!is_ok) ARCANE_FATAL("observer is not registered to this observable"); obs->_notifyDetach(); - m_p->rebuildOberversArray(); -} - -/*---------------------------------------------------------------------------*/ -/*---------------------------------------------------------------------------*/ - -ConstArrayView EventObservableBase:: -_observers() const -{ - return m_p->m_observers_array; + _rebuildObserversArray(); } /*---------------------------------------------------------------------------*/ @@ -138,16 +135,6 @@ detachAllObservers() delete o; } -/*---------------------------------------------------------------------------*/ -/*---------------------------------------------------------------------------*/ - -bool EventObservableBase:: -hasObservers() const -{ - return (m_p->m_observers.size()!=0); -} - - /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ @@ -218,79 +205,6 @@ add(EventObserverBase* obs) /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ -/*---------------------------------------------------------------------------*/ -/*---------------------------------------------------------------------------*/ - -namespace -{ -class TestMemberCall -{ - public: - void my_func(int a,int b) - { - std::cout << "THIS_IS_MY FUNC XA=" << a << " B=" << b << '\n'; - } - void operator()(int a,int b) - { - std::cout << "THIS_IS OPERATOR() FUNC XA=" << a << " B=" << b << '\n'; - } -}; -} -extern "C++" ARCANE_UTILS_EXPORT void - _internalTestEvent() -{ - using std::placeholders::_1; - using std::placeholders::_2; - - int f = 3; - auto func = [&](int a,int b){ - std::cout << "XA=" << a << " B=" << b << " f=" << f << '\n'; - f = a+b; - }; - auto func2 = [&](int a,int b){ - std::cout << "FUNC2: XA=" << a << " B=" << b << " f=" << f << '\n'; - }; - TestMemberCall tmc; - EventObserver x2(func); - { - EventObservable xevent; - EventObserverPool pool; - { - EventObserver xobserver; - // NOTE: le test suivnant ne marche pas avec MSVS2013 - //std::function kk1(&TestMemberCall::my_func); - std::function kk( std::bind( &TestMemberCall::my_func, tmc, _1, _2 ) ); - //std::function kk2( std::bind( &TestMemberCall::my_func, tmc ) ); - //auto kk( std::bind( &TestMemberCall::my_func, &tmc ) ); - EventObserver x4(kk); - EventObserver x3(tmc); - xevent.attach(&x2); - xevent.attach(&x3); - xevent.attach(&x4); - xevent.attach(&xobserver); - xevent.notify(2,3); - xevent.detach(&x4); - } - xevent.attach(pool,func2); - } - std::cout << "(After) F=" << f << '\n'; - if (f!=5) - ARCANE_FATAL("Bad value for f"); - { - EventObserver* eo1 = nullptr; - EventObservable xevent; - { - eo1 = new EventObserver( std::bind( &TestMemberCall::my_func, tmc, _1, _2 ) ); - xevent.attach(eo1); - } - xevent.notify(2,4); - delete eo1; - } -} - -/*---------------------------------------------------------------------------*/ -/*---------------------------------------------------------------------------*/ - } // End namespace Arcane /*---------------------------------------------------------------------------*/ diff --git a/arcane/src/arcane/utils/Event.h b/arcane/src/arcane/utils/Event.h index 641e49b3d..3faf3763d 100644 --- a/arcane/src/arcane/utils/Event.h +++ b/arcane/src/arcane/utils/Event.h @@ -1,11 +1,11 @@ // -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- //----------------------------------------------------------------------------- -// Copyright 2000-2023 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) // See the top-level COPYRIGHT file for details. // SPDX-License-Identifier: Apache-2.0 //----------------------------------------------------------------------------- /*---------------------------------------------------------------------------*/ -/* Event.h (C) 2000-2023 */ +/* Event.h (C) 2000-2025 */ /* */ /* Gestionnaires d'évènements. */ /*---------------------------------------------------------------------------*/ @@ -40,18 +40,41 @@ class ARCANE_UTILS_EXPORT EventObservableBase { friend class EventObserverBase; class Impl; + public: + EventObservableBase(); virtual ~EventObservableBase(); + public: - bool hasObservers() const; + + EventObservableBase(const EventObservableBase&) = delete; + EventObservableBase(EventObservableBase&&) = delete; + EventObservableBase& operator=(const EventObservableBase&) = delete; + EventObservableBase& operator=(EventObservableBase&&) = delete; + + public: + + bool hasObservers() const { return !m_observers_array.empty(); } void detachAllObservers(); + protected: - void _attachObserver(EventObserverBase* obs,bool is_auto_destroy); + + void _attachObserver(EventObserverBase* obs, bool is_auto_destroy); void _detachObserver(EventObserverBase* obs); - ConstArrayView _observers() const; + ConstArrayView _observers() const + { + return m_observers_array; + } + private: - Impl* m_p; + + Impl* m_p = nullptr; + UniqueArray m_observers_array; + + private: + + void _rebuildObserversArray(); }; /*---------------------------------------------------------------------------*/ @@ -66,14 +89,20 @@ class ARCANE_UTILS_EXPORT EventObservableBase class ARCANE_UTILS_EXPORT EventObserverBase { friend class EventObservableBase; + public: - EventObserverBase() : m_observable(nullptr) {} + + EventObserverBase() = default; virtual ~EventObserverBase() ARCANE_NOEXCEPT_FALSE; + protected: + void _notifyDetach(); void _notifyAttach(EventObservableBase* obs); + private: - EventObservableBase* m_observable; + + EventObservableBase* m_observable = nullptr; }; /*---------------------------------------------------------------------------*/ @@ -82,24 +111,31 @@ class ARCANE_UTILS_EXPORT EventObserverBase * \ingroup Utils * \brief Observateur d'évènements. */ -template +template class EventObserver : public EventObserverBase { public: + typedef EventObservable ObservableType; + public: + EventObserver() {} EventObserver(const std::function& func) - : m_functor(func){} + : m_functor(func) + {} EventObserver(std::function&& func) - : m_functor(func){} + : m_functor(func) + {} void observerUpdate(Args... args) { if (m_functor) m_functor(args...); } + private: + std::function m_functor; }; @@ -111,13 +147,18 @@ class EventObserver class ARCANE_UTILS_EXPORT EventObserverPool { public: + ~EventObserverPool(); + public: + //! Ajoute l'observateur \a x void add(EventObserverBase* x); //! Supprime tous les observateurs associés à cette instance. void clear(); + private: + UniqueArray m_observers; }; @@ -151,7 +192,7 @@ class ARCANE_UTILS_EXPORT EventObserverPool \endcode * */ -template +template class EventObservable : public EventObservableBase { @@ -161,12 +202,7 @@ class EventObservable public: - EventObservable() {} - - public: - - EventObservable(const EventObservable& rhs) = delete; - void operator=(const EventObservable& rhs) = delete; + EventObservable() = default; public: @@ -175,7 +211,7 @@ class EventObservable * * Une exception est levée si l'observateur est déjà attaché à un observable. */ - void attach(ObserverType* o) { _attachObserver(o,false); } + void attach(ObserverType* o) { _attachObserver(o, false); } /*! * \brief Détache l'observateur \a o de cet observable. * @@ -187,11 +223,11 @@ class EventObservable * \brief Ajoute un observateur utilisant la lambda \a lambda * et conserve une référence dans \a pool. */ - template - void attach(EventObserverPool& pool,const Lambda& lambda) + template + void attach(EventObserverPool& pool, const Lambda& lambda) { auto x = new ObserverType(lambda); - _attachObserver(x,false); + _attachObserver(x, false); pool.add(x); } @@ -200,7 +236,7 @@ class EventObservable { if (!hasObservers()) return; - for( auto o : _observers() ) + for (auto o : _observers()) ((ObserverType*)o)->observerUpdate(args...); } }; @@ -208,7 +244,7 @@ class EventObservable /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ -} +} // namespace Arcane /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ diff --git a/arcane/src/arcane/utils/tests/CMakeLists.txt b/arcane/src/arcane/utils/tests/CMakeLists.txt index a8afa09fe..f72cd05d9 100644 --- a/arcane/src/arcane/utils/tests/CMakeLists.txt +++ b/arcane/src/arcane/utils/tests/CMakeLists.txt @@ -1,6 +1,7 @@ set(SOURCE_FILES TestAutoRef.cc TestDependencyInjection.cc + TestEvent.cc TestRealN.cc TestNumVector.cc TestValueConvert.cc diff --git a/arcane/src/arcane/utils/tests/TestEvent.cc b/arcane/src/arcane/utils/tests/TestEvent.cc new file mode 100644 index 000000000..99e8a523b --- /dev/null +++ b/arcane/src/arcane/utils/tests/TestEvent.cc @@ -0,0 +1,89 @@ +// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- +//----------------------------------------------------------------------------- +// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// See the top-level COPYRIGHT file for details. +// SPDX-License-Identifier: Apache-2.0 +//----------------------------------------------------------------------------- + +#include + +#include "arcane/utils/Event.h" +#include "arcane/utils/FatalErrorException.h" + +#include + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +using namespace Arcane; + + +namespace +{ +class TestMemberCall +{ + public: + void my_func(int a,int b) + { + std::cout << "THIS_IS_MY FUNC XA=" << a << " B=" << b << '\n'; + } + void operator()(int a,int b) + { + std::cout << "THIS_IS OPERATOR() FUNC XA=" << a << " B=" << b << '\n'; + } +}; +} +TEST(TestEvent, Misc) +{ + using std::placeholders::_1; + using std::placeholders::_2; + + int f = 3; + auto func = [&](int a, int b) { + std::cout << "XA=" << a << " B=" << b << " f=" << f << '\n'; + f = a + b; + }; + auto func2 = [&](int a, int b) { + std::cout << "FUNC2: XA=" << a << " B=" << b << " f=" << f << '\n'; + }; + TestMemberCall tmc; + EventObserver x2(func); + { + EventObservable xevent; + EventObserverPool pool; + { + EventObserver xobserver; + // NOTE: le test suivnant ne marche pas avec MSVS2013 + std::function kk1(&TestMemberCall::my_func); + std::function kk(std::bind(&TestMemberCall::my_func, tmc, _1, _2)); + //std::function kk2( std::bind( &TestMemberCall::my_func, tmc ) ); + //auto kk( std::bind( &TestMemberCall::my_func, &tmc ) ); + EventObserver x4(kk); + EventObserver x3(tmc); + xevent.attach(&x2); + xevent.attach(&x3); + xevent.attach(&x4); + xevent.attach(&xobserver); + xevent.notify(2, 3); + xevent.detach(&x4); + } + xevent.attach(pool, func2); + } + std::cout << "(After) F=" << f << '\n'; + + ASSERT_EQ(f, 5); + + { + EventObserver* eo1 = nullptr; + EventObservable xevent; + { + eo1 = new EventObserver(std::bind(&TestMemberCall::my_func, tmc, _1, _2)); + xevent.attach(eo1); + } + xevent.notify(2, 4); + delete eo1; + } +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/