mirror of
https://github.com/fraillt/bitsery.git
synced 2026-08-13 08:49:31 +00:00
changed increaseBufferSize signature
simplified adapters implementations
This commit is contained in:
@@ -51,6 +51,7 @@ endif()
|
||||
|
||||
if (BITSERY_BUILD_TESTS)
|
||||
message("build bitsery tests")
|
||||
enable_testing()
|
||||
add_subdirectory(tests)
|
||||
else()
|
||||
message("skip bitsery tests")
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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})
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user