From 0e2e389681efd113b3cc334c05b4f6f7d1c8d372 Mon Sep 17 00:00:00 2001 From: Simon Praetorius Date: Sun, 3 Nov 2019 21:31:24 +0100 Subject: [PATCH 1/7] Observer rewritten using modern runtime polymorphism --- src/amdis/AdaptiveGrid.hpp | 2 +- src/amdis/DOFVector.hpp | 15 +- src/amdis/Observer.hpp | 274 +++++++------------- src/amdis/functions/ParallelGlobalBasis.hpp | 12 +- 4 files changed, 103 insertions(+), 200 deletions(-) diff --git a/src/amdis/AdaptiveGrid.hpp b/src/amdis/AdaptiveGrid.hpp index a40fcf91..18bfdad2 100644 --- a/src/amdis/AdaptiveGrid.hpp +++ b/src/amdis/AdaptiveGrid.hpp @@ -65,7 +65,7 @@ namespace AMDiS class AdaptiveGrid : public Dune::GridDefaultImplementation< HG::dimension, HG::dimensionworld, typename HG::ctype, AdaptiveGridFamily > - , public Signals + , public Notifier { using Self = AdaptiveGrid; diff --git a/src/amdis/DOFVector.hpp b/src/amdis/DOFVector.hpp index 02c80990..c0dc5373 100644 --- a/src/amdis/DOFVector.hpp +++ b/src/amdis/DOFVector.hpp @@ -43,11 +43,12 @@ namespace AMDiS template class DOFVector : public VectorBase>> - , public Observer, event::postAdapt> + , private Observer + , private Observer> + , private Observer { using Self = DOFVector; using Super = VectorBase>>; - using Obs = Observer, event::postAdapt>; public: using Backend = VectorBackend>; @@ -68,7 +69,9 @@ namespace AMDiS DOFVector(std::shared_ptr const& basis, DataTransferOperation op = DataTransferOperation::INTERPOLATE) : Super(basis) - , Obs(basis) + , Observer(this, basis->gridView().grid()) + , Observer>(this, *basis) + , Observer(this, basis->gridView().grid()) , dataTransfer_(op, basis) , basis_(basis) {} @@ -167,14 +170,14 @@ namespace AMDiS /// Override of Observer update(event::preAdapt) method. Redirects to preAdapt method of the /// \ref DataTransfer object. - void update(event::preAdapt const& e) override + void updateImpl(event::preAdapt const& e) { dataTransfer_.preAdapt(*this, e.mightCoarsen); } /// Override of Observer update(event::adapt) method. Redirects to adapt method of the /// \ref DataTransfer object. - void update(event::basisUpdate const&) override + void updateImpl(event::basisUpdate const&) { this->resize(); dataTransfer_.adapt(*this); @@ -182,7 +185,7 @@ namespace AMDiS /// Override of Observer update(event::postAdapt) method. Redirects to postAdapt method of the /// \ref DataTransfer object. - void update(event::postAdapt const&) override + void updateImpl(event::postAdapt const&) { dataTransfer_.postAdapt(*this); } diff --git a/src/amdis/Observer.hpp b/src/amdis/Observer.hpp index 3bf146e7..a507f53f 100644 --- a/src/amdis/Observer.hpp +++ b/src/amdis/Observer.hpp @@ -12,158 +12,14 @@ namespace AMDiS { - namespace Impl + template + class ObserverInterface { - // forward declaration - template - class ObserverInterface; - - template - class SignalBase - { - public: - /// Attaches an observer to this class. This method will be called by all observers with - /// with themselves as argument. - void attachObserver(ObserverInterface* o) const - { - observers_.push_back(o); - } - - /// Detaches an observer to this class. This method will be called by all observers with - /// with themselves as argument. - void detachObserver(ObserverInterface* o) const - { - auto it = std::find(observers_.begin(), observers_.end(), o); - if (it != observers_.end()) - observers_.erase(it); - } - - /// Notify all observers that have called attachObserver but have not called detachObserver - void notify(Event const& e) const - { - for (ObserverInterface* o : observers_) - o->update(e); - } - - private: - /// List of observers that need to be notified in case of an event - // NOTE: this list is mutable, since the notification list itself is not part - // of the internal state of the object signaling the event. - mutable std::list*> observers_; - }; - - - template - class ObserverInterface - { - public: - virtual ~ObserverInterface() = default; - - /// Attach the observer to a subject. It will then receive notifications from the subject when - /// an event of type Event it triggered. - void attach(std::shared_ptr const> const& subject) - { - if (bool(subject)) - subject->attachObserver(this); - } - - /// Detach the observer from the subject. It will then no longer receive notifications. This - /// must be called before the observer is deleted. - void detach(std::shared_ptr const> const& subject) - { - if (bool(subject)) - subject->detachObserver(this); - } - - /// This method will be called by the subject when triggering the event. - virtual void update(Event const&) - { - error_exit("Method must be overridden by derived class"); - } - }; - - - template - class ObserverBase - : virtual public ObserverInterface - { - using Self = ObserverBase; - - private: - ObserverBase() = default; - - // use subject if Event is handled directly - template , S>::value)> - ObserverBase(std::shared_ptr subject, Dune::PriorityTag<2>) - : subject_(std::move(subject)) - { - this->attach(subject_); - } - - // get next subject in hierarchy if Event is not handled - template ().subject_)> > - ObserverBase(std::shared_ptr const& o, Dune::PriorityTag<1>) - : ObserverBase(o->subject_) - {} - - // non-observable type - template - ObserverBase(std::shared_ptr const& other, Dune::PriorityTag<0>) - { - /* fallback implementation */ - } - - public: - template - ObserverBase(std::shared_ptr const& arg) - : ObserverBase(arg, Dune::PriorityTag<42>{}) - {} - - /// Copy constructor - ObserverBase(Self const& that) - : subject_(that.subject_) - { - this->attach(subject_); - } - - /// Move constructor - ObserverBase(Self&& that) - { - swap(*this, that); - } - - /// Destructor. Detaches observer from the subject - ~ObserverBase() override - { - this->detach(subject_); - } - - /// Copy/Move assignment - Self& operator=(Self that) - { - swap(*this, that); - return *this; - } - - /// Swaps the contents of lhs and rhs - friend void swap(Self& lhs, Self& rhs) - { - using std::swap; - lhs.detach(lhs.subject_); - rhs.detach(rhs.subject_); - swap(lhs.subject_, rhs.subject_); - lhs.attach(lhs.subject_); - rhs.attach(rhs.subject_); - } - - private: - /// The observed subject - std::shared_ptr const> subject_ = nullptr; - }; - - } // end namespace Impl + public: + virtual ~ObserverInterface() = default; + virtual ObserverInterface* clone(void* subject) const = 0; + virtual void update(Event const& e) = 0; + }; /// \brief Mixin for signaling of certain events. @@ -176,57 +32,103 @@ namespace AMDiS * to the instance of T (see Observer) */ template - class Signals - : public Impl::SignalBase - , public Signals + class Notifier + : public Notifier + , public Notifier { public: - using Impl::SignalBase::notify; - using Signals::notify; + using Notifier::notify; + using Notifier::notify; }; template - class Signals - : public Impl::SignalBase + class Notifier { public: - using Impl::SignalBase::notify; + void notify(Event const& e) + { + for (ObserverInterface* o : observers_) + o->update(e); + } + + void attach(ObserverInterface* o) + { + observers_.push_back(o); + } + + void detach(ObserverInterface* o) + { + auto it = std::find(observers_.begin(), observers_.end(), o); + if (it != observers_.end()) + observers_.erase(it); + } + + private: + std::list*> observers_; }; - /// \brief Mixin for reacting to certain events. - /** - * Derived classes can react to events by implementing the functions `update(Event)` for - * all Events specified in the template parameter list, whose origin is an instance of class - * `Subject` specified in the constructor to Observer and any indirectly observed class instances. - * Observed instances may include: - * - the instance of class `Subject` passed to the constructor - * - the instance passed to the constructor of `Subject::Observer` if Subject inherits from - * \ref Observer - * - all other instances indirectly accessible in the above way - * - * For each event E the first object in the above hierarchy that implements \ref Signals with E - * included in Es... will be observed by this class. - */ - template + template class Observer - : public Impl::ObserverBase... { - template - friend class Impl::ObserverBase; - public: - Observer(std::shared_ptr const& s) - : Impl::ObserverBase(s)... - , subject_(std::move(s)) - {} + template + Observer(Subject* subject, Notifier const& notifier) + : observer_(new ObserverModel{subject}) + , notifier_(const_cast(¬ifier)) + { + notifier_->attach(observer_); + } + + virtual ~Observer() + { + assert(notifier_ && observer_); + notifier_->detach(observer_); + delete observer_; + } + + Observer(Observer const& other) + : observer_(other.observer_->clone(this)) + , notifier_(other.notifier_) + { + notifier_->attach(observer_); + } + + Observer& operator=(Observer other) + { + using std::swap; + swap(notifier_, other.notifier_); + swap(observer_, other.observer_); + return *this; + } + + private: + template + struct ObserverModel + : public ObserverInterface + { + using Self = ObserverModel; + + ObserverModel(Subject* subject) + : subject_(subject) + {} - Observer(std::shared_ptr const& s) - : Observer(std::const_pointer_cast(s)) - {} + Self* clone(void* subject) const final + { + return new Self{reinterpret_cast(subject)}; + } + + void update(Event const& e) final + { + subject_->updateImpl(e, Tags{}...); + } + + Subject* subject_; + }; private: - std::shared_ptr subject_ = nullptr; + ObserverInterface* observer_ = nullptr; + Notifier* notifier_ = nullptr; }; } // end namespace AMDiS diff --git a/src/amdis/functions/ParallelGlobalBasis.hpp b/src/amdis/functions/ParallelGlobalBasis.hpp index 47f27873..2c1aab9c 100644 --- a/src/amdis/functions/ParallelGlobalBasis.hpp +++ b/src/amdis/functions/ParallelGlobalBasis.hpp @@ -65,15 +65,12 @@ namespace AMDiS */ template class ParallelGlobalBasis - : public Observer - , public Signals>> + : public Notifier>> + , private Observer { using Subject = typename PB::GridView::Grid; - using Super = Observer; using Self = ParallelGlobalBasis; - struct DummyImpl {}; - public: /// Pre-basis providing the implementation details @@ -109,6 +106,7 @@ namespace AMDiS /// Type of the communicator using Comm = typename BackendTraits::Comm; + struct DummyImpl {}; using ADH = Dune::AdaptDataHandle; @@ -124,7 +122,7 @@ namespace AMDiS template = 0> ParallelGlobalBasis(std::string const& name, Grid const& grid, Args&&... args) - : Super(Dune::stackobject_to_shared_ptr(grid)) + : Observer(this, grid) , preBasis_(FWD(args)...) { static_assert(Dune::models, PreBasis>(), @@ -173,7 +171,7 @@ namespace AMDiS } /// Updates the underlying basis when event::adapt is triggered by the observed grid - void update(event::adapt const& e) override + void updateImpl(event::adapt const& e) { if (e.adapted) { update(gridView()); -- GitLab From dc5fbe2ae12dd12c161c8a291c4ad5c598880e96 Mon Sep 17 00:00:00 2001 From: Simon Praetorius Date: Sun, 3 Nov 2019 22:15:21 +0100 Subject: [PATCH 2/7] rename basisUpdate event to just adapt --- src/amdis/AdaptiveGrid.hpp | 4 ++-- src/amdis/DOFVector.hpp | 15 ++++++++------- src/amdis/functions/ParallelGlobalBasis.hpp | 16 +++++----------- 3 files changed, 15 insertions(+), 20 deletions(-) diff --git a/src/amdis/AdaptiveGrid.hpp b/src/amdis/AdaptiveGrid.hpp index 18bfdad2..d4c728ab 100644 --- a/src/amdis/AdaptiveGrid.hpp +++ b/src/amdis/AdaptiveGrid.hpp @@ -33,13 +33,13 @@ namespace AMDiS * of preAdapt() as its 'mightCoarsen' member and is passed to registered observers after * calling preAdapt on the underlying grid. **/ - struct preAdapt { bool mightCoarsen; }; + struct preAdapt { bool value = true; }; /** Event generated from an AdaptiveGrid when calling adapt(). Its 'adapted' member contains the * value true if either preAdapt() or adapt() returned true. This event is passed to registered * observers after calling adapt on the underlying grid. **/ - struct adapt { bool adapted; }; + struct adapt { bool value = true; }; /** Event generated from an AdaptiveGrid when calling postAdapt().This event is passed to * registered observers after calling postAdapt on the underlying grid. diff --git a/src/amdis/DOFVector.hpp b/src/amdis/DOFVector.hpp index c0dc5373..e96e33e6 100644 --- a/src/amdis/DOFVector.hpp +++ b/src/amdis/DOFVector.hpp @@ -32,7 +32,7 @@ namespace AMDiS { struct preAdapt; struct postAdapt; - template struct basisUpdate; + struct basisUpdate; } /// \brief The basic container that stores a base vector and a corresponding basis @@ -44,7 +44,7 @@ namespace AMDiS class DOFVector : public VectorBase>> , private Observer - , private Observer> + , private Observer , private Observer { using Self = DOFVector; @@ -70,7 +70,7 @@ namespace AMDiS DataTransferOperation op = DataTransferOperation::INTERPOLATE) : Super(basis) , Observer(this, basis->gridView().grid()) - , Observer>(this, *basis) + , Observer(this, *basis) , Observer(this, basis->gridView().grid()) , dataTransfer_(op, basis) , basis_(basis) @@ -170,22 +170,23 @@ namespace AMDiS /// Override of Observer update(event::preAdapt) method. Redirects to preAdapt method of the /// \ref DataTransfer object. - void updateImpl(event::preAdapt const& e) + void updateImpl(event::preAdapt e) { - dataTransfer_.preAdapt(*this, e.mightCoarsen); + dataTransfer_.preAdapt(*this, e.value); } /// Override of Observer update(event::adapt) method. Redirects to adapt method of the /// \ref DataTransfer object. - void updateImpl(event::basisUpdate const&) + void updateImpl(event::adapt e) { + assert(e.value); this->resize(); dataTransfer_.adapt(*this); } /// Override of Observer update(event::postAdapt) method. Redirects to postAdapt method of the /// \ref DataTransfer object. - void updateImpl(event::postAdapt const&) + void updateImpl(event::postAdapt) { dataTransfer_.postAdapt(*this); } diff --git a/src/amdis/functions/ParallelGlobalBasis.hpp b/src/amdis/functions/ParallelGlobalBasis.hpp index 2c1aab9c..1e789f33 100644 --- a/src/amdis/functions/ParallelGlobalBasis.hpp +++ b/src/amdis/functions/ParallelGlobalBasis.hpp @@ -47,12 +47,7 @@ namespace AMDiS { namespace event { - template - struct basisUpdate - { - using Basis = B; - Basis const& basis; - }; + struct basisUpdate {}; } /** @@ -65,7 +60,7 @@ namespace AMDiS */ template class ParallelGlobalBasis - : public Notifier>> + : public Notifier , private Observer { using Subject = typename PB::GridView::Grid; @@ -171,12 +166,11 @@ namespace AMDiS } /// Updates the underlying basis when event::adapt is triggered by the observed grid - void updateImpl(event::adapt const& e) + void updateImpl(event::adapt e) { - if (e.adapted) { + if (e.value) { update(gridView()); - event::basisUpdate eNew{*this}; - this->notify(eNew); + this->notify(e); } } -- GitLab From 4c25b9c9d9cb3554595ad63b5827bb5e7117df25 Mon Sep 17 00:00:00 2001 From: Simon Praetorius Date: Thu, 5 Dec 2019 11:48:54 +0100 Subject: [PATCH 3/7] changed observer pattern to something simpler --- src/amdis/DOFVector.hpp | 14 ++--- src/amdis/Observer.hpp | 60 ++++++++------------- src/amdis/functions/ParallelGlobalBasis.hpp | 23 ++++---- 3 files changed, 41 insertions(+), 56 deletions(-) diff --git a/src/amdis/DOFVector.hpp b/src/amdis/DOFVector.hpp index e96e33e6..41fd8ccc 100644 --- a/src/amdis/DOFVector.hpp +++ b/src/amdis/DOFVector.hpp @@ -69,9 +69,9 @@ namespace AMDiS DOFVector(std::shared_ptr const& basis, DataTransferOperation op = DataTransferOperation::INTERPOLATE) : Super(basis) - , Observer(this, basis->gridView().grid()) - , Observer(this, *basis) - , Observer(this, basis->gridView().grid()) + , Observer(basis->gridView().grid()) + , Observer(*basis) + , Observer(basis->gridView().grid()) , dataTransfer_(op, basis) , basis_(basis) {} @@ -168,16 +168,18 @@ namespace AMDiS setDataTransfer(newDataTransfer(op, basis_)); } + protected: + /// Override of Observer update(event::preAdapt) method. Redirects to preAdapt method of the /// \ref DataTransfer object. - void updateImpl(event::preAdapt e) + void updateImpl(event::preAdapt e) override { dataTransfer_.preAdapt(*this, e.value); } /// Override of Observer update(event::adapt) method. Redirects to adapt method of the /// \ref DataTransfer object. - void updateImpl(event::adapt e) + void updateImpl(event::adapt e) override { assert(e.value); this->resize(); @@ -186,7 +188,7 @@ namespace AMDiS /// Override of Observer update(event::postAdapt) method. Redirects to postAdapt method of the /// \ref DataTransfer object. - void updateImpl(event::postAdapt) + void updateImpl(event::postAdapt) override { dataTransfer_.postAdapt(*this); } diff --git a/src/amdis/Observer.hpp b/src/amdis/Observer.hpp index a507f53f..fde4e254 100644 --- a/src/amdis/Observer.hpp +++ b/src/amdis/Observer.hpp @@ -17,8 +17,7 @@ namespace AMDiS { public: virtual ~ObserverInterface() = default; - virtual ObserverInterface* clone(void* subject) const = 0; - virtual void update(Event const& e) = 0; + virtual void update(Event e) = 0; }; @@ -70,64 +69,47 @@ namespace AMDiS template class Observer + : public ObserverInterface { public: - template - Observer(Subject* subject, Notifier const& notifier) - : observer_(new ObserverModel{subject}) - , notifier_(const_cast(¬ifier)) + template + Observer(Notifier const& notifier) + : notifier_(const_cast(¬ifier)) { - notifier_->attach(observer_); + notifier_->attach(this); } virtual ~Observer() { - assert(notifier_ && observer_); - notifier_->detach(observer_); - delete observer_; + assert(notifier_); + notifier_->detach(this); } Observer(Observer const& other) - : observer_(other.observer_->clone(this)) - , notifier_(other.notifier_) + : notifier_(other.notifier_) { - notifier_->attach(observer_); + notifier_->attach(this); } - Observer& operator=(Observer other) + Observer& operator=(Observer const& other) { - using std::swap; - swap(notifier_, other.notifier_); - swap(observer_, other.observer_); + notifier_ = other.notifier_; + notifier_->attach(this); return *this; } - private: - template - struct ObserverModel - : public ObserverInterface + void update(Event e) final { - using Self = ObserverModel; - - ObserverModel(Subject* subject) - : subject_(subject) - {} - - Self* clone(void* subject) const final - { - return new Self{reinterpret_cast(subject)}; - } - - void update(Event const& e) final - { - subject_->updateImpl(e, Tags{}...); - } + updateImpl(e, Tags{}...); + } - Subject* subject_; - }; + protected: + /// \brief Implementation of the update method in derived class + // NOTE: The additional `Tags...` arguments can be used to distinguish + // between multiple observers of the same event. + virtual void updateImpl(Event e, Tags...) = 0; private: - ObserverInterface* observer_ = nullptr; Notifier* notifier_ = nullptr; }; diff --git a/src/amdis/functions/ParallelGlobalBasis.hpp b/src/amdis/functions/ParallelGlobalBasis.hpp index 1e789f33..7de3179e 100644 --- a/src/amdis/functions/ParallelGlobalBasis.hpp +++ b/src/amdis/functions/ParallelGlobalBasis.hpp @@ -63,7 +63,6 @@ namespace AMDiS : public Notifier , private Observer { - using Subject = typename PB::GridView::Grid; using Self = ParallelGlobalBasis; public: @@ -117,7 +116,7 @@ namespace AMDiS template = 0> ParallelGlobalBasis(std::string const& name, Grid const& grid, Args&&... args) - : Observer(this, grid) + : Observer(grid) , preBasis_(FWD(args)...) { static_assert(Dune::models, PreBasis>(), @@ -165,15 +164,6 @@ namespace AMDiS return preBasis_; } - /// Updates the underlying basis when event::adapt is triggered by the observed grid - void updateImpl(event::adapt e) - { - if (e.value) { - update(gridView()); - this->notify(e); - } - } - /// \brief Update the stored grid view /** * This will update the indexing information of the global basis as well as the communicator. @@ -237,6 +227,17 @@ namespace AMDiS return ADH{}; } + protected: + + /// Updates the underlying basis when event::adapt is triggered by the observed grid + void updateImpl(event::adapt e) override + { + if (e.value) { + update(gridView()); + this->notify(e); + } + } + protected: PreBasis preBasis_; PrefixPath prefixPath_ = {}; -- GitLab From d3059fb34ae01e4bac347ade644fc2c4bc174492 Mon Sep 17 00:00:00 2001 From: Simon Praetorius Date: Fri, 6 Dec 2019 19:09:49 +0100 Subject: [PATCH 4/7] corrected ObserverTest --- test/ObserverTest.cpp | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/test/ObserverTest.cpp b/test/ObserverTest.cpp index 77039fee..7527ebfc 100644 --- a/test/ObserverTest.cpp +++ b/test/ObserverTest.cpp @@ -24,7 +24,7 @@ bool checkAndResetTestValue(std::string testName, std::string ref, std::string r } class A - : public Signals + : public Notifier { public: void foo() @@ -53,43 +53,52 @@ public: }; class B - : public Observer - , public Signals + : private Observer + , private Observer + , public Notifier { public: B(std::shared_ptr a) - : Observer(a) + : Observer(*a) + , Observer(*a) + , a_(a) {} - void update(event::fooEvent const& e) override + void updateImpl(event::fooEvent) override { std::cout << "B::update(foo)\n"; testValue += "B.foo "; } - void update(event::bazEvent const& e) override + void updateImpl(event::bazEvent e) override { std::cout << "B::update(baz)\n"; testValue += "B.baz "; this->notify(e); } + + std::shared_ptr const& a() const { return a_; } + + std::shared_ptr a_; }; class C - : public Observer + : private Observer + , private Observer { public: C(std::shared_ptr b) - : Observer(b) + : Observer(*b->a()) + , Observer(*b) {} - void update(event::barEvent const& e) override + void updateImpl(event::barEvent) override { std::cout << "C::update(bar)\n"; testValue += "C.bar "; } - void update(event::bazEvent const& e) override + void updateImpl(event::bazEvent) override { std::cout << "C::update(baz)\n"; testValue += "C.baz "; @@ -97,7 +106,7 @@ public: }; class D - : public Signals + : public Notifier { public: void bar() @@ -110,22 +119,22 @@ public: }; class E - : public Observer - , public Observer + : public Observer + , public Observer { public: E(std::shared_ptr a, std::shared_ptr d) - : Observer(a) - , Observer(d) + : Observer(*a) + , Observer(*d) {} - void update(event::fooEvent const& e) override + void updateImpl(event::fooEvent) override { std::cout << "E::update(foo)\n"; testValue += "E.foo "; } - void update(event::barEvent const& e) override + void updateImpl(event::barEvent) override { std::cout << "E::update(bar)\n"; testValue += "E.bar "; -- GitLab From 5199bfd38a1db33b12ba0c1d60004c9fca74dde2 Mon Sep 17 00:00:00 2001 From: Simon Praetorius Date: Mon, 23 Dec 2019 13:02:36 +0100 Subject: [PATCH 5/7] move standard events to Observer --- src/amdis/AdaptiveGrid.hpp | 21 --------- src/amdis/DOFVector.hpp | 6 --- src/amdis/Observer.hpp | 48 ++++++++++++++++++++- src/amdis/functions/ParallelGlobalBasis.hpp | 5 --- 4 files changed, 46 insertions(+), 34 deletions(-) diff --git a/src/amdis/AdaptiveGrid.hpp b/src/amdis/AdaptiveGrid.hpp index d4c728ab..f5dbb709 100644 --- a/src/amdis/AdaptiveGrid.hpp +++ b/src/amdis/AdaptiveGrid.hpp @@ -27,27 +27,6 @@ namespace AMDiS { - namespace event - { - /** Event generated from an AdaptiveGrid when calling preAdapt(). It contains the return value - * of preAdapt() as its 'mightCoarsen' member and is passed to registered observers after - * calling preAdapt on the underlying grid. - **/ - struct preAdapt { bool value = true; }; - - /** Event generated from an AdaptiveGrid when calling adapt(). Its 'adapted' member contains the - * value true if either preAdapt() or adapt() returned true. This event is passed to registered - * observers after calling adapt on the underlying grid. - **/ - struct adapt { bool value = true; }; - - /** Event generated from an AdaptiveGrid when calling postAdapt().This event is passed to - * registered observers after calling postAdapt on the underlying grid. - **/ - struct postAdapt {}; - } - - // forward declaration template class AdaptiveGridFamily; diff --git a/src/amdis/DOFVector.hpp b/src/amdis/DOFVector.hpp index 41fd8ccc..1230f216 100644 --- a/src/amdis/DOFVector.hpp +++ b/src/amdis/DOFVector.hpp @@ -28,12 +28,6 @@ namespace AMDiS template class ParallelGlobalBasis; - namespace event - { - struct preAdapt; - struct postAdapt; - struct basisUpdate; - } /// \brief The basic container that stores a base vector and a corresponding basis /** diff --git a/src/amdis/Observer.hpp b/src/amdis/Observer.hpp index fde4e254..dd5d675e 100644 --- a/src/amdis/Observer.hpp +++ b/src/amdis/Observer.hpp @@ -12,6 +12,27 @@ namespace AMDiS { + namespace event + { + /** + * An event that is signaled before the actual adaption happens. Example: grid.preAdapt(). + * The \ref value might indicate whether any pre-processing is necessary. + **/ + struct preAdapt { bool value = true; }; + + /** + * An event that is called directly of the adaption. Example: grid.adapt(). + * The \ref value indicates whether something is changed during adaption. + **/ + struct adapt { bool value = true; }; + + /** + * An event that is called after adaption to indicate the start of a clean-up phase. + **/ + struct postAdapt {}; + } + + template class ObserverInterface { @@ -44,17 +65,20 @@ namespace AMDiS class Notifier { public: + /// Call the \ref update method on all attached observers. void notify(Event const& e) { for (ObserverInterface* o : observers_) o->update(e); } + /// Attach a new observer that gets called on \ref notify void attach(ObserverInterface* o) { observers_.push_back(o); } + /// Detaches the passed observer from the list, if stored. void detach(ObserverInterface* o) { auto it = std::find(observers_.begin(), observers_.end(), o); @@ -67,6 +91,7 @@ namespace AMDiS }; + /// Implementation of the \ref ObserverInterface template class Observer : public ObserverInterface @@ -74,30 +99,49 @@ namespace AMDiS public: template Observer(Notifier const& notifier) - : notifier_(const_cast(¬ifier)) + : notifier_(¬ifier) { notifier_->attach(this); } + /// Destructor, detaches from the notifier virtual ~Observer() { assert(notifier_); notifier_->detach(this); } + /// Copy constructor. Attaches this to the copied notifier Observer(Observer const& other) : notifier_(other.notifier_) { notifier_->attach(this); } + /// Copy-assignment operator, implemented in terms of the copy + /// constructor and move-assignment operator Observer& operator=(Observer const& other) + { + return *this = Observer(other); + } + + /// Move assignment operator, implemented in terms of the move + /// assignment operator + Observer(Observer&& other) + { + *this = std::move(other); + } + + /// Move-assignment operator, copies the notifier and attaches this. + Observer& operator=(Observer&& other) { notifier_ = other.notifier_; notifier_->attach(this); return *this; } + /// Implementation of the interface method \ref ObserverInterface::update. + /// Redirects to the \ref updateImpl method with additional \ref Tags parameters void update(Event e) final { updateImpl(e, Tags{}...); @@ -110,7 +154,7 @@ namespace AMDiS virtual void updateImpl(Event e, Tags...) = 0; private: - Notifier* notifier_ = nullptr; + mutable Notifier const* notifier_ = nullptr; }; } // end namespace AMDiS diff --git a/src/amdis/functions/ParallelGlobalBasis.hpp b/src/amdis/functions/ParallelGlobalBasis.hpp index 7de3179e..3ec04546 100644 --- a/src/amdis/functions/ParallelGlobalBasis.hpp +++ b/src/amdis/functions/ParallelGlobalBasis.hpp @@ -45,11 +45,6 @@ namespace Dune namespace AMDiS { - namespace event - { - struct basisUpdate {}; - } - /** * \brief Parallel global basis defined on a (sequential) pre-basis * -- GitLab From 4b1645f8c147266676b2bd0d2d353d0b38795b45 Mon Sep 17 00:00:00 2001 From: Simon Praetorius Date: Mon, 23 Dec 2019 13:17:51 +0100 Subject: [PATCH 6/7] resolved const access problems --- src/amdis/Observer.hpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/amdis/Observer.hpp b/src/amdis/Observer.hpp index dd5d675e..b031e431 100644 --- a/src/amdis/Observer.hpp +++ b/src/amdis/Observer.hpp @@ -99,7 +99,7 @@ namespace AMDiS public: template Observer(Notifier const& notifier) - : notifier_(¬ifier) + : notifier_(const_cast(¬ifier)) { notifier_->attach(this); } @@ -118,11 +118,12 @@ namespace AMDiS notifier_->attach(this); } - /// Copy-assignment operator, implemented in terms of the copy - /// constructor and move-assignment operator + /// Copy-assignment operator, copies the notifier and attaches this. Observer& operator=(Observer const& other) { - return *this = Observer(other); + notifier_ = other.notifier_; + notifier_->attach(this); + return *this; } /// Move assignment operator, implemented in terms of the move @@ -154,7 +155,7 @@ namespace AMDiS virtual void updateImpl(Event e, Tags...) = 0; private: - mutable Notifier const* notifier_ = nullptr; + Notifier* notifier_ = nullptr; }; } // end namespace AMDiS -- GitLab From 0c0ff0d332744a2059374d29730330170c4209e7 Mon Sep 17 00:00:00 2001 From: Simon Praetorius Date: Mon, 23 Dec 2019 15:07:51 +0100 Subject: [PATCH 7/7] test for observer corrected --- test/ObserverTest.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/ObserverTest.cpp b/test/ObserverTest.cpp index 7527ebfc..8f82e888 100644 --- a/test/ObserverTest.cpp +++ b/test/ObserverTest.cpp @@ -6,7 +6,7 @@ #include "Tests.hpp" -using namespace AMDiS; +namespace AMDiS { namespace event { struct fooEvent {}; @@ -14,6 +14,8 @@ namespace event { struct bazEvent {}; } +} // end namespace AMDiS + std::string testValue = ""; bool checkAndResetTestValue(std::string testName, std::string ref, std::string refOpt = "X") @@ -23,6 +25,8 @@ bool checkAndResetTestValue(std::string testName, std::string ref, std::string r return result; } +using namespace AMDiS; + class A : public Notifier { @@ -161,6 +165,8 @@ public: */ int main() { + using namespace AMDiS; + auto a = std::make_shared(); auto b = std::make_shared(a); auto c = std::make_shared(b); -- GitLab