mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-12-01 01:36:09 +03:00
230 lines
5.8 KiB
C
230 lines
5.8 KiB
C
|
// 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.
|
||
|
|
||
|
#ifndef BASE_CALLBACK_LIST_H_
|
||
|
#define BASE_CALLBACK_LIST_H_
|
||
|
|
||
|
#include <list>
|
||
|
#include <memory>
|
||
|
|
||
|
#include "base/callback.h"
|
||
|
#include "base/compiler_specific.h"
|
||
|
#include "base/logging.h"
|
||
|
#include "base/macros.h"
|
||
|
|
||
|
// OVERVIEW:
|
||
|
//
|
||
|
// A container for a list of callbacks. Unlike a normal STL vector or list,
|
||
|
// this container can be modified during iteration without invalidating the
|
||
|
// iterator. It safely handles the case of a callback removing itself
|
||
|
// or another callback from the list while callbacks are being run.
|
||
|
//
|
||
|
// TYPICAL USAGE:
|
||
|
//
|
||
|
// class MyWidget {
|
||
|
// public:
|
||
|
// ...
|
||
|
//
|
||
|
// typedef base::Callback<void(const Foo&)> OnFooCallback;
|
||
|
//
|
||
|
// std::unique_ptr<base::CallbackList<void(const Foo&)>::Subscription>
|
||
|
// RegisterCallback(const OnFooCallback& cb) {
|
||
|
// return callback_list_.Add(cb);
|
||
|
// }
|
||
|
//
|
||
|
// private:
|
||
|
// void NotifyFoo(const Foo& foo) {
|
||
|
// callback_list_.Notify(foo);
|
||
|
// }
|
||
|
//
|
||
|
// base::CallbackList<void(const Foo&)> callback_list_;
|
||
|
//
|
||
|
// DISALLOW_COPY_AND_ASSIGN(MyWidget);
|
||
|
// };
|
||
|
//
|
||
|
//
|
||
|
// class MyWidgetListener {
|
||
|
// public:
|
||
|
// MyWidgetListener::MyWidgetListener() {
|
||
|
// foo_subscription_ = MyWidget::GetCurrent()->RegisterCallback(
|
||
|
// base::Bind(&MyWidgetListener::OnFoo, this)));
|
||
|
// }
|
||
|
//
|
||
|
// MyWidgetListener::~MyWidgetListener() {
|
||
|
// // Subscription gets deleted automatically and will deregister
|
||
|
// // the callback in the process.
|
||
|
// }
|
||
|
//
|
||
|
// private:
|
||
|
// void OnFoo(const Foo& foo) {
|
||
|
// // Do something.
|
||
|
// }
|
||
|
//
|
||
|
// std::unique_ptr<base::CallbackList<void(const Foo&)>::Subscription>
|
||
|
// foo_subscription_;
|
||
|
//
|
||
|
// DISALLOW_COPY_AND_ASSIGN(MyWidgetListener);
|
||
|
// };
|
||
|
|
||
|
namespace base {
|
||
|
|
||
|
namespace internal {
|
||
|
|
||
|
template <typename CallbackType>
|
||
|
class CallbackListBase {
|
||
|
public:
|
||
|
class Subscription {
|
||
|
public:
|
||
|
Subscription(CallbackListBase<CallbackType>* list,
|
||
|
typename std::list<CallbackType>::iterator iter)
|
||
|
: list_(list),
|
||
|
iter_(iter) {
|
||
|
}
|
||
|
|
||
|
~Subscription() {
|
||
|
if (list_->active_iterator_count_) {
|
||
|
iter_->Reset();
|
||
|
} else {
|
||
|
list_->callbacks_.erase(iter_);
|
||
|
if (!list_->removal_callback_.is_null())
|
||
|
list_->removal_callback_.Run();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
CallbackListBase<CallbackType>* list_;
|
||
|
typename std::list<CallbackType>::iterator iter_;
|
||
|
|
||
|
DISALLOW_COPY_AND_ASSIGN(Subscription);
|
||
|
};
|
||
|
|
||
|
// Add a callback to the list. The callback will remain registered until the
|
||
|
// returned Subscription is destroyed, which must occur before the
|
||
|
// CallbackList is destroyed.
|
||
|
std::unique_ptr<Subscription> Add(const CallbackType& cb) WARN_UNUSED_RESULT {
|
||
|
DCHECK(!cb.is_null());
|
||
|
return std::unique_ptr<Subscription>(
|
||
|
new Subscription(this, callbacks_.insert(callbacks_.end(), cb)));
|
||
|
}
|
||
|
|
||
|
// Sets a callback which will be run when a subscription list is changed.
|
||
|
void set_removal_callback(const Closure& callback) {
|
||
|
removal_callback_ = callback;
|
||
|
}
|
||
|
|
||
|
// Returns true if there are no subscriptions. This is only valid to call when
|
||
|
// not looping through the list.
|
||
|
bool empty() {
|
||
|
DCHECK_EQ(0, active_iterator_count_);
|
||
|
return callbacks_.empty();
|
||
|
}
|
||
|
|
||
|
protected:
|
||
|
// An iterator class that can be used to access the list of callbacks.
|
||
|
class Iterator {
|
||
|
public:
|
||
|
explicit Iterator(CallbackListBase<CallbackType>* list)
|
||
|
: list_(list),
|
||
|
list_iter_(list_->callbacks_.begin()) {
|
||
|
++list_->active_iterator_count_;
|
||
|
}
|
||
|
|
||
|
Iterator(const Iterator& iter)
|
||
|
: list_(iter.list_),
|
||
|
list_iter_(iter.list_iter_) {
|
||
|
++list_->active_iterator_count_;
|
||
|
}
|
||
|
|
||
|
~Iterator() {
|
||
|
if (list_ && --list_->active_iterator_count_ == 0) {
|
||
|
list_->Compact();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CallbackType* GetNext() {
|
||
|
while ((list_iter_ != list_->callbacks_.end()) && list_iter_->is_null())
|
||
|
++list_iter_;
|
||
|
|
||
|
CallbackType* cb = NULL;
|
||
|
if (list_iter_ != list_->callbacks_.end()) {
|
||
|
cb = &(*list_iter_);
|
||
|
++list_iter_;
|
||
|
}
|
||
|
return cb;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
CallbackListBase<CallbackType>* list_;
|
||
|
typename std::list<CallbackType>::iterator list_iter_;
|
||
|
};
|
||
|
|
||
|
CallbackListBase() : active_iterator_count_(0) {}
|
||
|
|
||
|
~CallbackListBase() {
|
||
|
DCHECK_EQ(0, active_iterator_count_);
|
||
|
DCHECK_EQ(0U, callbacks_.size());
|
||
|
}
|
||
|
|
||
|
// Returns an instance of a CallbackListBase::Iterator which can be used
|
||
|
// to run callbacks.
|
||
|
Iterator GetIterator() {
|
||
|
return Iterator(this);
|
||
|
}
|
||
|
|
||
|
// Compact the list: remove any entries which were NULLed out during
|
||
|
// iteration.
|
||
|
void Compact() {
|
||
|
typename std::list<CallbackType>::iterator it = callbacks_.begin();
|
||
|
bool updated = false;
|
||
|
while (it != callbacks_.end()) {
|
||
|
if ((*it).is_null()) {
|
||
|
updated = true;
|
||
|
it = callbacks_.erase(it);
|
||
|
} else {
|
||
|
++it;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (updated && !removal_callback_.is_null())
|
||
|
removal_callback_.Run();
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
std::list<CallbackType> callbacks_;
|
||
|
int active_iterator_count_;
|
||
|
Closure removal_callback_;
|
||
|
|
||
|
DISALLOW_COPY_AND_ASSIGN(CallbackListBase);
|
||
|
};
|
||
|
|
||
|
} // namespace internal
|
||
|
|
||
|
template <typename Sig> class CallbackList;
|
||
|
|
||
|
template <typename... Args>
|
||
|
class CallbackList<void(Args...)>
|
||
|
: public internal::CallbackListBase<Callback<void(Args...)> > {
|
||
|
public:
|
||
|
typedef Callback<void(Args...)> CallbackType;
|
||
|
|
||
|
CallbackList() {}
|
||
|
|
||
|
template <typename... RunArgs>
|
||
|
void Notify(RunArgs&&... args) {
|
||
|
typename internal::CallbackListBase<CallbackType>::Iterator it =
|
||
|
this->GetIterator();
|
||
|
CallbackType* cb;
|
||
|
while ((cb = it.GetNext()) != NULL) {
|
||
|
cb->Run(args...);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
DISALLOW_COPY_AND_ASSIGN(CallbackList);
|
||
|
};
|
||
|
|
||
|
} // namespace base
|
||
|
|
||
|
#endif // BASE_CALLBACK_LIST_H_
|