DynamicRingBuffer.cs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. //
  2. // Copyright (c) 2019-2021 Ryujinx
  3. //
  4. // This program is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public License
  15. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  16. //
  17. using Ryujinx.Common;
  18. using System;
  19. namespace Ryujinx.Audio.Backends.Common
  20. {
  21. /// <summary>
  22. /// A ring buffer that grow if data written to it is too big to fit.
  23. /// </summary>
  24. public class DynamicRingBuffer
  25. {
  26. private const int RingBufferAlignment = 2048;
  27. private object _lock = new object();
  28. private byte[] _buffer;
  29. private int _size;
  30. private int _headOffset;
  31. private int _tailOffset;
  32. public int Length => _size;
  33. public DynamicRingBuffer(int initialCapacity = RingBufferAlignment)
  34. {
  35. _buffer = new byte[initialCapacity];
  36. }
  37. public void Clear()
  38. {
  39. _size = 0;
  40. _headOffset = 0;
  41. _tailOffset = 0;
  42. }
  43. public void Clear(int size)
  44. {
  45. lock (_lock)
  46. {
  47. if (size > _size)
  48. {
  49. size = _size;
  50. }
  51. if (size == 0)
  52. {
  53. return;
  54. }
  55. _headOffset = (_headOffset + size) % _buffer.Length;
  56. _size -= size;
  57. if (_size == 0)
  58. {
  59. _headOffset = 0;
  60. _tailOffset = 0;
  61. }
  62. }
  63. }
  64. private void SetCapacityLocked(int capacity)
  65. {
  66. byte[] buffer = new byte[capacity];
  67. if (_size > 0)
  68. {
  69. if (_headOffset < _tailOffset)
  70. {
  71. Buffer.BlockCopy(_buffer, _headOffset, buffer, 0, _size);
  72. }
  73. else
  74. {
  75. Buffer.BlockCopy(_buffer, _headOffset, buffer, 0, _buffer.Length - _headOffset);
  76. Buffer.BlockCopy(_buffer, 0, buffer, _buffer.Length - _headOffset, _tailOffset);
  77. }
  78. }
  79. _buffer = buffer;
  80. _headOffset = 0;
  81. _tailOffset = _size;
  82. }
  83. public void Write<T>(T[] buffer, int index, int count)
  84. {
  85. if (count == 0)
  86. {
  87. return;
  88. }
  89. lock (_lock)
  90. {
  91. if ((_size + count) > _buffer.Length)
  92. {
  93. SetCapacityLocked(BitUtils.AlignUp(_size + count, RingBufferAlignment));
  94. }
  95. if (_headOffset < _tailOffset)
  96. {
  97. int tailLength = _buffer.Length - _tailOffset;
  98. if (tailLength >= count)
  99. {
  100. Buffer.BlockCopy(buffer, index, _buffer, _tailOffset, count);
  101. }
  102. else
  103. {
  104. Buffer.BlockCopy(buffer, index, _buffer, _tailOffset, tailLength);
  105. Buffer.BlockCopy(buffer, index + tailLength, _buffer, 0, count - tailLength);
  106. }
  107. }
  108. else
  109. {
  110. Buffer.BlockCopy(buffer, index, _buffer, _tailOffset, count);
  111. }
  112. _size += count;
  113. _tailOffset = (_tailOffset + count) % _buffer.Length;
  114. }
  115. }
  116. public int Read<T>(T[] buffer, int index, int count)
  117. {
  118. lock (_lock)
  119. {
  120. if (count > _size)
  121. {
  122. count = _size;
  123. }
  124. if (count == 0)
  125. {
  126. return 0;
  127. }
  128. if (_headOffset < _tailOffset)
  129. {
  130. Buffer.BlockCopy(_buffer, _headOffset, buffer, index, count);
  131. }
  132. else
  133. {
  134. int tailLength = _buffer.Length - _headOffset;
  135. if (tailLength >= count)
  136. {
  137. Buffer.BlockCopy(_buffer, _headOffset, buffer, index, count);
  138. }
  139. else
  140. {
  141. Buffer.BlockCopy(_buffer, _headOffset, buffer, index, tailLength);
  142. Buffer.BlockCopy(_buffer, 0, buffer, index + tailLength, count - tailLength);
  143. }
  144. }
  145. _size -= count;
  146. _headOffset = (_headOffset + count) % _buffer.Length;
  147. if (_size == 0)
  148. {
  149. _headOffset = 0;
  150. _tailOffset = 0;
  151. }
  152. return count;
  153. }
  154. }
  155. }
  156. }