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.
		
		
		
		
		
			
		
			
				
					132 lines
				
				3.0 KiB
			
		
		
			
		
	
	
					132 lines
				
				3.0 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Mnemonist CircularBuffer
							 | 
						||
| 
								 | 
							
								 * =========================
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * Circular buffer implementation fit to use as a finite deque.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								var iterables = require('./utils/iterables.js'),
							 | 
						||
| 
								 | 
							
								    FixedDeque = require('./fixed-deque');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * CircularBuffer.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @constructor
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function CircularBuffer(ArrayClass, capacity) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (arguments.length < 2)
							 | 
						||
| 
								 | 
							
								    throw new Error('mnemonist/circular-buffer: expecting an Array class and a capacity.');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (typeof capacity !== 'number' || capacity <= 0)
							 | 
						||
| 
								 | 
							
								    throw new Error('mnemonist/circular-buffer: `capacity` should be a positive number.');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  this.ArrayClass = ArrayClass;
							 | 
						||
| 
								 | 
							
								  this.capacity = capacity;
							 | 
						||
| 
								 | 
							
								  this.items = new ArrayClass(this.capacity);
							 | 
						||
| 
								 | 
							
								  this.clear();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Pasting most of the prototype from FixedDeque.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function paste(name) {
							 | 
						||
| 
								 | 
							
								  CircularBuffer.prototype[name] = FixedDeque.prototype[name];
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Object.keys(FixedDeque.prototype).forEach(paste);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								if (typeof Symbol !== 'undefined')
							 | 
						||
| 
								 | 
							
								  Object.getOwnPropertySymbols(FixedDeque.prototype).forEach(paste);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Method used to append a value to the buffer.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param  {any}    item - Item to append.
							 | 
						||
| 
								 | 
							
								 * @return {number}      - Returns the new size of the buffer.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								CircularBuffer.prototype.push = function(item) {
							 | 
						||
| 
								 | 
							
								  var index = (this.start + this.size) % this.capacity;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  this.items[index] = item;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Overwriting?
							 | 
						||
| 
								 | 
							
								  if (this.size === this.capacity) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // If start is at the end, we wrap around the buffer
							 | 
						||
| 
								 | 
							
								    this.start = (index + 1) % this.capacity;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return this.size;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return ++this.size;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Method used to prepend a value to the buffer.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param  {any}    item - Item to prepend.
							 | 
						||
| 
								 | 
							
								 * @return {number}      - Returns the new size of the buffer.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								CircularBuffer.prototype.unshift = function(item) {
							 | 
						||
| 
								 | 
							
								  var index = this.start - 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (this.start === 0)
							 | 
						||
| 
								 | 
							
								    index = this.capacity - 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  this.items[index] = item;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Overwriting
							 | 
						||
| 
								 | 
							
								  if (this.size === this.capacity) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    this.start = index;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return this.size;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  this.start = index;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return ++this.size;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Static @.from function taking an arbitrary iterable & converting it into
							 | 
						||
| 
								 | 
							
								 * a circular buffer.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param  {Iterable} iterable   - Target iterable.
							 | 
						||
| 
								 | 
							
								 * @param  {function} ArrayClass - Array class to use.
							 | 
						||
| 
								 | 
							
								 * @param  {number}   capacity   - Desired capacity.
							 | 
						||
| 
								 | 
							
								 * @return {FiniteStack}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								CircularBuffer.from = function(iterable, ArrayClass, capacity) {
							 | 
						||
| 
								 | 
							
								  if (arguments.length < 3) {
							 | 
						||
| 
								 | 
							
								    capacity = iterables.guessLength(iterable);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (typeof capacity !== 'number')
							 | 
						||
| 
								 | 
							
								      throw new Error('mnemonist/circular-buffer.from: could not guess iterable length. Please provide desired capacity as last argument.');
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var buffer = new CircularBuffer(ArrayClass, capacity);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (iterables.isArrayLike(iterable)) {
							 | 
						||
| 
								 | 
							
								    var i, l;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    for (i = 0, l = iterable.length; i < l; i++)
							 | 
						||
| 
								 | 
							
								      buffer.items[i] = iterable[i];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    buffer.size = l;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return buffer;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  iterables.forEach(iterable, function(value) {
							 | 
						||
| 
								 | 
							
								    buffer.push(value);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return buffer;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Exporting.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								module.exports = CircularBuffer;
							 |