blob: 3cd6882476121ba105eebfb9a8c75975619c1eb0 [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2020 The Chromium Authors
Sigurdur Asgeirsson046f5c72020-11-04 16:48:432// 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 <stddef.h>
9
David Sanders8cfb63a2022-04-14 19:36:3010#include "base/check.h"
Sigurdur Asgeirsson046f5c72020-11-04 16:48:4311#include "base/check_op.h"
Keishi Hattori44d4f4e92022-06-16 06:01:2012#include "base/memory/raw_ptr.h"
Andrew Rayskiy8fdfb672022-11-04 00:26:3013#include "base/scoped_observation_traits.h"
Sigurdur Asgeirsson046f5c72020-11-04 16:48:4314
Sigurdur Asgeirsson80f6e8f2020-11-04 20:14:1515namespace base {
16
Christian Flach0572efd2022-09-21 22:19:2117// `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
Sigurdur Asgeirssond272114c2021-06-08 12:37:3220// sources.
Sigurdur Asgeirsson11031652020-11-12 17:44:2521//
Christian Flach0572efd2022-09-21 22:19:2122// When a `ScopedObservation` is destroyed, it unregisters the observer from the
23// observable if it was currently observing something. Otherwise it does
24// nothing.
Sigurdur Asgeirsson046f5c72020-11-04 16:48:4325//
Christian Flach0572efd2022-09-21 22:19:2126// 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//
Andrew Rayskiy8fdfb672022-11-04 00:26:3039// A complete usage example can be found below.
Christian Flach0572efd2022-09-21 22:19:2140//
Andrew Rayskiy8fdfb672022-11-04 00:26:3041// `observer.h`:
42// class Observer {
Christian Flach0572efd2022-09-21 22:19:2143// public:
Andrew Rayskiy8fdfb672022-11-04 00:26:3044// 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);
Christian Flach0572efd2022-09-21 22:19:2165// // Note how there is no need to stop observing in the destructor.
Andrew Rayskiy8fdfb672022-11-04 00:26:3066// ~ObserverImpl() override {}
67//
68// void OnEvent() override {
69// ...
70// }
71//
Sigurdur Asgeirsson046f5c72020-11-04 16:48:4372// private:
Andrew Rayskiy8fdfb672022-11-04 00:26:3073// // Note that |obs_| can be instantiated with forward-declared Source.
74// base::ScopedObservation<Source, Observer> obs_{this};
Sigurdur Asgeirsson046f5c72020-11-04 16:48:4375// };
76//
Andrew Rayskiy8fdfb672022-11-04 00:26:3077// `observer_impl.cc`:
78// #include "observer_impl.h"
79// #include "source.h"
Sigurdur Asgeirsson046f5c72020-11-04 16:48:4380//
Andrew Rayskiy8fdfb672022-11-04 00:26:3081// 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)
Andrew Rayskiy3cf073392022-11-11 00:31:4991// by tailoring ScopedObservationTraits<> for the given Source and Observer --
92// see `base/scoped_observation_traits.h` for details.
Andrew Rayskiy8fdfb672022-11-04 00:26:3093//
94
Andrew Rayskiy3cf073392022-11-11 00:31:4995template <class Source, class Observer>
Sigurdur Asgeirsson046f5c72020-11-04 16:48:4396class ScopedObservation {
97 public:
98 explicit ScopedObservation(Observer* observer) : observer_(observer) {}
99 ScopedObservation(const ScopedObservation&) = delete;
100 ScopedObservation& operator=(const ScopedObservation&) = delete;
Sigurdur Asgeirssonc7a6ac22020-11-23 17:59:19101 ~ScopedObservation() { Reset(); }
Sigurdur Asgeirsson046f5c72020-11-04 16:48:43102
103 // Adds the object passed to the constructor as an observer on |source|.
104 // IsObserving() must be false.
105 void Observe(Source* source) {
Anthony Vallee-Dubois331683b2023-02-17 17:06:46106 DCHECK_EQ(source_, nullptr);
Sigurdur Asgeirsson046f5c72020-11-04 16:48:43107 source_ = source;
Andrew Rayskiy8fdfb672022-11-04 00:26:30108 Traits::AddObserver(source_, observer_);
Sigurdur Asgeirsson046f5c72020-11-04 16:48:43109 }
110
Sigurdur Asgeirssonc7a6ac22020-11-23 17:59:19111 // Remove the object passed to the constructor as an observer from |source_|
112 // if currently observing. Does nothing otherwise.
113 void Reset() {
Sigurdur Asgeirsson518e2082020-12-09 13:00:27114 if (source_) {
Andrew Rayskiy8fdfb672022-11-04 00:26:30115 Traits::RemoveObserver(source_, observer_);
Sigurdur Asgeirsson518e2082020-12-09 13:00:27116 source_ = nullptr;
117 }
Sigurdur Asgeirsson046f5c72020-11-04 16:48:43118 }
119
120 // Returns true if any source is being observed.
121 bool IsObserving() const { return source_ != nullptr; }
122
123 // Returns true if |source| is being observed.
Sigurdur Asgeirsson61cc21542020-11-19 00:12:07124 bool IsObservingSource(Source* source) const {
125 DCHECK(source);
126 return source_ == source;
127 }
Sigurdur Asgeirsson046f5c72020-11-04 16:48:43128
129 private:
Andrew Rayskiy3cf073392022-11-11 00:31:49130 using Traits = ScopedObservationTraits<Source, Observer>;
Andrew Rayskiy8fdfb672022-11-04 00:26:30131
Paul Semel8311c1a32023-05-04 17:12:46132 const raw_ptr<Observer, DanglingUntriaged> observer_;
Sigurdur Asgeirsson046f5c72020-11-04 16:48:43133
134 // The observed source, if any.
Paul Semeld40aad182023-06-06 17:39:30135 raw_ptr<Source, LeakedDanglingUntriaged> source_ = nullptr;
Sigurdur Asgeirsson046f5c72020-11-04 16:48:43136};
137
Sigurdur Asgeirsson80f6e8f2020-11-04 20:14:15138} // namespace base
139
Sigurdur Asgeirsson046f5c72020-11-04 16:48:43140#endif // BASE_SCOPED_OBSERVATION_H_