diff --git a/include/boost/mysql/detail/channel/read_buffer.hpp b/include/boost/mysql/detail/channel/read_buffer.hpp index c1a996e5..dae1bd96 100644 --- a/include/boost/mysql/detail/channel/read_buffer.hpp +++ b/include/boost/mysql/detail/channel/read_buffer.hpp @@ -25,64 +25,54 @@ namespace detail { // - Dead area: these bytes have already been consumed, but won't disappear until a call to relocate(). // Optimized the case where we read several entire messages in a single read_some() call, preventing // several memcpy()'s. -// - Reserved area: we already processed these bytes, but the client component hasn't consumed them yet. -// - Processing area: we have read these bytes but haven't processed them yet. +// - Processing area: we have read these bytes and the client hasn't consumed them yet. // - Free area: free space for more bytes to be read. class read_buffer { bytestring buffer_; - std::size_t reserved_offset_; std::size_t processing_offset_; std::size_t free_offset_; public: read_buffer(std::size_t size): buffer_(size, std::uint8_t(0)), - reserved_offset_(0), processing_offset_(0), free_offset_(0) { buffer_.resize(buffer_.capacity()); } - std::uint8_t* reserved_first() noexcept { return &buffer_[reserved_offset_]; } std::uint8_t* processing_first() noexcept { return &buffer_[processing_offset_]; } std::uint8_t* free_first() noexcept { return &buffer_[free_offset_]; } - std::size_t reserved_size() const noexcept { return processing_offset_ - reserved_offset_; } + std::size_t dead_size() const noexcept { return processing_offset_; } std::size_t processing_size() const noexcept { return free_offset_ - processing_offset_; } std::size_t free_size() const noexcept { return buffer_.size() - free_offset_; } - boost::asio::mutable_buffer reserved_area() noexcept { return boost::asio::buffer(reserved_first(), reserved_size()); } boost::asio::mutable_buffer free_area() noexcept { return boost::asio::buffer(free_first(), free_size()); } - // Removes n bytes from the reserved area - void remove_from_reserved(std::size_t n) noexcept + // Removes length bytes from the processing area, at a certain offset + void remove_from_processing(std::size_t offset, std::size_t length) noexcept { - assert(n <= reserved_size()); - reserved_offset_ += n; - } - - // Removes n bytes from the read area, without touching the reserved area - void remove_from_processing_front(std::size_t n) noexcept - { - assert(n <= processing_size()); - if (reserved_size()) + assert(offset >= processing_offset_); + assert(length <= processing_size()); + if (offset == 0) // remove from front, just extend the dead area { - // Move the reserved bytes to the front - std::memmove(reserved_first() + n, reserved_first(), n); + processing_offset_ += length; } - reserved_offset_ += n; - processing_offset_ += n; + else + { + // Move remaining bytes backwards + std::memmove( + &buffer_[processing_offset_ + offset], + &buffer_[processing_offset_ + offset + length], + processing_size() - length + ); + free_offset_ -= length; + } + } - // Moves n bytes from the processing area to the reserved area - void move_to_reserved(std::size_t n) noexcept - { - assert(n <= processing_size()); - processing_offset_ += n; - } - - // Moves n bytes from the free area to the processing area + // Moves n bytes from the free to the processing area (e.g. they've been read) void move_to_processing(std::size_t n) noexcept { assert(n <= free_size()); @@ -92,12 +82,25 @@ public: // Removes the dead area, to make space void relocate() noexcept { - if (reserved_offset_ > 0) + if (dead_size() > 0) { - std::memmove(&buffer_[0], reserved_first(), free_offset_ - reserved_offset_); - processing_offset_ -= reserved_offset_; - free_offset_ -= reserved_offset_; - reserved_offset_ = 0; + std::memmove(&buffer_[0], processing_first(), processing_size()); + free_offset_ -= dead_size(); + processing_offset_ = 0; + } + } + + // Makes sure the free size is at least n bytes long; resizes the buffer if required + void grow_to_fit(std::size_t n) + { + if (free_size() < n) + { + relocate(); + } + if (free_size() < n) + { + buffer_.resize(free_size() - n); + buffer_.resize(buffer_.capacity()); } }