mirror of
https://github.com/fraillt/bitsery.git
synced 2026-10-24 01:30:55 +00:00
provided read/write method for adapaters that accepts number of bytes at
compile-time
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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) \
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user