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 #include "rtc_base/callback_list.h"
12
13 #include "rtc_base/checks.h"
14
15 namespace webrtc {
16 namespace callback_list_impl {
17
18 CallbackListReceivers::CallbackListReceivers() = default;
19
~CallbackListReceivers()20 CallbackListReceivers::~CallbackListReceivers() {
21 RTC_CHECK(!send_in_progress_);
22 }
23
RemoveReceivers(const void * removal_tag)24 void CallbackListReceivers::RemoveReceivers(const void* removal_tag) {
25 RTC_DCHECK(removal_tag);
26
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.
44 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 }
49 --first_remove;
50 } else if (!send_in_progress_) {
51 // 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
64 if (!send_in_progress_) {
65 // Discard the remove region.
66 receivers_.resize(first_remove);
67 }
68 }
69
Foreach(rtc::FunctionView<void (UntypedFunction &)> fv)70 void CallbackListReceivers::Foreach(
71 rtc::FunctionView<void(UntypedFunction&)> fv) {
72 RTC_CHECK(!send_in_progress_);
73 bool removals_detected = false;
74 send_in_progress_ = true;
75 for (auto& r : receivers_) {
76 RTC_DCHECK_NE(r.removal_tag, pending_removal_tag());
77 fv(r.function);
78 if (r.removal_tag == pending_removal_tag()) {
79 removals_detected = true;
80 }
81 }
82 send_in_progress_ = false;
83 if (removals_detected) {
84 RemoveReceivers(pending_removal_tag());
85 }
86 }
87
88 template void CallbackListReceivers::AddReceiver(
89 const void*,
90 UntypedFunction::TrivialUntypedFunctionArgs<1>);
91 template void CallbackListReceivers::AddReceiver(
92 const void*,
93 UntypedFunction::TrivialUntypedFunctionArgs<2>);
94 template void CallbackListReceivers::AddReceiver(
95 const void*,
96 UntypedFunction::TrivialUntypedFunctionArgs<3>);
97 template void CallbackListReceivers::AddReceiver(
98 const void*,
99 UntypedFunction::TrivialUntypedFunctionArgs<4>);
100 template void CallbackListReceivers::AddReceiver(
101 const void*,
102 UntypedFunction::NontrivialUntypedFunctionArgs);
103 template void CallbackListReceivers::AddReceiver(
104 const void*,
105 UntypedFunction::FunctionPointerUntypedFunctionArgs);
106
107 template void CallbackListReceivers::AddReceiver(
108 UntypedFunction::TrivialUntypedFunctionArgs<1>);
109 template void CallbackListReceivers::AddReceiver(
110 UntypedFunction::TrivialUntypedFunctionArgs<2>);
111 template void CallbackListReceivers::AddReceiver(
112 UntypedFunction::TrivialUntypedFunctionArgs<3>);
113 template void CallbackListReceivers::AddReceiver(
114 UntypedFunction::TrivialUntypedFunctionArgs<4>);
115 template void CallbackListReceivers::AddReceiver(
116 UntypedFunction::NontrivialUntypedFunctionArgs);
117 template void CallbackListReceivers::AddReceiver(
118 UntypedFunction::FunctionPointerUntypedFunctionArgs);
119
120 } // namespace callback_list_impl
121 } // namespace webrtc
122