UNPKG

ds-algo-study

Version:

Just experimenting with publishing a package

337 lines (263 loc) 7.55 kB
'use strict' /* Expose. */ module.exports = List List.Item = ListItem var ListPrototype = List.prototype var ListItemPrototype = ListItem.prototype var IterPrototype = Iter.prototype /* istanbul ignore next */ var $iterator = typeof Symbol === 'undefined' ? undefined : Symbol.iterator ListPrototype.tail = ListPrototype.head = null List.of = of List.from = from ListPrototype.toArray = toArray ListPrototype.prepend = prepend ListPrototype.append = append /* istanbul ignore else */ if ($iterator !== undefined) { ListPrototype[$iterator] = iterator } ListItemPrototype.next = ListItemPrototype.prev = ListItemPrototype.list = null ListItemPrototype.prepend = prependItem ListItemPrototype.append = appendItem ListItemPrototype.detach = detach IterPrototype.next = next /* Constants. */ var errorMessage = 'An argument without append, prepend, or detach methods was given to `List' /* Creates a new List: A linked list is a bit like an Array, * but knows nothing about how many items are in it, and * knows only about its first (`head`) and last (`tail`) * items. Each item (e.g. `head`, `tail`, &c.) knows which * item comes before or after it (its more like the * implementation of the DOM in JavaScript). */ function List(/* items... */) { if (arguments.length !== 0) { appendAll(this, arguments) } } /* Creates a new list from the arguments (each a list item) * passed in. */ function appendAll(list, items) { var length var index var item var iter if (!items) { return list } if ($iterator !== undefined && items[$iterator]) { iter = items[$iterator]() item = {} while (!item.done) { item = iter.next() add(item.value) } } else { length = items.length index = -1 while (++index < length) { add(items[index]) } } return list function add(item) { if (item !== null && item !== undefined) { list.append(item) } } } /* Creates a new list from the arguments (each a list item) * passed in. */ function of(/* items... */) { return appendAll(new this(), arguments) } /* Creates a new list from the given array-like object * (each a list item) passed in. */ function from(items) { return appendAll(new this(), items) } /* Returns the list's items as an array. This does *not* detach the items. */ function toArray() { var item = this.head var result = [] while (item) { result.push(item) item = item.next } return result } /* Prepends the given item to the list: Item will be the * new first item (`head`). */ function prepend(item) { var self = this var head = self.head if (!item) { return false } if (!item.append || !item.prepend || !item.detach) { throw new Error(errorMessage + '#prepend`.') } if (head) { return head.prepend(item) } item.detach() item.list = self self.head = item return item } /* Appends the given item to the list: Item will be the new * last item (`tail`) if the list had a first item, and its * first item (`head`) otherwise. */ function append(item) { if (!item) { return false } if (!item.append || !item.prepend || !item.detach) { throw new Error(errorMessage + '#append`.') } var self = this var head = self.head var tail = self.tail /* If self has a last item, defer appending to the last items append * method, and return the result. */ if (tail) { return tail.append(item) } /* If self has a first item, defer appending to the first items append * method, and return the result. */ if (head) { return head.append(item) } /* ...otherwise, there is no `tail` or `head` item yet. */ item.detach() item.list = self self.head = item return item } /* Creates an iterator from the list. */ function iterator() { return new Iter(this.head) } /* Creates a new ListItem: A linked list item is a bit like * DOM node: It knows only about its "parent" (`list`), the * item before it (`prev`), and the item after it (`next`). */ function ListItem() {} /* Detaches the item operated on from its parent list. */ function detach() { var self = this var list = self.list var prev = self.prev var next = self.next if (!list) { return self } /* If self is the last item in the parent list, link the * lists last item to the previous item. */ if (list.tail === self) { list.tail = prev } /* If self is the first item in the parent list, link * the lists first item to the next item. */ if (list.head === self) { list.head = next } /* If both the last and first items in the parent list * are the same, remove the link to the last item. */ if (list.tail === list.head) { list.tail = null } /* If a previous item exists, link its next item to selfs * next item. */ if (prev) { prev.next = next } /* If a next item exists, link its previous item to selfs * previous item. */ if (next) { next.prev = prev } /* Remove links from self to both the next and previous * items, and to the parent list. */ self.prev = self.next = self.list = null return self } /* Prepends the given item *before* the item operated on. */ function prependItem(item) { if (!item || !item.append || !item.prepend || !item.detach) { throw new Error(errorMessage + 'Item#prepend`.') } var self = this var list = self.list var prev = self.prev /* If self is detached, return false. */ if (!list) { return false } /* Detach the prependee. */ item.detach() /* If self has a previous item... */ if (prev) { item.prev = prev prev.next = item } /* Connect the prependee. */ item.next = self item.list = list /* Set the previous item of self to the prependee. */ self.prev = item /* If self is the first item in the parent list, link the * lists first item to the prependee. */ if (self === list.head) { list.head = item } /* If the the parent list has no last item, link the lists * last item to self. */ if (!list.tail) { list.tail = self } return item } /* Appends the given item *after* the item operated on. */ function appendItem(item) { if (!item || !item.append || !item.prepend || !item.detach) { throw new Error(errorMessage + 'Item#append`.') } var self = this var list = self.list var next = self.next if (!list) { return false } /* Detach the appendee. */ item.detach() /* If self has a next item... */ if (next) { item.next = next next.prev = item } /* Connect the appendee. */ item.prev = self item.list = list /* Set the next item of self to the appendee. */ self.next = item /* If the the parent list has no last item or if self is * the parent lists last item, link the lists last item * to the appendee. */ if (self === list.tail || !list.tail) { list.tail = item } return item } /* Creates a new `Iter` for looping over the `LinkedList`. */ function Iter(item) { this.item = item } /* Move the `Iter` to the next item. */ function next() { var current = this.item this.value = current this.done = !current this.item = current ? current.next : undefined return this }