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
|
inline std::size_t
|
||||||
AsyncInputStream::ReadFromBuffer(std::span<std::byte> dest) noexcept
|
AsyncInputStream::ReadFromBuffer(std::span<std::byte> dest) noexcept
|
||||||
{
|
{
|
||||||
const auto r = buffer.Read();
|
const size_t nbytes = buffer.MoveTo(dest);
|
||||||
if (r.empty())
|
if (nbytes == 0)
|
||||||
return 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())
|
if (buffer.empty())
|
||||||
/* when the buffer becomes empty, reset its head and
|
/* when the buffer becomes empty, reset its head and
|
||||||
tail so the next write can fill the whole buffer
|
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
|
inline std::size_t
|
||||||
ThreadInputStream::ReadFromBuffer(std::span<std::byte> dest) noexcept
|
ThreadInputStream::ReadFromBuffer(std::span<std::byte> dest) noexcept
|
||||||
{
|
{
|
||||||
const auto r = buffer.Read();
|
const size_t nbytes = buffer.MoveTo(dest);
|
||||||
if (r.empty())
|
if (nbytes == 0)
|
||||||
return 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())
|
if (buffer.empty())
|
||||||
/* when the buffer becomes empty, reset its head and
|
/* when the buffer becomes empty, reset its head and
|
||||||
tail so the next write can fill the whole buffer
|
tail so the next write can fill the whole buffer
|
||||||
|
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <algorithm> // for std::move()
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <span>
|
#include <span>
|
||||||
@@ -153,4 +154,38 @@ public:
|
|||||||
if (head == buffer.size())
|
if (head == buffer.size())
|
||||||
head = 0;
|
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