@@ -49,6 +49,11 @@ const kMask = kSize - 1;
4949// | undefined | | item |
5050// +-----------+ +-----------+
5151//
52+ // Implementation detail: To reduce allocations, a single spare
53+ // FixedCircularBuffer may be kept for reuse. When a segment empties, it
54+ // is stored as the spare, and when the head fills, the spare is linked
55+ // in. This does not change the active list structure or queue semantics.
56+ //
5257// Adding a value means moving `top` forward by one, removing means
5358// moving `bottom` forward by one. After reaching the end, the queue
5459// wraps around.
@@ -74,36 +79,46 @@ class FixedCircularBuffer {
7479 }
7580
7681 push ( data ) {
77- this . list [ this . top ] = data ;
78- this . top = ( this . top + 1 ) & kMask ;
82+ const top = this . top ;
83+ this . list [ top ] = data ;
84+ this . top = ( top + 1 ) & kMask ;
7985 }
8086
8187 shift ( ) {
82- const nextItem = this . list [ this . bottom ] ;
88+ const bottom = this . bottom ;
89+ const nextItem = this . list [ bottom ] ;
8390 if ( nextItem === undefined )
8491 return null ;
85- this . list [ this . bottom ] = undefined ;
86- this . bottom = ( this . bottom + 1 ) & kMask ;
92+ this . list [ bottom ] = undefined ;
93+ this . bottom = ( bottom + 1 ) & kMask ;
8794 return nextItem ;
8895 }
8996}
9097
9198module . exports = class FixedQueue {
9299 constructor ( ) {
93100 this . head = this . tail = new FixedCircularBuffer ( ) ;
101+ this . _spare = null ;
94102 }
95103
96104 isEmpty ( ) {
97105 return this . head . isEmpty ( ) ;
98106 }
99107
100108 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 ( ) ;
109+ let head = this . head ;
110+ if ( head . isFull ( ) ) {
111+ // Head is full: reuse the spare buffer if available.
112+ // Otherwise create a new one. Link it and advance head.
113+ let nextBuf = this . _spare ;
114+ if ( nextBuf !== null ) {
115+ this . _spare = null ;
116+ } else {
117+ nextBuf = new FixedCircularBuffer ( ) ;
118+ }
119+ this . head = head = head . next = nextBuf ;
105120 }
106- this . head . push ( data ) ;
121+ head . push ( data ) ;
107122 }
108123
109124 shift ( ) {
@@ -112,7 +127,8 @@ module.exports = class FixedQueue {
112127 if ( tail . isEmpty ( ) && tail . next !== null ) {
113128 // If there is another queue, it forms the new tail.
114129 this . tail = tail . next ;
115- tail . next = null ;
130+ // Overwrite any existing spare
131+ this . _spare = tail ;
116132 }
117133 return next ;
118134 }
0 commit comments