mirror of
https://github.com/Unleash/unleash.git
synced 2025-01-06 00:07:44 +01:00
133 lines
3.0 KiB
JavaScript
133 lines
3.0 KiB
JavaScript
|
'use strict';
|
||
|
|
||
|
const { EventEmitter } = require('events');
|
||
|
|
||
|
class Node {
|
||
|
constructor (value) {
|
||
|
this.value = value;
|
||
|
this.next = null;
|
||
|
}
|
||
|
|
||
|
link (next) {
|
||
|
this.next = next;
|
||
|
next.prev = this;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* linked list
|
||
|
* ranged list, assumes start to end(tail) is a known order
|
||
|
* remove() is only implemented in reverse order for the usecase
|
||
|
* emits events on eviction
|
||
|
*/
|
||
|
module.exports = class List extends EventEmitter {
|
||
|
constructor () {
|
||
|
super();
|
||
|
this.start = null;
|
||
|
this.tail = null;
|
||
|
}
|
||
|
|
||
|
add (obj) {
|
||
|
const node = new Node(obj);
|
||
|
if (this.tail) {
|
||
|
this.tail.link(node);
|
||
|
this.tail = node;
|
||
|
} else {
|
||
|
this.start = node;
|
||
|
this.tail = node;
|
||
|
}
|
||
|
return node;
|
||
|
}
|
||
|
|
||
|
iterate (fn) {
|
||
|
if (!this.start) {
|
||
|
return;
|
||
|
}
|
||
|
let cursor = this.start;
|
||
|
while (cursor) {
|
||
|
const result = fn(cursor);
|
||
|
if (result === false) {
|
||
|
cursor = null;
|
||
|
} else {
|
||
|
cursor = cursor.next;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
iterateReverse (fn) {
|
||
|
if (!this.tail) {
|
||
|
return;
|
||
|
}
|
||
|
let cursor = this.tail;
|
||
|
while (cursor) {
|
||
|
const result = fn(cursor);
|
||
|
if (result === false) {
|
||
|
cursor = null;
|
||
|
} else {
|
||
|
cursor = cursor.prev;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
reverseRemoveUntilTrue (fn) {
|
||
|
if (!this.tail) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
let cursor = this.tail;
|
||
|
while (cursor) {
|
||
|
const result = fn(cursor);
|
||
|
if (result === false && cursor === this.start) {
|
||
|
// whole list is removed
|
||
|
this.emit('evicted', cursor.value);
|
||
|
this.start = null;
|
||
|
this.tail = null;
|
||
|
// stop iteration
|
||
|
cursor = null;
|
||
|
} else if (result === true) {
|
||
|
// when TRUE, set match as new tail
|
||
|
if (cursor !== this.tail) {
|
||
|
this.tail = cursor;
|
||
|
cursor.next = null;
|
||
|
}
|
||
|
// stop iteration
|
||
|
cursor = null;
|
||
|
} else {
|
||
|
// evicted
|
||
|
this.emit('evicted', cursor.value);
|
||
|
// iterate to next
|
||
|
cursor = cursor.prev;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
toArray () {
|
||
|
const result = [];
|
||
|
|
||
|
if (this.start) {
|
||
|
let cursor = this.start;
|
||
|
while (cursor) {
|
||
|
result.push(cursor.value);
|
||
|
cursor = cursor.next;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
toArrayReverse () {
|
||
|
const result = [];
|
||
|
|
||
|
if (this.tail) {
|
||
|
let cursor = this.tail;
|
||
|
while (cursor) {
|
||
|
result.push(cursor.value);
|
||
|
cursor = cursor.prev;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
};
|