1 // Copyright 2020 The Chromium Authors. All rights reserved.
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 
10 #include <vector>
11 
12 #include "base/check.h"
13 #include "base/ranges/algorithm.h"
14 #include "base/stl_util.h"
15 
16 namespace base {
17 
18 // ScopedMultiSourceObservation is used to keep track of plural observation,
19 // e.g. where an observer observes more than a single source.
20 //
21 // Use base::ScopedObservation for objects that observe only a single source.
22 // This class and base::ScopedObservation replace ScopedObserver.
23 //
24 // When ScopedMultiSourceObservation is destroyed, it removes the object as an
25 // observer from all sources it has been added to.
26 // Basic example (as a member variable):
27 //
28 //   class MyFooObserver : public FooObserver {
29 //     ...
30 //    private:
31 //     ScopedMultiSourceObservation<Foo, FooObserver> foo_observations_{this};
32 //   };
33 //
34 //   MyFooObserver::OnFooCreated(Foo* foo) {
35 //     foo_observations_.AddObservation(foo);
36 //   }
37 //
38 // For cases with methods not named AddObserver/RemoveObserver:
39 //
40 //   class MyFooStateObserver : public FooStateObserver {
41 //     ...
42 //    private:
43 //      ScopedMultiSourceObservation<Foo,
44 //                                  FooStateObserver,
45 //                                  &Foo::AddStateObserver,
46 //                                  &Foo::RemoveStateObserver>
47 //          foo_observations_{this};
48 //   };
49 template <class Source,
50           class Observer,
51           void (Source::*AddObsFn)(Observer*) = &Source::AddObserver,
52           void (Source::*RemoveObsFn)(Observer*) = &Source::RemoveObserver>
53 class ScopedMultiSourceObservation {
54  public:
ScopedMultiSourceObservation(Observer * observer)55   explicit ScopedMultiSourceObservation(Observer* observer)
56       : observer_(observer) {}
57   ScopedMultiSourceObservation(const ScopedMultiSourceObservation&) = delete;
58   ScopedMultiSourceObservation& operator=(const ScopedMultiSourceObservation&) =
59       delete;
~ScopedMultiSourceObservation()60   ~ScopedMultiSourceObservation() { RemoveAllObservations(); }
61 
62   // Adds the object passed to the constructor as an observer on |source|.
AddObservation(Source * source)63   void AddObservation(Source* source) {
64     sources_.push_back(source);
65     (source->*AddObsFn)(observer_);
66   }
67 
68   // Remove the object passed to the constructor as an observer from |source|.
RemoveObservation(Source * source)69   void RemoveObservation(Source* source) {
70     auto it = base::ranges::find(sources_, source);
71     DCHECK(it != sources_.end());
72     sources_.erase(it);
73     (source->*RemoveObsFn)(observer_);
74   }
75 
76   // Remove the object passed to the constructor as an observer from all sources
77   // it's observing.
RemoveAllObservations()78   void RemoveAllObservations() {
79     for (Source* source : sources_)
80       (source->*RemoveObsFn)(observer_);
81     sources_.clear();
82   }
83 
84   // Returns true if any source is being observed.
IsObservingAnySource()85   bool IsObservingAnySource() const { return !sources_.empty(); }
86 
87   // Returns true if |source| is being observed.
IsObservingSource(Source * source)88   bool IsObservingSource(Source* source) const {
89     return base::Contains(sources_, source);
90   }
91 
92   // Returns the number of sources being observed.
GetSourcesCount()93   size_t GetSourcesCount() const { return sources_.size(); }
94 
95  private:
96   Observer* const observer_;
97 
98   std::vector<Source*> sources_;
99 };
100 
101 }  // namespace base
102 
103 #endif  // BASE_SCOPED_MULTI_SOURCE_OBSERVATION_H_
104