diff --git a/include/bitsery/adapter/buffer.h b/include/bitsery/adapter/buffer.h index 1093c0c..9cd48c8 100644 --- a/include/bitsery/adapter/buffer.h +++ b/include/bitsery/adapter/buffer.h @@ -28,57 +28,27 @@ namespace bitsery { - - template - class BufferIterators { - static constexpr bool isConstBuffer = std::is_const::value; - using BuffNonConst = typename std::remove_const::type; - public: - BufferIterators(const BufferIterators&) = delete; - BufferIterators& operator=(const BufferIterators&) = delete; - BufferIterators(BufferIterators&&) = default; - BufferIterators& operator=(BufferIterators&&) = default; - virtual ~BufferIterators() = default; - protected: - - using TIterator = typename std::conditional::TConstIterator, - typename traits::BufferAdapterTraits::TIterator>::type; - static_assert(details::IsDefined::value, - "Please define BufferAdapterTraits or include from "); - BufferIterators(TIterator begin, TIterator end) - : beginIt{begin}, - posIt{begin}, - endIt{end} { - } - - TIterator beginIt; - TIterator posIt; - TIterator endIt; - }; - template - class InputBufferAdapter: public BufferIterators, - public details::InputAdapterBaseCRTP> { + class InputBufferAdapter: public details::InputAdapterBaseCRTP> { public: friend details::InputAdapterBaseCRTP>; using TConfig = Config; - using TIterator = typename BufferIterators::TIterator; + using TIterator = typename traits::BufferAdapterTraits::type>::TConstIterator; using TValue = typename traits::BufferAdapterTraits::type>::TValue; static_assert(details::IsDefined::value, "Please define BufferAdapterTraits or include from "); static_assert(traits::ContainerTraits::type>::isContiguous, "BufferAdapter only works with contiguous containers"); - InputBufferAdapter(TIterator begin, TIterator endIt) - : BufferIterators(begin, endIt), - _endReadPos{endIt} { + InputBufferAdapter(TIterator beginIt, size_t size) + : _beginIt{beginIt}, + _currOffset{0}, + _endReadOffset{size}, + _bufferSize{size} { + }; - } - - InputBufferAdapter(TIterator begin, size_t size) - : BufferIterators(begin, std::next(begin, size)), - _endReadPos{std::next(begin, size)} { + InputBufferAdapter(TIterator beginIt, TIterator endIt) + :InputBufferAdapter(beginIt, std::distance(beginIt, endIt)) { } InputBufferAdapter(const InputBufferAdapter&) = delete; @@ -92,18 +62,17 @@ namespace bitsery { } size_t currentReadPos() const { - return static_cast(std::distance(this->beginIt, this->posIt)); + return currentReadPosChecked(std::integral_constant{}); } void currentReadEndPos(size_t pos) { // assert that CheckAdapterErrors is enabled, otherwise it will simply will not work even if data and buffer is not corrupted static_assert(Config::CheckAdapterErrors, "Please enable CheckAdapterErrors to use this functionality."); - const auto buffSize = static_cast(std::distance(this->beginIt, this->endIt)); - if (buffSize >= pos) { + if (_bufferSize >= pos && error() == ReaderError::NoError) { _overflowOnReadEndPos = pos == 0; if (pos == 0) - pos = buffSize; - _endReadPos = std::next(this->beginIt, pos); + pos = _bufferSize; + _endReadOffset = pos; } else { error(ReaderError::DataOverflow); } @@ -112,44 +81,42 @@ namespace bitsery { size_t currentReadEndPos() const { if (_overflowOnReadEndPos) return 0; - return static_cast(std::distance(this->beginIt, _endReadPos)); + return _endReadOffset; } ReaderError error() const { - return _err; + return _currOffset <= _endReadOffset + ? ReaderError::NoError + : static_cast(_currOffset - _endReadOffset); } void error(ReaderError error) { - if (_err == ReaderError::NoError) { - _err = error; - _endReadPos = this->endIt; - this->beginIt = this->endIt; - this->posIt = this->endIt; + if (_currOffset <= _endReadOffset) { + _endReadOffset = 0; + _bufferSize = 0; + _currOffset = static_cast(error); } } bool isCompletedSuccessfully() const { - return this->posIt == this->endIt && _err == ReaderError::NoError; + return _currOffset == _bufferSize; } private: void readChecked(TValue *data, size_t size, std::false_type) { - //for optimization - auto tmp = this->posIt; - this->posIt += size; - assert(std::distance(this->posIt, this->endIt) >= 0); - std::memcpy(data, std::addressof(*tmp), size); + 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) { - //for optimization - auto tmp = this->posIt; - this->posIt += size; - if (std::distance(this->posIt, _endReadPos) >= 0) { - std::memcpy(data, std::addressof(*tmp), size); + const auto newOffset = _currOffset + size; + if (newOffset <= _endReadOffset) { + std::copy_n(_beginIt + _currOffset, size, data); + _currOffset = newOffset; } else { - this->posIt -= size; //set everything to zeros std::memset(data, 0, size); if (_overflowOnReadEndPos) @@ -162,19 +129,30 @@ namespace bitsery { } void currentReadPosChecked(size_t pos, std::true_type) { - if (static_cast(std::distance(this->beginIt, this->endIt)) >= pos) { - this->posIt = std::next(this->beginIt, pos); + if (_bufferSize >= pos && error() == ReaderError::NoError) { + _currOffset = pos; } else { error(ReaderError::DataOverflow); } } void currentReadPosChecked(size_t pos, std::false_type) { - this->posIt = std::next(this->beginIt, pos); + _currOffset = pos; } - TIterator _endReadPos; - ReaderError _err = ReaderError::NoError; + size_t currentReadPosChecked(std::true_type) const { + return error() == ReaderError::NoError ? _currOffset : 0; + } + + size_t currentReadPosChecked(std::false_type) const { + return _currOffset; + } + + + TIterator _beginIt; + size_t _currOffset; + size_t _endReadOffset; + size_t _bufferSize; bool _overflowOnReadEndPos = true; }; @@ -192,8 +170,8 @@ namespace bitsery { "BufferAdapter only works with contiguous containers"); OutputBufferAdapter(Buffer &buffer) - : _buffer{std::addressof(buffer)} { - + : _buffer{std::addressof(buffer)}, + _beginIt{std::begin(buffer)} { init(TResizable{}); } @@ -203,8 +181,7 @@ namespace bitsery { OutputBufferAdapter& operator = (OutputBufferAdapter&&) = default; void currentWritePos(size_t pos) { - const auto currPos =static_cast(std::distance(std::begin(*_buffer), _outIt)); - const auto maxPos = currPos > pos ? currPos : pos; + const auto maxPos = _currOffset > pos ? _currOffset : pos; if (maxPos > _biggestCurrentPos) { _biggestCurrentPos = maxPos; } @@ -212,7 +189,7 @@ namespace bitsery { } size_t currentWritePos() const { - return static_cast (std::distance(std::begin(*_buffer), _outIt)); + return _currOffset; } void flush() { @@ -220,8 +197,7 @@ namespace bitsery { } size_t writtenBytesCount() const { - const auto pos =static_cast(std::distance(std::begin(*_buffer), _outIt)); - return pos > _biggestCurrentPos ? pos : _biggestCurrentPos; + return _currOffset > _biggestCurrentPos ? _currOffset : _biggestCurrentPos; } private: @@ -232,9 +208,10 @@ namespace bitsery { } Buffer* _buffer; - TIterator _outIt{}; - TIterator _end{}; - size_t _biggestCurrentPos{}; + TIterator _beginIt; + size_t _currOffset{0}; + size_t _bufferSize{0}; + size_t _biggestCurrentPos{0}; /* * resizable buffer @@ -245,47 +222,27 @@ namespace bitsery { if (traits::ContainerTraits::size(*_buffer) == 0u) { traits::BufferAdapterTraits::increaseBufferSize(*_buffer); } - _end = std::end(*_buffer); - _outIt = std::begin(*_buffer); + updateIteratorAndSize(); } void writeInternalImpl(const TValue *data, const size_t size, std::true_type) { - //optimization -#if defined(_MSC_VER) && (_ITERATOR_DEBUG_LEVEL > 0) - using TDistance = typename std::iterator_traits::difference_type; - if (std::distance(_outIt , _end) >= static_cast(size)) { - std::memcpy(std::addressof(*_outIt), data, size); - _outIt += size; -#else - auto tmp = _outIt; - _outIt += size; - if (std::distance(_outIt, _end) >= 0) { - std::memcpy(std::addressof(*tmp), data, size); -#endif + const auto newOffset = _currOffset + size; + if (newOffset <= _bufferSize) { + std::copy_n(data, size, _beginIt + _currOffset); + _currOffset = newOffset; } else { -#if defined(_MSC_VER) && (_ITERATOR_DEBUG_LEVEL > 0) - -#else - _outIt -= size; -#endif - //get current position before invalidating iterators - const auto pos = std::distance(std::begin(*_buffer), _outIt); - //increase container size traits::BufferAdapterTraits::increaseBufferSize(*_buffer); - //restore iterators - _end = std::end(*_buffer); - _outIt = std::next(std::begin(*_buffer), pos); - + updateIteratorAndSize(); writeInternalImpl(data, size, std::true_type{}); } } void setCurrentWritePos(size_t pos, std::true_type) { - const auto begin = std::begin(*_buffer); - if (static_cast(std::distance(begin, std::end(*_buffer))) >= pos) { - _outIt = std::next(begin, pos); + if (pos <= _bufferSize) { + _currOffset = pos; } else { traits::BufferAdapterTraits::increaseBufferSize(*_buffer); + updateIteratorAndSize(); setCurrentWritePos(pos, std::true_type{}); } } @@ -294,22 +251,24 @@ namespace bitsery { * non resizable buffer */ void init(std::false_type) { - _outIt = std::begin(*_buffer); - _end = std::end(*_buffer); + updateIteratorAndSize(); } void writeInternalImpl(const TValue *data, size_t size, std::false_type) { - //optimization - auto tmp = _outIt; - _outIt += size; - assert(std::distance(_outIt, _end) >= 0); - memcpy(std::addressof(*tmp), data, size); + const auto newOffset = _currOffset + size; + assert(newOffset <= _bufferSize); + std::copy_n(data, size, _beginIt + _currOffset); + _currOffset = newOffset; } void setCurrentWritePos(size_t pos, std::false_type) { - const auto begin = std::begin(*_buffer); - assert(static_cast(std::distance(begin, std::end(*_buffer))) >= pos); - _outIt = std::next(begin, pos); + assert(pos <= _bufferSize); + _currOffset = pos; + } + + void updateIteratorAndSize() { + _beginIt = std::begin(*_buffer); + _bufferSize = traits::ContainerTraits::size(*_buffer); } };