| /* |
| * Copyright 2020 The WebRTC Project Authors. All rights reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #include "rtc_base/callback_list.h" |
| |
| #include "rtc_base/checks.h" |
| |
| namespace webrtc { |
| namespace callback_list_impl { |
| |
| CallbackListReceivers::CallbackListReceivers() = default; |
| |
| CallbackListReceivers::~CallbackListReceivers() { |
| RTC_CHECK(!send_in_progress_); |
| } |
| |
| void CallbackListReceivers::RemoveReceivers(const void* removal_tag) { |
| RTC_DCHECK(removal_tag); |
| |
| // We divide the receivers_ vector into three regions: from right to left, the |
| // "keep" region, the "todo" region, and the "remove" region. The "todo" |
| // region initially covers the whole vector. |
| size_t first_todo = 0; // First element of the "todo" |
| // region. |
| size_t first_remove = receivers_.size(); // First element of the "remove" |
| // region. |
| |
| // Loop until the "todo" region is empty. |
| while (first_todo != first_remove) { |
| if (receivers_[first_todo].removal_tag != removal_tag) { |
| // The first element of the "todo" region should be kept. Move the |
| // "keep"/"todo" boundary. |
| ++first_todo; |
| } else if (receivers_[first_remove - 1].removal_tag == removal_tag) { |
| // The last element of the "todo" region should be removed. Move the |
| // "todo"/"remove" boundary. |
| if (send_in_progress_) { |
| // Tag this receiver for removal, which will be done when `ForEach` |
| // has completed. |
| receivers_[first_remove - 1].removal_tag = pending_removal_tag(); |
| } |
| --first_remove; |
| } else if (!send_in_progress_) { |
| // The first element of the "todo" region should be removed, and the last |
| // element of the "todo" region should be kept. Swap them, and then shrink |
| // the "todo" region from both ends. |
| RTC_DCHECK_NE(first_todo, first_remove - 1); |
| using std::swap; |
| swap(receivers_[first_todo], receivers_[first_remove - 1]); |
| RTC_DCHECK_NE(receivers_[first_todo].removal_tag, removal_tag); |
| ++first_todo; |
| RTC_DCHECK_EQ(receivers_[first_remove - 1].removal_tag, removal_tag); |
| --first_remove; |
| } |
| } |
| |
| if (!send_in_progress_) { |
| // Discard the remove region. |
| receivers_.resize(first_remove); |
| } |
| } |
| |
| void CallbackListReceivers::Foreach( |
| rtc::FunctionView<void(UntypedFunction&)> fv) { |
| RTC_CHECK(!send_in_progress_); |
| bool removals_detected = false; |
| send_in_progress_ = true; |
| for (auto& r : receivers_) { |
| RTC_DCHECK_NE(r.removal_tag, pending_removal_tag()); |
| fv(r.function); |
| if (r.removal_tag == pending_removal_tag()) { |
| removals_detected = true; |
| } |
| } |
| send_in_progress_ = false; |
| if (removals_detected) { |
| RemoveReceivers(pending_removal_tag()); |
| } |
| } |
| |
| template void CallbackListReceivers::AddReceiver( |
| const void*, |
| UntypedFunction::TrivialUntypedFunctionArgs<1>); |
| template void CallbackListReceivers::AddReceiver( |
| const void*, |
| UntypedFunction::TrivialUntypedFunctionArgs<2>); |
| template void CallbackListReceivers::AddReceiver( |
| const void*, |
| UntypedFunction::TrivialUntypedFunctionArgs<3>); |
| template void CallbackListReceivers::AddReceiver( |
| const void*, |
| UntypedFunction::TrivialUntypedFunctionArgs<4>); |
| template void CallbackListReceivers::AddReceiver( |
| const void*, |
| UntypedFunction::NontrivialUntypedFunctionArgs); |
| template void CallbackListReceivers::AddReceiver( |
| const void*, |
| UntypedFunction::FunctionPointerUntypedFunctionArgs); |
| |
| template void CallbackListReceivers::AddReceiver( |
| UntypedFunction::TrivialUntypedFunctionArgs<1>); |
| template void CallbackListReceivers::AddReceiver( |
| UntypedFunction::TrivialUntypedFunctionArgs<2>); |
| template void CallbackListReceivers::AddReceiver( |
| UntypedFunction::TrivialUntypedFunctionArgs<3>); |
| template void CallbackListReceivers::AddReceiver( |
| UntypedFunction::TrivialUntypedFunctionArgs<4>); |
| template void CallbackListReceivers::AddReceiver( |
| UntypedFunction::NontrivialUntypedFunctionArgs); |
| template void CallbackListReceivers::AddReceiver( |
| UntypedFunction::FunctionPointerUntypedFunctionArgs); |
| |
| } // namespace callback_list_impl |
| } // namespace webrtc |