util/CircularBuffer: add method MoveTo()
This implements wraparound, so AsyncInputStream and ThreadInputStream can now return all of the buffer contents in one Read() call.
This commit is contained in:
@@ -162,14 +162,10 @@ AsyncInputStream::IsAvailable() const noexcept
|
||||
inline std::size_t
|
||||
AsyncInputStream::ReadFromBuffer(std::span<std::byte> dest) noexcept
|
||||
{
|
||||
const auto r = buffer.Read();
|
||||
if (r.empty())
|
||||
const size_t nbytes = buffer.MoveTo(dest);
|
||||
if (nbytes == 0)
|
||||
return 0;
|
||||
|
||||
const size_t nbytes = std::min(dest.size(), r.size());
|
||||
memcpy(dest.data(), r.data(), nbytes);
|
||||
buffer.Consume(nbytes);
|
||||
|
||||
if (buffer.empty())
|
||||
/* when the buffer becomes empty, reset its head and
|
||||
tail so the next write can fill the whole buffer
|
||||
|
@@ -152,14 +152,10 @@ ThreadInputStream::Seek([[maybe_unused]] std::unique_lock<Mutex> &lock,
|
||||
inline std::size_t
|
||||
ThreadInputStream::ReadFromBuffer(std::span<std::byte> dest) noexcept
|
||||
{
|
||||
const auto r = buffer.Read();
|
||||
if (r.empty())
|
||||
const size_t nbytes = buffer.MoveTo(dest);
|
||||
if (nbytes == 0)
|
||||
return 0;
|
||||
|
||||
const size_t nbytes = std::min(dest.size(), r.size());
|
||||
memcpy(dest.data(), r.data(), nbytes);
|
||||
buffer.Consume(nbytes);
|
||||
|
||||
if (buffer.empty())
|
||||
/* when the buffer becomes empty, reset its head and
|
||||
tail so the next write can fill the whole buffer
|
||||
|
@@ -3,6 +3,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm> // for std::move()
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <span>
|
||||
@@ -153,4 +154,38 @@ public:
|
||||
if (head == buffer.size())
|
||||
head = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move data from the buffer to the destination. This method
|
||||
* considers ring buffer wraparound.
|
||||
*
|
||||
* @return the number of items moved
|
||||
*/
|
||||
constexpr size_type MoveTo(Range dest) noexcept {
|
||||
size_type n = 0;
|
||||
|
||||
auto a = Read();
|
||||
if (a.size() > dest.size())
|
||||
a = a.first(dest.size());
|
||||
|
||||
if (!a.empty()) {
|
||||
dest = {std::move(a.begin(), a.end(), dest.begin()), dest.end()};
|
||||
Consume(a.size());
|
||||
n += a.size();
|
||||
|
||||
if (dest.empty())
|
||||
return n;
|
||||
|
||||
if (auto b = Read(); !b.empty()) {
|
||||
if (b.size() > dest.size())
|
||||
b = b.first(dest.size());
|
||||
|
||||
std::move(b.begin(), b.end(), dest.begin());
|
||||
Consume(b.size());
|
||||
n += b.size();
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
};
|
||||
|
Reference in New Issue
Block a user