1*6777b538SAndroid Build Coastguard Worker // Copyright 2020 The Chromium Authors 2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be 3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file. 4*6777b538SAndroid Build Coastguard Worker 5*6777b538SAndroid Build Coastguard Worker #ifndef BASE_SCOPED_OBSERVATION_H_ 6*6777b538SAndroid Build Coastguard Worker #define BASE_SCOPED_OBSERVATION_H_ 7*6777b538SAndroid Build Coastguard Worker 8*6777b538SAndroid Build Coastguard Worker #include <utility> 9*6777b538SAndroid Build Coastguard Worker 10*6777b538SAndroid Build Coastguard Worker #include "base/check.h" 11*6777b538SAndroid Build Coastguard Worker #include "base/check_op.h" 12*6777b538SAndroid Build Coastguard Worker #include "base/memory/raw_ptr.h" 13*6777b538SAndroid Build Coastguard Worker #include "base/scoped_observation_traits.h" 14*6777b538SAndroid Build Coastguard Worker 15*6777b538SAndroid Build Coastguard Worker namespace base { 16*6777b538SAndroid Build Coastguard Worker 17*6777b538SAndroid Build Coastguard Worker // `ScopedObservation` is used to keep track of a singular observation, i.e., 18*6777b538SAndroid Build Coastguard Worker // where an observer observes a single source only. Use 19*6777b538SAndroid Build Coastguard Worker // `base::ScopedMultiSourceObservation` for objects that observe multiple 20*6777b538SAndroid Build Coastguard Worker // sources. 21*6777b538SAndroid Build Coastguard Worker // 22*6777b538SAndroid Build Coastguard Worker // When a `ScopedObservation` is destroyed, it unregisters the observer from the 23*6777b538SAndroid Build Coastguard Worker // observable if it was currently observing something. Otherwise it does 24*6777b538SAndroid Build Coastguard Worker // nothing. 25*6777b538SAndroid Build Coastguard Worker // 26*6777b538SAndroid Build Coastguard Worker // Using a `ScopedObservation` instead of manually observing and unobserving has 27*6777b538SAndroid Build Coastguard Worker // the following benefits: 28*6777b538SAndroid Build Coastguard Worker // - The observer cannot accidentally forget to stop observing when it is 29*6777b538SAndroid Build Coastguard Worker // destroyed. 30*6777b538SAndroid Build Coastguard Worker // - By calling `Reset`, an ongoing observation can be stopped before the 31*6777b538SAndroid Build Coastguard Worker // `ScopedObservation` is destroyed. If nothing was currently observed, then 32*6777b538SAndroid Build Coastguard Worker // calling `Reset` does nothing. This can be useful for when the observable is 33*6777b538SAndroid Build Coastguard Worker // destroyed before the observer is destroyed, because it prevents the 34*6777b538SAndroid Build Coastguard Worker // observer from accidentally unregistering itself from the destroyed 35*6777b538SAndroid Build Coastguard Worker // observable a second time when it itself is destroyed. Without 36*6777b538SAndroid Build Coastguard Worker // `ScopedObservation`, one might need to keep track of whether one has 37*6777b538SAndroid Build Coastguard Worker // already stopped observing in a separate boolean. 38*6777b538SAndroid Build Coastguard Worker // 39*6777b538SAndroid Build Coastguard Worker // A complete usage example can be found below. 40*6777b538SAndroid Build Coastguard Worker // 41*6777b538SAndroid Build Coastguard Worker // `observer.h`: 42*6777b538SAndroid Build Coastguard Worker // class Observer { 43*6777b538SAndroid Build Coastguard Worker // public: 44*6777b538SAndroid Build Coastguard Worker // virtual ~Observer() {} 45*6777b538SAndroid Build Coastguard Worker // 46*6777b538SAndroid Build Coastguard Worker // virtual void OnEvent() {} 47*6777b538SAndroid Build Coastguard Worker // }; 48*6777b538SAndroid Build Coastguard Worker // 49*6777b538SAndroid Build Coastguard Worker // `source.h`: 50*6777b538SAndroid Build Coastguard Worker // class Observer; 51*6777b538SAndroid Build Coastguard Worker // class Source { 52*6777b538SAndroid Build Coastguard Worker // public: 53*6777b538SAndroid Build Coastguard Worker // void AddObserver(Observer* observer); 54*6777b538SAndroid Build Coastguard Worker // void RemoveObserver(Observer* observer); 55*6777b538SAndroid Build Coastguard Worker // }; 56*6777b538SAndroid Build Coastguard Worker // 57*6777b538SAndroid Build Coastguard Worker // `observer_impl.h`: 58*6777b538SAndroid Build Coastguard Worker // #include "observer.h" 59*6777b538SAndroid Build Coastguard Worker // 60*6777b538SAndroid Build Coastguard Worker // class Source; 61*6777b538SAndroid Build Coastguard Worker // 62*6777b538SAndroid Build Coastguard Worker // class ObserverImpl: public Observer { 63*6777b538SAndroid Build Coastguard Worker // public: 64*6777b538SAndroid Build Coastguard Worker // ObserverImpl(Source* source); 65*6777b538SAndroid Build Coastguard Worker // // Note how there is no need to stop observing in the destructor. 66*6777b538SAndroid Build Coastguard Worker // ~ObserverImpl() override {} 67*6777b538SAndroid Build Coastguard Worker // 68*6777b538SAndroid Build Coastguard Worker // void OnEvent() override { 69*6777b538SAndroid Build Coastguard Worker // ... 70*6777b538SAndroid Build Coastguard Worker // } 71*6777b538SAndroid Build Coastguard Worker // 72*6777b538SAndroid Build Coastguard Worker // private: 73*6777b538SAndroid Build Coastguard Worker // // Note that |obs_| can be instantiated with forward-declared Source. 74*6777b538SAndroid Build Coastguard Worker // base::ScopedObservation<Source, Observer> obs_{this}; 75*6777b538SAndroid Build Coastguard Worker // }; 76*6777b538SAndroid Build Coastguard Worker // 77*6777b538SAndroid Build Coastguard Worker // `observer_impl.cc`: 78*6777b538SAndroid Build Coastguard Worker // #include "observer_impl.h" 79*6777b538SAndroid Build Coastguard Worker // #include "source.h" 80*6777b538SAndroid Build Coastguard Worker // 81*6777b538SAndroid Build Coastguard Worker // ObserverImpl::ObserverImpl(Source* source) { 82*6777b538SAndroid Build Coastguard Worker // // After the call |this| starts listening to events from |source|. 83*6777b538SAndroid Build Coastguard Worker // obs_.Observe(source); 84*6777b538SAndroid Build Coastguard Worker // } 85*6777b538SAndroid Build Coastguard Worker // 86*6777b538SAndroid Build Coastguard Worker //////////////////////////////////////////////////////////////////////////////// 87*6777b538SAndroid Build Coastguard Worker // 88*6777b538SAndroid Build Coastguard Worker // By default `ScopedObservation` only works with sources that expose 89*6777b538SAndroid Build Coastguard Worker // `AddObserver` and `RemoveObserver`. However, it's also possible to 90*6777b538SAndroid Build Coastguard Worker // adapt it to custom function names (say `AddFoo` and `RemoveFoo` accordingly) 91*6777b538SAndroid Build Coastguard Worker // by tailoring ScopedObservationTraits<> for the given Source and Observer -- 92*6777b538SAndroid Build Coastguard Worker // see `base/scoped_observation_traits.h` for details. 93*6777b538SAndroid Build Coastguard Worker // 94*6777b538SAndroid Build Coastguard Worker 95*6777b538SAndroid Build Coastguard Worker template <class Source, class Observer> 96*6777b538SAndroid Build Coastguard Worker class ScopedObservation { 97*6777b538SAndroid Build Coastguard Worker public: ScopedObservation(Observer * observer)98*6777b538SAndroid Build Coastguard Worker explicit ScopedObservation(Observer* observer) : observer_(observer) {} 99*6777b538SAndroid Build Coastguard Worker ScopedObservation(const ScopedObservation&) = delete; 100*6777b538SAndroid Build Coastguard Worker ScopedObservation& operator=(const ScopedObservation&) = delete; ~ScopedObservation()101*6777b538SAndroid Build Coastguard Worker ~ScopedObservation() { Reset(); } 102*6777b538SAndroid Build Coastguard Worker 103*6777b538SAndroid Build Coastguard Worker // Adds the object passed to the constructor as an observer on |source|. 104*6777b538SAndroid Build Coastguard Worker // IsObserving() must be false. Observe(Source * source)105*6777b538SAndroid Build Coastguard Worker void Observe(Source* source) { 106*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(source_, nullptr); 107*6777b538SAndroid Build Coastguard Worker source_ = source; 108*6777b538SAndroid Build Coastguard Worker Traits::AddObserver(source_, observer_); 109*6777b538SAndroid Build Coastguard Worker } 110*6777b538SAndroid Build Coastguard Worker 111*6777b538SAndroid Build Coastguard Worker // Remove the object passed to the constructor as an observer from |source_| 112*6777b538SAndroid Build Coastguard Worker // if currently observing. Does nothing otherwise. Reset()113*6777b538SAndroid Build Coastguard Worker void Reset() { 114*6777b538SAndroid Build Coastguard Worker if (source_) { 115*6777b538SAndroid Build Coastguard Worker Traits::RemoveObserver(std::exchange(source_, nullptr), observer_); 116*6777b538SAndroid Build Coastguard Worker } 117*6777b538SAndroid Build Coastguard Worker } 118*6777b538SAndroid Build Coastguard Worker 119*6777b538SAndroid Build Coastguard Worker // Returns true if any source is being observed. IsObserving()120*6777b538SAndroid Build Coastguard Worker bool IsObserving() const { return source_ != nullptr; } 121*6777b538SAndroid Build Coastguard Worker 122*6777b538SAndroid Build Coastguard Worker // Returns true if |source| is being observed. IsObservingSource(Source * source)123*6777b538SAndroid Build Coastguard Worker bool IsObservingSource(Source* source) const { 124*6777b538SAndroid Build Coastguard Worker DCHECK(source); 125*6777b538SAndroid Build Coastguard Worker return source_ == source; 126*6777b538SAndroid Build Coastguard Worker } 127*6777b538SAndroid Build Coastguard Worker 128*6777b538SAndroid Build Coastguard Worker // Gets a pointer to the observed source, or nullptr if no source is being 129*6777b538SAndroid Build Coastguard Worker // observed. GetSource()130*6777b538SAndroid Build Coastguard Worker Source* GetSource() { return source_; } GetSource()131*6777b538SAndroid Build Coastguard Worker const Source* GetSource() const { return source_; } 132*6777b538SAndroid Build Coastguard Worker 133*6777b538SAndroid Build Coastguard Worker private: 134*6777b538SAndroid Build Coastguard Worker using Traits = ScopedObservationTraits<Source, Observer>; 135*6777b538SAndroid Build Coastguard Worker 136*6777b538SAndroid Build Coastguard Worker const raw_ptr<Observer> observer_; 137*6777b538SAndroid Build Coastguard Worker 138*6777b538SAndroid Build Coastguard Worker // The observed source, if any. 139*6777b538SAndroid Build Coastguard Worker raw_ptr<Source, LeakedDanglingUntriaged> source_ = nullptr; 140*6777b538SAndroid Build Coastguard Worker }; 141*6777b538SAndroid Build Coastguard Worker 142*6777b538SAndroid Build Coastguard Worker } // namespace base 143*6777b538SAndroid Build Coastguard Worker 144*6777b538SAndroid Build Coastguard Worker #endif // BASE_SCOPED_OBSERVATION_H_ 145