dajiangroute/tiles/TracePoint/circQueue.js
2025-09-13 17:38:35 +08:00

189 lines
6.9 KiB
JavaScript
Raw 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.

/*==============================================================================================================
*
* CircQueue_t
*
* =============================================================================================================
* 描述:
* 这是一个环形队列, 支持入队、出队、丢弃数据等操作。
* 支持深拷贝入队数据,避免外部修改影响队列内部数据。
* 支持最大内存限制,超过限制则拒绝入队。
* 支持异步入队和出队操作,适用于异步场景。
* 支持 JSON 序列化,方便调试和存储。
* 注意事项:
* 1. 队列满时入队会失败,需处理返回值
* 2. 出队时返回深拷贝对象,避免修改影响队列
* 3. 异步操作时需注意超时处理,避免死循环
* 4. 仅支持可序列化对象, 深拷贝基于 JSON 方法,可能无法处理函数、循环引用等复杂对象
* 5. 内存限制基于估算的 JSON 字符串长度
* 示例:
* const queue = new CircQueue(5, { deepCopy: true, maxMemoryBytes: 1024 }); // 创建容量为5的队列启用深拷贝最大内存限制1KB
* queue.enter({ name: "Alice" }); // 入队一个对象
* const item = queue.out(); // 出队一个对象,返回深拷贝
* queue.discard(2); // 丢弃队尾2个对象
* queue.send({ msg: "async item" }, 1000); // 异步入队超时1秒
* queue.recv(1000); // 异步出队超时1秒
* console.log(JSON.stringify(queue)); // 序列化队列内容
*=============================================================================================================*/
class CircQueue
{
/**
* 构造函数
* capacity :队列可容纳的最大项目数
* options :可选的配置对象,用于自定义环形队列的行为。它支持以下配置项:
* deepCopy :控制入队时是否深拷贝元素, 默认 true
* maxMemoryBytes :队列的最大内存限制 (单位:字节),默认 Infinity, 不限制内存
* 若传 1024 * 1024 代表限制 1 M ,超出则队满, 队列会拒绝入队
*/
constructor(capacity, options = {})
{
this.capacity = capacity; /* 队列容量 (最多存储项目数) */
this.buffer = new Array(capacity); /* 队列存储区,使用数组存任意对象 */
this.head = 0; /* 队头索引 */
this.tail = 0; /* 队尾索引 */
this.isFull = false; /* 队满标志 */
this.deepCopy = options.deepCopy ?? true; /* 是否启用深拷贝 (默认启用) */
this.maxMemoryBytes = options.maxMemoryBytes ?? Infinity; /* 队列最大内存限制 (单位:字节) */
this.currentMemoryBytes = 0; /* 当前已使用内存大小 (单位:字节) */
}
/* 判断队列是否为空 */
isEmpty()
{
return this.head === this.tail && !this.isFull;
}
/* 判断队列是否已满 */
isFullFn()
{
return this.isFull;
}
/* 估算对象大小 (以 JSON 字符串的 UTF-8 编码长度作为近似值) */
_estimateSize(obj)
{
try
{
return Buffer.byteLength(JSON.stringify(obj), 'utf8'); /* Node.js 中用于计算字节长度 */
}
catch
{
return 0; /* 若对象不可序列化,返回 0 (避免出错) */
}
}
/* 深拷贝对象 (基于 JSON 的方式,仅支持可序列化对象) */
_deepClone(obj)
{
return this.deepCopy ? JSON.parse(JSON.stringify(obj)) : obj;
}
/* 入队操作:将对象放入队尾 */
enter(item)
{
const itemSize = this._estimateSize(item); /* 估算项目内存大小 */
if (this.isFullFn() || (this.currentMemoryBytes + itemSize > this.maxMemoryBytes))
{
return false; /* 若队满或超过内存限制则入队失败 */
}
const clone = this._deepClone(item); /* 深拷贝入队数据 (避免外部修改影响队列) */
this.buffer[this.tail] = clone; /* 存入队尾 */
this.tail = (this.tail + 1) % this.capacity; /* 环形增长 tail */
this.currentMemoryBytes += itemSize; /* 增加当前内存使用 */
if (this.tail === this.head) this.isFull = true; /* 若尾追头,表示队满 */
return true;
}
/* 出队操作:从队头取出一个对象, 返回深拷贝 */
out()
{
if (this.isEmpty()) return null; /* 队空返回 null */
const item = this.buffer[this.head]; /* 读取队头项目 */
this.currentMemoryBytes -= this._estimateSize(item); /* 更新内存使用 */
this.head = (this.head + 1) % this.capacity; /* 环形增长 head */
this.isFull = false; /* 出队必然队不满 */
return this._deepClone(item); /* 返回深拷贝,保护队列内部数据 */
}
/* 丢弃数据:从队尾向前丢弃 len 项 (反向移动 tail) */
discard(len)
{
for (let i = 0; i < len; i++)
{
if (this.isEmpty()) return false; /* 队空则不能继续丢弃 */
/* 定位最后一项 */
const item = this.buffer[(this.tail - 1 + this.capacity) % this.capacity];
this.currentMemoryBytes -= this._estimateSize(item); /* 减去内存大小 */
this.tail = (this.tail - 1 + this.capacity) % this.capacity; /* tail 回退 */
this.isFull = false;
}
return true;
}
/* 获取当前队列中元素个数 */
getDepth()
{
return this.isFull
? this.capacity
: (this.tail + this.capacity - this.head) % this.capacity;
}
/**
* 异步入队,支持超时退出,不会阻塞主线程, 可用于异步场景
* buf : 需要发送的数据
* timeoutMs : 超时时间
*/
async send(item, timeoutMs = 0)
{
const start = Date.now();
/* 循环直到成功入队或超时 */
while (!this.enter(item))
{
if (Date.now() - start >= timeoutMs) return false; /* 超时退出 */
await new Promise(resolve => setTimeout(resolve, 1)); /* 异步轮询, 自旋加 sleep 挂起 1ms */
}
return true;
}
/**
* 异步出队,支持超时退出,不会阻塞主线程, 可用于异步场景
* buf : 需要发送的数据
* timeoutMs : 超时时间
* 返回值:成功取出一个对象(深拷贝)或 null (超时)
*/
async recv(timeoutMs = 0)
{
const start = Date.now();
while (true)
{
const item = this.out();
if (item !== null) return item; /* 成功取出则返回 */
if (Date.now() - start >= timeoutMs) return null; /* 超时退出 */
await new Promise(resolve => setTimeout(resolve, 1)); /* 异步轮询, 自旋加 sleep 挂起 1ms */
}
}
/* JSON 序列化接口,用于 JSON.stringify(queue) */
toJSON()
{
const result = [];
let i = this.head;
let count = this.getDepth();
while (count-- > 0)
{
result.push(this._deepClone(this.buffer[i])); /* 复制每个元素 */
i = (i + 1) % this.capacity; /* 移动到下一个元素 */
}
return result;
}
}
export default CircQueue;
// module.exports = CircQueue;