139 lines
3.0 KiB
C
139 lines
3.0 KiB
C
![]() |
#ifndef BASE_FRAMEWORK_OBSERVER_LIST_H_
|
|||
|
#define BASE_FRAMEWORK_OBSERVER_LIST_H_
|
|||
|
|
|||
|
#include <assert.h>
|
|||
|
#include <vector>
|
|||
|
#include <algorithm>
|
|||
|
|
|||
|
/*
|
|||
|
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>⣺
|
|||
|
* <EFBFBD><EFBFBD>MessagePump<EFBFBD>ڱ<EFBFBD><EFBFBD><EFBFBD>ObserverList<EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD>Observer<EFBFBD>ڲ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>RemoveObserver<EFBFBD><EFBFBD><EFBFBD>Ƴ<EFBFBD><EFBFBD>Լ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Observer<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ᵼ<EFBFBD>½<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ı<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>iterator<EFBFBD><EFBFBD>erase<EFBFBD><EFBFBD>
|
|||
|
*
|
|||
|
* Google Chrome<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>iterator<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>lazy erase<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>룺
|
|||
|
*
|
|||
|
* ObserverList<Observer> observers;
|
|||
|
* ...
|
|||
|
* observers.AquireLazyErase(); // aquire lazy erase
|
|||
|
* size_t index = 0;
|
|||
|
* for (;;)
|
|||
|
* {
|
|||
|
* Observer *observer = observers.GetObject(index++);
|
|||
|
* if (observer == NULL)
|
|||
|
* break;
|
|||
|
* // use observer here
|
|||
|
* }
|
|||
|
* observers.ReleaseLazyErase(); // release lazy erase
|
|||
|
* observer.Compact(); // compact the list
|
|||
|
*/
|
|||
|
|
|||
|
class LazyEraser
|
|||
|
{
|
|||
|
public:
|
|||
|
LazyEraser() : lazy_erase_(0) {}
|
|||
|
/* NOTE: calling 'ApplyLasyErase' increases the reference count, calling 'ReleaseLasyErase' decreases the reference count */
|
|||
|
int AquireLazyErase() { return ++lazy_erase_; }
|
|||
|
int ReleaseLazyErase() { assert(lazy_erase_ > 0); return --lazy_erase_; }
|
|||
|
virtual void Compact() = 0;
|
|||
|
|
|||
|
protected:
|
|||
|
int lazy_erase_;
|
|||
|
};
|
|||
|
|
|||
|
class AutoLazyEraser
|
|||
|
{
|
|||
|
public:
|
|||
|
AutoLazyEraser(LazyEraser* lazy_eraser) : ptr_(lazy_eraser)
|
|||
|
{
|
|||
|
if (ptr_)
|
|||
|
ptr_->AquireLazyErase();
|
|||
|
}
|
|||
|
|
|||
|
AutoLazyEraser(AutoLazyEraser &lazy_eraser)
|
|||
|
{
|
|||
|
if (lazy_eraser.ptr_)
|
|||
|
lazy_eraser.ptr_->AquireLazyErase();
|
|||
|
ptr_ = lazy_eraser.ptr_;
|
|||
|
}
|
|||
|
|
|||
|
void operator=(AutoLazyEraser &lazy_eraser)
|
|||
|
{
|
|||
|
if (lazy_eraser.ptr_)
|
|||
|
lazy_eraser.ptr_->AquireLazyErase();
|
|||
|
ptr_ = lazy_eraser.ptr_;
|
|||
|
}
|
|||
|
|
|||
|
~AutoLazyEraser()
|
|||
|
{
|
|||
|
if (ptr_)
|
|||
|
{
|
|||
|
if (ptr_->ReleaseLazyErase() < 1)
|
|||
|
ptr_->Compact();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private:
|
|||
|
LazyEraser *ptr_;
|
|||
|
};
|
|||
|
|
|||
|
template<typename ObserverType>
|
|||
|
class ObserverList : public LazyEraser
|
|||
|
{
|
|||
|
public:
|
|||
|
void AddObserver(ObserverType *observer)
|
|||
|
{
|
|||
|
assert(observer);
|
|||
|
if (std::find(observers_.begin(), observers_.end(), observer) == observers_.end())
|
|||
|
observers_.push_back(observer);
|
|||
|
}
|
|||
|
|
|||
|
void RemoveObserver(ObserverType *observer)
|
|||
|
{
|
|||
|
typename std::vector<ObserverType *>::iterator pos = std::find(observers_.begin(), observers_.end(), observer);
|
|||
|
if (pos == observers_.end())
|
|||
|
return;
|
|||
|
/* this method may be called within a traversal of the list */
|
|||
|
if (lazy_erase_ > 0)
|
|||
|
*pos = NULL;
|
|||
|
else
|
|||
|
observers_.erase(pos);
|
|||
|
}
|
|||
|
|
|||
|
void Compact()
|
|||
|
{
|
|||
|
if (lazy_erase_ > 0 || observers_.empty())
|
|||
|
return;
|
|||
|
ObserverType **src = &observers_[0];
|
|||
|
ObserverType **target = src;
|
|||
|
ObserverType **end = src + observers_.size();
|
|||
|
|
|||
|
/* fast compacting algorithm */
|
|||
|
while (src < end)
|
|||
|
{
|
|||
|
if (*src != NULL)
|
|||
|
{
|
|||
|
if (target != src)
|
|||
|
*target = *src;
|
|||
|
target++;
|
|||
|
}
|
|||
|
src++;
|
|||
|
}
|
|||
|
|
|||
|
observers_.resize(target - &observers_[0]);
|
|||
|
}
|
|||
|
|
|||
|
ObserverType* GetObserver(size_t index) const
|
|||
|
{
|
|||
|
if (index >= GetObserverCount())
|
|||
|
return NULL;
|
|||
|
return observers_[index];
|
|||
|
}
|
|||
|
|
|||
|
size_t GetObserverCount() const { return observers_.size(); };
|
|||
|
|
|||
|
private:
|
|||
|
std::vector<ObserverType *> observers_;
|
|||
|
};
|
|||
|
|
|||
|
#endif // BASE_FRAMEWORK_OBSERVER_LIST_H_
|