CodeFree/6_solution/高性能定时器/最小堆定时器/heap_timer.hpp

274 lines
7.1 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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