xref: /aosp_15_r20/external/cronet/base/scoped_observation.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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