Spaces:
Runtime error
Runtime error
/* eslint-disable */ | |
// Extracted from node/lib/internal/fixed_queue.js | |
// Currently optimal queue size, tested on V8 6.0 - 6.6. Must be power of two. | |
const kSize = 2048; | |
const kMask = kSize - 1; | |
// The FixedQueue is implemented as a singly-linked list of fixed-size | |
// circular buffers. It looks something like this: | |
// | |
// head tail | |
// | | | |
// v v | |
// +-----------+ <-----\ +-----------+ <------\ +-----------+ | |
// | [null] | \----- | next | \------- | next | | |
// +-----------+ +-----------+ +-----------+ | |
// | item | <-- bottom | item | <-- bottom | [empty] | | |
// | item | | item | | [empty] | | |
// | item | | item | | [empty] | | |
// | item | | item | | [empty] | | |
// | item | | item | bottom --> | item | | |
// | item | | item | | item | | |
// | ... | | ... | | ... | | |
// | item | | item | | item | | |
// | item | | item | | item | | |
// | [empty] | <-- top | item | | item | | |
// | [empty] | | item | | item | | |
// | [empty] | | [empty] | <-- top top --> | [empty] | | |
// +-----------+ +-----------+ +-----------+ | |
// | |
// Or, if there is only one circular buffer, it looks something | |
// like either of these: | |
// | |
// head tail head tail | |
// | | | | | |
// v v v v | |
// +-----------+ +-----------+ | |
// | [null] | | [null] | | |
// +-----------+ +-----------+ | |
// | [empty] | | item | | |
// | [empty] | | item | | |
// | item | <-- bottom top --> | [empty] | | |
// | item | | [empty] | | |
// | [empty] | <-- top bottom --> | item | | |
// | [empty] | | item | | |
// +-----------+ +-----------+ | |
// | |
// Adding a value means moving `top` forward by one, removing means | |
// moving `bottom` forward by one. After reaching the end, the queue | |
// wraps around. | |
// | |
// When `top === bottom` the current queue is empty and when | |
// `top + 1 === bottom` it's full. This wastes a single space of storage | |
// but allows much quicker checks. | |
class FixedCircularBuffer { | |
constructor() { | |
this.bottom = 0; | |
this.top = 0; | |
this.list = new Array(kSize); | |
this.next = null; | |
} | |
isEmpty() { | |
return this.top === this.bottom; | |
} | |
isFull() { | |
return ((this.top + 1) & kMask) === this.bottom; | |
} | |
push(data) { | |
this.list[this.top] = data; | |
this.top = (this.top + 1) & kMask; | |
} | |
shift() { | |
const nextItem = this.list[this.bottom]; | |
if (nextItem === undefined) | |
return null; | |
this.list[this.bottom] = undefined; | |
this.bottom = (this.bottom + 1) & kMask; | |
return nextItem; | |
} | |
} | |
module.exports = class FixedQueue { | |
constructor() { | |
this.head = this.tail = new FixedCircularBuffer(); | |
} | |
isEmpty() { | |
return this.head.isEmpty(); | |
} | |
push(data) { | |
if (this.head.isFull()) { | |
// Head is full: Creates a new queue, sets the old queue's `.next` to it, | |
// and sets it as the new main queue. | |
this.head = this.head.next = new FixedCircularBuffer(); | |
} | |
this.head.push(data); | |
} | |
shift() { | |
const tail = this.tail; | |
const next = tail.shift(); | |
if (tail.isEmpty() && tail.next !== null) { | |
// If there is another queue, it forms the new tail. | |
this.tail = tail.next; | |
} | |
return next; | |
} | |
}; | |