CircularBuffer.cs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. namespace NTERA.EmuEra.Game.EraEmu.GameProc.Function
  5. {
  6. public interface ICircularBuffer<T>
  7. {
  8. int Count { get; }
  9. int Capacity { get; set; }
  10. T Enqueue(T item);
  11. T Dequeue();
  12. void Clear();
  13. T this[int index] { get; set; }
  14. int IndexOf(T item);
  15. void Insert(int index, T item);
  16. void RemoveAt(int index);
  17. }
  18. public class CircularBuffer<T> : ICircularBuffer<T>, IEnumerable<T>
  19. {
  20. private T[] _buffer;
  21. private int _head;
  22. private int _tail;
  23. public CircularBuffer(int capacity)
  24. {
  25. if (capacity < 0)
  26. throw new ArgumentOutOfRangeException("capacity", "must be positive");
  27. _buffer = new T[capacity];
  28. _head = capacity - 1;
  29. }
  30. public int Count { get; private set; }
  31. public int Capacity
  32. {
  33. get => _buffer.Length;
  34. set
  35. {
  36. if (value < 0)
  37. throw new ArgumentOutOfRangeException("value", "must be positive");
  38. if (value == _buffer.Length)
  39. return;
  40. var buffer = new T[value];
  41. var newCount = 0;
  42. while (Count > 0 && newCount < value)
  43. buffer[newCount++] = Dequeue();
  44. _buffer = buffer;
  45. Count = newCount;
  46. _head = newCount - 1;
  47. _tail = 0;
  48. }
  49. }
  50. public T Enqueue(T item)
  51. {
  52. _head = (_head + 1) % Capacity;
  53. var overwritten = _buffer[_head];
  54. _buffer[_head] = item;
  55. if (Count == Capacity)
  56. _tail = (_tail + 1) % Capacity;
  57. else
  58. ++Count;
  59. return overwritten;
  60. }
  61. public T Dequeue()
  62. {
  63. if (Count == 0)
  64. throw new InvalidOperationException("queue exhausted");
  65. var dequeued = _buffer[_tail];
  66. _buffer[_tail] = default(T);
  67. _tail = (_tail + 1) % Capacity;
  68. --Count;
  69. return dequeued;
  70. }
  71. public void Clear()
  72. {
  73. _head = Capacity - 1;
  74. _tail = 0;
  75. Count = 0;
  76. }
  77. public T this[int index]
  78. {
  79. get
  80. {
  81. if (index < 0 || index >= Count)
  82. throw new ArgumentOutOfRangeException("index");
  83. return _buffer[(_tail + index) % Capacity];
  84. }
  85. set
  86. {
  87. if (index < 0 || index >= Count)
  88. throw new ArgumentOutOfRangeException("index");
  89. _buffer[(_tail + index) % Capacity] = value;
  90. }
  91. }
  92. public int IndexOf(T item)
  93. {
  94. for (var i = 0; i < Count; ++i)
  95. if (Equals(item, this[i]))
  96. return i;
  97. return -1;
  98. }
  99. public void Insert(int index, T item)
  100. {
  101. if (index < 0 || index > Count)
  102. throw new ArgumentOutOfRangeException("index");
  103. if (Count == index)
  104. Enqueue(item);
  105. else
  106. {
  107. var last = this[Count - 1];
  108. for (var i = index; i < Count - 2; ++i)
  109. this[i + 1] = this[i];
  110. this[index] = item;
  111. Enqueue(last);
  112. }
  113. }
  114. public void RemoveAt(int index)
  115. {
  116. if (index < 0 || index >= Count)
  117. throw new ArgumentOutOfRangeException("index");
  118. for (var i = index; i > 0; --i)
  119. this[i] = this[i - 1];
  120. Dequeue();
  121. }
  122. public IEnumerator<T> GetEnumerator()
  123. {
  124. if (Count == 0 || Capacity == 0)
  125. yield break;
  126. for (var i = 0; i < Count; ++i)
  127. yield return this[i];
  128. }
  129. IEnumerator IEnumerable.GetEnumerator()
  130. {
  131. return GetEnumerator();
  132. }
  133. }
  134. }