diff options
Diffstat (limited to 'src/core/buffer.cpp')
-rw-r--r-- | src/core/buffer.cpp | 434 |
1 files changed, 434 insertions, 0 deletions
diff --git a/src/core/buffer.cpp b/src/core/buffer.cpp new file mode 100644 index 0000000..ad471d7 --- /dev/null +++ b/src/core/buffer.cpp @@ -0,0 +1,434 @@ +#include "buffer.h" + +#include <algorithm> +#include <cassert> +#include <cstring> +#include <iomanip> +#include <sstream> + +namespace saw { +error buffer::push(const uint8_t &value) { + size_t write_remain = write_composite_length(); + if (write_remain > 0) { + write() = value; + write_advance(1); + } else { + return make_error<err::buffer_exhausted>(); + } + return no_error(); +} + +error buffer::push(const uint8_t &buffer, size_t size) { + error error = write_require_length(size); + if (error.failed()) { + return error; + } + const uint8_t *buffer_ptr = &buffer; + while (size > 0) { + size_t segment = std::min(write_segment_length(), size); + memcpy(&write(), buffer_ptr, segment); + write_advance(segment); + size -= segment; + buffer_ptr += segment; + } + return no_error(); +} + +error buffer::pop(uint8_t &value) { + if (read_composite_length() > 0) { + value = read(); + read_advance(1); + } else { + return make_error<err::buffer_exhausted>(); + } + return no_error(); +} + +error buffer::pop(uint8_t &buffer, size_t size) { + if (read_composite_length() >= size) { + uint8_t *buffer_ptr = &buffer; + while (size > 0) { + size_t segment = std::min(read_segment_length(), size); + memcpy(buffer_ptr, &read(), segment); + read_advance(segment); + size -= segment; + buffer_ptr += segment; + } + } else { + return make_error<err::buffer_exhausted>(); + } + return no_error(); +} + +std::string buffer::to_string() const { + std::ostringstream oss; + for (size_t i = 0; i < read_composite_length(); ++i) { + oss << read(i); + } + return oss.str(); +} + +std::string buffer::to_hex() const { + std::ostringstream oss; + oss << std::hex << std::setfill('0'); + for (size_t i = 0; i < read_composite_length(); ++i) { + oss << std::setw(2) << (uint16_t)read(i); + if ((i + 1) < read_composite_length()) { + oss << ((i % 4 == 3) ? '\n' : ' '); + } + } + return oss.str(); +} + +buffer_view::buffer_view(buffer &buffer) + : buffer_{buffer}, read_offset_{0}, write_offset_{0} {} + +size_t buffer_view::read_position() const { + return read_offset_ + buffer_.read_position(); +} + +size_t buffer_view::read_composite_length() const { + assert(read_offset_ <= buffer_.read_composite_length()); + if (read_offset_ > buffer_.read_composite_length()) { + return 0; + } + + return buffer_.read_composite_length() - read_offset_; +} + +size_t buffer_view::read_segment_length(size_t offset) const { + size_t off = offset + read_offset_; + assert(off <= buffer_.read_composite_length()); + if (off > buffer_.read_composite_length()) { + return 0; + } + + return buffer_.read_segment_length(off); +} + +void buffer_view::read_advance(size_t bytes) { + size_t offset = bytes + read_offset_; + assert(offset <= buffer_.read_composite_length()); + if (offset > buffer_.read_composite_length()) { + read_offset_ += buffer_.read_composite_length(); + return; + } + + read_offset_ += bytes; +} + +uint8_t &buffer_view::read(size_t i) { + size_t pos = i + read_offset_; + + assert(pos < buffer_.read_composite_length()); + + return buffer_.read(pos); +} + +const uint8_t &buffer_view::read(size_t i) const { + size_t pos = i + read_offset_; + + assert(pos < buffer_.read_composite_length()); + + return buffer_.read(pos); +} + +size_t buffer_view::write_position() const { + return write_offset_ + buffer_.write_position(); +} + +size_t buffer_view::write_composite_length() const { + assert(write_offset_ <= buffer_.write_composite_length()); + if (write_offset_ > buffer_.write_composite_length()) { + return 0; + } + + return buffer_.write_composite_length() - write_offset_; +} + +size_t buffer_view::write_segment_length(size_t offset) const { + size_t off = offset + write_offset_; + assert(off <= buffer_.write_composite_length()); + if (off > buffer_.write_composite_length()) { + return 0; + } + + return buffer_.write_segment_length(off); +} + +void buffer_view::write_advance(size_t bytes) { + size_t offset = bytes + write_offset_; + assert(offset <= buffer_.write_composite_length()); + if (offset > buffer_.write_composite_length()) { + write_offset_ += buffer_.write_composite_length(); + return; + } + + write_offset_ += bytes; +} + +uint8_t &buffer_view::write(size_t i) { + size_t pos = i + write_offset_; + + assert(pos < buffer_.write_composite_length()); + + return buffer_.write(pos); +} + +const uint8_t &buffer_view::write(size_t i) const { + size_t pos = i + write_offset_; + + assert(pos < buffer_.write_composite_length()); + + return buffer_.write(pos); +} + +error buffer_view::write_require_length(size_t bytes) { + return buffer_.write_require_length(bytes + write_offset_); +} + +size_t buffer_view::read_offset() const { return read_offset_; } + +size_t buffer_view::write_offset() const { return write_offset_; } + +ring_buffer::ring_buffer() : read_position_{0}, write_position_{0} { + buffer_.resize(RING_BUFFER_MAX_SIZE); +} + +ring_buffer::ring_buffer(size_t size) : read_position_{0}, write_position_{0} { + buffer_.resize(size); +} + +size_t ring_buffer::read_position() const { return read_position_; } + +/* + * If write is ahead of read it is a simple distance, but if read ist ahead of + * write then there are two segments + * + */ +size_t ring_buffer::read_composite_length() const { + return write_position() < read_position() + ? buffer_.size() - (read_position() - write_position()) + : (write_reached_read_ ? buffer_.size() + : write_position() - read_position()); +} + +/* + * If write is ahead then it's the simple distance again. If read is ahead it's + * until the end of the buffer/segment + */ +size_t ring_buffer::read_segment_length(size_t offset) const { + size_t read_composite = read_composite_length(); + assert(offset <= read_composite); + offset = std::min(offset, read_composite); + size_t remaining = read_composite - offset; + + size_t read_offset = read_position() + offset; + read_offset = read_offset >= buffer_.size() ? read_offset - buffer_.size() + : read_offset; + + // case 1 write is located before read and reached read + // then offset can be used normally + // case 2 write is located at read, but read reached write + // then it is set to zero by readCompositeLength() + // case 3 write is located after read + // since std::min you can use simple subtraction + if (write_position() < read_offset) { + return buffer_.size() - read_offset; + } + + if (write_position() == read_offset) { + if (remaining > 0) { + return buffer_.size() - read_offset; + } else { + return 0; + } + } + + return write_position() - read_offset; +} + +void ring_buffer::read_advance(size_t bytes) { + size_t read_composite = read_composite_length(); + + assert(bytes <= read_composite); + bytes = std::min(bytes, read_composite); + size_t advanced = read_position_ + bytes; + read_position_ = advanced >= buffer_.size() ? advanced - buffer_.size() + : advanced; + write_reached_read_ = bytes > 0 ? false : write_reached_read_; +} + +uint8_t &ring_buffer::read(size_t i) { + assert(i < read_composite_length()); + size_t pos = read_position_ + i; + pos = pos >= buffer_.size() ? pos - buffer_.size() : pos; + return buffer_[pos]; +} + +const uint8_t &ring_buffer::read(size_t i) const { + assert(i < read_composite_length()); + size_t pos = read_position_ + i; + pos = pos >= buffer_.size() ? pos - buffer_.size() : pos; + return buffer_[pos]; +} + +size_t ring_buffer::write_position() const { return write_position_; } + +size_t ring_buffer::write_composite_length() const { + return read_position() > write_position() + ? (read_position() - write_position()) + : (write_reached_read_ + ? 0 + : buffer_.size() - (write_position() - read_position())); +} + +size_t ring_buffer::write_segment_length(size_t offset) const { + size_t write_composite = write_composite_length(); + assert(offset <= write_composite); + offset = std::min(offset, write_composite); + + size_t write_offset = write_position() + offset; + write_offset = write_offset >= buffer_.size() + ? write_offset - buffer_.size() + : write_offset; + + if (read_position_ > write_offset) { + return read_position_ - write_offset; + } + + if (write_reached_read_) { + return 0; + } + + return buffer_.size() - write_offset; +} + +void ring_buffer::write_advance(size_t bytes) { + assert(bytes <= write_composite_length()); + size_t advanced = write_position_ + bytes; + write_position_ = advanced >= buffer_.size() ? advanced - buffer_.size() + : advanced; + + write_reached_read_ = + (write_position_ == read_position_ && bytes > 0 ? true : false); +} + +uint8_t &ring_buffer::write(size_t i) { + assert(i < write_composite_length()); + size_t pos = write_position_ + i; + pos = pos >= buffer_.size() ? pos - buffer_.size() : pos; + return buffer_[pos]; +} + +const uint8_t &ring_buffer::write(size_t i) const { + assert(i < write_composite_length()); + size_t pos = write_position_ + i; + pos = pos >= buffer_.size() ? pos - buffer_.size() : pos; + return buffer_[pos]; +} +/* + Error RingBuffer::increaseSize(size_t size){ + size_t old_size = buffer.size(); + size_t new_size = old_size + size; + buffer.resize(new_size); + if(readPosition() > writePosition() || (readPosition() == + writePosition() && write_reached_read)){ size_t remaining = old_size - + writePosition(); size_t real_remaining = 0; while(remaining > 0){ size_t + segment = std::min(remaining, size); memcpy(&buffer[new_size-segment], + &buffer[old_size-segment], segment); remaining -= segment; size -= segment; + old_size -= segment; + new_size -= segment; + } + } + + return noError(); + } +*/ +error ring_buffer::write_require_length(size_t bytes) { + size_t write_remain = write_composite_length(); + if (bytes > write_remain) { + return make_error<err::buffer_exhausted>(); + } + return no_error(); +} + +array_buffer::array_buffer(size_t size) + : read_position_{0}, write_position_{0} { + buffer_.resize(size); +} + +size_t array_buffer::read_position() const { return read_position_; } + +size_t array_buffer::read_composite_length() const { + return write_position_ - read_position_; +} + +size_t array_buffer::read_segment_length(size_t offset) const { + size_t read_composite = read_composite_length(); + assert(offset <= read_composite); + + offset = std::min(read_composite, offset); + size_t read_offset = read_position_ + offset; + + return write_position_ - read_offset; +} + +void array_buffer::read_advance(size_t bytes) { + assert(bytes <= read_composite_length()); + read_position_ += bytes; +} + +uint8_t &array_buffer::read(size_t i) { + assert(i < read_composite_length()); + + return buffer_[i + read_position_]; +} + +const uint8_t &array_buffer::read(size_t i) const { + assert(i + read_position_ < buffer_.size()); + + return buffer_[i + read_position_]; +} + +size_t array_buffer::write_position() const { return write_position_; } + +size_t array_buffer::write_composite_length() const { + assert(write_position_ <= buffer_.size()); + return buffer_.size() - write_position_; +} + +size_t array_buffer::write_segment_length(size_t offset) const { + assert(write_position_ <= buffer_.size()); + size_t write_composite = write_composite_length(); + + assert(offset <= write_composite); + offset = std::min(write_composite, offset); + size_t write_offset = write_position_ + offset; + + return buffer_.size() - write_offset; +} + +void array_buffer::write_advance(size_t bytes) { + assert(bytes <= write_composite_length()); + write_position_ += bytes; +} + +uint8_t &array_buffer::write(size_t i) { + assert(i < write_composite_length()); + return buffer_[i + write_position_]; +} + +const uint8_t &array_buffer::write(size_t i) const { + assert(i < write_composite_length()); + return buffer_[i + write_position_]; +} +error array_buffer::write_require_length(size_t bytes) { + size_t write_remain = write_composite_length(); + if (bytes > write_remain) { + return make_error<err::buffer_exhausted>(); + } + return no_error(); +} + +} // namespace saw |