blob: a9d71a6562a7c99785af1ffe4727dd2f74dabbd6 [file] [log] [blame]
Karl Wiberg3d452cf2020-09-11 14:09:461/*
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 10:04:4011#ifndef RTC_BASE_CALLBACK_LIST_H_
12#define RTC_BASE_CALLBACK_LIST_H_
Karl Wiberg3d452cf2020-09-11 14:09:4613
14#include <utility>
15#include <vector>
16
17#include "api/function_view.h"
Karl Wiberg01a36f32020-11-11 10:48:0418#include "rtc_base/checks.h"
Karl Wiberg3d452cf2020-09-11 14:09:4619#include "rtc_base/system/assume.h"
Karl Wibergd2c69672020-09-29 11:55:1320#include "rtc_base/system/inline.h"
Tomas Gunnarsson9797dcd2022-04-10 11:27:1321#include "rtc_base/system/rtc_export.h"
Karl Wiberg70026f92020-09-18 08:03:1622#include "rtc_base/untyped_function.h"
Karl Wiberg3d452cf2020-09-11 14:09:4623
24namespace webrtc {
Mirko Bonadei3d259352020-10-23 10:04:4025namespace callback_list_impl {
Karl Wiberg3d452cf2020-09-11 14:09:4626
Tomas Gunnarsson9797dcd2022-04-10 11:27:1327class RTC_EXPORT CallbackListReceivers {
Karl Wiberg3d452cf2020-09-11 14:09:4628 public:
Mirko Bonadei3d259352020-10-23 10:04:4029 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 07:59:5035
Karl Wibergd2c69672020-09-29 11:55:1336 template <typename UntypedFunctionArgsT>
Karl Wiberg54b91412020-11-25 20:26:1737 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 11:55:1345 RTC_NO_INLINE void AddReceiver(UntypedFunctionArgsT args) {
Karl Wiberg01a36f32020-11-11 10:48:0446 RTC_CHECK(!send_in_progress_);
Karl Wiberg54b91412020-11-25 20:26:1747 receivers_.push_back({nullptr, UntypedFunction::Create(args)});
Karl Wiberg3d452cf2020-09-11 14:09:4648 }
Karl Wiberg8d875582020-09-18 07:59:5049
Karl Wiberg54b91412020-11-25 20:26:1750 void RemoveReceivers(const void* removal_tag);
51
Karl Wiberg3d452cf2020-09-11 14:09:4652 void Foreach(rtc::FunctionView<void(UntypedFunction&)> fv);
53
54 private:
Tomas Gunnarsson8bd5d482022-04-09 15:49:0055 // 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 20:26:1762 struct Callback {
63 const void* removal_tag;
64 UntypedFunction function;
65 };
Tomas Gunnarsson8bd5d482022-04-09 15:49:0066
Karl Wiberg54b91412020-11-25 20:26:1767 std::vector<Callback> receivers_;
Karl Wiberg01a36f32020-11-11 10:48:0468 bool send_in_progress_ = false;
Karl Wiberg3d452cf2020-09-11 14:09:4669};
70
Mirko Bonadei3d259352020-10-23 10:04:4071extern template void CallbackListReceivers::AddReceiver(
Karl Wiberg54b91412020-11-25 20:26:1772 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 11:55:1391 UntypedFunction::TrivialUntypedFunctionArgs<1>);
Mirko Bonadei3d259352020-10-23 10:04:4092extern template void CallbackListReceivers::AddReceiver(
Karl Wibergd2c69672020-09-29 11:55:1393 UntypedFunction::TrivialUntypedFunctionArgs<2>);
Mirko Bonadei3d259352020-10-23 10:04:4094extern template void CallbackListReceivers::AddReceiver(
Karl Wibergd2c69672020-09-29 11:55:1395 UntypedFunction::TrivialUntypedFunctionArgs<3>);
Mirko Bonadei3d259352020-10-23 10:04:4096extern template void CallbackListReceivers::AddReceiver(
Karl Wibergd2c69672020-09-29 11:55:1397 UntypedFunction::TrivialUntypedFunctionArgs<4>);
Mirko Bonadei3d259352020-10-23 10:04:4098extern template void CallbackListReceivers::AddReceiver(
Karl Wibergd2c69672020-09-29 11:55:1399 UntypedFunction::NontrivialUntypedFunctionArgs);
Mirko Bonadei3d259352020-10-23 10:04:40100extern template void CallbackListReceivers::AddReceiver(
Karl Wibergd2c69672020-09-29 11:55:13101 UntypedFunction::FunctionPointerUntypedFunctionArgs);
102
Mirko Bonadei3d259352020-10-23 10:04:40103} // namespace callback_list_impl
Karl Wiberg3d452cf2020-09-11 14:09:46104
105// A collection of receivers (callable objects) that can be called all at once.
Karl Wiberg1a88ea12020-11-09 09:36:32106// 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 14:09:46109//
Karl Wiberg1a88ea12020-11-09 09:36:32110// 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 07:59:50112//
Karl Wiberg1a88ea12020-11-09 09:36:32113// 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 14:09:46170template <typename... ArgT>
Mirko Bonadei3d259352020-10-23 10:04:40171class CallbackList {
Karl Wiberg3d452cf2020-09-11 14:09:46172 public:
Mirko Bonadei3d259352020-10-23 10:04:40173 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 07:59:50178
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 20:26:17181 // `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 14:09:46193 template <typename F>
194 void AddReceiver(F&& f) {
195 receivers_.AddReceiver(
Karl Wibergd2c69672020-09-29 11:55:13196 UntypedFunction::PrepareArgs<void(ArgT...)>(std::forward<F>(f)));
Karl Wiberg3d452cf2020-09-11 14:09:46197 }
Karl Wiberg8d875582020-09-18 07:59:50198
Karl Wiberg54b91412020-11-25 20:26:17199 // 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 10:48:04204 // 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 20:26:17207 //
208 // Note: Receivers are called serially, but not necessarily in the same order
209 // they were added.
Karl Wibergd88b1692020-09-25 04:16:12210 template <typename... ArgU>
211 void Send(ArgU&&... args) {
Karl Wiberg3d452cf2020-09-11 14:09:46212 receivers_.Foreach([&](UntypedFunction& f) {
Karl Wibergd88b1692020-09-25 04:16:12213 f.Call<void(ArgT...)>(std::forward<ArgU>(args)...);
Karl Wiberg3d452cf2020-09-11 14:09:46214 });
215 }
216
217 private:
Mirko Bonadei3d259352020-10-23 10:04:40218 callback_list_impl::CallbackListReceivers receivers_;
Karl Wiberg3d452cf2020-09-11 14:09:46219};
220
221} // namespace webrtc
222
Mirko Bonadei3d259352020-10-23 10:04:40223#endif // RTC_BASE_CALLBACK_LIST_H_