Skip to content

Commit b10855f

Browse files
committed
lib: optimize FixedQueue by reusing one segment
1 parent 2e5c8df commit b10855f

File tree

1 file changed

+35
-11
lines changed

1 file changed

+35
-11
lines changed

lib/internal/fixed_queue.js

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,16 @@ class FixedCircularBuffer {
6565
this.next = null;
6666
}
6767

68+
/**
69+
* Resets the buffer for reuse without reallocating the backing array.
70+
* Assumes all used slots have been set back to `undefined` by shift().
71+
*/
72+
reset() {
73+
this.bottom = 0;
74+
this.top = 0;
75+
this.next = null;
76+
}
77+
6878
isEmpty() {
6979
return this.top === this.bottom;
7080
}
@@ -74,36 +84,48 @@ class FixedCircularBuffer {
7484
}
7585

7686
push(data) {
77-
this.list[this.top] = data;
78-
this.top = (this.top + 1) & kMask;
87+
const top = this.top;
88+
this.list[top] = data;
89+
this.top = (top + 1) & kMask;
7990
}
8091

8192
shift() {
82-
const nextItem = this.list[this.bottom];
93+
const bottom = this.bottom;
94+
const nextItem = this.list[bottom];
8395
if (nextItem === undefined)
8496
return null;
85-
this.list[this.bottom] = undefined;
86-
this.bottom = (this.bottom + 1) & kMask;
97+
this.list[bottom] = undefined;
98+
this.bottom = (bottom + 1) & kMask;
8799
return nextItem;
88100
}
89101
}
90102

91103
module.exports = class FixedQueue {
92104
constructor() {
93105
this.head = this.tail = new FixedCircularBuffer();
106+
this._spare = null;
94107
}
95108

96109
isEmpty() {
97110
return this.head.isEmpty();
98111
}
99112

100113
push(data) {
101-
if (this.head.isFull()) {
102-
// Head is full: Creates a new queue, sets the old queue's `.next` to it,
103-
// and sets it as the new main queue.
104-
this.head = this.head.next = new FixedCircularBuffer();
114+
let head = this.head;
115+
if (head.isFull()) {
116+
// Head is full: reuse the spare buffer if available.
117+
// Otherwise create a new one. Link it and advance head.
118+
let nextBuf = this._spare;
119+
if (nextBuf !== null) {
120+
this._spare = null;
121+
nextBuf.reset();
122+
} else {
123+
nextBuf = new FixedCircularBuffer();
124+
}
125+
head = head.next = nextBuf;
126+
this.head = head;
105127
}
106-
this.head.push(data);
128+
head.push(data);
107129
}
108130

109131
shift() {
@@ -112,7 +134,9 @@ module.exports = class FixedQueue {
112134
if (tail.isEmpty() && tail.next !== null) {
113135
// If there is another queue, it forms the new tail.
114136
this.tail = tail.next;
115-
tail.next = null;
137+
// Place the emptied buffer into the spare slot for potential reuse.
138+
tail.reset();
139+
this._spare = tail; // Overwrite any existing spare
116140
}
117141
return next;
118142
}

0 commit comments

Comments
 (0)