ringbuffer.cpp 6.4 KB

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