summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Klinghed <the_jk@spawned.biz>2025-09-10 23:57:12 +0200
committerJoel Klinghed <the_jk@spawned.biz>2025-09-10 23:57:12 +0200
commitac878281d42b9e5291f96204283c65229c8f392a (patch)
tree9ec07abf89e176e675c04dca86bdcccec87c198f
parent32e14551a90e85000e41b3f0445d34d58a1431e4 (diff)
Fix issues in buffer
-rw-r--r--src/buffer.cc30
-rw-r--r--test/buffer.cc252
2 files changed, 246 insertions, 36 deletions
diff --git a/src/buffer.cc b/src/buffer.cc
index 65c6757..3073a45 100644
--- a/src/buffer.cc
+++ b/src/buffer.cc
@@ -20,7 +20,7 @@ class FixedBuffer : public Buffer {
avail = 0;
} else {
avail = (data_.get() + size_) - rptr_;
- if (avail < need) {
+ if (avail < need && rptr_ > data_.get()) {
rotate();
return rptr(avail, need);
}
@@ -36,7 +36,7 @@ class FixedBuffer : public Buffer {
if (rptr_ == wptr_)
reset();
} else {
- assert(rptr_ != wptr_ || !full_);
+ assert(rptr_ != wptr_ || full_);
assert(std::cmp_greater_equal((data_.get() + size_) - rptr_, size));
rptr_ += size;
if (rptr_ == data_.get() + size_) {
@@ -59,7 +59,7 @@ class FixedBuffer : public Buffer {
avail = 0;
} else {
avail = (data_.get() + size_) - wptr_;
- if (avail < need) {
+ if (avail < need && rptr_ > data_.get()) {
rotate();
return wptr(avail, need);
}
@@ -102,18 +102,24 @@ class FixedBuffer : public Buffer {
}
void rotate() {
- size_t to_move = (data_.get() + size_) - rptr_;
- if (wptr_ + to_move > rptr_) {
- auto tmp = std::make_unique_for_overwrite<char[]>(to_move);
- memcpy(tmp.get(), rptr_, to_move);
- memmove(data_.get() + to_move, data_.get(), wptr_ - data_.get());
- memcpy(data_.get(), tmp.get(), to_move);
+ if (rptr_ < wptr_) {
+ size_t size = wptr_ - rptr_;
+ memmove(data_.get(), rptr_, size);
+ wptr_ = data_.get() + size;
} else {
- memmove(data_.get() + to_move, data_.get(), wptr_ - data_.get());
- memcpy(data_.get(), rptr_, to_move);
+ size_t to_move = (data_.get() + size_) - rptr_;
+ if (wptr_ + to_move > rptr_) {
+ auto tmp = std::make_unique_for_overwrite<char[]>(to_move);
+ memcpy(tmp.get(), rptr_, to_move);
+ memmove(data_.get() + to_move, data_.get(), wptr_ - data_.get());
+ memcpy(data_.get(), tmp.get(), to_move);
+ } else {
+ memmove(data_.get() + to_move, data_.get(), wptr_ - data_.get());
+ memcpy(data_.get(), rptr_, to_move);
+ }
+ wptr_ += to_move;
}
rptr_ = data_.get();
- wptr_ += to_move;
}
size_t const size_;
diff --git a/test/buffer.cc b/test/buffer.cc
index 869e781..3bbfc95 100644
--- a/test/buffer.cc
+++ b/test/buffer.cc
@@ -4,19 +4,30 @@
#include <cstring>
-TEST(buffer_fixed, empty) {
- auto buffer = Buffer::fixed(10);
- EXPECT_TRUE(buffer->empty());
- EXPECT_FALSE(buffer->full());
- size_t avail;
- buffer->rptr(avail);
- EXPECT_EQ(0, avail);
- buffer->wptr(avail);
- EXPECT_EQ(10, avail);
-}
+namespace {
+
+enum class BufferType : uint8_t {
+ Fixed,
+ Dynamic,
+};
+
+class BufferTest : public testing::TestWithParam<BufferType> {
+ protected:
+ std::unique_ptr<Buffer> make(size_t min_size, size_t max_size) {
+ switch (GetParam()) {
+ case BufferType::Fixed:
+ return Buffer::fixed(min_size);
+ case BufferType::Dynamic:
+ return Buffer::dynamic(min_size, max_size);
+ }
+ std::unreachable();
+ }
+};
+
+} // namespace
-TEST(buffer_dynamic, empty) {
- auto buffer = Buffer::dynamic(10, 100);
+TEST_P(BufferTest, empty) {
+ auto buffer = make(10, 100);
EXPECT_TRUE(buffer->empty());
EXPECT_FALSE(buffer->full());
size_t avail;
@@ -26,8 +37,8 @@ TEST(buffer_dynamic, empty) {
EXPECT_EQ(10, avail);
}
-TEST(buffer_fixed, write_read) {
- auto buffer = Buffer::fixed(10);
+TEST_P(BufferTest, write_read) {
+ auto buffer = make(10, 100);
size_t avail;
auto* wptr = buffer->wptr(avail);
EXPECT_EQ(10, avail);
@@ -45,21 +56,214 @@ TEST(buffer_fixed, write_read) {
EXPECT_TRUE(buffer->empty());
}
-TEST(buffer_dynamic, write_read) {
- auto buffer = Buffer::dynamic(10, 100);
+TEST_P(BufferTest, write_read2) {
+ auto buffer = make(10, 10);
size_t avail;
auto* wptr = buffer->wptr(avail);
EXPECT_EQ(10, avail);
- memcpy(wptr, "Hello", 6);
- buffer->commit(6);
- EXPECT_FALSE(buffer->empty());
+ memcpy(wptr, "0123456789", 10);
+ buffer->commit(10);
+
auto* rptr = buffer->rptr(avail);
- EXPECT_EQ(6, avail);
- EXPECT_STREQ("Hello", reinterpret_cast<const char*>(rptr));
- buffer->consume(3);
+ EXPECT_EQ(10, avail);
+ char tmp[11];
+ memcpy(tmp, rptr, 5);
+ tmp[5] = '\0';
+ EXPECT_STREQ("01234", tmp);
+ buffer->consume(5);
+
+ wptr = buffer->wptr(avail, 5);
+ EXPECT_EQ(5, avail);
+ memcpy(wptr, "abcde", 5);
+ buffer->commit(5);
+
rptr = buffer->rptr(avail);
- EXPECT_EQ(3, avail);
- EXPECT_STREQ("lo", reinterpret_cast<const char*>(rptr));
+ EXPECT_LE(5, avail);
+ memcpy(tmp, rptr, 5);
+ tmp[5] = '\0';
+ EXPECT_STREQ("56789", tmp);
+ buffer->consume(5);
+
+ rptr = buffer->rptr(avail, 5);
+ EXPECT_EQ(5, avail);
+ memcpy(tmp, rptr, 5);
+ tmp[5] = '\0';
+ EXPECT_STREQ("abcde", tmp);
+ buffer->consume(5);
+}
+
+TEST_P(BufferTest, write_read3) {
+ auto buffer = make(10, 10);
+ size_t avail;
+ auto* wptr = buffer->wptr(avail);
+ EXPECT_EQ(10, avail);
+ memcpy(wptr, "0123456789", 10);
+ buffer->commit(10);
+
+ auto* rptr = buffer->rptr(avail);
+ EXPECT_EQ(10, avail);
+ char tmp[11];
+ memcpy(tmp, rptr, 5);
+ tmp[5] = '\0';
+ EXPECT_STREQ("01234", tmp);
+ buffer->consume(5);
+
+ wptr = buffer->wptr(avail, 5);
+ EXPECT_EQ(5, avail);
+ memcpy(wptr, "abcde", 5);
+ buffer->commit(5);
+
+ rptr = buffer->rptr(avail, 10);
+ EXPECT_EQ(10, avail);
+ memcpy(tmp, rptr, 10);
+ tmp[10] = '\0';
+ EXPECT_STREQ("56789abcde", tmp);
+ buffer->consume(5);
+}
+
+TEST_P(BufferTest, write_read4) {
+ auto buffer = make(10, 10);
+ size_t avail;
+ auto* wptr = buffer->wptr(avail);
+ EXPECT_EQ(10, avail);
+ memcpy(wptr, "0123456789", 10);
+ buffer->commit(10);
+
+ auto* rptr = buffer->rptr(avail);
+ EXPECT_EQ(10, avail);
+ char tmp[11];
+ memcpy(tmp, rptr, 10);
+ tmp[10] = '\0';
+ EXPECT_STREQ("0123456789", tmp);
+ buffer->consume(10);
+}
+
+TEST_P(BufferTest, write_read5) {
+ auto buffer = make(10, 10);
+ size_t avail;
+ auto* wptr = buffer->wptr(avail);
+ EXPECT_EQ(10, avail);
+ memcpy(wptr, "01234", 5);
+ buffer->commit(5);
+
+ auto* rptr = buffer->rptr(avail);
+ EXPECT_EQ(5, avail);
+ char tmp[11];
+ memcpy(tmp, rptr, 3);
+ tmp[3] = '\0';
+ EXPECT_STREQ("012", tmp);
buffer->consume(3);
+
+ wptr = buffer->wptr(avail, 8);
+ EXPECT_EQ(8, avail);
+ memcpy(wptr, "<xxxxxx>", 8);
+ buffer->commit(8);
+
+ rptr = buffer->rptr(avail, 10);
+ EXPECT_EQ(10, avail);
+ memcpy(tmp, rptr, 10);
+ tmp[10] = '\0';
+ EXPECT_STREQ("34<xxxxxx>", tmp);
+ buffer->consume(10);
+}
+
+TEST_P(BufferTest, write_read6) {
+ auto buffer = make(10, 10);
+ size_t avail;
+ auto* wptr = buffer->wptr(avail);
+ EXPECT_EQ(10, avail);
+ memcpy(wptr, "0123456789", 10);
+ buffer->commit(10);
+
+ auto* rptr = buffer->rptr(avail);
+ EXPECT_EQ(10, avail);
+ char tmp[11];
+ memcpy(tmp, rptr, 8);
+ tmp[8] = '\0';
+ EXPECT_STREQ("01234567", tmp);
+ buffer->consume(8);
+
+ wptr = buffer->wptr(avail, 3);
+ EXPECT_LE(3, avail);
+ memcpy(wptr, "abc", 3);
+ buffer->commit(3);
+
+ rptr = buffer->rptr(avail, 5);
+ EXPECT_EQ(5, avail);
+ memcpy(tmp, rptr, 5);
+ tmp[5] = '\0';
+ EXPECT_STREQ("89abc", tmp);
+ buffer->consume(5);
+}
+
+TEST_P(BufferTest, full) {
+ auto buffer = make(10, 10);
+ size_t avail;
+ auto* wptr = buffer->wptr(avail);
+ EXPECT_EQ(10, avail);
+ memcpy(wptr, "0123456789", 10);
+ buffer->commit(10);
+ EXPECT_TRUE(buffer->full());
+ std::ignore = buffer->wptr(avail);
+ EXPECT_EQ(0, avail);
+ buffer->commit(0);
+
+ auto* rptr = buffer->rptr(avail, 10);
+ EXPECT_EQ(10, avail);
+ char tmp[11];
+ memcpy(tmp, rptr, 5);
+ tmp[5] = '\0';
+ EXPECT_STREQ("01234", tmp);
+ buffer->consume(5);
+ EXPECT_FALSE(buffer->full());
+
+ wptr = buffer->wptr(avail, 5);
+ EXPECT_EQ(5, avail);
+ memcpy(wptr, "abcde", 5);
+ buffer->commit(5);
+ EXPECT_TRUE(buffer->full());
+
+ rptr = buffer->rptr(avail, 10);
+ EXPECT_EQ(10, avail);
+ memcpy(tmp, rptr, 10);
+ tmp[10] = '\0';
+ EXPECT_STREQ("56789abcde", tmp);
+ buffer->consume(10);
+ EXPECT_FALSE(buffer->full());
+ EXPECT_TRUE(buffer->empty());
+
+ std::ignore = buffer->rptr(avail, 10);
+ EXPECT_EQ(0, avail);
+ buffer->consume(0);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ AllTypes,
+ BufferTest,
+ testing::Values(BufferType::Fixed, BufferType::Dynamic));
+
+TEST(buffer, dynamic_increase) {
+ auto buffer = Buffer::dynamic(10, 20);
+
+ size_t avail;
+ auto* wptr = buffer->wptr(avail, 15);
+ EXPECT_EQ(15, avail);
+ memcpy(wptr, "0123456789abcde", 15);
+ buffer->commit(15);
+ EXPECT_FALSE(buffer->full());
+ wptr = buffer->wptr(avail, 5);
+ EXPECT_EQ(5, avail);
+ memcpy(wptr, "fghij", 5);
+ buffer->commit(5);
+ EXPECT_TRUE(buffer->full());
+
+ auto* rptr = buffer->rptr(avail, 20);
+ EXPECT_EQ(20, avail);
+ char tmp[21];
+ memcpy(tmp, rptr, 20);
+ tmp[20] = '\0';
+ EXPECT_STREQ("0123456789abcdefghij", tmp);
+ buffer->consume(20);
+ EXPECT_FALSE(buffer->full());
EXPECT_TRUE(buffer->empty());
}