123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100 |
- "use strict";
- /**
- * Creates an interator for a DoublyLinkedList starting at the given node
- * It's internal cursor will remains relative to the last "iterated" node as that
- * node moves through the list until it either iterates to the end of the list,
- * or the the node it's tracking is removed from the list. Until the first 'next'
- * call it tracks the head/tail of the linked list. This means that one can create
- * an iterator on an empty list, then add nodes, and then the iterator will follow
- * those nodes. Because the DoublyLinkedList nodes don't track their owning "list" and
- * it's highly inefficient to walk the list for every iteration, the iterator won't know
- * if the node has been detached from one List and added to another list, or if the iterator
- *
- * The created object is an es6 compatible iterator
- */
- class DoublyLinkedListIterator {
- /**
- * @param {Object} doublyLinkedList a node that is part of a doublyLinkedList
- * @param {Boolean} [reverse=false] is this a reverse iterator? default: false
- */
- constructor(doublyLinkedList, reverse) {
- this._list = doublyLinkedList;
- // NOTE: these key names are tied to the DoublyLinkedListIterator
- this._direction = reverse === true ? "prev" : "next";
- this._startPosition = reverse === true ? "tail" : "head";
- this._started = false;
- this._cursor = null;
- this._done = false;
- }
- _start() {
- this._cursor = this._list[this._startPosition];
- this._started = true;
- }
- _advanceCursor() {
- if (this._started === false) {
- this._started = true;
- this._cursor = this._list[this._startPosition];
- return;
- }
- this._cursor = this._cursor[this._direction];
- }
- reset() {
- this._done = false;
- this._started = false;
- this._cursor = null;
- }
- remove() {
- if (
- this._started === false ||
- this._done === true ||
- this._isCursorDetached()
- ) {
- return false;
- }
- this._list.remove(this._cursor);
- }
- next() {
- if (this._done === true) {
- return { done: true };
- }
- this._advanceCursor();
- // if there is no node at the cursor or the node at the cursor is no longer part of
- // a doubly linked list then we are done/finished/kaput
- if (this._cursor === null || this._isCursorDetached()) {
- this._done = true;
- return { done: true };
- }
- return {
- value: this._cursor,
- done: false
- };
- }
- /**
- * Is the node detached from a list?
- * NOTE: you can trick/bypass/confuse this check by removing a node from one DoublyLinkedList
- * and adding it to another.
- * TODO: We can make this smarter by checking the direction of travel and only checking
- * the required next/prev/head/tail rather than all of them
- * @return {Boolean} [description]
- */
- _isCursorDetached() {
- return (
- this._cursor.prev === null &&
- this._cursor.next === null &&
- this._list.tail !== this._cursor &&
- this._list.head !== this._cursor
- );
- }
- }
- module.exports = DoublyLinkedListIterator;
|