196 lines
5.9 KiB
JavaScript
196 lines
5.9 KiB
JavaScript
/**
|
|
* @fileOverview Implementation of an iterator for a linked list
|
|
* data structure
|
|
* @author Jason S. Jones
|
|
* @license MIT
|
|
*/
|
|
|
|
(function () {
|
|
'use strict';
|
|
|
|
/**************************************************
|
|
* Iterator class
|
|
*
|
|
* Represents an instantiation of an iterator to be used
|
|
* within a linked list. The iterator will provide the ability
|
|
* to iterate over all nodes in a list by keeping track of the
|
|
* postition of a 'currentNode'. This 'currentNode' pointer
|
|
* will keep state until a reset() operation is called at which
|
|
* time it will reset to point the head of the list.
|
|
*
|
|
* Even though this iterator class is inextricably linked
|
|
* (no pun intended) to a linked list instatiation, it was removed
|
|
* from within the linked list code to adhere to the best practice
|
|
* of separation of concerns.
|
|
*
|
|
***************************************************/
|
|
|
|
/**
|
|
* Creates an iterator instance to iterate over the linked list provided.
|
|
*
|
|
* @constructor
|
|
* @param {object} theList the linked list to iterate over
|
|
*/
|
|
function Iterator(theList) {
|
|
this.list = theList || null;
|
|
this.stopIterationFlag = false;
|
|
|
|
// a pointer the current node in the list that will be returned.
|
|
// initially this will be null since the 'list' will be empty
|
|
this.currentNode = null;
|
|
}
|
|
|
|
/* Functions attached to the Iterator prototype. All iterator instances
|
|
* will share these methods, meaning there will NOT be copies made for each
|
|
* instance.
|
|
*/
|
|
Iterator.prototype = {
|
|
|
|
/**
|
|
* Returns the next node in the iteration.
|
|
*
|
|
* @returns {object} the next node in the iteration.
|
|
*/
|
|
next: function() {
|
|
var current = this.currentNode;
|
|
// a check to prevent error if randomly calling next() when
|
|
// iterator is at the end of the list, meaining the currentNode
|
|
// will be pointing to null.
|
|
//
|
|
// When this function is called, it will return the node currently
|
|
// assigned to this.currentNode and move the pointer to the next
|
|
// node in the list (if it exists)
|
|
if (this.currentNode !== null) {
|
|
this.currentNode = this.currentNode.next;
|
|
}
|
|
|
|
return current;
|
|
},
|
|
|
|
/**
|
|
* Determines if the iterator has a node to return
|
|
*
|
|
* @returns true if the iterator has a node to return, false otherwise
|
|
*/
|
|
hasNext: function() {
|
|
return this.currentNode !== null;
|
|
},
|
|
|
|
/**
|
|
* Resets the iterator to the beginning of the list.
|
|
*/
|
|
reset: function() {
|
|
this.currentNode = this.list.getHeadNode();
|
|
},
|
|
|
|
/**
|
|
* Returns the first node in the list and moves the iterator to
|
|
* point to the second node.
|
|
*
|
|
* @returns the first node in the list
|
|
*/
|
|
first: function() {
|
|
this.reset();
|
|
return this.next();
|
|
},
|
|
|
|
/**
|
|
* Sets the list to iterate over
|
|
*
|
|
* @param {object} theList the linked list to iterate over
|
|
*/
|
|
setList: function(theList) {
|
|
this.list = theList;
|
|
this.reset();
|
|
},
|
|
|
|
/**
|
|
* Iterates over all nodes in the list and calls the provided callback
|
|
* function with each node as an argument.
|
|
* Iteration will break if interrupt() is called
|
|
*
|
|
* @param {function} callback the callback function to be called with
|
|
* each node of the list as an arg
|
|
*/
|
|
each: function(callback) {
|
|
this.reset();
|
|
var el;
|
|
while (this.hasNext() && !this.stopIterationFlag) {
|
|
el = this.next();
|
|
callback(el);
|
|
}
|
|
this.stopIterationFlag = false;
|
|
},
|
|
|
|
/*
|
|
* ### REVERSE ITERATION (TAIL -> HEAD) ###
|
|
*/
|
|
|
|
/**
|
|
* Returns the first node in the list and moves the iterator to
|
|
* point to the second node.
|
|
*
|
|
* @returns the first node in the list
|
|
*/
|
|
last: function() {
|
|
this.reset_reverse();
|
|
return this.next_reverse();
|
|
},
|
|
|
|
/**
|
|
* Resets the iterator to the tail of the list.
|
|
*/
|
|
reset_reverse: function() {
|
|
this.currentNode = this.list.getTailNode();
|
|
},
|
|
|
|
/**
|
|
* Returns the next node in the iteration, when iterating from tail to head
|
|
*
|
|
* @returns {object} the next node in the iteration.
|
|
*/
|
|
next_reverse: function() {
|
|
var current = this.currentNode;
|
|
if (this.currentNode !== null) {
|
|
this.currentNode = this.currentNode.prev;
|
|
}
|
|
|
|
return current;
|
|
},
|
|
|
|
/**
|
|
* Iterates over all nodes in the list and calls the provided callback
|
|
* function with each node as an argument,
|
|
* starting from the tail and going towards the head.
|
|
* The iteration will break if interrupt() is called.
|
|
*
|
|
* @param {function} callback the callback function to be called within
|
|
* each node as an arg
|
|
*/
|
|
each_reverse: function(callback) {
|
|
this.reset_reverse();
|
|
var el;
|
|
while (this.hasNext() && !this.stopIterationFlag) {
|
|
el = this.next_reverse();
|
|
callback(el);
|
|
}
|
|
this.stopIterationFlag = false;
|
|
},
|
|
|
|
/*
|
|
* ### INTERRUPT ITERATION ###
|
|
*/
|
|
|
|
/**
|
|
* Raises interrupt flag (that will stop each() or each_reverse())
|
|
*/
|
|
|
|
interrupt: function() {
|
|
this.stopIterationFlag = true;
|
|
}
|
|
};
|
|
|
|
module.exports = Iterator;
|
|
|
|
}());
|