You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
426 lines
8.2 KiB
426 lines
8.2 KiB
'use strict' |
|
module.exports = Yallist |
|
|
|
Yallist.Node = Node |
|
Yallist.create = Yallist |
|
|
|
function Yallist (list) { |
|
var self = this |
|
if (!(self instanceof Yallist)) { |
|
self = new Yallist() |
|
} |
|
|
|
self.tail = null |
|
self.head = null |
|
self.length = 0 |
|
|
|
if (list && typeof list.forEach === 'function') { |
|
list.forEach(function (item) { |
|
self.push(item) |
|
}) |
|
} else if (arguments.length > 0) { |
|
for (var i = 0, l = arguments.length; i < l; i++) { |
|
self.push(arguments[i]) |
|
} |
|
} |
|
|
|
return self |
|
} |
|
|
|
Yallist.prototype.removeNode = function (node) { |
|
if (node.list !== this) { |
|
throw new Error('removing node which does not belong to this list') |
|
} |
|
|
|
var next = node.next |
|
var prev = node.prev |
|
|
|
if (next) { |
|
next.prev = prev |
|
} |
|
|
|
if (prev) { |
|
prev.next = next |
|
} |
|
|
|
if (node === this.head) { |
|
this.head = next |
|
} |
|
if (node === this.tail) { |
|
this.tail = prev |
|
} |
|
|
|
node.list.length-- |
|
node.next = null |
|
node.prev = null |
|
node.list = null |
|
|
|
return next |
|
} |
|
|
|
Yallist.prototype.unshiftNode = function (node) { |
|
if (node === this.head) { |
|
return |
|
} |
|
|
|
if (node.list) { |
|
node.list.removeNode(node) |
|
} |
|
|
|
var head = this.head |
|
node.list = this |
|
node.next = head |
|
if (head) { |
|
head.prev = node |
|
} |
|
|
|
this.head = node |
|
if (!this.tail) { |
|
this.tail = node |
|
} |
|
this.length++ |
|
} |
|
|
|
Yallist.prototype.pushNode = function (node) { |
|
if (node === this.tail) { |
|
return |
|
} |
|
|
|
if (node.list) { |
|
node.list.removeNode(node) |
|
} |
|
|
|
var tail = this.tail |
|
node.list = this |
|
node.prev = tail |
|
if (tail) { |
|
tail.next = node |
|
} |
|
|
|
this.tail = node |
|
if (!this.head) { |
|
this.head = node |
|
} |
|
this.length++ |
|
} |
|
|
|
Yallist.prototype.push = function () { |
|
for (var i = 0, l = arguments.length; i < l; i++) { |
|
push(this, arguments[i]) |
|
} |
|
return this.length |
|
} |
|
|
|
Yallist.prototype.unshift = function () { |
|
for (var i = 0, l = arguments.length; i < l; i++) { |
|
unshift(this, arguments[i]) |
|
} |
|
return this.length |
|
} |
|
|
|
Yallist.prototype.pop = function () { |
|
if (!this.tail) { |
|
return undefined |
|
} |
|
|
|
var res = this.tail.value |
|
this.tail = this.tail.prev |
|
if (this.tail) { |
|
this.tail.next = null |
|
} else { |
|
this.head = null |
|
} |
|
this.length-- |
|
return res |
|
} |
|
|
|
Yallist.prototype.shift = function () { |
|
if (!this.head) { |
|
return undefined |
|
} |
|
|
|
var res = this.head.value |
|
this.head = this.head.next |
|
if (this.head) { |
|
this.head.prev = null |
|
} else { |
|
this.tail = null |
|
} |
|
this.length-- |
|
return res |
|
} |
|
|
|
Yallist.prototype.forEach = function (fn, thisp) { |
|
thisp = thisp || this |
|
for (var walker = this.head, i = 0; walker !== null; i++) { |
|
fn.call(thisp, walker.value, i, this) |
|
walker = walker.next |
|
} |
|
} |
|
|
|
Yallist.prototype.forEachReverse = function (fn, thisp) { |
|
thisp = thisp || this |
|
for (var walker = this.tail, i = this.length - 1; walker !== null; i--) { |
|
fn.call(thisp, walker.value, i, this) |
|
walker = walker.prev |
|
} |
|
} |
|
|
|
Yallist.prototype.get = function (n) { |
|
for (var i = 0, walker = this.head; walker !== null && i < n; i++) { |
|
// abort out of the list early if we hit a cycle |
|
walker = walker.next |
|
} |
|
if (i === n && walker !== null) { |
|
return walker.value |
|
} |
|
} |
|
|
|
Yallist.prototype.getReverse = function (n) { |
|
for (var i = 0, walker = this.tail; walker !== null && i < n; i++) { |
|
// abort out of the list early if we hit a cycle |
|
walker = walker.prev |
|
} |
|
if (i === n && walker !== null) { |
|
return walker.value |
|
} |
|
} |
|
|
|
Yallist.prototype.map = function (fn, thisp) { |
|
thisp = thisp || this |
|
var res = new Yallist() |
|
for (var walker = this.head; walker !== null;) { |
|
res.push(fn.call(thisp, walker.value, this)) |
|
walker = walker.next |
|
} |
|
return res |
|
} |
|
|
|
Yallist.prototype.mapReverse = function (fn, thisp) { |
|
thisp = thisp || this |
|
var res = new Yallist() |
|
for (var walker = this.tail; walker !== null;) { |
|
res.push(fn.call(thisp, walker.value, this)) |
|
walker = walker.prev |
|
} |
|
return res |
|
} |
|
|
|
Yallist.prototype.reduce = function (fn, initial) { |
|
var acc |
|
var walker = this.head |
|
if (arguments.length > 1) { |
|
acc = initial |
|
} else if (this.head) { |
|
walker = this.head.next |
|
acc = this.head.value |
|
} else { |
|
throw new TypeError('Reduce of empty list with no initial value') |
|
} |
|
|
|
for (var i = 0; walker !== null; i++) { |
|
acc = fn(acc, walker.value, i) |
|
walker = walker.next |
|
} |
|
|
|
return acc |
|
} |
|
|
|
Yallist.prototype.reduceReverse = function (fn, initial) { |
|
var acc |
|
var walker = this.tail |
|
if (arguments.length > 1) { |
|
acc = initial |
|
} else if (this.tail) { |
|
walker = this.tail.prev |
|
acc = this.tail.value |
|
} else { |
|
throw new TypeError('Reduce of empty list with no initial value') |
|
} |
|
|
|
for (var i = this.length - 1; walker !== null; i--) { |
|
acc = fn(acc, walker.value, i) |
|
walker = walker.prev |
|
} |
|
|
|
return acc |
|
} |
|
|
|
Yallist.prototype.toArray = function () { |
|
var arr = new Array(this.length) |
|
for (var i = 0, walker = this.head; walker !== null; i++) { |
|
arr[i] = walker.value |
|
walker = walker.next |
|
} |
|
return arr |
|
} |
|
|
|
Yallist.prototype.toArrayReverse = function () { |
|
var arr = new Array(this.length) |
|
for (var i = 0, walker = this.tail; walker !== null; i++) { |
|
arr[i] = walker.value |
|
walker = walker.prev |
|
} |
|
return arr |
|
} |
|
|
|
Yallist.prototype.slice = function (from, to) { |
|
to = to || this.length |
|
if (to < 0) { |
|
to += this.length |
|
} |
|
from = from || 0 |
|
if (from < 0) { |
|
from += this.length |
|
} |
|
var ret = new Yallist() |
|
if (to < from || to < 0) { |
|
return ret |
|
} |
|
if (from < 0) { |
|
from = 0 |
|
} |
|
if (to > this.length) { |
|
to = this.length |
|
} |
|
for (var i = 0, walker = this.head; walker !== null && i < from; i++) { |
|
walker = walker.next |
|
} |
|
for (; walker !== null && i < to; i++, walker = walker.next) { |
|
ret.push(walker.value) |
|
} |
|
return ret |
|
} |
|
|
|
Yallist.prototype.sliceReverse = function (from, to) { |
|
to = to || this.length |
|
if (to < 0) { |
|
to += this.length |
|
} |
|
from = from || 0 |
|
if (from < 0) { |
|
from += this.length |
|
} |
|
var ret = new Yallist() |
|
if (to < from || to < 0) { |
|
return ret |
|
} |
|
if (from < 0) { |
|
from = 0 |
|
} |
|
if (to > this.length) { |
|
to = this.length |
|
} |
|
for (var i = this.length, walker = this.tail; walker !== null && i > to; i--) { |
|
walker = walker.prev |
|
} |
|
for (; walker !== null && i > from; i--, walker = walker.prev) { |
|
ret.push(walker.value) |
|
} |
|
return ret |
|
} |
|
|
|
Yallist.prototype.splice = function (start, deleteCount, ...nodes) { |
|
if (start > this.length) { |
|
start = this.length - 1 |
|
} |
|
if (start < 0) { |
|
start = this.length + start; |
|
} |
|
|
|
for (var i = 0, walker = this.head; walker !== null && i < start; i++) { |
|
walker = walker.next |
|
} |
|
|
|
var ret = [] |
|
for (var i = 0; walker && i < deleteCount; i++) { |
|
ret.push(walker.value) |
|
walker = this.removeNode(walker) |
|
} |
|
if (walker === null) { |
|
walker = this.tail |
|
} |
|
|
|
if (walker !== this.head && walker !== this.tail) { |
|
walker = walker.prev |
|
} |
|
|
|
for (var i = 0; i < nodes.length; i++) { |
|
walker = insert(this, walker, nodes[i]) |
|
} |
|
return ret; |
|
} |
|
|
|
Yallist.prototype.reverse = function () { |
|
var head = this.head |
|
var tail = this.tail |
|
for (var walker = head; walker !== null; walker = walker.prev) { |
|
var p = walker.prev |
|
walker.prev = walker.next |
|
walker.next = p |
|
} |
|
this.head = tail |
|
this.tail = head |
|
return this |
|
} |
|
|
|
function insert (self, node, value) { |
|
var inserted = node === self.head ? |
|
new Node(value, null, node, self) : |
|
new Node(value, node, node.next, self) |
|
|
|
if (inserted.next === null) { |
|
self.tail = inserted |
|
} |
|
if (inserted.prev === null) { |
|
self.head = inserted |
|
} |
|
|
|
self.length++ |
|
|
|
return inserted |
|
} |
|
|
|
function push (self, item) { |
|
self.tail = new Node(item, self.tail, null, self) |
|
if (!self.head) { |
|
self.head = self.tail |
|
} |
|
self.length++ |
|
} |
|
|
|
function unshift (self, item) { |
|
self.head = new Node(item, null, self.head, self) |
|
if (!self.tail) { |
|
self.tail = self.head |
|
} |
|
self.length++ |
|
} |
|
|
|
function Node (value, prev, next, list) { |
|
if (!(this instanceof Node)) { |
|
return new Node(value, prev, next, list) |
|
} |
|
|
|
this.list = list |
|
this.value = value |
|
|
|
if (prev) { |
|
prev.next = this |
|
this.prev = prev |
|
} else { |
|
this.prev = null |
|
} |
|
|
|
if (next) { |
|
next.prev = this |
|
this.next = next |
|
} else { |
|
this.next = null |
|
} |
|
} |
|
|
|
try { |
|
// add if support for Symbol.iterator is present |
|
require('./iterator.js')(Yallist) |
|
} catch (er) {}
|
|
|