| /* | 
 |  *  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 |