ring_buffer.h 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. #pragma once
  2. #include <util/generic/array_ref.h>
  3. #include <util/generic/maybe.h>
  4. #include <util/generic/utility.h>
  5. #include <util/generic/vector.h>
  6. #include <util/system/yassert.h>
  7. template <typename T>
  8. struct TRingBuffer {
  9. private:
  10. ui32 CapacityPow;
  11. ui32 CapacityMask;
  12. ui32 Capacity;
  13. ui32 WritePos;
  14. ui32 ReadPos;
  15. TVector<T> Data;
  16. void StateCheck() const {
  17. Y_ASSERT(Capacity == Data.size());
  18. Y_ASSERT(Capacity == (1u << CapacityPow));
  19. Y_ASSERT((Capacity & CapacityMask) == 0u);
  20. Y_ASSERT(Capacity - CapacityMask == 1u);
  21. Y_ASSERT(WritePos < Capacity);
  22. Y_ASSERT(ReadPos < Capacity);
  23. }
  24. size_t Writable() const {
  25. return (Capacity + ReadPos - WritePos - 1) & CapacityMask;
  26. }
  27. void ReserveWritable(ui32 sz) {
  28. if (sz <= Writable())
  29. return;
  30. ui32 newCapacityPow = CapacityPow;
  31. while ((1u << newCapacityPow) < sz + ui32(Size()) + 1u) {
  32. ++newCapacityPow;
  33. }
  34. ui32 newCapacity = 1u << newCapacityPow;
  35. ui32 newCapacityMask = newCapacity - 1u;
  36. TVector<T> newData(newCapacity);
  37. ui32 oldSize = Size();
  38. // Copy old elements
  39. for (size_t i = 0; i < oldSize; ++i) {
  40. newData[i] = Get(i);
  41. }
  42. CapacityPow = newCapacityPow;
  43. Capacity = newCapacity;
  44. CapacityMask = newCapacityMask;
  45. Data.swap(newData);
  46. ReadPos = 0;
  47. WritePos = oldSize;
  48. StateCheck();
  49. }
  50. const T& Get(ui32 i) const {
  51. return Data[(ReadPos + i) & CapacityMask];
  52. }
  53. public:
  54. TRingBuffer()
  55. : CapacityPow(0)
  56. , CapacityMask(0)
  57. , Capacity(1 << CapacityPow)
  58. , WritePos(0)
  59. , ReadPos(0)
  60. , Data(Capacity)
  61. {
  62. StateCheck();
  63. }
  64. size_t Size() const {
  65. return (Capacity + WritePos - ReadPos) & CapacityMask;
  66. }
  67. bool Empty() const {
  68. return WritePos == ReadPos;
  69. }
  70. void PushAll(TArrayRef<const T> value) {
  71. ReserveWritable(value.size());
  72. ui32 secondSize;
  73. ui32 firstSize;
  74. if (WritePos + value.size() <= Capacity) {
  75. firstSize = value.size();
  76. secondSize = 0;
  77. } else {
  78. firstSize = Capacity - WritePos;
  79. secondSize = value.size() - firstSize;
  80. }
  81. for (size_t i = 0; i < firstSize; ++i) {
  82. Data[WritePos + i] = value[i];
  83. }
  84. for (size_t i = 0; i < secondSize; ++i) {
  85. Data[i] = value[firstSize + i];
  86. }
  87. WritePos = (WritePos + value.size()) & CapacityMask;
  88. StateCheck();
  89. }
  90. void Push(const T& t) {
  91. PushAll(MakeArrayRef(&t, 1));
  92. }
  93. bool TryPop(T* r) {
  94. StateCheck();
  95. if (Empty()) {
  96. return false;
  97. }
  98. *r = Data[ReadPos];
  99. ReadPos = (ReadPos + 1) & CapacityMask;
  100. return true;
  101. }
  102. TMaybe<T> TryPop() {
  103. T tmp;
  104. if (TryPop(&tmp)) {
  105. return tmp;
  106. } else {
  107. return TMaybe<T>();
  108. }
  109. }
  110. T Pop() {
  111. return *TryPop();
  112. }
  113. };