Skip to content

Commit e06d775

Browse files
committed
util/CircularBuffer: add method MoveTo()
This implements wraparound, so AsyncInputStream and ThreadInputStream can now return all of the buffer contents in one Read() call.
1 parent 950f5f4 commit e06d775

File tree

3 files changed

+39
-12
lines changed

3 files changed

+39
-12
lines changed

src/input/AsyncInputStream.cxx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -162,14 +162,10 @@ AsyncInputStream::IsAvailable() const noexcept
162162
inline std::size_t
163163
AsyncInputStream::ReadFromBuffer(std::span<std::byte> dest) noexcept
164164
{
165-
const auto r = buffer.Read();
166-
if (r.empty())
165+
const size_t nbytes = buffer.MoveTo(dest);
166+
if (nbytes == 0)
167167
return 0;
168168

169-
const size_t nbytes = std::min(dest.size(), r.size());
170-
memcpy(dest.data(), r.data(), nbytes);
171-
buffer.Consume(nbytes);
172-
173169
if (buffer.empty())
174170
/* when the buffer becomes empty, reset its head and
175171
tail so the next write can fill the whole buffer

src/input/ThreadInputStream.cxx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -152,14 +152,10 @@ ThreadInputStream::Seek([[maybe_unused]] std::unique_lock<Mutex> &lock,
152152
inline std::size_t
153153
ThreadInputStream::ReadFromBuffer(std::span<std::byte> dest) noexcept
154154
{
155-
const auto r = buffer.Read();
156-
if (r.empty())
155+
const size_t nbytes = buffer.MoveTo(dest);
156+
if (nbytes == 0)
157157
return 0;
158158

159-
const size_t nbytes = std::min(dest.size(), r.size());
160-
memcpy(dest.data(), r.data(), nbytes);
161-
buffer.Consume(nbytes);
162-
163159
if (buffer.empty())
164160
/* when the buffer becomes empty, reset its head and
165161
tail so the next write can fill the whole buffer

src/util/CircularBuffer.hxx

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#pragma once
55

6+
#include <algorithm> // for std::move()
67
#include <cassert>
78
#include <cstddef>
89
#include <span>
@@ -153,4 +154,38 @@ public:
153154
if (head == buffer.size())
154155
head = 0;
155156
}
157+
158+
/**
159+
* Move data from the buffer to the destination. This method
160+
* considers ring buffer wraparound.
161+
*
162+
* @return the number of items moved
163+
*/
164+
constexpr size_type MoveTo(Range dest) noexcept {
165+
size_type n = 0;
166+
167+
auto a = Read();
168+
if (a.size() > dest.size())
169+
a = a.first(dest.size());
170+
171+
if (!a.empty()) {
172+
dest = {std::move(a.begin(), a.end(), dest.begin()), dest.end()};
173+
Consume(a.size());
174+
n += a.size();
175+
176+
if (dest.empty())
177+
return n;
178+
179+
if (auto b = Read(); !b.empty()) {
180+
if (b.size() > dest.size())
181+
b = b.first(dest.size());
182+
183+
std::move(b.begin(), b.end(), dest.begin());
184+
Consume(b.size());
185+
n += b.size();
186+
}
187+
}
188+
189+
return n;
190+
}
156191
};

0 commit comments

Comments
 (0)