xref: /aosp_15_r20/external/webrtc/rtc_base/callback_list.h (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright 2020 The WebRTC Project Authors. All rights reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #ifndef RTC_BASE_CALLBACK_LIST_H_
12 #define RTC_BASE_CALLBACK_LIST_H_
13 
14 #include <utility>
15 #include <vector>
16 
17 #include "api/function_view.h"
18 #include "rtc_base/checks.h"
19 #include "rtc_base/system/assume.h"
20 #include "rtc_base/system/inline.h"
21 #include "rtc_base/system/rtc_export.h"
22 #include "rtc_base/untyped_function.h"
23 
24 namespace webrtc {
25 namespace callback_list_impl {
26 
27 class RTC_EXPORT CallbackListReceivers {
28  public:
29   CallbackListReceivers();
30   CallbackListReceivers(const CallbackListReceivers&) = delete;
31   CallbackListReceivers& operator=(const CallbackListReceivers&) = delete;
32   CallbackListReceivers(CallbackListReceivers&&) = delete;
33   CallbackListReceivers& operator=(CallbackListReceivers&&) = delete;
34   ~CallbackListReceivers();
35 
36   template <typename UntypedFunctionArgsT>
AddReceiver(const void * removal_tag,UntypedFunctionArgsT args)37   RTC_NO_INLINE void AddReceiver(const void* removal_tag,
38                                  UntypedFunctionArgsT args) {
39     RTC_CHECK(!send_in_progress_);
40     RTC_DCHECK(removal_tag != nullptr);
41     receivers_.push_back({removal_tag, UntypedFunction::Create(args)});
42   }
43 
44   template <typename UntypedFunctionArgsT>
AddReceiver(UntypedFunctionArgsT args)45   RTC_NO_INLINE void AddReceiver(UntypedFunctionArgsT args) {
46     RTC_CHECK(!send_in_progress_);
47     receivers_.push_back({nullptr, UntypedFunction::Create(args)});
48   }
49 
50   void RemoveReceivers(const void* removal_tag);
51 
52   void Foreach(rtc::FunctionView<void(UntypedFunction&)> fv);
53 
54  private:
55   // Special protected pointer value that's used as a removal_tag for
56   // receivers that want to unsubscribe from within a callback.
57   // Note we could use `&receivers_` too, but since it's the first member
58   // variable of the class, its address will be the same as the instance
59   // CallbackList instance, so we take an extra step to avoid collision.
pending_removal_tag()60   const void* pending_removal_tag() const { return &send_in_progress_; }
61 
62   struct Callback {
63     const void* removal_tag;
64     UntypedFunction function;
65   };
66 
67   std::vector<Callback> receivers_;
68   bool send_in_progress_ = false;
69 };
70 
71 extern template void CallbackListReceivers::AddReceiver(
72     const void*,
73     UntypedFunction::TrivialUntypedFunctionArgs<1>);
74 extern template void CallbackListReceivers::AddReceiver(
75     const void*,
76     UntypedFunction::TrivialUntypedFunctionArgs<2>);
77 extern template void CallbackListReceivers::AddReceiver(
78     const void*,
79     UntypedFunction::TrivialUntypedFunctionArgs<3>);
80 extern template void CallbackListReceivers::AddReceiver(
81     const void*,
82     UntypedFunction::TrivialUntypedFunctionArgs<4>);
83 extern template void CallbackListReceivers::AddReceiver(
84     const void*,
85     UntypedFunction::NontrivialUntypedFunctionArgs);
86 extern template void CallbackListReceivers::AddReceiver(
87     const void*,
88     UntypedFunction::FunctionPointerUntypedFunctionArgs);
89 
90 extern template void CallbackListReceivers::AddReceiver(
91     UntypedFunction::TrivialUntypedFunctionArgs<1>);
92 extern template void CallbackListReceivers::AddReceiver(
93     UntypedFunction::TrivialUntypedFunctionArgs<2>);
94 extern template void CallbackListReceivers::AddReceiver(
95     UntypedFunction::TrivialUntypedFunctionArgs<3>);
96 extern template void CallbackListReceivers::AddReceiver(
97     UntypedFunction::TrivialUntypedFunctionArgs<4>);
98 extern template void CallbackListReceivers::AddReceiver(
99     UntypedFunction::NontrivialUntypedFunctionArgs);
100 extern template void CallbackListReceivers::AddReceiver(
101     UntypedFunction::FunctionPointerUntypedFunctionArgs);
102 
103 }  // namespace callback_list_impl
104 
105 // A collection of receivers (callable objects) that can be called all at once.
106 // Optimized for minimal binary size. The template arguments dictate what
107 // signature the callbacks must have; for example, a CallbackList<int, float>
108 // will require callbacks with signature void(int, float).
109 //
110 // CallbackList is neither copyable nor movable (could easily be made movable if
111 // necessary). Callbacks must be movable, but need not be copyable.
112 //
113 // Usage example:
114 //
115 //   // Declaration (usually a member variable).
116 //   CallbackList<int, float> foo_;
117 //
118 //   // Register callbacks. This can be done zero or more times. The
119 //   // callbacks must accept the arguments types listed in the CallbackList's
120 //   // template argument list, and must return void.
121 //   foo_.AddReceiver([...](int a, float b) {...});  // Lambda.
122 //   foo_.AddReceiver(SomeFunction);                 // Function pointer.
123 //
124 //   // Call the zero or more receivers, one after the other.
125 //   foo_.Send(17, 3.14);
126 //
127 // Callback lifetime considerations
128 // --------------------------------
129 //
130 // CallbackList::AddReceiver() takes ownership of the given callback by moving
131 // it in place. The callback can be any callable object; in particular, it may
132 // have a nontrivial destructor, which will be run when the CallbackList is
133 // destroyed. The callback may thus access data via any type of smart pointer,
134 // expressing e.g. unique, shared, or weak ownership. Of course, if the data is
135 // guaranteed to outlive the callback, a plain raw pointer can be used.
136 //
137 // Take care when trying to have the callback own reference-counted data. The
138 // CallbackList will keep the callback alive, and the callback will keep its
139 // data alive, so as usual with reference-counted ownership, keep an eye out for
140 // cycles!
141 //
142 // Thread safety
143 // -------------
144 //
145 // Like most C++ types, CallbackList is thread compatible: it's not safe to
146 // access it concurrently from multiple threads, but it can be made safe if it
147 // is protected by a mutex, for example.
148 //
149 // Excercise some care when deciding what mutexes to hold when you call
150 // CallbackList::Send(). In particular, do not hold mutexes that callbacks may
151 // need to grab. If a larger object has a CallbackList member and a single mutex
152 // that protects all of its data members, this may e.g. make it necessary to
153 // protect its CallbackList with a separate mutex; otherwise, there will be a
154 // deadlock if the callbacks try to access the object.
155 //
156 // CallbackList as a class data member
157 // -----------------------------------
158 //
159 // CallbackList is a normal C++ data type, and should be private when it is a
160 // data member of a class. For thread safety reasons (see above), it is likely
161 // best to not have an accessor for the entire CallbackList, and instead only
162 // allow callers to add callbacks:
163 //
164 //   template <typename F>
165 //   void AddFooCallback(F&& callback) {
166 //     // Maybe grab a mutex here?
167 //     foo_callbacks_.AddReceiver(std::forward<F>(callback));
168 //   }
169 //
170 template <typename... ArgT>
171 class CallbackList {
172  public:
173   CallbackList() = default;
174   CallbackList(const CallbackList&) = delete;
175   CallbackList& operator=(const CallbackList&) = delete;
176   CallbackList(CallbackList&&) = delete;
177   CallbackList& operator=(CallbackList&&) = delete;
178 
179   // Adds a new receiver. The receiver (a callable object or a function pointer)
180   // must be movable, but need not be copyable. Its call signature should be
181   // `void(ArgT...)`. The removal tag is a pointer to an arbitrary object that
182   // you own, and that will stay alive until the CallbackList is gone, or until
183   // all receivers using it as a removal tag have been removed; you can use it
184   // to remove the receiver.
185   template <typename F>
AddReceiver(const void * removal_tag,F && f)186   void AddReceiver(const void* removal_tag, F&& f) {
187     receivers_.AddReceiver(
188         removal_tag,
189         UntypedFunction::PrepareArgs<void(ArgT...)>(std::forward<F>(f)));
190   }
191 
192   // Adds a new receiver with no removal tag.
193   template <typename F>
AddReceiver(F && f)194   void AddReceiver(F&& f) {
195     receivers_.AddReceiver(
196         UntypedFunction::PrepareArgs<void(ArgT...)>(std::forward<F>(f)));
197   }
198 
199   // Removes all receivers that were added with the given removal tag.
RemoveReceivers(const void * removal_tag)200   void RemoveReceivers(const void* removal_tag) {
201     receivers_.RemoveReceivers(removal_tag);
202   }
203 
204   // Calls all receivers with the given arguments. While the Send is in
205   // progress, no method calls are allowed; specifically, this means that the
206   // callbacks may not do anything with this CallbackList instance.
207   //
208   // Note: Receivers are called serially, but not necessarily in the same order
209   // they were added.
210   template <typename... ArgU>
Send(ArgU &&...args)211   void Send(ArgU&&... args) {
212     receivers_.Foreach([&](UntypedFunction& f) {
213       f.Call<void(ArgT...)>(std::forward<ArgU>(args)...);
214     });
215   }
216 
217  private:
218   callback_list_impl::CallbackListReceivers receivers_;
219 };
220 
221 }  // namespace webrtc
222 
223 #endif  // RTC_BASE_CALLBACK_LIST_H_
224