provided read/write method for adapaters that accepts number of bytes at

compile-time
This commit is contained in:
Mindaugas Vinkelis
2020-01-29 15:08:25 +02:00
parent ee68261124
commit d24dfe14f5
9 changed files with 187 additions and 96 deletions

View File

@@ -104,14 +104,45 @@ namespace bitsery {
private:
void readChecked(TValue *data, size_t size, std::false_type) {
template <size_t SIZE>
void readInternalValue(TValue *data) {
readInternalValueChecked<SIZE>(data, std::integral_constant<bool, Config::CheckAdapterErrors>{});
}
void readInternalBuffer(TValue *data, size_t size) {
readInternalBufferChecked(data, size, std::integral_constant<bool, Config::CheckAdapterErrors>{});
}
template <size_t SIZE>
void readInternalValueChecked(TValue *data, std::false_type) {
const auto newOffset = _currOffset + SIZE;
assert(newOffset <= _endReadOffset);
std::copy_n(_beginIt + _currOffset, SIZE, data);
_currOffset = newOffset;
}
template <size_t SIZE>
void readInternalValueChecked(TValue *data, std::true_type) {
const auto newOffset = _currOffset + SIZE;
if (newOffset <= _endReadOffset) {
std::copy_n(_beginIt + _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) {
const auto newOffset = _currOffset + size;
assert(newOffset <= _endReadOffset);
std::copy_n(_beginIt + _currOffset, size, data);
_currOffset = newOffset;
}
void readChecked(TValue *data, size_t size, std::true_type) {
void readInternalBufferChecked(TValue *data, size_t size, std::true_type) {
const auto newOffset = _currOffset + size;
if (newOffset <= _endReadOffset) {
std::copy_n(_beginIt + _currOffset, size, data);
@@ -124,10 +155,6 @@ namespace bitsery {
}
}
void readInternal(TValue *data, size_t size) {
readChecked(data, size, std::integral_constant<bool, Config::CheckAdapterErrors>{});
}
void currentReadPosChecked(size_t pos, std::true_type) {
if (_bufferSize >= pos && error() == ReaderError::NoError) {
_currOffset = pos;
@@ -203,8 +230,13 @@ namespace bitsery {
private:
using TResizable = std::integral_constant<bool, traits::ContainerTraits<Buffer>::isResizable>;
void writeInternal(const TValue *data, size_t size) {
writeInternalImpl(data, size, TResizable{});
template <size_t SIZE>
void writeInternalValue(const TValue *data) {
writeInternalValueImpl<SIZE>(data, TResizable{});
}
void writeInternalBuffer(const TValue *data, size_t size) {
writeInternalBufferImpl(data, size, TResizable{});
}
Buffer* _buffer;
@@ -225,7 +257,20 @@ namespace bitsery {
updateIteratorAndSize();
}
void writeInternalImpl(const TValue *data, const size_t size, std::true_type) {
template <size_t SIZE>
void writeInternalValueImpl(const TValue *data, std::true_type) {
const auto newOffset = _currOffset + SIZE;
if (newOffset <= _bufferSize) {
std::copy_n(data, SIZE, _beginIt + _currOffset);
_currOffset = newOffset;
} else {
traits::BufferAdapterTraits<Buffer>::increaseBufferSize(*_buffer);
updateIteratorAndSize();
writeInternalValueImpl<SIZE>(data, std::true_type{});
}
}
void writeInternalBufferImpl(const TValue *data, const size_t size, std::true_type) {
const auto newOffset = _currOffset + size;
if (newOffset <= _bufferSize) {
std::copy_n(data, size, _beginIt + _currOffset);
@@ -233,7 +278,7 @@ namespace bitsery {
} else {
traits::BufferAdapterTraits<Buffer>::increaseBufferSize(*_buffer);
updateIteratorAndSize();
writeInternalImpl(data, size, std::true_type{});
writeInternalBufferImpl(data, size, std::true_type{});
}
}
@@ -254,7 +299,15 @@ namespace bitsery {
updateIteratorAndSize();
}
void writeInternalImpl(const TValue *data, size_t size, std::false_type) {
template <size_t SIZE>
void writeInternalValueImpl(const TValue *data, std::false_type) {
const auto newOffset = _currOffset + SIZE;
assert(newOffset <= _bufferSize);
std::copy_n(data, SIZE, _beginIt + _currOffset);
_currOffset = newOffset;
}
void writeInternalBufferImpl(const TValue *data, size_t size, std::false_type) {
const auto newOffset = _currOffset + size;
assert(newOffset <= _bufferSize);
std::copy_n(data, size, _beginIt + _currOffset);

View File

@@ -83,7 +83,12 @@ namespace bitsery {
private:
void readInternal(TValue* data, size_t size) {
template <size_t SIZE>
void readInternalValue(TValue* data) {
readChecked(data, SIZE, std::integral_constant<bool, Config::CheckAdapterErrors>{});
}
void readInternalBuffer(TValue* data, size_t size) {
readChecked(data, size, std::integral_constant<bool, Config::CheckAdapterErrors>{});
}
@@ -139,8 +144,12 @@ namespace bitsery {
private:
void writeInternal(const TValue* data, size_t size) {
//for optimization
template <size_t SIZE>
void writeInternalValue(const TValue* data) {
_ios->rdbuf()->sputn( data , SIZE );
}
void writeInternalBuffer(const TValue* data, size_t size) {
_ios->rdbuf()->sputn( data , size );
}
@@ -163,9 +172,12 @@ namespace bitsery {
BasicBufferedOutputStreamAdapter(std::basic_ios<TChar, CharTraits>& ostream, size_t bufferSize = 256)
:_ios(std::addressof(ostream)),
_buf{},
_outIt{}
_beginIt{std::begin(_buf)},
_currOffset{0}
{
init(bufferSize, TResizable{});
// buffer size must be atleast 16, because writeIntervalValue expect that atleast one value fits to buffer.
assert(_bufferSize >= 16);
}
//we need to explicitly declare move logic, because after move buffer might be invalidated
@@ -174,20 +186,19 @@ namespace bitsery {
BasicBufferedOutputStreamAdapter(BasicBufferedOutputStreamAdapter&& rhs)
: _ios{rhs._ios},
_buf{},
_outIt{}
_buf{std::move(rhs._buf)},
_beginIt{std::begin(_buf)},
_currOffset{rhs._currOffset},
_bufferSize{rhs._bufferSize}
{
auto size = std::distance(std::begin(rhs._buf), rhs._outIt);
_buf = std::move(rhs._buf);
_outIt = std::next(std::begin(_buf), size);
};
BasicBufferedOutputStreamAdapter& operator = (BasicBufferedOutputStreamAdapter&& rhs) {
_ios = rhs._ios;
//get current written size, before move
auto size = std::distance(std::begin(rhs._buf), rhs._outIt);
_buf = std::move(rhs._buf);
_outIt = std::next(std::begin(_buf), size);
_beginIt = std::begin(_buf);
_currOffset = rhs._currOffset;
_bufferSize = rhs._bufferSize;
return *this;
};
@@ -201,9 +212,7 @@ namespace bitsery {
}
void flush() {
auto begin = std::begin(_buf);
writeToStream(std::addressof(*begin), static_cast<size_t>(std::distance(begin, _outIt)));
_outIt = begin;
writeBufferToStream();
if (auto ostream = dynamic_cast<std::basic_ostream<TChar, CharTraits>*>(_ios))
ostream->flush();
}
@@ -217,44 +226,50 @@ namespace bitsery {
private:
using TResizable = std::integral_constant<bool, traits::ContainerTraits<TBuffer>::isResizable>;
void writeInternal(const TValue* data, size_t size) {
auto tmp = _outIt;
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 + _currOffset);
_currOffset = newOffset;
}
#if defined(_MSC_VER) && (_ITERATOR_DEBUG_LEVEL > 0)
using TDistance = typename std::iterator_traits<BufferIt>::difference_type;
if (std::distance(_outIt , std::end(_buf)) >= static_cast<TDistance>(size)) {
std::memcpy(std::addressof(*_outIt), data, size);
_outIt += size;
}
#else
_outIt += size;
if (std::distance(_outIt , std::end(_buf)) >= 0) {
std::memcpy(std::addressof(*tmp), data, size);
}
#endif
else {
//when buffer is full write out to stream
_outIt = std::begin(_buf);
writeToStream(std::addressof(*_outIt), static_cast<size_t>(std::distance(_outIt, tmp)));
writeToStream(data, size);
void writeInternalBuffer(const TValue* data, size_t size) {
const auto newOffset = _currOffset + size;
if (newOffset <= _bufferSize) {
std::copy_n(data, size, _beginIt + _currOffset);
_currOffset = newOffset;
} else {
writeBufferToStream();
// write buffer directly to stream
_ios->rdbuf()->sputn(data, size);
}
}
void writeToStream(const TValue* data, size_t size) {
_ios->rdbuf()->sputn( data , size );
void writeBufferToStream() {
_ios->rdbuf()->sputn(std::addressof(*_beginIt), _currOffset);
_currOffset = 0;
}
void init (size_t bufferSize, std::true_type) {
_buf.resize(bufferSize);
_outIt = std::begin(_buf);
void init (size_t buffSize, std::true_type) {
// resize buffer
_bufferSize = buffSize;
_buf.resize(_bufferSize);
_beginIt = std::begin(_buf);
}
void init (size_t, std::false_type) {
_outIt = std::begin(_buf);
void init (size_t , std::false_type) {
// ignore buffer size parameter, and instead take actual buffer size
_bufferSize = traits::ContainerTraits<Buffer>::size(_buf);
}
std::basic_ios<TChar, CharTraits>* _ios;
TBuffer _buf;
BufferIt _outIt;
BufferIt _beginIt;
size_t _currOffset;
size_t _bufferSize{0};
};
template <typename TChar, typename Config, typename CharTraits>

View File

@@ -26,7 +26,7 @@
#define BITSERY_MAJOR_VERSION 5
#define BITSERY_MINOR_VERSION 0
#define BITSERY_PATCH_VERSION 1
#define BITSERY_PATCH_VERSION 3
#define BITSERY_QUOTE_MACRO(name) #name
#define BITSERY_BUILD_VERSION_STR(major,minor, patch) \

View File

@@ -192,15 +192,14 @@ namespace bitsery {
void writeBytes(const T &v) {
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
writeSwapped(&v, 1, ShouldSwap<typename Adapter::TConfig>{});
writeSwappedValue(&v, ShouldSwap<typename Adapter::TConfig>{});
}
template<size_t SIZE, typename T>
void writeBuffer(const T *buf, size_t count) {
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
writeSwapped(buf, count, ShouldSwap<typename Adapter::TConfig>{});
writeSwappedBuffer(buf, count, ShouldSwap<typename Adapter::TConfig>{});
}
template<typename T>
@@ -222,16 +221,27 @@ namespace bitsery {
private:
template<typename T>
void writeSwapped(const T *v, size_t count, std::true_type) {
void writeSwappedValue(const T *v, std::true_type) {
const auto res = details::swap(*v);
static_cast<Adapter*>(this)->template writeInternalValue<sizeof(T)>(reinterpret_cast<const typename Adapter::TValue *>(&res));
}
template<typename T>
void writeSwappedValue(const T *v, std::false_type) {
static_cast<Adapter*>(this)->template writeInternalValue<sizeof(T)>(reinterpret_cast<const typename Adapter::TValue *>(v));
}
template<typename T>
void writeSwappedBuffer(const T *v, size_t count, std::true_type) {
std::for_each(v, std::next(v, count), [this](const T &v) {
const auto res = details::swap(v);
static_cast<Adapter*>(this)->writeInternal(reinterpret_cast<const typename Adapter::TValue *>(&res), sizeof(T));
static_cast<Adapter*>(this)->template writeInternalValue<sizeof(T)>(reinterpret_cast<const typename Adapter::TValue *>(&res));
});
}
template<typename T>
void writeSwapped(const T *v, size_t count, std::false_type) {
static_cast<Adapter*>(this)->writeInternal(reinterpret_cast<const typename Adapter::TValue *>(v), count * sizeof(T));
void writeSwappedBuffer(const T *v, size_t count, std::false_type) {
static_cast<Adapter*>(this)->writeInternalBuffer(reinterpret_cast<const typename Adapter::TValue *>(v), count * sizeof(T));
}
};
@@ -245,14 +255,16 @@ namespace bitsery {
void readBytes(T& v) {
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
directRead(&v, 1);
static_cast<Base*>(this)->template readInternalValue<sizeof(T)>(reinterpret_cast<typename Base::TValue *>(&v));
swapDataBits(v, ShouldSwap<typename Base::TConfig>{});
}
template<size_t SIZE, typename T>
void readBuffer(T* buf, size_t count) {
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
directRead(buf, count);
static_cast<Base*>(this)->readInternalBuffer(reinterpret_cast<typename Base::TValue *>(buf), sizeof(T) * count);
swapDataBits(buf, count, ShouldSwap<typename Base::TConfig>{});
}
template<typename T>
@@ -277,23 +289,26 @@ namespace bitsery {
private:
template<typename T>
void directRead(T *v, size_t count) {
static_assert(!std::is_const<T>::value, "");
static_cast<Base*>(this)->readInternal(reinterpret_cast<typename Base::TValue *>(v), sizeof(T) * count);
//swap each byte if necessary
_swapDataBits(v, count, ShouldSwap<typename Base::TConfig>{});
}
template<typename T>
void _swapDataBits(T *v, size_t count, std::true_type) {
void swapDataBits(T *v, size_t count, std::true_type) {
std::for_each(v, std::next(v, count), [](T &x) { x = details::swap(x); });
}
template<typename T>
void _swapDataBits(T *, size_t , std::false_type) {
void swapDataBits(T *, size_t , std::false_type) {
//empty function because no swap is required
}
template<typename T>
void swapDataBits(T &v, std::true_type) {
v = details::swap(v);
}
template<typename T>
void swapDataBits(T &, std::false_type) {
//empty function because no swap is required
}
};
}