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.
5 #ifndef BASE_SCOPED_OBSERVATION_H_
6 #define BASE_SCOPED_OBSERVATION_H_
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"
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
22 // When a `ScopedObservation` is destroyed, it unregisters the observer from the
23 // observable if it was currently observing something. Otherwise it does
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
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.
39 // A complete usage example can be found below.
44 // virtual ~Observer() {}
46 // virtual void OnEvent() {}
53 // void AddObserver(Observer* observer);
54 // void RemoveObserver(Observer* observer);
58 // #include "observer.h"
62 // class ObserverImpl: public Observer {
64 // ObserverImpl(Source* source);
65 // // Note how there is no need to stop observing in the destructor.
66 // ~ObserverImpl() override {}
68 // void OnEvent() override {
73 // // Note that |obs_| can be instantiated with forward-declared Source.
74 // base::ScopedObservation<Source, Observer> obs_{this};
77 // `observer_impl.cc`:
78 // #include "observer_impl.h"
79 // #include "source.h"
81 // ObserverImpl::ObserverImpl(Source* source) {
82 // // After the call |this| starts listening to events from |source|.
83 // obs_.Observe(source);
86 ////////////////////////////////////////////////////////////////////////////////
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.
95 template <class Source, class Observer>
96 class ScopedObservation {
98 explicit ScopedObservation(Observer* observer) : observer_(observer) {}
99 ScopedObservation(const ScopedObservation&) = delete;
100 ScopedObservation& operator=(const ScopedObservation&) = delete;
101 ~ScopedObservation() { Reset(); }
103 // Adds the object passed to the constructor as an observer on |source|.
104 // IsObserving() must be false.
105 void Observe(Source* source) {
106 DCHECK_EQ(source_, nullptr);
108 Traits::AddObserver(source_, observer_);
111 // Remove the object passed to the constructor as an observer from |source_|
112 // if currently observing. Does nothing otherwise.
115 Traits::RemoveObserver(std::exchange(source_, nullptr), observer_);
119 // Returns true if any source is being observed.
120 bool IsObserving() const { return source_ != nullptr; }
122 // Returns true if |source| is being observed.
123 bool IsObservingSource(Source* source) const {
125 return source_ == source;
128 // Gets a pointer to the observed source, or nullptr if no source is being
130 Source* GetSource() { return source_; }
131 const Source* GetSource() const { return source_; }
134 using Traits = ScopedObservationTraits<Source, Observer>;
136 const raw_ptr<Observer, DanglingUntriaged> observer_;
138 // The observed source, if any.
139 raw_ptr<Source, LeakedDanglingUntriaged> source_ = nullptr;
144 #endif // BASE_SCOPED_OBSERVATION_H_