274 lines
7.1 KiB
C++
274 lines
7.1 KiB
C++
#ifndef _LIB_SRC_HEAD_TIMER_H_
|
||
#define _LIB_SRC_HEAD_TIMER_H_
|
||
|
||
#include "timer_common.hpp"
|
||
#include <iostream>
|
||
|
||
#define HEAD_DEFAULT_SIZE 128
|
||
|
||
// 定时器数据结构的定义
|
||
template <typename _User_Data>
|
||
class HeapTimer {
|
||
public:
|
||
HeapTimer() = default;
|
||
HeapTimer(int msec) {
|
||
timer.setTimeout(msec);
|
||
}
|
||
~HeapTimer() {}
|
||
|
||
void setTimeout(time_t timeout) {
|
||
timer.setTimeout(timeout);
|
||
}
|
||
|
||
time_t getExpire() {
|
||
return timer.getExpire();
|
||
}
|
||
|
||
void setUserData(_User_Data* userData) {
|
||
timer.setUserData(userData);
|
||
}
|
||
|
||
int getPos() {
|
||
return _pos;
|
||
}
|
||
|
||
void setPos(int pos) {
|
||
this->_pos = pos;
|
||
}
|
||
|
||
void handleTimeout() {
|
||
timer.handleTimeout();
|
||
}
|
||
|
||
using TimeOutCbFunc = void (*)(_User_Data*);
|
||
void setCallBack(TimeOutCbFunc callBack) {
|
||
timer.setCallBack(callBack);
|
||
}
|
||
|
||
public:
|
||
Timer<_User_Data> timer;
|
||
private:
|
||
// 保存该定时器在数组中的位置,便于查找删除
|
||
int _pos;
|
||
};
|
||
/*
|
||
疑问1:为什么要再将Timer包装呢?新包装的HeapTimer内部嵌合了Timer与pos,整体可以成为我们进行复杂数据结构的操作对象。
|
||
另一方面还可以复用原先的Timer数据结构,定义另外一层更加抽象的数据结构
|
||
*/
|
||
// 定时容器,使用最小堆实现
|
||
template <typename _UData>
|
||
class HeapTimerContainer : public ITimerContainer<_UData> {
|
||
public:
|
||
HeapTimerContainer();
|
||
HeapTimerContainer(int capacity);
|
||
HeapTimerContainer(HeapTimer<_UData>** initArray, int arrSize, int capacity);
|
||
virtual ~HeapTimerContainer() override;
|
||
public:
|
||
virtual void tick() override;
|
||
Timer<_UData>* addTimer(time_t timeout) override;
|
||
void delTimer(Timer<_UData>* timer) override;
|
||
void resetTimer(Timer<_UData>* timer, time_t timeout) override;
|
||
int getMinExpire() override;
|
||
Timer<_UData>* top();
|
||
void popTimer();
|
||
|
||
private:
|
||
void percolateDown(int hole);
|
||
void percolateUp(int hole);
|
||
void resize();
|
||
bool isEmpty();
|
||
|
||
private:
|
||
HeapTimer<_UData>** _array; // 堆数据
|
||
int _capacity; // 堆数组的容量
|
||
int _size; // 当前包含的元素
|
||
};
|
||
|
||
template <typename _UData>
|
||
HeapTimerContainer<_UData>::HeapTimerContainer() : HeapTimerContainer(HEAD_DEFAULT_SIZE) {}
|
||
|
||
// 初始化一个大小为cap的空堆
|
||
template <typename _UData>
|
||
HeapTimerContainer<_UData>::HeapTimerContainer(int capacity) {
|
||
this->_capacity = capacity;
|
||
this->_size = 0;
|
||
|
||
// 不理解为什么加个nullptr
|
||
_array = new HeapTimer<_UData>* [capacity]{nullptr};
|
||
}
|
||
|
||
// 用已有数组来初始化堆
|
||
template <typename _UData>
|
||
HeapTimerContainer<_UData>::HeapTimerContainer(HeapTimer<_UData>** initArray,
|
||
int arrSize, int capacity) : _size(arrSize) {
|
||
if(capacity < arrSize) {
|
||
this->_capacity = capacity = 2 * arrSize;
|
||
}
|
||
_array = new HeapTimer<_UData>*[capacity];
|
||
for (int i = 0; i < capacity; i++) {
|
||
_array[i] = nullptr;
|
||
}
|
||
if (arrSize > 0) {
|
||
for (int i = 0; i < arrSize; i++) {
|
||
_array[i] = initArray[i];
|
||
}
|
||
for (int i = (_size - 1) / 2; i >= 0; i--) {
|
||
percolateDown(i);
|
||
}
|
||
}
|
||
}
|
||
|
||
template<typename _UData>
|
||
HeapTimerContainer<_UData>::~HeapTimerContainer() {
|
||
if(_array) {
|
||
for(int i = 0; i < _size; i++) {
|
||
delete _array[i];
|
||
}
|
||
delete []_array;
|
||
}
|
||
}
|
||
|
||
template <typename _UData>
|
||
void HeapTimerContainer<_UData>::tick() {
|
||
std::cout << "-----------------tick-----------------" << std::endl;
|
||
HeapTimer<_UData>* tmp = _array[0];
|
||
time_t cur = getMsec();
|
||
// 循环处理到期的定时器
|
||
while(!isEmpty()) {
|
||
if(!tmp) break;
|
||
if(tmp->getExpire() > cur) break;
|
||
|
||
tmp->handleTimeout();
|
||
// 将堆顶元素删除,同时生成新的堆顶定时器
|
||
popTimer();
|
||
tmp = _array[0];
|
||
}
|
||
}
|
||
|
||
// 获取一个定时器
|
||
template <typename _UData>
|
||
Timer<_UData>* HeapTimerContainer<_UData>::addTimer(time_t timeout) {
|
||
if(_size >= _capacity) this->resize();
|
||
|
||
int hole = _size++;
|
||
HeapTimer<_UData>* timer = new HeapTimer<_UData>(timeout);
|
||
_array[hole] = timer;
|
||
|
||
percolateUp(hole);
|
||
return &timer->timer;
|
||
}
|
||
|
||
// 删除目标定时器
|
||
template <typename _UData>
|
||
void HeapTimerContainer<_UData>::delTimer(Timer<_UData>* timer) {
|
||
if(!timer) return;
|
||
|
||
timer->setCallBack(nullptr);
|
||
timer->setUserData(nullptr);
|
||
}
|
||
|
||
// 重置一个定时器
|
||
template <typename _UData>
|
||
void HeapTimerContainer<_UData>::resetTimer(Timer<_UData>* timer, time_t timeout) {
|
||
HeapTimer<_UData>* htimer = reinterpret_cast<HeapTimer<_UData>*>(timer);
|
||
|
||
int pos = htimer->getPos();
|
||
int lastPos = _size - 1;
|
||
if(pos != lastPos) {
|
||
HeapTimer<_UData>* temp = _array[pos];
|
||
_array[pos] = _array[lastPos];
|
||
_array[lastPos] = temp;
|
||
}
|
||
timer->setTimeout(timeout);
|
||
|
||
percolateDown(pos);
|
||
percolateUp(lastPos);
|
||
}
|
||
|
||
// 获取容器中超时值最小的值
|
||
template <typename _UData>
|
||
int HeapTimerContainer<_UData>::getMinExpire() {
|
||
Timer<_UData>* timer = top();
|
||
if(timer) return timer->getExpire();
|
||
return -1;
|
||
}
|
||
|
||
// 获取顶部的定时器
|
||
template <typename _UData>
|
||
Timer<_UData>* HeapTimerContainer<_UData>::top(){
|
||
if(!isEmpty()) return nullptr;
|
||
return &_array[0]->timer;
|
||
}
|
||
|
||
template <typename _UData>
|
||
void HeapTimerContainer<_UData>::popTimer() {
|
||
if(!isEmpty()) return;
|
||
if(_array[0]) {
|
||
delete _array[0];
|
||
_array[0] = _array[--_size];
|
||
percolateDown(0);
|
||
}
|
||
}
|
||
|
||
// 最小堆的下滤操作,它确保数组中以第 hole 个节点作为根的子树拥有最小堆性质
|
||
template <typename _UData>
|
||
void HeapTimerContainer<_UData>::percolateDown(int hole) {
|
||
if(_size == 0) return ;
|
||
HeapTimer<_UData>* temp = _array[hole];
|
||
int child = 0;
|
||
for(; ((hole * 2 + 1) <= _size - 1 ); hole = child) {
|
||
child = hole * 2 + 1;
|
||
if((child < (_size - 1)) && (_array[child + 1]->getExpire() < _array[child]->getExpire())) {
|
||
child++;
|
||
}
|
||
if(_array[child]->getExpire() < temp->getExpire()) {
|
||
_array[hole] = _array[child];
|
||
_array[hole]->setPos(hole);
|
||
} else {
|
||
break;
|
||
}
|
||
}
|
||
_array[hole] = temp;
|
||
_array[hole]->setPos(hole);
|
||
}
|
||
|
||
template <typename _UData>
|
||
void HeapTimerContainer<_UData>::percolateUp(int hole) {
|
||
int parent = 0;
|
||
HeapTimer<_UData>* temp = _array[hole];
|
||
|
||
for(; hole > 0; hole = parent) {
|
||
parent = (hole - 1) / 2;
|
||
if(_array[parent]->getExpire() <= temp->getExpire()) {
|
||
break;
|
||
}
|
||
_array[hole] = _array[parent];
|
||
_array[hole]->setPos(hole);
|
||
}
|
||
_array[hole] = temp;
|
||
_array[hole]->setPos(hole);
|
||
}
|
||
|
||
// 将数组的容量扩大一倍
|
||
template <typename _UData>
|
||
void HeapTimerContainer<_UData>::resize() {
|
||
HeapTimer<_UData>** temp = new HeapTimer<_UData>* [2 * _capacity];
|
||
_capacity = 2 * _capacity;
|
||
|
||
for(int i = 0; i < _size; i++) {
|
||
temp[i] = _array[i];
|
||
}
|
||
for(int i = _size; i < _capacity; i++) {
|
||
temp[i] = nullptr;
|
||
}
|
||
delete []_array;
|
||
_array = temp;
|
||
}
|
||
|
||
template <typename _UData>
|
||
bool HeapTimerContainer<_UData>::isEmpty() {
|
||
return _size == 0;
|
||
}
|
||
|
||
|
||
#endif |