diff --git a/Modules/Core/include/mitkITKEventObserverGuard.h b/Modules/Core/include/mitkITKEventObserverGuard.h index df3c495c08..fb8903f116 100644 --- a/Modules/Core/include/mitkITKEventObserverGuard.h +++ b/Modules/Core/include/mitkITKEventObserverGuard.h @@ -1,93 +1,93 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkITKEventObserverGuard_h #define mitkITKEventObserverGuard_h #include - +#include #include "MitkCoreExports.h" namespace itk { class Object; class Command; class EventObject; } namespace mitk { /** \brief Convenience class that helps to manage the lifetime of itk event observers. This helper class can be used to ensure itk event observers are removed form a sender object at the end of a certain scope. - This class behaves simelar to a std::unique_ptr but for event observers. - Therfore the observer will be removed from the sender when one of the following + This class behaves similar to a std::unique_ptr but for event observers. + Therefore the observer will be removed from the sender when one of the following conditions are met: - the guard is destroyed - - the guard is resetted (by Reset() or operator = ) + - the guard is reseted (by Reset() or operator = ) Sample usage: \code { auto &objRef = *o.GetPointer(); auto guard = ITKEventObserverGuard(o, itk::AnyEvent(), [&objRef](const itk::EventObject &event) { std::cout << "Object: " << objRef.GetNameOfClass() << " Event: " << event << std::endl; }); //some code } //now the guard is destroyed \endcode This will add an Observer to o executing the lambda for any event as long as the guard exists. @remark If the sender is already destroyed at the moment, when the guard wants to remove the observer, the removal will be skipped. */ class MITKCORE_EXPORT ITKEventObserverGuard { public: ITKEventObserverGuard(); ITKEventObserverGuard(const itk::Object* sender, unsigned long observerTag); ITKEventObserverGuard(const itk::Object* sender, const itk::EventObject& event, itk::Command* command); ITKEventObserverGuard(const itk::Object* sender, const itk::EventObject& event, std::function function); - ITKEventObserverGuard(ITKEventObserverGuard&); - ITKEventObserverGuard& operator=(ITKEventObserverGuard&); + ITKEventObserverGuard(ITKEventObserverGuard&&); + ITKEventObserverGuard& operator=(ITKEventObserverGuard&&); ~ITKEventObserverGuard(); /** Resets the guard by removing the currently guarded observer. After the reset the guard is uninitialized. *@remark resetting an uninitialized guard has no effect.*/ void Reset(); /** Resets the guard by first removing the currently guarded observer. Then the passed observer tag for the * passed sender will be guarded.*/ void Reset(const itk::Object* sender, unsigned long observerTag); /** Resets the guard by first removing the currently guarded observer. Then a observer will be added for * the passed sender with the passed event and command. The new observer is now guarded.*/ void Reset(const itk::Object* sender, const itk::EventObject& event, itk::Command* command); /** Resets the guard by first removing the currently guarded observer. Then a observer will be added for - * the passed sender with the passed event and lamba function. The new observer is now guarded.*/ + * the passed sender with the passed event and lambda function. The new observer is now guarded.*/ void Reset(const itk::Object* sender, const itk::EventObject& event, std::function function); bool IsInitialized() const; private: struct Impl; - Impl *m_ITKEventObserverGuardImpl; + std::unique_ptr m_ITKEventObserverGuardImpl; }; } #endif diff --git a/Modules/Core/src/DataManagement/mitkITKEventObserverGuard.cpp b/Modules/Core/src/DataManagement/mitkITKEventObserverGuard.cpp index d227f1ad59..01afcff13a 100644 --- a/Modules/Core/src/DataManagement/mitkITKEventObserverGuard.cpp +++ b/Modules/Core/src/DataManagement/mitkITKEventObserverGuard.cpp @@ -1,112 +1,107 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkITKEventObserverGuard.h" #include #include #include namespace mitk { struct ITKEventObserverGuard::Impl { explicit Impl(const itk::Object* sender, unsigned long observerTag); ~Impl(); private: mitk::WeakPointer m_Sender; unsigned long m_ObserverTag; }; ITKEventObserverGuard::Impl::Impl(const itk::Object* sender, unsigned long observerTag) : m_Sender(const_cast(sender)), m_ObserverTag(observerTag) { //we cast const sender to non const in order to be able to remove observers but //also support constness in code that uses the guard. } ITKEventObserverGuard::Impl::~Impl() { auto sender = m_Sender.Lock(); if (sender.IsNotNull()) { sender->RemoveObserver(m_ObserverTag); } } ITKEventObserverGuard::ITKEventObserverGuard() : m_ITKEventObserverGuardImpl(nullptr) {} ITKEventObserverGuard::ITKEventObserverGuard(const itk::Object* sender, unsigned long observerTag) : m_ITKEventObserverGuardImpl(new Impl(sender, observerTag)) {} ITKEventObserverGuard::ITKEventObserverGuard(const itk::Object* sender, const itk::EventObject& event, itk::Command* command) { auto tag = sender->AddObserver(event, command); - m_ITKEventObserverGuardImpl = new Impl(sender, tag); + m_ITKEventObserverGuardImpl = std::make_unique(sender, tag); } ITKEventObserverGuard::ITKEventObserverGuard(const itk::Object* sender, const itk::EventObject& event, std::function function) { auto tag = sender->AddObserver(event, function); - m_ITKEventObserverGuardImpl = new Impl(sender, tag); + m_ITKEventObserverGuardImpl = std::make_unique(sender, tag); } - ITKEventObserverGuard::ITKEventObserverGuard(ITKEventObserverGuard& g) + ITKEventObserverGuard::ITKEventObserverGuard(ITKEventObserverGuard&& other): m_ITKEventObserverGuardImpl(std::move(other.m_ITKEventObserverGuardImpl)) { - m_ITKEventObserverGuardImpl = nullptr; - - std::swap(m_ITKEventObserverGuardImpl, g.m_ITKEventObserverGuardImpl); } - ITKEventObserverGuard& ITKEventObserverGuard::operator=(ITKEventObserverGuard& g) + ITKEventObserverGuard::~ITKEventObserverGuard() { } + + ITKEventObserverGuard& ITKEventObserverGuard::operator=(ITKEventObserverGuard&& other) { - this->Reset(); + if (&other != this) + { + m_ITKEventObserverGuardImpl = std::move(other.m_ITKEventObserverGuardImpl); + } - std::swap(m_ITKEventObserverGuardImpl, g.m_ITKEventObserverGuardImpl); return *this; } - ITKEventObserverGuard::~ITKEventObserverGuard() { delete m_ITKEventObserverGuardImpl; } - void ITKEventObserverGuard::Reset() { - delete m_ITKEventObserverGuardImpl; - m_ITKEventObserverGuardImpl = nullptr; + m_ITKEventObserverGuardImpl.reset(); } void ITKEventObserverGuard::Reset(const itk::Object* sender, unsigned long observerTag) { - delete m_ITKEventObserverGuardImpl; - m_ITKEventObserverGuardImpl = new Impl(sender, observerTag); + m_ITKEventObserverGuardImpl.reset(new Impl(sender, observerTag)); } void ITKEventObserverGuard::Reset(const itk::Object* sender, const itk::EventObject& event, itk::Command* command) { - delete m_ITKEventObserverGuardImpl; auto tag = sender->AddObserver(event, command); - m_ITKEventObserverGuardImpl = new Impl(sender, tag); + m_ITKEventObserverGuardImpl.reset(new Impl(sender, tag)); } void ITKEventObserverGuard::Reset(const itk::Object* sender, const itk::EventObject& event, std::function function) { - delete m_ITKEventObserverGuardImpl; auto tag = sender->AddObserver(event, function); - m_ITKEventObserverGuardImpl = new Impl(sender, tag); + m_ITKEventObserverGuardImpl.reset(new Impl(sender, tag)); } bool ITKEventObserverGuard::IsInitialized() const { return nullptr != this->m_ITKEventObserverGuardImpl; } } diff --git a/Modules/Core/test/mitkITKEventObserverGuardTest.cpp b/Modules/Core/test/mitkITKEventObserverGuardTest.cpp index 7634bfaccf..a46aad6a75 100644 --- a/Modules/Core/test/mitkITKEventObserverGuardTest.cpp +++ b/Modules/Core/test/mitkITKEventObserverGuardTest.cpp @@ -1,258 +1,258 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkITKEventObserverGuard.h" #include #include #include #include // Create a command to observe events class DummyCommand : public itk::Command { public: using Self = DummyCommand; using Superclass = itk::Command; using Pointer = itk::SmartPointer; using ConstPointer = itk::SmartPointer; itkNewMacro(DummyCommand); void Execute(itk::Object*, const itk::EventObject&) override { ++ExecutionCount; } void Execute(const itk::Object*, const itk::EventObject&) override { ++ExecutionCount; } int ExecutionCount; protected: DummyCommand() : ExecutionCount(0) {} }; class mitkITKEventObserverGuardTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkITKEventObserverGuardTestSuite); MITK_TEST(TestConstructor); MITK_TEST(TestConstructor2); MITK_TEST(TestConstructor3); MITK_TEST(TestConstructor4); MITK_TEST(TestReset); MITK_TEST(TestReset2); MITK_TEST(TestOperateAssign); CPPUNIT_TEST_SUITE_END(); itk::Object::Pointer m_TestObject; DummyCommand::Pointer m_DummyCommand; DummyCommand::Pointer m_DummyCommand2; public: void setUp() override { m_TestObject = itk::Object::New(); m_DummyCommand = DummyCommand::New(); m_DummyCommand2 = DummyCommand::New(); } void tearDown() override { m_TestObject = nullptr; m_DummyCommand = nullptr; m_DummyCommand2 = nullptr; } // This test is supposed to verify inheritance behaviour, this test will fail if the behaviour changes in the future void TestConstructor() { mitk::ITKEventObserverGuard guard; CPPUNIT_ASSERT(!guard.IsInitialized()); } void TestConstructor2() { m_TestObject->InvokeEvent(itk::ModifiedEvent()); CPPUNIT_ASSERT_EQUAL(0, m_DummyCommand->ExecutionCount); { auto tag = m_TestObject->AddObserver(itk::ModifiedEvent(), m_DummyCommand); mitk::ITKEventObserverGuard guard(m_TestObject, tag); CPPUNIT_ASSERT(guard.IsInitialized()); m_TestObject->InvokeEvent(itk::ModifiedEvent()); CPPUNIT_ASSERT_EQUAL(1, m_DummyCommand->ExecutionCount); m_TestObject->InvokeEvent(itk::ProgressEvent()); CPPUNIT_ASSERT_EQUAL(1, m_DummyCommand->ExecutionCount); } m_TestObject->InvokeEvent(itk::ModifiedEvent()); CPPUNIT_ASSERT_EQUAL(1, m_DummyCommand->ExecutionCount); } void TestConstructor3() { m_TestObject->InvokeEvent(itk::ModifiedEvent()); CPPUNIT_ASSERT_EQUAL(0, m_DummyCommand->ExecutionCount); { mitk::ITKEventObserverGuard guard(m_TestObject, itk::ModifiedEvent(), m_DummyCommand); CPPUNIT_ASSERT(guard.IsInitialized()); m_TestObject->InvokeEvent(itk::ModifiedEvent()); CPPUNIT_ASSERT_EQUAL(1, m_DummyCommand->ExecutionCount); m_TestObject->InvokeEvent(itk::ProgressEvent()); CPPUNIT_ASSERT_EQUAL(1, m_DummyCommand->ExecutionCount); } m_TestObject->InvokeEvent(itk::ModifiedEvent()); CPPUNIT_ASSERT_EQUAL(1, m_DummyCommand->ExecutionCount); } void TestConstructor4() { m_TestObject->InvokeEvent(itk::ModifiedEvent()); CPPUNIT_ASSERT_EQUAL(0, m_DummyCommand->ExecutionCount); { mitk::ITKEventObserverGuard guard(m_TestObject, itk::ModifiedEvent(), [this](const itk::EventObject&) {++(this->m_DummyCommand->ExecutionCount); }); CPPUNIT_ASSERT(guard.IsInitialized()); m_TestObject->InvokeEvent(itk::ModifiedEvent()); CPPUNIT_ASSERT_EQUAL(1, m_DummyCommand->ExecutionCount); m_TestObject->InvokeEvent(itk::ProgressEvent()); CPPUNIT_ASSERT_EQUAL(1, m_DummyCommand->ExecutionCount); } m_TestObject->InvokeEvent(itk::ModifiedEvent()); CPPUNIT_ASSERT_EQUAL(1, m_DummyCommand->ExecutionCount); } void TestReset() { m_TestObject->InvokeEvent(itk::ModifiedEvent()); CPPUNIT_ASSERT_EQUAL(0, m_DummyCommand->ExecutionCount); mitk::ITKEventObserverGuard guard(m_TestObject, itk::ModifiedEvent(), m_DummyCommand); CPPUNIT_ASSERT(guard.IsInitialized()); m_TestObject->InvokeEvent(itk::ModifiedEvent()); CPPUNIT_ASSERT_EQUAL(1, m_DummyCommand->ExecutionCount); guard.Reset(); CPPUNIT_ASSERT(!guard.IsInitialized()); m_TestObject->InvokeEvent(itk::ModifiedEvent()); CPPUNIT_ASSERT_EQUAL(1, m_DummyCommand->ExecutionCount); guard.Reset(); CPPUNIT_ASSERT(!guard.IsInitialized()); } void TestReset2() { m_TestObject->InvokeEvent(itk::ModifiedEvent()); CPPUNIT_ASSERT_EQUAL(0, m_DummyCommand->ExecutionCount); mitk::ITKEventObserverGuard guard(m_TestObject, itk::ModifiedEvent(), m_DummyCommand); CPPUNIT_ASSERT(guard.IsInitialized()); m_TestObject->InvokeEvent(itk::ModifiedEvent()); CPPUNIT_ASSERT_EQUAL(1, m_DummyCommand->ExecutionCount); auto tag = m_TestObject->AddObserver(itk::ProgressEvent(), m_DummyCommand2); guard.Reset(m_TestObject, tag); CPPUNIT_ASSERT(guard.IsInitialized()); m_TestObject->InvokeEvent(itk::ModifiedEvent()); CPPUNIT_ASSERT_EQUAL(1, m_DummyCommand->ExecutionCount); m_TestObject->InvokeEvent(itk::ProgressEvent()); CPPUNIT_ASSERT_EQUAL(1, m_DummyCommand2->ExecutionCount); } void TestReset3() { m_TestObject->InvokeEvent(itk::ModifiedEvent()); CPPUNIT_ASSERT_EQUAL(0, m_DummyCommand->ExecutionCount); mitk::ITKEventObserverGuard guard(m_TestObject, itk::ModifiedEvent(), m_DummyCommand); CPPUNIT_ASSERT(guard.IsInitialized()); m_TestObject->InvokeEvent(itk::ModifiedEvent()); CPPUNIT_ASSERT_EQUAL(1, m_DummyCommand->ExecutionCount); guard.Reset(m_TestObject, itk::ProgressEvent(), m_DummyCommand2); CPPUNIT_ASSERT(guard.IsInitialized()); m_TestObject->InvokeEvent(itk::ModifiedEvent()); CPPUNIT_ASSERT_EQUAL(1, m_DummyCommand->ExecutionCount); m_TestObject->InvokeEvent(itk::ProgressEvent()); CPPUNIT_ASSERT_EQUAL(1, m_DummyCommand2->ExecutionCount); } void TestReset4() { m_TestObject->InvokeEvent(itk::ModifiedEvent()); CPPUNIT_ASSERT_EQUAL(0, m_DummyCommand->ExecutionCount); mitk::ITKEventObserverGuard guard(m_TestObject, itk::ModifiedEvent(), m_DummyCommand); CPPUNIT_ASSERT(guard.IsInitialized()); m_TestObject->InvokeEvent(itk::ModifiedEvent()); CPPUNIT_ASSERT_EQUAL(1, m_DummyCommand->ExecutionCount); guard.Reset(m_TestObject, itk::ProgressEvent(), [this](const itk::EventObject&) {++(this->m_DummyCommand2->ExecutionCount); }); CPPUNIT_ASSERT(guard.IsInitialized()); m_TestObject->InvokeEvent(itk::ModifiedEvent()); CPPUNIT_ASSERT_EQUAL(1, m_DummyCommand->ExecutionCount); m_TestObject->InvokeEvent(itk::ProgressEvent()); CPPUNIT_ASSERT_EQUAL(1, m_DummyCommand2->ExecutionCount); } void TestOperateAssign() { m_TestObject->InvokeEvent(itk::ModifiedEvent()); CPPUNIT_ASSERT_EQUAL(0, m_DummyCommand->ExecutionCount); mitk::ITKEventObserverGuard guard(m_TestObject, itk::ModifiedEvent(), m_DummyCommand); CPPUNIT_ASSERT(guard.IsInitialized()); m_TestObject->InvokeEvent(itk::ModifiedEvent()); CPPUNIT_ASSERT_EQUAL(1, m_DummyCommand->ExecutionCount); auto guard2 = mitk::ITKEventObserverGuard(m_TestObject, itk::ProgressEvent(), [this](const itk::EventObject&) {++(this->m_DummyCommand2->ExecutionCount); }); CPPUNIT_ASSERT(guard.IsInitialized()); CPPUNIT_ASSERT(guard2.IsInitialized()); m_TestObject->InvokeEvent(itk::ProgressEvent()); CPPUNIT_ASSERT_EQUAL(1, m_DummyCommand2->ExecutionCount); - guard = guard2; + guard = std::move(guard2); CPPUNIT_ASSERT(guard.IsInitialized()); CPPUNIT_ASSERT(!guard2.IsInitialized()); m_TestObject->InvokeEvent(itk::ModifiedEvent()); CPPUNIT_ASSERT_EQUAL(1, m_DummyCommand->ExecutionCount); m_TestObject->InvokeEvent(itk::ProgressEvent()); CPPUNIT_ASSERT_EQUAL(2, m_DummyCommand2->ExecutionCount); } }; MITK_TEST_SUITE_REGISTRATION(mitkITKEventObserverGuard)