From 399aabd436b7f375bb40b37128b2fffdfac99129 Mon Sep 17 00:00:00 2001 From: Aleksandr Lyapunov Date: Wed, 10 Jul 2024 14:46:04 +0300 Subject: [PATCH] buffer: allow to write zero bytes Encoder can try to write zero bytes sometimes. For example, when it encodes an empty string. Let's simply handle this case in buffer and iterators instead of assertion. Along the way, replace the assertion in `iterator::get` method as well. It should have be done in 28bae01, but we forgot about this method because it's not used by decoder. Co-authored-by: Andrey Saranchin --- src/Buffer/Buffer.hpp | 14 ++++++++++---- test/BufferUnitTest.cpp | 20 ++++++++++++++++++++ test/EncDecTest.cpp | 5 ++++- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/Buffer/Buffer.hpp b/src/Buffer/Buffer.hpp index cf73dd9af..8200c3a98 100644 --- a/src/Buffer/Buffer.hpp +++ b/src/Buffer/Buffer.hpp @@ -703,7 +703,8 @@ template void Buffer::write(WData data) { - assert(data.size != 0); + if (data.size == 0) + return; char *new_end = m_end + data.size; if (TNT_LIKELY(isSameBlock(m_end, new_end))) { @@ -1105,7 +1106,9 @@ template void Buffer::iterator_common::set(WData data) { - assert(data.size > 0); + if (data.size == 0) + return; + char *pos = m_position; size_t left_in_block = N - (uintptr_t) pos % N; while (TNT_UNLIKELY(data.size > left_in_block)) { @@ -1160,7 +1163,9 @@ template void Buffer::iterator_common::write(WData data) { - assert(data.size > 0); + if (data.size == 0) + return; + size_t left_in_block = N - (uintptr_t) m_position % N; while (TNT_UNLIKELY(data.size >= left_in_block)) { std::memcpy(m_position, data.data, left_in_block); @@ -1216,7 +1221,8 @@ template void Buffer::iterator_common::get(RData data) { - assert(data.size > 0); + if (data.size == 0) + return; /* * The same implementation as in ::set() method buf vice versa: * buffer and data sources are swapped. diff --git a/test/BufferUnitTest.cpp b/test/BufferUnitTest.cpp index acf678d0c..bad625c15 100644 --- a/test/BufferUnitTest.cpp +++ b/test/BufferUnitTest.cpp @@ -125,6 +125,12 @@ buffer_basic() TEST_INIT(1, N); tnt::Buffer buf; fail_unless(buf.empty()); + + /* Empty write should work and don't write anything. */ + buf.write(typename tnt::Buffer::WData {nullptr, 0}); + fail_unless(buf.empty()); + fail_if(buf.debugSelfCheck()); + buf.write(int_sample); fail_unless(! buf.empty()); fail_if(buf.debugSelfCheck()); @@ -383,6 +389,20 @@ buffer_iterator() const auto& citr = itr; typename tnt::Buffer::iterator itr2(itr); + /* Empty writes and reads should work and don't write anything. */ + itr.write(typename tnt::Buffer::WData {nullptr, 0}); + fail_unless(buf.empty()); + fail_if(buf.debugSelfCheck()); + itr.set(typename tnt::Buffer::WData {nullptr, 0}); + fail_unless(buf.empty()); + fail_if(buf.debugSelfCheck()); + itr.get(typename tnt::Buffer::RData {nullptr, 0}); + fail_unless(buf.empty()); + fail_if(buf.debugSelfCheck()); + itr.read(typename tnt::Buffer::RData {nullptr, 0}); + fail_unless(buf.empty()); + fail_if(buf.debugSelfCheck()); + auto litr1 = itr.enlight(); { auto itr_test = litr1; diff --git a/test/EncDecTest.cpp b/test/EncDecTest.cpp index dc1579878..69dd2cf61 100644 --- a/test/EncDecTest.cpp +++ b/test/EncDecTest.cpp @@ -221,6 +221,7 @@ test_basic() mpp::encode(buf, std::integral_constant{}); mpp::encode(buf, std::integral_constant{}); // Strings. + mpp::encode(buf, ""); mpp::encode(buf, "abc"); const char *bbb = "defg"; mpp::encode(buf, bbb); @@ -313,7 +314,9 @@ test_basic() fail_if(bt != true); // Strings. - std::string a; + std::string a = "to be overwritten"; + fail_unless(mpp::decode(run, a)); + fail_if(a != ""); char b_data[10]; size_t b_size = 0; auto b = tnt::make_ref_vector(b_data, b_size);