nim_duilib/base/framework/observer_list.h

139 lines
3.0 KiB
C
Raw Normal View History

2019-04-19 17:19:57 +08:00
#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_