blob: c452c79b3843f5447b47ebd2149f5ede72ddb78d [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#include "rtc_base/callback_list.h"
Karl Wiberg3d452cf2020-09-11 14:09:4612
Karl Wiberg01a36f32020-11-11 10:48:0413#include "rtc_base/checks.h"
14
Karl Wiberg3d452cf2020-09-11 14:09:4615namespace webrtc {
Mirko Bonadei3d259352020-10-23 10:04:4016namespace callback_list_impl {
Karl Wiberg3d452cf2020-09-11 14:09:4617
Mirko Bonadei3d259352020-10-23 10:04:4018CallbackListReceivers::CallbackListReceivers() = default;
Karl Wiberg01a36f32020-11-11 10:48:0419
20CallbackListReceivers::~CallbackListReceivers() {
21 RTC_CHECK(!send_in_progress_);
22}
Karl Wiberg3d452cf2020-09-11 14:09:4623
Karl Wiberg54b91412020-11-25 20:26:1724void CallbackListReceivers::RemoveReceivers(const void* removal_tag) {
Tomas Gunnarsson8bd5d482022-04-09 15:49:0025 RTC_DCHECK(removal_tag);
Karl Wiberg54b91412020-11-25 20:26:1726
27 // We divide the receivers_ vector into three regions: from right to left, the
28 // "keep" region, the "todo" region, and the "remove" region. The "todo"
29 // region initially covers the whole vector.
30 size_t first_todo = 0; // First element of the "todo"
31 // region.
32 size_t first_remove = receivers_.size(); // First element of the "remove"
33 // region.
34
35 // Loop until the "todo" region is empty.
36 while (first_todo != first_remove) {
37 if (receivers_[first_todo].removal_tag != removal_tag) {
38 // The first element of the "todo" region should be kept. Move the
39 // "keep"/"todo" boundary.
40 ++first_todo;
41 } else if (receivers_[first_remove - 1].removal_tag == removal_tag) {
42 // The last element of the "todo" region should be removed. Move the
43 // "todo"/"remove" boundary.
Tomas Gunnarsson8bd5d482022-04-09 15:49:0044 if (send_in_progress_) {
45 // Tag this receiver for removal, which will be done when `ForEach`
46 // has completed.
47 receivers_[first_remove - 1].removal_tag = pending_removal_tag();
48 }
Karl Wiberg54b91412020-11-25 20:26:1749 --first_remove;
Tomas Gunnarsson8bd5d482022-04-09 15:49:0050 } else if (!send_in_progress_) {
Karl Wiberg54b91412020-11-25 20:26:1751 // The first element of the "todo" region should be removed, and the last
52 // element of the "todo" region should be kept. Swap them, and then shrink
53 // the "todo" region from both ends.
54 RTC_DCHECK_NE(first_todo, first_remove - 1);
55 using std::swap;
56 swap(receivers_[first_todo], receivers_[first_remove - 1]);
57 RTC_DCHECK_NE(receivers_[first_todo].removal_tag, removal_tag);
58 ++first_todo;
59 RTC_DCHECK_EQ(receivers_[first_remove - 1].removal_tag, removal_tag);
60 --first_remove;
61 }
62 }
63
Tomas Gunnarsson8bd5d482022-04-09 15:49:0064 if (!send_in_progress_) {
65 // Discard the remove region.
66 receivers_.resize(first_remove);
67 }
Karl Wiberg54b91412020-11-25 20:26:1768}
69
Mirko Bonadei3d259352020-10-23 10:04:4070void CallbackListReceivers::Foreach(
Karl Wiberg3d452cf2020-09-11 14:09:4671 rtc::FunctionView<void(UntypedFunction&)> fv) {
Karl Wiberg01a36f32020-11-11 10:48:0472 RTC_CHECK(!send_in_progress_);
Tomas Gunnarsson8bd5d482022-04-09 15:49:0073 bool removals_detected = false;
Karl Wiberg01a36f32020-11-11 10:48:0474 send_in_progress_ = true;
Karl Wiberg3d452cf2020-09-11 14:09:4675 for (auto& r : receivers_) {
Tomas Gunnarsson8bd5d482022-04-09 15:49:0076 RTC_DCHECK_NE(r.removal_tag, pending_removal_tag());
Karl Wiberg54b91412020-11-25 20:26:1777 fv(r.function);
Tomas Gunnarsson8bd5d482022-04-09 15:49:0078 if (r.removal_tag == pending_removal_tag()) {
79 removals_detected = true;
80 }
Karl Wiberg3d452cf2020-09-11 14:09:4681 }
Karl Wiberg01a36f32020-11-11 10:48:0482 send_in_progress_ = false;
Tomas Gunnarsson8bd5d482022-04-09 15:49:0083 if (removals_detected) {
84 RemoveReceivers(pending_removal_tag());
85 }
Karl Wiberg3d452cf2020-09-11 14:09:4686}
87
Mirko Bonadei3d259352020-10-23 10:04:4088template void CallbackListReceivers::AddReceiver(
Karl Wiberg54b91412020-11-25 20:26:1789 const void*,
90 UntypedFunction::TrivialUntypedFunctionArgs<1>);
91template void CallbackListReceivers::AddReceiver(
92 const void*,
93 UntypedFunction::TrivialUntypedFunctionArgs<2>);
94template void CallbackListReceivers::AddReceiver(
95 const void*,
96 UntypedFunction::TrivialUntypedFunctionArgs<3>);
97template void CallbackListReceivers::AddReceiver(
98 const void*,
99 UntypedFunction::TrivialUntypedFunctionArgs<4>);
100template void CallbackListReceivers::AddReceiver(
101 const void*,
102 UntypedFunction::NontrivialUntypedFunctionArgs);
103template void CallbackListReceivers::AddReceiver(
104 const void*,
105 UntypedFunction::FunctionPointerUntypedFunctionArgs);
106
107template void CallbackListReceivers::AddReceiver(
Karl Wibergd2c69672020-09-29 11:55:13108 UntypedFunction::TrivialUntypedFunctionArgs<1>);
Mirko Bonadei3d259352020-10-23 10:04:40109template void CallbackListReceivers::AddReceiver(
Karl Wibergd2c69672020-09-29 11:55:13110 UntypedFunction::TrivialUntypedFunctionArgs<2>);
Mirko Bonadei3d259352020-10-23 10:04:40111template void CallbackListReceivers::AddReceiver(
Karl Wibergd2c69672020-09-29 11:55:13112 UntypedFunction::TrivialUntypedFunctionArgs<3>);
Mirko Bonadei3d259352020-10-23 10:04:40113template void CallbackListReceivers::AddReceiver(
Karl Wibergd2c69672020-09-29 11:55:13114 UntypedFunction::TrivialUntypedFunctionArgs<4>);
Mirko Bonadei3d259352020-10-23 10:04:40115template void CallbackListReceivers::AddReceiver(
Karl Wibergd2c69672020-09-29 11:55:13116 UntypedFunction::NontrivialUntypedFunctionArgs);
Mirko Bonadei3d259352020-10-23 10:04:40117template void CallbackListReceivers::AddReceiver(
Karl Wibergd2c69672020-09-29 11:55:13118 UntypedFunction::FunctionPointerUntypedFunctionArgs);
119
Mirko Bonadei3d259352020-10-23 10:04:40120} // namespace callback_list_impl
Karl Wiberg3d452cf2020-09-11 14:09:46121} // namespace webrtc