blob: a9d71a6562a7c99785af1ffe4727dd2f74dabbd6 [file] [log] [blame]
Karl Wiberg3d452cf2020-09-11 16:09:46 +02001/*
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
Mirko Bonadei3d259352020-10-23 12:04:40 +020011#ifndef RTC_BASE_CALLBACK_LIST_H_
12#define RTC_BASE_CALLBACK_LIST_H_
Karl Wiberg3d452cf2020-09-11 16:09:46 +020013
14#include <utility>
15#include <vector>
16
17#include "api/function_view.h"
Karl Wiberg01a36f32020-11-11 11:48:04 +010018#include "rtc_base/checks.h"
Karl Wiberg3d452cf2020-09-11 16:09:46 +020019#include "rtc_base/system/assume.h"
Karl Wibergd2c69672020-09-29 13:55:13 +020020#include "rtc_base/system/inline.h"
Tomas Gunnarsson9797dcd2022-04-10 13:27:13 +020021#include "rtc_base/system/rtc_export.h"
Karl Wiberg70026f92020-09-18 10:03:16 +020022#include "rtc_base/untyped_function.h"
Karl Wiberg3d452cf2020-09-11 16:09:46 +020023
24namespace webrtc {
Mirko Bonadei3d259352020-10-23 12:04:40 +020025namespace callback_list_impl {
Karl Wiberg3d452cf2020-09-11 16:09:46 +020026
Tomas Gunnarsson9797dcd2022-04-10 13:27:13 +020027class RTC_EXPORT CallbackListReceivers {
Karl Wiberg3d452cf2020-09-11 16:09:46 +020028 public:
Mirko Bonadei3d259352020-10-23 12:04:40 +020029 CallbackListReceivers();
30 CallbackListReceivers(const CallbackListReceivers&) = delete;
31 CallbackListReceivers& operator=(const CallbackListReceivers&) = delete;
32 CallbackListReceivers(CallbackListReceivers&&) = delete;
33 CallbackListReceivers& operator=(CallbackListReceivers&&) = delete;
34 ~CallbackListReceivers();
Karl Wiberg8d875582020-09-18 09:59:50 +020035
Karl Wibergd2c69672020-09-29 13:55:13 +020036 template <typename UntypedFunctionArgsT>
Karl Wiberg54b91412020-11-25 21:26:17 +010037 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>
Karl Wibergd2c69672020-09-29 13:55:13 +020045 RTC_NO_INLINE void AddReceiver(UntypedFunctionArgsT args) {
Karl Wiberg01a36f32020-11-11 11:48:04 +010046 RTC_CHECK(!send_in_progress_);
Karl Wiberg54b91412020-11-25 21:26:17 +010047 receivers_.push_back({nullptr, UntypedFunction::Create(args)});
Karl Wiberg3d452cf2020-09-11 16:09:46 +020048 }
Karl Wiberg8d875582020-09-18 09:59:50 +020049
Karl Wiberg54b91412020-11-25 21:26:17 +010050 void RemoveReceivers(const void* removal_tag);
51
Karl Wiberg3d452cf2020-09-11 16:09:46 +020052 void Foreach(rtc::FunctionView<void(UntypedFunction&)> fv);
53
54 private:
Tomas Gunnarsson8bd5d482022-04-09 17:49:00 +020055 // 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.
60 const void* pending_removal_tag() const { return &send_in_progress_; }
61
Karl Wiberg54b91412020-11-25 21:26:17 +010062 struct Callback {
63 const void* removal_tag;
64 UntypedFunction function;
65 };
Tomas Gunnarsson8bd5d482022-04-09 17:49:00 +020066
Karl Wiberg54b91412020-11-25 21:26:17 +010067 std::vector<Callback> receivers_;
Karl Wiberg01a36f32020-11-11 11:48:04 +010068 bool send_in_progress_ = false;
Karl Wiberg3d452cf2020-09-11 16:09:46 +020069};
70
Mirko Bonadei3d259352020-10-23 12:04:40 +020071extern template void CallbackListReceivers::AddReceiver(
Karl Wiberg54b91412020-11-25 21:26:17 +010072 const void*,
73 UntypedFunction::TrivialUntypedFunctionArgs<1>);
74extern template void CallbackListReceivers::AddReceiver(
75 const void*,
76 UntypedFunction::TrivialUntypedFunctionArgs<2>);
77extern template void CallbackListReceivers::AddReceiver(
78 const void*,
79 UntypedFunction::TrivialUntypedFunctionArgs<3>);
80extern template void CallbackListReceivers::AddReceiver(
81 const void*,
82 UntypedFunction::TrivialUntypedFunctionArgs<4>);
83extern template void CallbackListReceivers::AddReceiver(
84 const void*,
85 UntypedFunction::NontrivialUntypedFunctionArgs);
86extern template void CallbackListReceivers::AddReceiver(
87 const void*,
88 UntypedFunction::FunctionPointerUntypedFunctionArgs);
89
90extern template void CallbackListReceivers::AddReceiver(
Karl Wibergd2c69672020-09-29 13:55:13 +020091 UntypedFunction::TrivialUntypedFunctionArgs<1>);
Mirko Bonadei3d259352020-10-23 12:04:40 +020092extern template void CallbackListReceivers::AddReceiver(
Karl Wibergd2c69672020-09-29 13:55:13 +020093 UntypedFunction::TrivialUntypedFunctionArgs<2>);
Mirko Bonadei3d259352020-10-23 12:04:40 +020094extern template void CallbackListReceivers::AddReceiver(
Karl Wibergd2c69672020-09-29 13:55:13 +020095 UntypedFunction::TrivialUntypedFunctionArgs<3>);
Mirko Bonadei3d259352020-10-23 12:04:40 +020096extern template void CallbackListReceivers::AddReceiver(
Karl Wibergd2c69672020-09-29 13:55:13 +020097 UntypedFunction::TrivialUntypedFunctionArgs<4>);
Mirko Bonadei3d259352020-10-23 12:04:40 +020098extern template void CallbackListReceivers::AddReceiver(
Karl Wibergd2c69672020-09-29 13:55:13 +020099 UntypedFunction::NontrivialUntypedFunctionArgs);
Mirko Bonadei3d259352020-10-23 12:04:40 +0200100extern template void CallbackListReceivers::AddReceiver(
Karl Wibergd2c69672020-09-29 13:55:13 +0200101 UntypedFunction::FunctionPointerUntypedFunctionArgs);
102
Mirko Bonadei3d259352020-10-23 12:04:40 +0200103} // namespace callback_list_impl
Karl Wiberg3d452cf2020-09-11 16:09:46 +0200104
105// A collection of receivers (callable objects) that can be called all at once.
Karl Wiberg1a88ea12020-11-09 10:36:32 +0100106// 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).
Karl Wiberg3d452cf2020-09-11 16:09:46 +0200109//
Karl Wiberg1a88ea12020-11-09 10:36:32 +0100110// CallbackList is neither copyable nor movable (could easily be made movable if
111// necessary). Callbacks must be movable, but need not be copyable.
Karl Wiberg8d875582020-09-18 09:59:50 +0200112//
Karl Wiberg1a88ea12020-11-09 10:36:32 +0100113// 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//
Karl Wiberg3d452cf2020-09-11 16:09:46 +0200170template <typename... ArgT>
Mirko Bonadei3d259352020-10-23 12:04:40 +0200171class CallbackList {
Karl Wiberg3d452cf2020-09-11 16:09:46 +0200172 public:
Mirko Bonadei3d259352020-10-23 12:04:40 +0200173 CallbackList() = default;
174 CallbackList(const CallbackList&) = delete;
175 CallbackList& operator=(const CallbackList&) = delete;
176 CallbackList(CallbackList&&) = delete;
177 CallbackList& operator=(CallbackList&&) = delete;
Karl Wiberg8d875582020-09-18 09:59:50 +0200178
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
Karl Wiberg54b91412020-11-25 21:26:17 +0100181 // `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>
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.
Karl Wiberg3d452cf2020-09-11 16:09:46 +0200193 template <typename F>
194 void AddReceiver(F&& f) {
195 receivers_.AddReceiver(
Karl Wibergd2c69672020-09-29 13:55:13 +0200196 UntypedFunction::PrepareArgs<void(ArgT...)>(std::forward<F>(f)));
Karl Wiberg3d452cf2020-09-11 16:09:46 +0200197 }
Karl Wiberg8d875582020-09-18 09:59:50 +0200198
Karl Wiberg54b91412020-11-25 21:26:17 +0100199 // Removes all receivers that were added with the given removal tag.
200 void RemoveReceivers(const void* removal_tag) {
201 receivers_.RemoveReceivers(removal_tag);
202 }
203
Karl Wiberg01a36f32020-11-11 11:48:04 +0100204 // 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.
Karl Wiberg54b91412020-11-25 21:26:17 +0100207 //
208 // Note: Receivers are called serially, but not necessarily in the same order
209 // they were added.
Karl Wibergd88b1692020-09-25 06:16:12 +0200210 template <typename... ArgU>
211 void Send(ArgU&&... args) {
Karl Wiberg3d452cf2020-09-11 16:09:46 +0200212 receivers_.Foreach([&](UntypedFunction& f) {
Karl Wibergd88b1692020-09-25 06:16:12 +0200213 f.Call<void(ArgT...)>(std::forward<ArgU>(args)...);
Karl Wiberg3d452cf2020-09-11 16:09:46 +0200214 });
215 }
216
217 private:
Mirko Bonadei3d259352020-10-23 12:04:40 +0200218 callback_list_impl::CallbackListReceivers receivers_;
Karl Wiberg3d452cf2020-09-11 16:09:46 +0200219};
220
221} // namespace webrtc
222
Mirko Bonadei3d259352020-10-23 12:04:40 +0200223#endif // RTC_BASE_CALLBACK_LIST_H_