diff options
| author | Joel Klinghed <the_jk@spawned.biz> | 2025-09-10 23:57:12 +0200 |
|---|---|---|
| committer | Joel Klinghed <the_jk@spawned.biz> | 2025-09-10 23:57:12 +0200 |
| commit | ac878281d42b9e5291f96204283c65229c8f392a (patch) | |
| tree | 9ec07abf89e176e675c04dca86bdcccec87c198f | |
| parent | 32e14551a90e85000e41b3f0445d34d58a1431e4 (diff) | |
Fix issues in buffer
| -rw-r--r-- | src/buffer.cc | 30 | ||||
| -rw-r--r-- | test/buffer.cc | 252 |
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()); } |
