🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

224 lines
6.3 KiB

  1. /**
  2. * OpenAL cross platform audio library
  3. * Copyright (C) 1999-2007 by authors.
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Library General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2 of the License, or (at your option) any later version.
  8. *
  9. * This library 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 GNU
  12. * Library General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Library General Public
  15. * License along with this library; if not, write to the
  16. * Free Software Foundation, Inc.,
  17. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  18. * Or go to http://www.gnu.org/copyleft/lgpl.html
  19. */
  20. #include "config.h"
  21. #include "ringbuffer.h"
  22. #include <algorithm>
  23. #include <climits>
  24. #include <stdexcept>
  25. #include "almalloc.h"
  26. RingBufferPtr RingBuffer::Create(size_t sz, size_t elem_sz, int limit_writes)
  27. {
  28. size_t power_of_two{0u};
  29. if(sz > 0)
  30. {
  31. power_of_two = sz;
  32. power_of_two |= power_of_two>>1;
  33. power_of_two |= power_of_two>>2;
  34. power_of_two |= power_of_two>>4;
  35. power_of_two |= power_of_two>>8;
  36. power_of_two |= power_of_two>>16;
  37. #if SIZE_MAX > UINT_MAX
  38. power_of_two |= power_of_two>>32;
  39. #endif
  40. }
  41. ++power_of_two;
  42. if(power_of_two <= sz || power_of_two > std::numeric_limits<size_t>::max()/elem_sz)
  43. throw std::overflow_error{"Ring buffer size overflow"};
  44. const size_t bufbytes{power_of_two * elem_sz};
  45. RingBufferPtr rb{new(FamCount(bufbytes)) RingBuffer{bufbytes}};
  46. rb->mWriteSize = limit_writes ? sz : (power_of_two-1);
  47. rb->mSizeMask = power_of_two - 1;
  48. rb->mElemSize = elem_sz;
  49. return rb;
  50. }
  51. void RingBuffer::reset() noexcept
  52. {
  53. mWritePtr.store(0, std::memory_order_relaxed);
  54. mReadPtr.store(0, std::memory_order_relaxed);
  55. std::fill_n(mBuffer.begin(), (mSizeMask+1)*mElemSize, al::byte{});
  56. }
  57. size_t RingBuffer::read(void *dest, size_t cnt) noexcept
  58. {
  59. const size_t free_cnt{readSpace()};
  60. if(free_cnt == 0) return 0;
  61. const size_t to_read{std::min(cnt, free_cnt)};
  62. size_t read_ptr{mReadPtr.load(std::memory_order_relaxed) & mSizeMask};
  63. size_t n1, n2;
  64. const size_t cnt2{read_ptr + to_read};
  65. if(cnt2 > mSizeMask+1)
  66. {
  67. n1 = mSizeMask+1 - read_ptr;
  68. n2 = cnt2 & mSizeMask;
  69. }
  70. else
  71. {
  72. n1 = to_read;
  73. n2 = 0;
  74. }
  75. auto outiter = std::copy_n(mBuffer.begin() + read_ptr*mElemSize, n1*mElemSize,
  76. static_cast<al::byte*>(dest));
  77. read_ptr += n1;
  78. if(n2 > 0)
  79. {
  80. std::copy_n(mBuffer.begin(), n2*mElemSize, outiter);
  81. read_ptr += n2;
  82. }
  83. mReadPtr.store(read_ptr, std::memory_order_release);
  84. return to_read;
  85. }
  86. size_t RingBuffer::peek(void *dest, size_t cnt) const noexcept
  87. {
  88. const size_t free_cnt{readSpace()};
  89. if(free_cnt == 0) return 0;
  90. const size_t to_read{std::min(cnt, free_cnt)};
  91. size_t read_ptr{mReadPtr.load(std::memory_order_relaxed) & mSizeMask};
  92. size_t n1, n2;
  93. const size_t cnt2{read_ptr + to_read};
  94. if(cnt2 > mSizeMask+1)
  95. {
  96. n1 = mSizeMask+1 - read_ptr;
  97. n2 = cnt2 & mSizeMask;
  98. }
  99. else
  100. {
  101. n1 = to_read;
  102. n2 = 0;
  103. }
  104. auto outiter = std::copy_n(mBuffer.begin() + read_ptr*mElemSize, n1*mElemSize,
  105. static_cast<al::byte*>(dest));
  106. if(n2 > 0)
  107. std::copy_n(mBuffer.begin(), n2*mElemSize, outiter);
  108. return to_read;
  109. }
  110. size_t RingBuffer::write(const void *src, size_t cnt) noexcept
  111. {
  112. const size_t free_cnt{writeSpace()};
  113. if(free_cnt == 0) return 0;
  114. const size_t to_write{std::min(cnt, free_cnt)};
  115. size_t write_ptr{mWritePtr.load(std::memory_order_relaxed) & mSizeMask};
  116. size_t n1, n2;
  117. const size_t cnt2{write_ptr + to_write};
  118. if(cnt2 > mSizeMask+1)
  119. {
  120. n1 = mSizeMask+1 - write_ptr;
  121. n2 = cnt2 & mSizeMask;
  122. }
  123. else
  124. {
  125. n1 = to_write;
  126. n2 = 0;
  127. }
  128. auto srcbytes = static_cast<const al::byte*>(src);
  129. std::copy_n(srcbytes, n1*mElemSize, mBuffer.begin() + write_ptr*mElemSize);
  130. write_ptr += n1;
  131. if(n2 > 0)
  132. {
  133. std::copy_n(srcbytes + n1*mElemSize, n2*mElemSize, mBuffer.begin());
  134. write_ptr += n2;
  135. }
  136. mWritePtr.store(write_ptr, std::memory_order_release);
  137. return to_write;
  138. }
  139. auto RingBuffer::getReadVector() const noexcept -> DataPair
  140. {
  141. DataPair ret;
  142. size_t w{mWritePtr.load(std::memory_order_acquire)};
  143. size_t r{mReadPtr.load(std::memory_order_acquire)};
  144. w &= mSizeMask;
  145. r &= mSizeMask;
  146. const size_t free_cnt{(w-r) & mSizeMask};
  147. const size_t cnt2{r + free_cnt};
  148. if(cnt2 > mSizeMask+1)
  149. {
  150. /* Two part vector: the rest of the buffer after the current read ptr,
  151. * plus some from the start of the buffer. */
  152. ret.first.buf = const_cast<al::byte*>(mBuffer.data() + r*mElemSize);
  153. ret.first.len = mSizeMask+1 - r;
  154. ret.second.buf = const_cast<al::byte*>(mBuffer.data());
  155. ret.second.len = cnt2 & mSizeMask;
  156. }
  157. else
  158. {
  159. /* Single part vector: just the rest of the buffer */
  160. ret.first.buf = const_cast<al::byte*>(mBuffer.data() + r*mElemSize);
  161. ret.first.len = free_cnt;
  162. ret.second.buf = nullptr;
  163. ret.second.len = 0;
  164. }
  165. return ret;
  166. }
  167. auto RingBuffer::getWriteVector() const noexcept -> DataPair
  168. {
  169. DataPair ret;
  170. size_t w{mWritePtr.load(std::memory_order_acquire)};
  171. size_t r{mReadPtr.load(std::memory_order_acquire) + mWriteSize - mSizeMask};
  172. w &= mSizeMask;
  173. r &= mSizeMask;
  174. const size_t free_cnt{(r-w-1) & mSizeMask};
  175. const size_t cnt2{w + free_cnt};
  176. if(cnt2 > mSizeMask+1)
  177. {
  178. /* Two part vector: the rest of the buffer after the current write ptr,
  179. * plus some from the start of the buffer. */
  180. ret.first.buf = const_cast<al::byte*>(mBuffer.data() + w*mElemSize);
  181. ret.first.len = mSizeMask+1 - w;
  182. ret.second.buf = const_cast<al::byte*>(mBuffer.data());
  183. ret.second.len = cnt2 & mSizeMask;
  184. }
  185. else
  186. {
  187. ret.first.buf = const_cast<al::byte*>(mBuffer.data() + w*mElemSize);
  188. ret.first.len = free_cnt;
  189. ret.second.buf = nullptr;
  190. ret.second.len = 0;
  191. }
  192. return ret;
  193. }