feat: fully implement circular buffer semantic
[poolifier.git] / src / circular-buffer.ts
1 /**
2 * Default buffer size.
3 */
4 export const defaultBufferSize = 2048
5
6 /**
7 * Circular buffer.
8 *
9 * @typeParam T - Type of buffer data.
10 * @internal
11 */
12 export class CircularBuffer<T> {
13 private readIdx: number
14 private writeIdx: number
15 private items: Array<T | undefined>
16 private readonly maxArrayIdx: number
17 public size: number
18
19 /**
20 * @param size - Buffer size. @defaultValue defaultBufferSize
21 * @returns CircularBuffer.
22 */
23 constructor (size: number = defaultBufferSize) {
24 this.checkSize(size)
25 this.readIdx = 0
26 this.writeIdx = 0
27 this.maxArrayIdx = size - 1
28 this.size = 0
29 this.items = new Array<T | undefined>(size)
30 }
31
32 /**
33 * Checks whether the buffer is empty.
34 *
35 * @returns Whether the buffer is empty.
36 */
37 public empty (): boolean {
38 return this.size === 0
39 }
40
41 /**
42 * Checks whether the buffer is full.
43 *
44 * @returns Whether the buffer is full.
45 */
46 public full (): boolean {
47 return this.size === this.items.length
48 }
49
50 /**
51 * Puts data into buffer.
52 *
53 * @param data - Data to put into buffer.
54 */
55 public put (data: T): void {
56 this.items[this.writeIdx] = data
57 this.writeIdx = this.writeIdx === this.maxArrayIdx ? 0 : this.writeIdx + 1
58 if (this.size < this.items.length) {
59 ++this.size
60 }
61 }
62
63 /**
64 * Gets data from buffer.
65 *
66 * @returns Data from buffer.
67 */
68 public get (): T | undefined {
69 const data = this.items[this.readIdx]
70 if (data == null) {
71 return
72 }
73 this.items[this.readIdx] = undefined
74 this.readIdx = this.readIdx === this.maxArrayIdx ? 0 : this.readIdx + 1
75 --this.size
76 return data
77 }
78
79 /**
80 * Returns buffer as array.
81 *
82 * @returns Array of buffer data.
83 */
84 public toArray (): T[] {
85 return this.items.filter(item => item != null) as T[]
86 }
87
88 private checkSize (size: number): void {
89 if (!Number.isSafeInteger(size)) {
90 throw new TypeError(
91 `Invalid circular buffer size: ${size} is not an integer`
92 )
93 }
94 if (size < 0) {
95 throw new RangeError(`Invalid circular buffer size: ${size} < 0`)
96 }
97 }
98 }