You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			77 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			TypeScript
		
	
			
		
		
	
	
			77 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			TypeScript
		
	
| /**
 | |
|  * This ringbuffer class can be used to keep a list of at most a size and removing old items first when the size is exceeded.
 | |
|  * Internally, it uses an array to keep track of the order, so two times the same item can exist in it.
 | |
|  *
 | |
|  */
 | |
| export class RingBuffer<T> {
 | |
|   private newest = -1;
 | |
|   private oldest = 0;
 | |
|   private buffer: Array<T> = [];
 | |
|   private readonly capacity: number;
 | |
| 
 | |
|   constructor(capacity: number) {
 | |
|     this.capacity = capacity;
 | |
|   }
 | |
| 
 | |
|   public getCapacity(): number {
 | |
|     return this.capacity;
 | |
|   }
 | |
| 
 | |
|   public getLength(): number {
 | |
|     if (this.isEmpty()) {
 | |
|       return 0;
 | |
|     }
 | |
| 
 | |
|     // When only one item was added, newest = 0 and oldest = 0.
 | |
|     // When more than one item was added, but less than capacity, newest = nbItemsAdded & oldest = 0.
 | |
|     // As soon as we overflow, oldest is incremented to oldest+1 and newest rolls back to 0,
 | |
|     // so this test fails here and we have to extract the length based on the two parts instead.
 | |
|     if (this.newest >= this.oldest) {
 | |
|       return this.newest + 1;
 | |
|     }
 | |
|     const firstPart = this.capacity - this.oldest;
 | |
|     const secondPart = this.newest + 1;
 | |
|     return firstPart + secondPart;
 | |
|   }
 | |
| 
 | |
|   public insert(item: T) {
 | |
|     // see comments in `getLength()`
 | |
|     this.newest = (this.newest + 1) % this.capacity;
 | |
|     if (this.buffer.length >= this.capacity) {
 | |
|       this.oldest = (this.oldest + 1) % this.capacity;
 | |
|     }
 | |
|     this.buffer[this.newest] = item;
 | |
|   }
 | |
| 
 | |
|   public has(item: T) {
 | |
|     // no items at all
 | |
|     if (this.isEmpty()) {
 | |
|       return false;
 | |
|     }
 | |
|     return this.toArray().includes(item);
 | |
|   }
 | |
| 
 | |
|   public isEmpty() {
 | |
|     return this.newest === -1;
 | |
|   }
 | |
| 
 | |
|   public clear() {
 | |
|     this.buffer = [];
 | |
|     this.newest = -1;
 | |
|     this.oldest = 0;
 | |
|   }
 | |
| 
 | |
|   public toArray(): Array<T> {
 | |
|     if (this.isEmpty()) {
 | |
|       return [];
 | |
|     }
 | |
| 
 | |
|     if (this.newest >= this.oldest) {
 | |
|       return this.buffer.slice(0, this.newest + 1);
 | |
|     }
 | |
|     const firstPart = this.buffer.slice(this.oldest, this.capacity);
 | |
|     const secondPart = this.buffer.slice(0, this.newest + 1);
 | |
|     return [...firstPart, ...secondPart];
 | |
|   }
 | |
| }
 |