changed increaseBufferSize signature

simplified adapters implementations
This commit is contained in:
Mindaugas Vinkelis
2022-04-15 22:58:33 +03:00
parent d24e0ab1b3
commit d3dd64baaf
8 changed files with 53 additions and 142 deletions

View File

@@ -51,6 +51,7 @@ endif()
if (BITSERY_BUILD_TESTS)
message("build bitsery tests")
enable_testing()
add_subdirectory(tests)
else()
message("skip bitsery tests")

View File

@@ -108,43 +108,21 @@ namespace bitsery {
template <size_t SIZE>
void readInternalValue(TValue *data) {
readInternalValueChecked<SIZE>(data, std::integral_constant<bool, Config::CheckAdapterErrors>{});
readInternalChecked(data, SIZE, std::integral_constant<bool, Config::CheckAdapterErrors>{});
}
void readInternalBuffer(TValue *data, size_t size) {
readInternalBufferChecked(data, size, std::integral_constant<bool, Config::CheckAdapterErrors>{});
readInternalChecked(data, size, std::integral_constant<bool, Config::CheckAdapterErrors>{});
}
template <size_t SIZE>
void readInternalValueChecked(TValue *data, std::false_type) {
const size_t newOffset = _currOffset + SIZE;
assert(newOffset <= _endReadOffset);
std::copy_n(_beginIt + static_cast<diff_t>(_currOffset), SIZE, data);
_currOffset = newOffset;
}
template <size_t SIZE>
void readInternalValueChecked(TValue *data, std::true_type) {
const size_t newOffset = _currOffset + SIZE;
if (newOffset <= _endReadOffset) {
std::copy_n(_beginIt + static_cast<diff_t>(_currOffset), SIZE, data);
_currOffset = newOffset;
} else {
//set everything to zeros
std::memset(data, 0, SIZE);
if (_overflowOnReadEndPos)
error(ReaderError::DataOverflow);
}
}
void readInternalBufferChecked(TValue *data, size_t size, std::false_type) {
void readInternalChecked(TValue *data, size_t size, std::false_type) {
const size_t newOffset = _currOffset + size;
assert(newOffset <= _endReadOffset);
std::copy_n(_beginIt + static_cast<diff_t>(_currOffset), size, data);
_currOffset = newOffset;
}
void readInternalBufferChecked(TValue *data, size_t size, std::true_type) {
void readInternalChecked(TValue *data, size_t size, std::true_type) {
const size_t newOffset = _currOffset + size;
if (newOffset <= _endReadOffset) {
std::copy_n(_beginIt + static_cast<diff_t>(_currOffset), size, data);
@@ -177,7 +155,6 @@ namespace bitsery {
return _currOffset;
}
TIterator _beginIt;
size_t _currOffset;
size_t _endReadOffset;
@@ -201,8 +178,8 @@ namespace bitsery {
OutputBufferAdapter(Buffer &buffer)
: _buffer{std::addressof(buffer)},
_beginIt{std::begin(buffer)} {
init(TResizable{});
_beginIt{std::begin(buffer)},
_bufferSize{traits::ContainerTraits<Buffer>::size(buffer)} {
}
OutputBufferAdapter(const OutputBufferAdapter&) = delete;
@@ -215,7 +192,8 @@ namespace bitsery {
if (maxPos > _biggestCurrentPos) {
_biggestCurrentPos = maxPos;
}
setCurrentWritePos(pos, TResizable{});
maybeResize(pos, TResizable{});
_currOffset = pos;
}
size_t currentWritePos() const {
@@ -236,11 +214,11 @@ namespace bitsery {
template <size_t SIZE>
void writeInternalValue(const TValue *data) {
writeInternalValueImpl<SIZE>(data, TResizable{});
writeInternalImpl(data, SIZE);
}
void writeInternalBuffer(const TValue *data, size_t size) {
writeInternalBufferImpl(data, size, TResizable{});
writeInternalImpl(data, size);
}
Buffer* _buffer;
@@ -249,84 +227,25 @@ namespace bitsery {
size_t _bufferSize{0};
size_t _biggestCurrentPos{0};
/*
* resizable buffer
*/
void init(std::true_type) {
//resize buffer immediately, because we need output iterator at valid position
if (traits::ContainerTraits<Buffer>::size(*_buffer) == 0u) {
traits::BufferAdapterTraits<Buffer>::increaseBufferSize(*_buffer);
}
updateIteratorAndSize();
}
template <size_t SIZE>
void writeInternalValueImpl(const TValue *data, std::true_type) {
const size_t newOffset = _currOffset + SIZE;
if (newOffset <= _bufferSize) {
std::copy_n(data, SIZE, _beginIt + static_cast<diff_t>(_currOffset));
_currOffset = newOffset;
} else {
traits::BufferAdapterTraits<Buffer>::increaseBufferSize(*_buffer);
updateIteratorAndSize();
writeInternalValueImpl<SIZE>(data, std::true_type{});
void maybeResize(size_t newOffset, std::true_type) {
if (newOffset > _bufferSize) {
traits::BufferAdapterTraits<Buffer>::increaseBufferSize(*_buffer, _currOffset, newOffset);
_beginIt = std::begin(*_buffer);
_bufferSize = traits::ContainerTraits<Buffer>::size(*_buffer);
}
}
void writeInternalBufferImpl(const TValue *data, const size_t size, std::true_type) {
const size_t newOffset = _currOffset + size;
if (newOffset <= _bufferSize) {
std::copy_n(data, size, _beginIt + static_cast<diff_t>(_currOffset));
_currOffset = newOffset;
} else {
traits::BufferAdapterTraits<Buffer>::increaseBufferSize(*_buffer);
updateIteratorAndSize();
writeInternalBufferImpl(data, size, std::true_type{});
}
}
void setCurrentWritePos(size_t pos, std::true_type) {
if (pos <= _bufferSize) {
_currOffset = pos;
} else {
traits::BufferAdapterTraits<Buffer>::increaseBufferSize(*_buffer);
updateIteratorAndSize();
setCurrentWritePos(pos, std::true_type{});
}
}
/*
* non resizable buffer
*/
void init(std::false_type) {
updateIteratorAndSize();
}
template <size_t SIZE>
void writeInternalValueImpl(const TValue *data, std::false_type) {
const size_t newOffset = _currOffset + SIZE;
void maybeResize(size_t newOffset, std::false_type) {
assert(newOffset <= _bufferSize);
std::copy_n(data, SIZE, _beginIt + static_cast<diff_t>(_currOffset));
_currOffset = newOffset;
}
void writeInternalBufferImpl(const TValue *data, size_t size, std::false_type) {
void writeInternalImpl(const TValue *data, size_t size) {
const size_t newOffset = _currOffset + size;
assert(newOffset <= _bufferSize);
maybeResize(newOffset, TResizable{});
std::copy_n(data, size, _beginIt + static_cast<diff_t>(_currOffset));
_currOffset = newOffset;
}
void setCurrentWritePos(size_t pos, std::false_type) {
assert(pos <= _bufferSize);
_currOffset = pos;
}
void updateIteratorAndSize() {
_beginIt = std::begin(*_buffer);
_bufferSize = traits::ContainerTraits<Buffer>::size(*_buffer);
}
};
}

View File

@@ -228,16 +228,14 @@ namespace bitsery {
template <size_t SIZE>
void writeInternalValue(const TValue* data) {
auto newOffset = _currOffset + SIZE;
if (newOffset > _bufferSize) {
writeBufferToStream();
newOffset = SIZE;
}
std::copy_n(data, SIZE, _beginIt + static_cast<diff_t>(_currOffset));
_currOffset = newOffset;
writeInternalImpl(data, SIZE);
}
void writeInternalBuffer(const TValue* data, size_t size) {
writeInternalImpl(data, size);
}
void writeInternalImpl(const TValue* data, size_t size) {
const auto newOffset = _currOffset + size;
if (newOffset <= _bufferSize) {
std::copy_n(data, size, _beginIt + static_cast<diff_t>(_currOffset));

View File

@@ -49,8 +49,21 @@ namespace bitsery {
/**
* size read/write functions
*/
template <typename Reader, typename TCheckMaxSize>
void readSize(Reader& r, size_t& size, size_t maxSize, TCheckMaxSize) {
template <typename Reader>
void handleReadMaxSize(Reader& r, size_t& size, size_t maxSize, std::true_type) {
if (size > maxSize) {
r.error(ReaderError::InvalidData);
size = {};
}
}
template <typename Reader>
void handleReadMaxSize(Reader&, size_t&, size_t, std::false_type) {
}
template <typename Reader, bool CheckMaxSize>
void readSize(Reader& r, size_t& size, size_t maxSize, std::integral_constant<bool, CheckMaxSize> checkMaxSize) {
uint8_t hb{};
r.template readBytes<1>(hb);
if (hb < 0x80u) {
@@ -66,19 +79,7 @@ namespace bitsery {
size = ((hb & 0x7Fu) << 8) | lb;
}
}
handleReadMaxSize(r, size, maxSize, TCheckMaxSize{});
}
template <typename Reader>
void handleReadMaxSize(Reader& r, size_t& size, size_t maxSize, std::true_type) {
if (size > maxSize) {
r.error(ReaderError::InvalidData);
size = {};
}
}
template <typename Reader>
void handleReadMaxSize(Reader&, size_t&, size_t, std::false_type) {
handleReadMaxSize(r, size, maxSize, checkMaxSize);
}
template <typename Writer>

View File

@@ -83,18 +83,19 @@ namespace bitsery {
//specialization for resizable buffers
template <typename T>
struct StdContainerForBufferAdapter<T, true> {
using TIterator = typename T::iterator;
using TConstIterator = typename T::const_iterator;
using TValue = typename ContainerTraits<T>::TValue;
static void increaseBufferSize(T& container) {
static void increaseBufferSize(T& container, size_t currSize, size_t minSize) {
//since we're writing to buffer use different resize strategy than default implementation
//when small size grow faster, to avoid thouse 2/4/8/16... byte allocations
auto newSize = static_cast<size_t>(static_cast<double>(container.size()) * 1.5) + 128;
//make data cache friendly
newSize -= newSize % 64;//64 is cache line size
container.resize((std::max)(newSize, container.capacity()));
container.resize((std::max)(newSize > minSize ? newSize : minSize, container.capacity()));
}
using TIterator = typename T::iterator;
using TConstIterator = typename T::const_iterator;
using TValue = typename ContainerTraits<T>::TValue;
};
}

View File

@@ -141,6 +141,10 @@ namespace bitsery {
//traits only for buffer adapters
template <typename T>
struct BufferAdapterTraits {
using TIterator = details::NotDefinedType;
using TConstIterator = details::NotDefinedType;
using TValue = typename ContainerTraits<T>::TValue;
//this function is only applies to resizable containers
//this function is only used by Writer, when writing data to buffer,
@@ -148,14 +152,11 @@ namespace bitsery {
//it is used to dramaticaly improve performance by updating buffer directly
//instead of using back_insert_iterator to append each byte to buffer.
static void increaseBufferSize(T& ) {
static void increaseBufferSize(T& ,size_t currentOffset, size_t minSize) {
static_assert(std::is_void<T>::value,
"Define BufferAdapterTraits or include from <bitsery/traits/...> to use as buffer adapter container");
}
using TIterator = details::NotDefinedType;
using TConstIterator = details::NotDefinedType;
using TValue = typename ContainerTraits<T>::TValue;
};
//specialization for c-style buffer

View File

@@ -32,8 +32,6 @@ endif()
file(GLOB TestSourceFiles ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
enable_testing()
foreach (TestFile ${TestSourceFiles})
get_filename_component(TestName ${TestFile} NAME_WE)
set(TestName bitsery.test.${TestName})

View File

@@ -47,14 +47,6 @@ struct DisableAdapterErrorsConfig {
static constexpr bool CheckDataErrors = true;
};
TEST(OutputBuffer, WhenInitialBufferIsEmptyThenResizeInAdapterConstructor) {
//setup data
Buffer buf{};
EXPECT_THAT(buf.size(), Eq(0));
OutputAdapter adapter{buf};
EXPECT_THAT(buf.size(), Ge(1));
}
TEST(OutputBuffer, WhenSetWritePositionThenResizeUnderlyingBufferIfRequired) {
//setup data
Buffer buf{};
@@ -502,13 +494,13 @@ using BufferedAdapterInternalBufferTypes = ::testing::Types<
TYPED_TEST_SUITE(OutputStreamBuffered, BufferedAdapterInternalBufferTypes,);
TYPED_TEST(OutputStreamBuffered, WhenInternalBufferIsFullThenWriteBufferToStream) {
TYPED_TEST(OutputStreamBuffered, WhenInternalBufferIsFullThenWriteBufferAndValueToStream) {
uint8_t x{};
for (auto i = 0u; i < TestFixture::InternalBufferSize; ++i)
this->writer.template writeBytes<1>(x);
EXPECT_TRUE(this->stream.str().empty());
this->writer.template writeBytes<1>(x);
EXPECT_THAT(this->stream.str().size(), Eq(TestFixture::InternalBufferSize));
EXPECT_THAT(this->stream.str().size(), Eq(TestFixture::InternalBufferSize + 1));
}
TYPED_TEST(OutputStreamBuffered, WhenFlushThenWriteImmediately) {