Chromium Code Reviews| Index: base/callback_list_internal.cc |
| diff --git a/base/callback_list_internal.cc b/base/callback_list_internal.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..2072f3df9f2daf9a6b5a02512d67fdb68a3f620b |
| --- /dev/null |
| +++ b/base/callback_list_internal.cc |
| @@ -0,0 +1,105 @@ |
| +// Copyright 2013 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "base/callback_list_internal.h" |
| + |
| +#include <algorithm> |
| + |
| +#include "base/bind.h" |
| +#include "base/bind_helpers.h" |
| + |
| +namespace base { |
| +namespace internal { |
| + |
| +CallbackListBase::Iterator::Iterator(CallbackListBase* list); |
| + : list_(list->GetWeakPtr()), |
| + index_(0), |
| + max_index_(list->type_ == NOTIFY_ALL ? |
| + std::numeric_limits<size_t>::max() : |
| + list->callbacks_.size()) { |
| + ++list_->active_iterator_count_; |
| +} |
| + |
| +CallbackListBase::Iterator::~Iterator(); { |
| + if (list_ && --list_->active_iterator_count_ == 0) { |
| + list_->Compact(); |
| + } |
| +} |
| + |
| +CallbackBase* CallbackListBase::Iterator::GetNext(); { |
| + if (!list_) |
| + return NULL; |
| + ListType& callbacks = list_->callbacks_; |
|
awong
2013/08/29 19:30:48
Normally I would object to the use of a reference
Cait (Slow)
2013/08/30 00:28:02
Done.
|
| + size_t max_index = std::min(max_index_, callbacks.size()); |
| + while (index_ < max_index && !callbacks[index_]) |
| + ++index_; |
| + return index_ < max_index ? callbacks[index_++] : NULL; |
| +} |
| + |
| +CallbackListBase::CallbackListBase(NotificationType type) |
| + : active_iterator_count_(0), |
| + type_(type), |
| + weak_factory_(this) {} |
| + |
| +CallbackListBase::~CallbackListBase() { |
| + Compact(); |
|
awong
2013/08/29 20:45:34
Is this safe if there is an active iterator?
Cait (Slow)
2013/08/30 00:28:02
Not really...but since we're destroying the list,
|
| + DCHECK_EQ(0U, size()); |
|
awong
2013/08/29 20:45:34
Was just thinking about this...in your original CL
Cait (Slow)
2013/08/30 00:28:02
So I already sort of have this (with the might_hav
|
| + Clear(); |
| +} |
| + |
| +void CallbackListBase::Clear() { |
| + if (active_iterator_count_) { |
| + for (size_t i = 0; i < callbacks_.size(); ++i) { |
| + CallbackBase* tmp = callbacks_[i]; |
| + tmp->Reset(); |
| + delete tmp; |
| + callbacks_[i] = NULL; |
| + } |
| + } else { |
| + for (size_t i = 0; i < callbacks_.size(); ++i) |
| + delete callbacks_[i]; |
| + callbacks_.clear(); |
| + } |
| +} |
| + |
| +void CallbackListBase::RemoveCallback(base::internal::CallbackBase* cb) { |
| + for (size_t i = 0; i < callbacks_.size(); i++) { |
| + if (callbacks_[i] == cb) { |
| + CallbackBase* tmp = callbacks_[i]; |
| + tmp->Reset(); |
| + delete tmp; |
| + if (active_iterator_count_) { |
| + callbacks_[i] = NULL; |
| + } else { |
| + callbacks_.erase(callbacks_.begin() + i); |
| + } |
| + return; |
| + } |
| + } |
| +} |
| + |
| +base::Closure CallbackListBase::AddCallback(base::internal::CallbackBase* cb) { |
| + for (size_t i = 0; i < callbacks_.size(); i++) { |
| + if (callbacks_[i] == cb) { |
| + NOTREACHED() << "Callbacks can only be added once!"; |
|
awong
2013/08/29 19:30:48
This check doesn't do anything useful beyond a set
Cait (Slow)
2013/08/30 00:28:02
Done.
|
| + return base::Bind(&base::DoNothing);; |
| + } |
| + } |
| + callbacks_.push_back(cb); |
| + return base::Bind(&CallbackListBase::RemoveCallback, Unretained(this), cb); |
| +} |
| + |
| +base::WeakPtr<CallbackListBase> CallbackListBase::GetWeakPtr() { |
| + return weak_factory_.GetWeakPtr(); |
| +} |
| + |
| +void CallbackListBase::Compact() { |
| + callbacks_.erase( |
| + std::remove(callbacks_.begin(), callbacks_.end(), |
| + static_cast<base::internal::CallbackBase*>(NULL)), |
| + callbacks_.end()); |
| +} |
| + |
| +} // namespace internal |
| +} // namespace base |