Skip to content

Commit

Permalink
util/CircularBuffer: add method MoveTo()
Browse files Browse the repository at this point in the history
This implements wraparound, so AsyncInputStream and ThreadInputStream
can now return all of the buffer contents in one Read() call.
  • Loading branch information
MaxKellermann committed Jan 29, 2025
1 parent 950f5f4 commit e06d775
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 12 deletions.
8 changes: 2 additions & 6 deletions src/input/AsyncInputStream.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 2 additions & 6 deletions src/input/ThreadInputStream.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
35 changes: 35 additions & 0 deletions src/util/CircularBuffer.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#pragma once

#include <algorithm> // for std::move()
#include <cassert>
#include <cstddef>
#include <span>
Expand Down Expand Up @@ -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;
}
};

0 comments on commit e06d775

Please sign in to comment.