Avi Drissman | e4622aa | 2022-09-08 20:36:06 | [diff] [blame] | 1 | // Copyright 2020 The Chromium Authors |
Sigurdur Asgeirsson | 1a164fd | 2020-11-05 20:13:17 | [diff] [blame] | 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_MULTI_SOURCE_OBSERVATION_H_ |
| 6 | #define BASE_SCOPED_MULTI_SOURCE_OBSERVATION_H_ |
| 7 | |
| 8 | #include <stddef.h> |
| 9 | |
Peter Kasting | 025a9425 | 2025-01-29 21:28:37 | [diff] [blame] | 10 | #include <algorithm> |
Sigurdur Asgeirsson | 1a164fd | 2020-11-05 20:13:17 | [diff] [blame] | 11 | #include <vector> |
| 12 | |
| 13 | #include "base/check.h" |
Jan Wilken Dörrie | b5a41c3 | 2020-12-09 18:55:47 | [diff] [blame] | 14 | #include "base/containers/contains.h" |
Keishi Hattori | 0e45c02 | 2021-11-27 09:25:52 | [diff] [blame] | 15 | #include "base/memory/raw_ptr.h" |
Andrew Rayskiy | 799ce71 | 2022-11-04 22:42:53 | [diff] [blame] | 16 | #include "base/scoped_observation_traits.h" |
Sigurdur Asgeirsson | 1a164fd | 2020-11-05 20:13:17 | [diff] [blame] | 17 | |
| 18 | namespace base { |
| 19 | |
Sigurdur Asgeirsson | 1103165 | 2020-11-12 17:44:25 | [diff] [blame] | 20 | // ScopedMultiSourceObservation is used to keep track of plural observation, |
| 21 | // e.g. where an observer observes more than a single source. |
Sigurdur Asgeirsson | 1a164fd | 2020-11-05 20:13:17 | [diff] [blame] | 22 | // |
Sigurdur Asgeirsson | 1103165 | 2020-11-12 17:44:25 | [diff] [blame] | 23 | // Use base::ScopedObservation for objects that observe only a single source. |
Sigurdur Asgeirsson | 1a164fd | 2020-11-05 20:13:17 | [diff] [blame] | 24 | // |
Sigurdur Asgeirsson | 1103165 | 2020-11-12 17:44:25 | [diff] [blame] | 25 | // When ScopedMultiSourceObservation is destroyed, it removes the object as an |
Sigurdur Asgeirsson | 1a164fd | 2020-11-05 20:13:17 | [diff] [blame] | 26 | // observer from all sources it has been added to. |
| 27 | // Basic example (as a member variable): |
| 28 | // |
| 29 | // class MyFooObserver : public FooObserver { |
| 30 | // ... |
| 31 | // private: |
Sigurdur Asgeirsson | 1103165 | 2020-11-12 17:44:25 | [diff] [blame] | 32 | // ScopedMultiSourceObservation<Foo, FooObserver> foo_observations_{this}; |
Sigurdur Asgeirsson | 1a164fd | 2020-11-05 20:13:17 | [diff] [blame] | 33 | // }; |
| 34 | // |
Sigurdur Asgeirsson | 1103165 | 2020-11-12 17:44:25 | [diff] [blame] | 35 | // MyFooObserver::OnFooCreated(Foo* foo) { |
| 36 | // foo_observations_.AddObservation(foo); |
| 37 | // } |
| 38 | // |
Andrew Rayskiy | 799ce71 | 2022-11-04 22:42:53 | [diff] [blame] | 39 | //////////////////////////////////////////////////////////////////////////////// |
Sigurdur Asgeirsson | 1a164fd | 2020-11-05 20:13:17 | [diff] [blame] | 40 | // |
Andrew Rayskiy | 799ce71 | 2022-11-04 22:42:53 | [diff] [blame] | 41 | // By default `ScopedMultiSourceObservation` only works with sources that expose |
| 42 | // `AddObserver` and `RemoveObserver`. However, it's also possible to |
| 43 | // adapt it to custom function names (say `AddFoo` and `RemoveFoo` accordingly) |
Andrew Rayskiy | 3cf07339 | 2022-11-11 00:31:49 | [diff] [blame] | 44 | // by tailoring ScopedObservationTraits<> for the given Source and Observer -- |
| 45 | // see `base/scoped_observation_traits.h` for details. |
Andrew Rayskiy | 799ce71 | 2022-11-04 22:42:53 | [diff] [blame] | 46 | // |
| 47 | |
Andrew Rayskiy | 3cf07339 | 2022-11-11 00:31:49 | [diff] [blame] | 48 | template <class Source, class Observer> |
Sigurdur Asgeirsson | 1a164fd | 2020-11-05 20:13:17 | [diff] [blame] | 49 | class ScopedMultiSourceObservation { |
| 50 | public: |
| 51 | explicit ScopedMultiSourceObservation(Observer* observer) |
| 52 | : observer_(observer) {} |
| 53 | ScopedMultiSourceObservation(const ScopedMultiSourceObservation&) = delete; |
| 54 | ScopedMultiSourceObservation& operator=(const ScopedMultiSourceObservation&) = |
| 55 | delete; |
| 56 | ~ScopedMultiSourceObservation() { RemoveAllObservations(); } |
| 57 | |
| 58 | // Adds the object passed to the constructor as an observer on |source|. |
| 59 | void AddObservation(Source* source) { |
Peter Kasting | 013e3645 | 2024-02-03 13:15:28 | [diff] [blame] | 60 | CHECK(!IsObservingSource(source)); |
Sigurdur Asgeirsson | 1a164fd | 2020-11-05 20:13:17 | [diff] [blame] | 61 | sources_.push_back(source); |
Andrew Rayskiy | 799ce71 | 2022-11-04 22:42:53 | [diff] [blame] | 62 | Traits::AddObserver(source, observer_); |
Sigurdur Asgeirsson | 1a164fd | 2020-11-05 20:13:17 | [diff] [blame] | 63 | } |
| 64 | |
| 65 | // Remove the object passed to the constructor as an observer from |source|. |
| 66 | void RemoveObservation(Source* source) { |
Peter Kasting | 025a9425 | 2025-01-29 21:28:37 | [diff] [blame] | 67 | auto it = std::ranges::find(sources_, source); |
Peter Boström | 1aec0b2 | 2023-02-24 00:33:06 | [diff] [blame] | 68 | CHECK(it != sources_.end()); |
Sigurdur Asgeirsson | 1a164fd | 2020-11-05 20:13:17 | [diff] [blame] | 69 | sources_.erase(it); |
Andrew Rayskiy | 799ce71 | 2022-11-04 22:42:53 | [diff] [blame] | 70 | Traits::RemoveObserver(source, observer_); |
Sigurdur Asgeirsson | 1a164fd | 2020-11-05 20:13:17 | [diff] [blame] | 71 | } |
| 72 | |
Sigurdur Asgeirsson | 1103165 | 2020-11-12 17:44:25 | [diff] [blame] | 73 | // Remove the object passed to the constructor as an observer from all sources |
| 74 | // it's observing. |
Sigurdur Asgeirsson | 1a164fd | 2020-11-05 20:13:17 | [diff] [blame] | 75 | void RemoveAllObservations() { |
Andrew Rayskiy | 799ce71 | 2022-11-04 22:42:53 | [diff] [blame] | 76 | for (Source* source : sources_) { |
| 77 | Traits::RemoveObserver(source, observer_); |
| 78 | } |
Sigurdur Asgeirsson | 1a164fd | 2020-11-05 20:13:17 | [diff] [blame] | 79 | sources_.clear(); |
| 80 | } |
| 81 | |
Sigurdur Asgeirsson | 1103165 | 2020-11-12 17:44:25 | [diff] [blame] | 82 | // Returns true if any source is being observed. |
| 83 | bool IsObservingAnySource() const { return !sources_.empty(); } |
| 84 | |
| 85 | // Returns true if |source| is being observed. |
Sigurdur Asgeirsson | 1a164fd | 2020-11-05 20:13:17 | [diff] [blame] | 86 | bool IsObservingSource(Source* source) const { |
Sigurdur Asgeirsson | 61cc2154 | 2020-11-19 00:12:07 | [diff] [blame] | 87 | DCHECK(source); |
Sigurdur Asgeirsson | 1a164fd | 2020-11-05 20:13:17 | [diff] [blame] | 88 | return base::Contains(sources_, source); |
| 89 | } |
| 90 | |
Sigurdur Asgeirsson | 1103165 | 2020-11-12 17:44:25 | [diff] [blame] | 91 | // Returns the number of sources being observed. |
Sigurdur Asgeirsson | 1a164fd | 2020-11-05 20:13:17 | [diff] [blame] | 92 | size_t GetSourcesCount() const { return sources_.size(); } |
| 93 | |
Theo Cristea | 09b9456 | 2024-09-04 08:07:31 | [diff] [blame] | 94 | // Returns a pointer to the observer that observes the sources. |
| 95 | Observer* observer() { return observer_; } |
| 96 | const Observer* observer() const { return observer_; } |
| 97 | |
minch | 6759241 | 2024-01-05 17:20:59 | [diff] [blame] | 98 | // Returns the sources being observed. Note: It is invalid to add or remove |
| 99 | // sources while iterating on it. |
Julie Jeongeun Kim | 61027f8 | 2024-01-16 08:18:03 | [diff] [blame] | 100 | const std::vector<raw_ptr<Source>>& sources() const { return sources_; } |
minch | 6759241 | 2024-01-05 17:20:59 | [diff] [blame] | 101 | |
Sigurdur Asgeirsson | 1a164fd | 2020-11-05 20:13:17 | [diff] [blame] | 102 | private: |
Andrew Rayskiy | 3cf07339 | 2022-11-11 00:31:49 | [diff] [blame] | 103 | using Traits = ScopedObservationTraits<Source, Observer>; |
Andrew Rayskiy | 799ce71 | 2022-11-04 22:42:53 | [diff] [blame] | 104 | |
Keishi Hattori | 0e45c02 | 2021-11-27 09:25:52 | [diff] [blame] | 105 | const raw_ptr<Observer> observer_; |
Sigurdur Asgeirsson | 1a164fd | 2020-11-05 20:13:17 | [diff] [blame] | 106 | |
Julie Jeongeun Kim | 61027f8 | 2024-01-16 08:18:03 | [diff] [blame] | 107 | std::vector<raw_ptr<Source>> sources_; |
Sigurdur Asgeirsson | 1a164fd | 2020-11-05 20:13:17 | [diff] [blame] | 108 | }; |
| 109 | |
| 110 | } // namespace base |
| 111 | |
| 112 | #endif // BASE_SCOPED_MULTI_SOURCE_OBSERVATION_H_ |