Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | 94x 94x 94x 94x 150x 1x 107x 106x 106x 106x 106x 105x 40809x 105x 105x 105x 87x 57x 57x 13109x 57x 57x 57x 57x 89x 52x 52x 52x 13579x 52x 52x 52x 52x 3x 2x 2x 8x 2x 79x 79x 6160x 1x 1x | /**
* Ring Buffer (Circular Buffer)
*
* High-performance binary buffer for efficient serial output batching.
* Eliminates string accumulation overhead and prevents O(n²) garbage collection pressure.
*
* Features:
* - Fixed-size Uint8Array allocation (no dynamic reallocation)
* - Write pointer advances without shifting data (circular semantics)
* - Fast write/read without string copies
* - Efficient extraction to string (single decoder pass)
* - Memory-bounded (no unbounded growth)
*/
export class RingBuffer {
private buffer: Uint8Array;
private writePos = 0;
private readPos = 0;
private size = 0; // Current number of bytes in buffer
/**
* Create a ring buffer with fixed capacity
* @param capacity Maximum bytes to hold (e.g., 8192 for typical serial batching)
*/
constructor(capacity: number = 8192) {
this.buffer = new Uint8Array(capacity);
}
/**
* Get current number of bytes in buffer
*/
getSize(): number {
return this.size;
}
/**
* Get buffer capacity
*/
getCapacity(): number {
return this.buffer.length;
}
/**
* Write string data to buffer as UTF-8 bytes
* If buffer would overflow, returns number of bytes actually written (may be less than input)
* @returns bytes written
*/
write(data: string): number {
if (!data.length) return 0;
// Encode string to UTF-8 bytes
const encoded = new TextEncoder().encode(data);
const availableSpace = this.buffer.length - this.size;
// Truncate if overflow
const bytesToWrite = Math.min(encoded.length, availableSpace);
if (bytesToWrite === 0) return 0;
// Write to circular buffer without modifying readPos
for (let i = 0; i < bytesToWrite; i++) {
this.buffer[(this.writePos + i) % this.buffer.length] = encoded[i];
}
this.writePos = (this.writePos + bytesToWrite) % this.buffer.length;
this.size += bytesToWrite;
return bytesToWrite;
}
/**
* Read and extract all buffered data as string, clearing the buffer
* @returns extracted string
*/
readAll(): string {
if (this.size === 0) return '';
// Extract bytes in order (handling wrap-around)
const result = new Uint8Array(this.size);
for (let i = 0; i < this.size; i++) {
result[i] = this.buffer[(this.readPos + i) % this.buffer.length];
}
// Decode to string once
const str = new TextDecoder().decode(result);
// Clear buffer
this.readPos = this.writePos;
this.size = 0;
return str;
}
/**
* Read up to maxBytes and extract as string, clearing those bytes from buffer
* @returns extracted string
*/
read(maxBytes: number): string {
if (this.size === 0 || maxBytes <= 0) return '';
const bytesToRead = Math.min(maxBytes, this.size);
const result = new Uint8Array(bytesToRead);
for (let i = 0; i < bytesToRead; i++) {
result[i] = this.buffer[(this.readPos + i) % this.buffer.length];
}
const str = new TextDecoder().decode(result);
this.readPos = (this.readPos + bytesToRead) % this.buffer.length;
this.size -= bytesToRead;
return str;
}
/**
* Peek at buffered data without clearing it
* @returns string view of all buffered data
*/
peek(): string {
if (this.size === 0) return '';
const result = new Uint8Array(this.size);
for (let i = 0; i < this.size; i++) {
result[i] = this.buffer[(this.readPos + i) % this.buffer.length];
}
return new TextDecoder().decode(result);
}
/**
* Clear all buffered data
*/
clear(): void {
this.readPos = this.writePos;
this.size = 0;
}
/**
* Check if buffer is empty
*/
isEmpty(): boolean {
return this.size === 0;
}
/**
* Check if buffer is at capacity
*/
isFull(): boolean {
return this.size === this.buffer.length;
}
/**
* Get available space for writing
*/
getAvailableSpace(): number {
return this.buffer.length - this.size;
}
}
|