moved higher level buffer impl to parent and adjusted some encoding code to guarantee resizes

This commit is contained in:
keldu.magnus 2020-11-16 22:48:04 +01:00
parent ee4e48e0b2
commit c3c325d662
4 changed files with 174 additions and 111 deletions

View File

@ -165,7 +165,7 @@ void EventLoop::leaveScope() {
local_loop = nullptr;
}
bool EventLoop::turnLoop(){
bool EventLoop::turnLoop() {
size_t turn_step = 0;
while (head && turn_step < 65536) {
if (!turn()) {

View File

@ -7,6 +7,79 @@
#include <sstream>
namespace gin {
Error Buffer::push(const uint8_t &value) {
size_t write_remain = writeCompositeLength();
if (write_remain > 0) {
write() = value;
writeAdvance(1);
} else {
return recoverableError("Buffer too small");
}
return noError();
}
Error Buffer::push(const uint8_t &buffer, size_t size) {
Error error = writeRequireLength(size);
if (error.failed()) {
return error;
}
const uint8_t *buffer_ptr = &buffer;
while (size > 0) {
size_t segment = std::min(writeSegmentLength(), size);
memcpy(&write(), buffer_ptr, segment);
writeAdvance(segment);
size -= segment;
buffer_ptr += segment;
}
return noError();
}
Error Buffer::pop(uint8_t &value) {
if (readCompositeLength() > 0) {
value = read();
readAdvance(1);
} else {
return recoverableError("Buffer too small");
}
return noError();
}
Error Buffer::pop(uint8_t &buffer, size_t size) {
if (readCompositeLength() >= size) {
uint8_t *buffer_ptr = &buffer;
while (size > 0) {
size_t segment = std::min(readSegmentLength(), size);
memcpy(buffer_ptr, &read(), segment);
readAdvance(segment);
size -= segment;
buffer_ptr += segment;
}
} else {
return recoverableError("Buffer too small");
}
return noError();
}
std::string Buffer::toString() const {
std::ostringstream oss;
for (size_t i = 0; i < readCompositeLength(); ++i) {
oss << read(i);
}
return oss.str();
}
std::string Buffer::toHex() const {
std::ostringstream oss;
oss << std::hex << std::setfill('0');
for (size_t i = 0; i < readCompositeLength(); ++i) {
oss << std::setw(2) << (uint16_t)read(i);
if ((i + 1) < readCompositeLength()) {
oss << ((i % 4 == 3) ? '\n' : ' ');
}
}
return oss.str();
}
RingBuffer::RingBuffer() : read_position{0}, write_position{0} {
buffer.resize(RING_BUFFER_MAX_SIZE);
}
@ -123,76 +196,77 @@ const uint8_t &RingBuffer::write(size_t i) const {
return noError();
}
*/
Error RingBuffer::push(const uint8_t &value) {
Error RingBuffer::writeRequireLength(size_t bytes) {
size_t write_remain = writeCompositeLength();
if (write_remain > 0) {
write() = value;
writeAdvance(1);
} else {
if (bytes > write_remain) {
return recoverableError("Buffer too small");
}
return noError();
}
Error RingBuffer::push(const uint8_t &buffer, size_t size) {
if (writeCompositeLength() >= size) {
const uint8_t *buffer_ptr = &buffer;
while (size > 0) {
size_t segment = std::min(writeSegmentLength(), size);
memcpy(&write(), buffer_ptr, segment);
writeAdvance(segment);
size -= segment;
buffer_ptr += segment;
}
} else {
ArrayBuffer::ArrayBuffer(size_t size) : read_position{0}, write_position{0} {
buffer.resize(size);
}
size_t ArrayBuffer::readPosition() const { return read_position; }
size_t ArrayBuffer::readCompositeLength() const {
return write_position - read_position;
}
size_t ArrayBuffer::readSegmentLength() const {
return write_position - read_position;
}
void ArrayBuffer::readAdvance(size_t bytes) {
assert(bytes <= readCompositeLength());
read_position += bytes;
}
uint8_t &ArrayBuffer::read(size_t i) {
assert(i < readCompositeLength());
return buffer[i + read_position];
}
const uint8_t &ArrayBuffer::read(size_t i) const {
assert(i + read_position < buffer.size());
return buffer[i + read_position];
}
size_t ArrayBuffer::writePosition() const { return write_position; }
size_t ArrayBuffer::writeCompositeLength() const {
assert(write_position <= buffer.size());
return buffer.size() - write_position;
}
size_t ArrayBuffer::writeSegmentLength() const {
assert(write_position <= buffer.size());
return buffer.size() - write_position;
}
void ArrayBuffer::writeAdvance(size_t bytes) {
assert(bytes <= writeCompositeLength());
write_position += bytes;
}
uint8_t &ArrayBuffer::write(size_t i) {
assert(i < writeCompositeLength());
return buffer[i + write_position];
}
const uint8_t &ArrayBuffer::write(size_t i) const {
assert(i < writeCompositeLength());
return buffer[i + write_position];
}
Error ArrayBuffer::writeRequireLength(size_t bytes) {
size_t write_remain = writeCompositeLength();
if (bytes > write_remain) {
return recoverableError("Buffer too small");
}
return noError();
}
Error RingBuffer::pop(uint8_t &value) {
if (readCompositeLength() > 0) {
value = read();
readAdvance(1);
} else {
return recoverableError("Buffer too small");
}
return noError();
}
Error RingBuffer::pop(uint8_t &buffer, size_t size) {
if (readCompositeLength() >= size) {
uint8_t *buffer_ptr = &buffer;
while (size > 0) {
size_t segment = std::min(readSegmentLength(), size);
memcpy(buffer_ptr, &read(), segment);
readAdvance(segment);
size -= segment;
buffer_ptr += segment;
}
} else {
return recoverableError("Buffer too small");
}
return noError();
}
std::string RingBuffer::toString() const {
std::ostringstream oss;
for (size_t i = 0; i < readCompositeLength(); ++i) {
oss << read(i);
}
return oss.str();
}
std::string RingBuffer::toHex() const {
std::ostringstream oss;
oss << std::hex << std::setfill('0');
for (size_t i = 0; i < readCompositeLength(); ++i) {
oss << std::setw(2) << (uint16_t)read(i);
if ((i + 1) < readCompositeLength()) {
oss << ((i % 4 == 3) ? '\n' : ' ');
}
}
return oss.str();
}
} // namespace gin

View File

@ -14,8 +14,7 @@ namespace gin {
* Access class to reduce templated BufferSegments bloat
*/
class Buffer {
private:
friend class RingBuffer;
protected:
~Buffer() = default;
public:
@ -36,29 +35,29 @@ public:
virtual const uint8_t &write(size_t i = 0) const = 0;
/*
* Sometime buffers need to grow with a little more control
* than with push and pop for more efficient calls.
* There is nothing you can do if read hasn't been filled, but at
* least write can be increased if it is demanded.
*/
* Sometime buffers need to grow with a little more control
* than with push and pop for more efficient calls.
* There is nothing you can do if read hasn't been filled, but at
* least write can be increased if it is demanded.
*/
virtual Error writeRequireLength(size_t bytes) = 0;
virtual Error push(const uint8_t &value) = 0;
virtual Error push(const uint8_t &buffer, size_t size) = 0;
virtual Error pop(uint8_t &value) = 0;
virtual Error pop(uint8_t &buffer, size_t size) = 0;
Error push(const uint8_t &value);
Error push(const uint8_t &buffer, size_t size);
Error pop(uint8_t &value);
Error pop(uint8_t &buffer, size_t size);
virtual std::string toString() const = 0;
virtual std::string toHex() const = 0;
std::string toString() const;
std::string toHex() const;
};
/*
* Buffer size meant for default allocation size of the ringbuffer since
* this class currently doesn't support proper resizing
*/
* Buffer size meant for default allocation size of the ringbuffer since
* this class currently doesn't support proper resizing
*/
constexpr size_t RING_BUFFER_MAX_SIZE = 4096;
/*
* Buffer wrapping around if read caught up
*/
* Buffer wrapping around if read caught up
*/
class RingBuffer final : public Buffer {
private:
std::vector<uint8_t> buffer;
@ -91,13 +90,7 @@ public:
uint8_t &write(size_t i = 0) override;
const uint8_t &write(size_t i = 0) const override;
Error push(const uint8_t &value) override;
Error push(const uint8_t &buffer, size_t size) override;
Error pop(uint8_t &value) override;
Error pop(uint8_t &buffer, size_t size) override;
std::string toString() const override;
std::string toHex() const override;
Error writeRequireLength(size_t bytes) override;
};
/*
@ -129,10 +122,7 @@ public:
uint8_t &write(size_t i = 0) override;
const uint8_t &write(size_t i = 0) const override;
Error push(const uint8_t &value) override;
Error push(const uint8_t &buffer, size_t size) override;
Error pop(uint8_t &value) override;
Error pop(uint8_t &buffer, size_t size) override;
Error writeRequireLength(size_t bytes) override;
};
class ChainArrayBuffer : public Buffer {
@ -161,9 +151,6 @@ public:
uint8_t &write(size_t i = 0) override;
const uint8_t &write(size_t i = 0) const override;
Error push(const uint8_t &value) override;
Error push(const uint8_t &buffer, size_t size) override;
Error pop(uint8_t &value) override;
Error pop(uint8_t &buffer, size_t size) override;
Error writeRequireLength(size_t bytes) override;
};
} // namespace gin

View File

@ -12,12 +12,12 @@ template <typename T, size_t size = sizeof(T)> class ShiftStreamValue;
template <typename T> class ShiftStreamValue<T, 1> {
public:
inline static Error decode(T &val, Buffer &buffer) {
uint8_t& raw = reinterpret_cast<uint8_t&>(val);
uint8_t &raw = reinterpret_cast<uint8_t &>(val);
return buffer.pop(raw, sizeof(T));
}
inline static Error encode(const T &val, Buffer &buffer) {
uint8_t& raw = reinterpret_cast<uint8_t&>(val);
uint8_t &raw = reinterpret_cast<uint8_t &>(val);
return buffer.push(raw, sizeof(T));
}
@ -30,26 +30,24 @@ public:
if (buffer.readCompositeLength() < sizeof(T)) {
return recoverableError("Buffer too small");
}
uint16_t& raw = reinterpret_cast<uint16_t&>(val);
uint8_t buf[sizeof(T)] = 0;
Error error = buffer.pop(buf, sizeof(T));
if(error.failed()){
return error;
}
uint16_t raw = 0;
for (size_t i = 0; i < sizeof(T); ++i) {
raw |= buf[i] << (i * 8);
raw |= buffer.read(i) << (i * 8);
}
memcpy(&val, &raw, sizeof(T));
buffer.readAdvance(sizeof(T));
return noError();
}
inline static Error encode(const T &val, Buffer &buffer) {
if (buffer.writeCompositeLength() < sizeof(T)) {
return recoverableError("Buffer too small");
Error error = buffer.writeRequireLength(sizeof(T));
if (error.failed()) {
return error;
}
uint16_t raw;
memcpy(&raw, &val, sizeof(T));
@ -83,9 +81,11 @@ public:
}
inline static Error encode(const T &val, Buffer &buffer) {
if (buffer.writeCompositeLength() < sizeof(T)) {
return recoverableError("Buffer too small");
Error error = buffer.writeRequireLength(sizeof(T));
if (error.failed()) {
return error;
}
uint32_t raw;
memcpy(&raw, &val, sizeof(T));
@ -119,9 +119,11 @@ public:
}
inline static Error encode(const T &val, Buffer &buffer) {
if (buffer.writeCompositeLength() < sizeof(T)) {
return recoverableError("Buffer too small");
Error error = buffer.writeRequireLength(sizeof(T));
if (error.failed()) {
return error;
}
uint64_t raw;
memcpy(&raw, &val, sizeof(T));