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