license /**
 * A ring buffer, providing O(1) FIFO, LIFO, and related operations.
 */ export class RingBuffer < T > { protected begin = 0 ; protected end = 0 ; protected doubledCapacity : number ; protected data : T [ ] ; param capacity constructor ( public capacity ) { if ( capacity == null ) { throw new RangeError ( 'Can\'t create a ring buffer of unknown capacity.' ) ; } if ( capacity < 1 ) { throw new RangeError ( 'Can\'t create ring buffer of capacity < 1.' ) ; } this . data = new Array < T > ( capacity ) ; this . doubledCapacity = 2 * capacity ; } /**
     * Map any index into the range 0 <= index < 2*capacity.
     */ protected wrap ( index ) { while ( index < 0 ) { index += this . doubledCapacity ; } return index % this . doubledCapacity ; } protected get ( index ) { if ( index < 0 ) { throw new RangeError ( 'Can\'t get item at a negative index.' ) ; } return this . data [ index % this . capacity ] ; } protected set ( index , value ) { if ( index < 0 ) { throw new RangeError ( 'Can\'t set item at a negative index.' ) ; } this . data [ index % this . capacity ] = value ; } /**
     * Returns the current number of items in the buffer.
     */ length ( ) { let length = this . end - this . begin ; if ( length < 0 ) { length = this . doubledCapacity + length ; } return length ; } returns isFull ( ) { return this . length ( ) === this . capacity ; } returns isEmpty ( ) { return this . length ( ) === 0 ; } /**
     * Adds an item to the end of the buffer.
     */ push ( value ) { if ( this . isFull ( ) ) { throw new RangeError ( 'Ring buffer is full.' ) ; } this . set ( this . end , value ) ; this . end = this . wrap ( this . end + 1 ) ; } /**
     * Adds many items to the end of the buffer, in order.
     */ pushAll ( values ) { for ( const value of values ) { this . push ( value ) ; } } /**
     * Removes and returns the last item in the buffer.
     */ pop ( ) { if ( this . isEmpty ( ) ) { throw new RangeError ( 'Ring buffer is empty.' ) ; } this . end = this . wrap ( this . end - 1 ) ; const result = this . get ( this . end ) ; this . set ( this . end , undefined ) ; return result ; } /**
     * Adds an item to the beginning of the buffer.
     */ unshift ( value ) { if ( this . isFull ( ) ) { throw new RangeError ( 'Ring buffer is full.' ) ; } this . begin = this . wrap ( this . begin - 1 ) ; this . set ( this . begin , value ) ; } /**
     * Removes and returns the first item in the buffer.
     */ shift ( ) { if ( this . isEmpty ( ) ) { throw new RangeError ( 'Ring buffer is empty.' ) ; } const result = this . get ( this . begin ) ; this . set ( this . begin , undefined ) ; this . begin = this . wrap ( this . begin + 1 ) ; return result ; } param relativeIndex shuffleExcise ( relativeIndex ) { if ( this . isEmpty ( ) ) { throw new RangeError ( 'Ring buffer is empty.' ) ; } const index = this . wrap ( this . begin + relativeIndex ) ; const result = this . get ( index ) ; this . set ( index , this . pop ( ) ) ; return result ; } }