ringbuffer.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  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 <array>
  24. #include <cstdint>
  25. #include <limits>
  26. #include <stdexcept>
  27. #include "alnumeric.h"
  28. #include "alspan.h"
  29. auto RingBuffer::Create(std::size_t sz, std::size_t elem_sz, bool limit_writes) -> RingBufferPtr
  30. {
  31. std::size_t power_of_two{0u};
  32. if(sz > 0)
  33. {
  34. power_of_two = sz - 1;
  35. power_of_two |= power_of_two>>1;
  36. power_of_two |= power_of_two>>2;
  37. power_of_two |= power_of_two>>4;
  38. power_of_two |= power_of_two>>8;
  39. power_of_two |= power_of_two>>16;
  40. if constexpr(sizeof(size_t) > sizeof(uint32_t))
  41. power_of_two |= power_of_two>>32;
  42. }
  43. ++power_of_two;
  44. if(power_of_two < sz || power_of_two > std::numeric_limits<std::size_t>::max()>>1
  45. || power_of_two > std::numeric_limits<std::size_t>::max()/elem_sz)
  46. throw std::overflow_error{"Ring buffer size overflow"};
  47. const std::size_t bufbytes{power_of_two * elem_sz};
  48. RingBufferPtr rb{new(FamCount(bufbytes)) RingBuffer{limit_writes ? sz : power_of_two,
  49. power_of_two-1, elem_sz, bufbytes}};
  50. return rb;
  51. }
  52. void RingBuffer::reset() noexcept
  53. {
  54. mWriteCount.store(0, std::memory_order_relaxed);
  55. mReadCount.store(0, std::memory_order_relaxed);
  56. std::fill_n(mBuffer.begin(), (mSizeMask+1)*mElemSize, std::byte{});
  57. }
  58. auto RingBuffer::read(void *dest, std::size_t count) noexcept -> std::size_t
  59. {
  60. const std::size_t w{mWriteCount.load(std::memory_order_acquire)};
  61. const std::size_t r{mReadCount.load(std::memory_order_relaxed)};
  62. const std::size_t readable{w - r};
  63. if(readable == 0) return 0;
  64. const std::size_t to_read{std::min(count, readable)};
  65. const std::size_t read_idx{r & mSizeMask};
  66. const std::size_t rdend{read_idx + to_read};
  67. const auto [n1, n2] = (rdend <= mSizeMask+1) ? std::array{to_read, 0_uz}
  68. : std::array{mSizeMask+1 - read_idx, rdend&mSizeMask};
  69. auto dstbytes = al::span{static_cast<std::byte*>(dest), count*mElemSize};
  70. auto outiter = std::copy_n(mBuffer.begin() + ptrdiff_t(read_idx*mElemSize), n1*mElemSize,
  71. dstbytes.begin());
  72. if(n2 > 0)
  73. std::copy_n(mBuffer.begin(), n2*mElemSize, outiter);
  74. mReadCount.store(r+n1+n2, std::memory_order_release);
  75. return to_read;
  76. }
  77. auto RingBuffer::peek(void *dest, std::size_t count) const noexcept -> std::size_t
  78. {
  79. const std::size_t w{mWriteCount.load(std::memory_order_acquire)};
  80. const std::size_t r{mReadCount.load(std::memory_order_relaxed)};
  81. const std::size_t readable{w - r};
  82. if(readable == 0) return 0;
  83. const std::size_t to_read{std::min(count, readable)};
  84. const std::size_t read_idx{r & mSizeMask};
  85. const std::size_t rdend{read_idx + to_read};
  86. const auto [n1, n2] = (rdend <= mSizeMask+1) ? std::array{to_read, 0_uz}
  87. : std::array{mSizeMask+1 - read_idx, rdend&mSizeMask};
  88. auto dstbytes = al::span{static_cast<std::byte*>(dest), count*mElemSize};
  89. auto outiter = std::copy_n(mBuffer.begin() + ptrdiff_t(read_idx*mElemSize), n1*mElemSize,
  90. dstbytes.begin());
  91. if(n2 > 0)
  92. std::copy_n(mBuffer.begin(), n2*mElemSize, outiter);
  93. return to_read;
  94. }
  95. auto RingBuffer::write(const void *src, std::size_t count) noexcept -> std::size_t
  96. {
  97. const std::size_t w{mWriteCount.load(std::memory_order_relaxed)};
  98. const std::size_t r{mReadCount.load(std::memory_order_acquire)};
  99. const std::size_t writable{mWriteSize - (w - r)};
  100. if(writable == 0) return 0;
  101. const std::size_t to_write{std::min(count, writable)};
  102. const std::size_t write_idx{w & mSizeMask};
  103. const std::size_t wrend{write_idx + to_write};
  104. const auto [n1, n2] = (wrend <= mSizeMask+1) ? std::array{to_write, 0_uz}
  105. : std::array{mSizeMask+1 - write_idx, wrend&mSizeMask};
  106. auto srcbytes = al::span{static_cast<const std::byte*>(src), count*mElemSize};
  107. std::copy_n(srcbytes.cbegin(), n1*mElemSize, mBuffer.begin() + ptrdiff_t(write_idx*mElemSize));
  108. if(n2 > 0)
  109. std::copy_n(srcbytes.cbegin() + ptrdiff_t(n1*mElemSize), n2*mElemSize, mBuffer.begin());
  110. mWriteCount.store(w+n1+n2, std::memory_order_release);
  111. return to_write;
  112. }
  113. auto RingBuffer::getReadVector() noexcept -> DataPair
  114. {
  115. const std::size_t w{mWriteCount.load(std::memory_order_acquire)};
  116. const std::size_t r{mReadCount.load(std::memory_order_relaxed)};
  117. const std::size_t readable{w - r};
  118. const std::size_t read_idx{r & mSizeMask};
  119. const std::size_t rdend{read_idx + readable};
  120. if(rdend > mSizeMask+1)
  121. {
  122. /* Two part vector: the rest of the buffer after the current read ptr,
  123. * plus some from the start of the buffer.
  124. */
  125. return DataPair{{{mBuffer.data() + read_idx*mElemSize, mSizeMask+1 - read_idx},
  126. {mBuffer.data(), rdend&mSizeMask}}};
  127. }
  128. return DataPair{{{mBuffer.data() + read_idx*mElemSize, readable}, {}}};
  129. }
  130. auto RingBuffer::getWriteVector() noexcept -> DataPair
  131. {
  132. const std::size_t w{mWriteCount.load(std::memory_order_relaxed)};
  133. const std::size_t r{mReadCount.load(std::memory_order_acquire)};
  134. const std::size_t writable{mWriteSize - (w - r)};
  135. const std::size_t write_idx{w & mSizeMask};
  136. const std::size_t wrend{write_idx + writable};
  137. if(wrend > mSizeMask+1)
  138. {
  139. /* Two part vector: the rest of the buffer after the current write ptr,
  140. * plus some from the start of the buffer.
  141. */
  142. return DataPair{{{mBuffer.data() + write_idx*mElemSize, mSizeMask+1 - write_idx},
  143. {mBuffer.data(), wrend&mSizeMask}}};
  144. }
  145. return DataPair{{{mBuffer.data() + write_idx*mElemSize, writable}, {}}};
  146. }