forstio/source/forstio/buffer.cpp

435 lines
11 KiB
C++

#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 recoverable_error("Buffer too small");
}
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 recoverable_error("Buffer too small");
}
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 recoverable_error("Buffer too small");
}
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 recoverable_error("Buffer too small");
}
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 recoverable_error("Buffer too small");
}
return no_error();
}
} // namespace saw