ringBuffer.ts 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. export class RingBuffer<T> {
  2. private readonly capacity: number
  3. private readonly buffer: (T | undefined)[]
  4. private head = 0
  5. private tail = 0
  6. private size = 0
  7. constructor(capacity: number) {
  8. if (!Number.isInteger(capacity) || capacity <= 0) {
  9. throw new Error('RingBuffer capacity must be a positive integer')
  10. }
  11. this.capacity = capacity
  12. this.buffer = new Array<T | undefined>(capacity).fill(undefined)
  13. }
  14. get length(): number {
  15. return this.size
  16. }
  17. pushBack(value: T): void {
  18. this.buffer[this.tail] = value
  19. if (this.size === this.capacity) {
  20. this.head = (this.head + 1) % this.capacity
  21. } else {
  22. this.size += 1
  23. }
  24. this.tail = (this.tail + 1) % this.capacity
  25. }
  26. popFront(): T | undefined {
  27. if (this.size === 0) {
  28. return undefined
  29. }
  30. const value = this.buffer[this.head]
  31. this.buffer[this.head] = undefined
  32. this.head = (this.head + 1) % this.capacity
  33. this.size -= 1
  34. return value
  35. }
  36. popBack(): T | undefined {
  37. if (this.size === 0) {
  38. return undefined
  39. }
  40. const index = (this.tail - 1 + this.capacity) % this.capacity
  41. const value = this.buffer[index]
  42. this.buffer[index] = undefined
  43. this.tail = index
  44. this.size -= 1
  45. return value
  46. }
  47. toArray(start?: number, end?: number): T[] {
  48. const len = this.size
  49. let startIndex = start === undefined ? 0 : Math.trunc(start)
  50. if (startIndex < 0) {
  51. startIndex = Math.max(len + startIndex, 0)
  52. } else {
  53. startIndex = Math.min(startIndex, len)
  54. }
  55. let endIndex = end === undefined ? len : Math.trunc(end)
  56. if (endIndex < 0) {
  57. endIndex = Math.max(len + endIndex, 0)
  58. } else {
  59. endIndex = Math.min(endIndex, len)
  60. }
  61. const sliceLength = Math.max(endIndex - startIndex, 0)
  62. const result = new Array<T>(sliceLength)
  63. for (let offset = 0; offset < sliceLength; offset += 1) {
  64. const physicalIndex = (this.head + startIndex + offset) % this.capacity
  65. result[offset] = this.buffer[physicalIndex] as T
  66. }
  67. return result
  68. }
  69. }