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.
		
		
		
		
		
			
		
			
				
					
					
						
							243 lines
						
					
					
						
							5.3 KiB
						
					
					
				
			
		
		
	
	
							243 lines
						
					
					
						
							5.3 KiB
						
					
					
				| /**
 | |
|  * Mnemonist FixedStack
 | |
|  * =====================
 | |
|  *
 | |
|  * The fixed stack is a stack whose capacity is defined beforehand and that
 | |
|  * cannot be exceeded. This class is really useful when combined with
 | |
|  * byte arrays to save up some memory and avoid memory re-allocation, hence
 | |
|  * speeding up computations.
 | |
|  *
 | |
|  * This has however a downside: you need to know the maximum size you stack
 | |
|  * can have during your iteration (which is not too difficult to compute when
 | |
|  * performing, say, a DFS on a balanced binary tree).
 | |
|  */
 | |
| var Iterator = require('obliterator/iterator'),
 | |
|     iterables = require('./utils/iterables.js');
 | |
| 
 | |
| /**
 | |
|  * FixedStack
 | |
|  *
 | |
|  * @constructor
 | |
|  * @param {function} ArrayClass - Array class to use.
 | |
|  * @param {number}   capacity   - Desired capacity.
 | |
|  */
 | |
| function FixedStack(ArrayClass, capacity) {
 | |
| 
 | |
|   if (arguments.length < 2)
 | |
|     throw new Error('mnemonist/fixed-stack: expecting an Array class and a capacity.');
 | |
| 
 | |
|   if (typeof capacity !== 'number' || capacity <= 0)
 | |
|     throw new Error('mnemonist/fixed-stack: `capacity` should be a positive number.');
 | |
| 
 | |
|   this.capacity = capacity;
 | |
|   this.ArrayClass = ArrayClass;
 | |
|   this.items = new this.ArrayClass(this.capacity);
 | |
|   this.clear();
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Method used to clear the stack.
 | |
|  *
 | |
|  * @return {undefined}
 | |
|  */
 | |
| FixedStack.prototype.clear = function() {
 | |
| 
 | |
|   // Properties
 | |
|   this.size = 0;
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Method used to add an item to the stack.
 | |
|  *
 | |
|  * @param  {any}    item - Item to add.
 | |
|  * @return {number}
 | |
|  */
 | |
| FixedStack.prototype.push = function(item) {
 | |
|   if (this.size === this.capacity)
 | |
|     throw new Error('mnemonist/fixed-stack.push: stack capacity (' + this.capacity + ') exceeded!');
 | |
| 
 | |
|   this.items[this.size++] = item;
 | |
|   return this.size;
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Method used to retrieve & remove the last item of the stack.
 | |
|  *
 | |
|  * @return {any}
 | |
|  */
 | |
| FixedStack.prototype.pop = function() {
 | |
|   if (this.size === 0)
 | |
|     return;
 | |
| 
 | |
|   return this.items[--this.size];
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Method used to get the last item of the stack.
 | |
|  *
 | |
|  * @return {any}
 | |
|  */
 | |
| FixedStack.prototype.peek = function() {
 | |
|   return this.items[this.size - 1];
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Method used to iterate over the stack.
 | |
|  *
 | |
|  * @param  {function}  callback - Function to call for each item.
 | |
|  * @param  {object}    scope    - Optional scope.
 | |
|  * @return {undefined}
 | |
|  */
 | |
| FixedStack.prototype.forEach = function(callback, scope) {
 | |
|   scope = arguments.length > 1 ? scope : this;
 | |
| 
 | |
|   for (var i = 0, l = this.items.length; i < l; i++)
 | |
|     callback.call(scope, this.items[l - i - 1], i, this);
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Method used to convert the stack to a JavaScript array.
 | |
|  *
 | |
|  * @return {array}
 | |
|  */
 | |
| FixedStack.prototype.toArray = function() {
 | |
|   var array = new this.ArrayClass(this.size),
 | |
|       l = this.size - 1,
 | |
|       i = this.size;
 | |
| 
 | |
|   while (i--)
 | |
|     array[i] = this.items[l - i];
 | |
| 
 | |
|   return array;
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Method used to create an iterator over a stack's values.
 | |
|  *
 | |
|  * @return {Iterator}
 | |
|  */
 | |
| FixedStack.prototype.values = function() {
 | |
|   var items = this.items,
 | |
|       l = this.size,
 | |
|       i = 0;
 | |
| 
 | |
|   return new Iterator(function() {
 | |
|     if (i >= l)
 | |
|       return {
 | |
|         done: true
 | |
|       };
 | |
| 
 | |
|     var value = items[l - i - 1];
 | |
|     i++;
 | |
| 
 | |
|     return {
 | |
|       value: value,
 | |
|       done: false
 | |
|     };
 | |
|   });
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Method used to create an iterator over a stack's entries.
 | |
|  *
 | |
|  * @return {Iterator}
 | |
|  */
 | |
| FixedStack.prototype.entries = function() {
 | |
|   var items = this.items,
 | |
|       l = this.size,
 | |
|       i = 0;
 | |
| 
 | |
|   return new Iterator(function() {
 | |
|     if (i >= l)
 | |
|       return {
 | |
|         done: true
 | |
|       };
 | |
| 
 | |
|     var value = items[l - i - 1];
 | |
| 
 | |
|     return {
 | |
|       value: [i++, value],
 | |
|       done: false
 | |
|     };
 | |
|   });
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Attaching the #.values method to Symbol.iterator if possible.
 | |
|  */
 | |
| if (typeof Symbol !== 'undefined')
 | |
|   FixedStack.prototype[Symbol.iterator] = FixedStack.prototype.values;
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Convenience known methods.
 | |
|  */
 | |
| FixedStack.prototype.toString = function() {
 | |
|   return this.toArray().join(',');
 | |
| };
 | |
| 
 | |
| FixedStack.prototype.toJSON = function() {
 | |
|   return this.toArray();
 | |
| };
 | |
| 
 | |
| FixedStack.prototype.inspect = function() {
 | |
|   var array = this.toArray();
 | |
| 
 | |
|   array.type = this.ArrayClass.name;
 | |
|   array.capacity = this.capacity;
 | |
| 
 | |
|   // Trick so that node displays the name of the constructor
 | |
|   Object.defineProperty(array, 'constructor', {
 | |
|     value: FixedStack,
 | |
|     enumerable: false
 | |
|   });
 | |
| 
 | |
|   return array;
 | |
| };
 | |
| 
 | |
| if (typeof Symbol !== 'undefined')
 | |
|   FixedStack.prototype[Symbol.for('nodejs.util.inspect.custom')] = FixedStack.prototype.inspect;
 | |
| 
 | |
| /**
 | |
|  * Static @.from function taking an arbitrary iterable & converting it into
 | |
|  * a stack.
 | |
|  *
 | |
|  * @param  {Iterable} iterable   - Target iterable.
 | |
|  * @param  {function} ArrayClass - Array class to use.
 | |
|  * @param  {number}   capacity   - Desired capacity.
 | |
|  * @return {FixedStack}
 | |
|  */
 | |
| FixedStack.from = function(iterable, ArrayClass, capacity) {
 | |
| 
 | |
|   if (arguments.length < 3) {
 | |
|     capacity = iterables.guessLength(iterable);
 | |
| 
 | |
|     if (typeof capacity !== 'number')
 | |
|       throw new Error('mnemonist/fixed-stack.from: could not guess iterable length. Please provide desired capacity as last argument.');
 | |
|   }
 | |
| 
 | |
|   var stack = new FixedStack(ArrayClass, capacity);
 | |
| 
 | |
|   if (iterables.isArrayLike(iterable)) {
 | |
|     var i, l;
 | |
| 
 | |
|     for (i = 0, l = iterable.length; i < l; i++)
 | |
|       stack.items[i] = iterable[i];
 | |
| 
 | |
|     stack.size = l;
 | |
| 
 | |
|     return stack;
 | |
|   }
 | |
| 
 | |
|   iterables.forEach(iterable, function(value) {
 | |
|     stack.push(value);
 | |
|   });
 | |
| 
 | |
|   return stack;
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Exporting.
 | |
|  */
 | |
| module.exports = FixedStack;
 |