95 lines
3.3 KiB
JavaScript
95 lines
3.3 KiB
JavaScript
// Copyright (c) Microsoft Corporation.
|
|
// Licensed under the MIT License.
|
|
import { BuffersStream } from "./BuffersStream.js";
|
|
import buffer from "node:buffer";
|
|
/**
|
|
* maxBufferLength is max size of each buffer in the pooled buffers.
|
|
*/
|
|
const maxBufferLength = buffer.constants.MAX_LENGTH;
|
|
/**
|
|
* This class provides a buffer container which conceptually has no hard size limit.
|
|
* It accepts a capacity, an array of input buffers and the total length of input data.
|
|
* It will allocate an internal "buffer" of the capacity and fill the data in the input buffers
|
|
* into the internal "buffer" serially with respect to the total length.
|
|
* Then by calling PooledBuffer.getReadableStream(), you can get a readable stream
|
|
* assembled from all the data in the internal "buffer".
|
|
*/
|
|
export class PooledBuffer {
|
|
/**
|
|
* Internal buffers used to keep the data.
|
|
* Each buffer has a length of the maxBufferLength except last one.
|
|
*/
|
|
buffers = [];
|
|
/**
|
|
* The total size of internal buffers.
|
|
*/
|
|
capacity;
|
|
/**
|
|
* The total size of data contained in internal buffers.
|
|
*/
|
|
_size;
|
|
/**
|
|
* The size of the data contained in the pooled buffers.
|
|
*/
|
|
get size() {
|
|
return this._size;
|
|
}
|
|
constructor(capacity, buffers, totalLength) {
|
|
this.capacity = capacity;
|
|
this._size = 0;
|
|
// allocate
|
|
const bufferNum = Math.ceil(capacity / maxBufferLength);
|
|
for (let i = 0; i < bufferNum; i++) {
|
|
let len = i === bufferNum - 1 ? capacity % maxBufferLength : maxBufferLength;
|
|
if (len === 0) {
|
|
len = maxBufferLength;
|
|
}
|
|
this.buffers.push(Buffer.allocUnsafe(len));
|
|
}
|
|
if (buffers) {
|
|
this.fill(buffers, totalLength);
|
|
}
|
|
}
|
|
/**
|
|
* Fill the internal buffers with data in the input buffers serially
|
|
* with respect to the total length and the total capacity of the internal buffers.
|
|
* Data copied will be shift out of the input buffers.
|
|
*
|
|
* @param buffers - Input buffers containing the data to be filled in the pooled buffer
|
|
* @param totalLength - Total length of the data to be filled in.
|
|
*
|
|
*/
|
|
fill(buffers, totalLength) {
|
|
this._size = Math.min(this.capacity, totalLength);
|
|
let i = 0, j = 0, targetOffset = 0, sourceOffset = 0, totalCopiedNum = 0;
|
|
while (totalCopiedNum < this._size) {
|
|
const source = buffers[i];
|
|
const target = this.buffers[j];
|
|
const copiedNum = source.copy(target, targetOffset, sourceOffset);
|
|
totalCopiedNum += copiedNum;
|
|
sourceOffset += copiedNum;
|
|
targetOffset += copiedNum;
|
|
if (sourceOffset === source.length) {
|
|
i++;
|
|
sourceOffset = 0;
|
|
}
|
|
if (targetOffset === target.length) {
|
|
j++;
|
|
targetOffset = 0;
|
|
}
|
|
}
|
|
// clear copied from source buffers
|
|
buffers.splice(0, i);
|
|
if (buffers.length > 0) {
|
|
buffers[0] = buffers[0].slice(sourceOffset);
|
|
}
|
|
}
|
|
/**
|
|
* Get the readable stream assembled from all the data in the internal buffers.
|
|
*
|
|
*/
|
|
getReadableStream() {
|
|
return new BuffersStream(this.buffers, this.size);
|
|
}
|
|
}
|
|
//# sourceMappingURL=PooledBuffer.js.map
|