#pragma once #include #include #include namespace tw::net { /** * Circular byte buffer. */ class ByteBufferReader { public: ByteBufferReader(std::span target) : buffer(target), readOffset(0) {} ByteBufferReader(std::span target) : buffer(target), readOffset(0) {} size_t peek_bytes(void* dst, size_t size, size_t offset = 0) { if(remaining() - offset < size) { spdlog::warn("Could not peek entire frame, remaining: {}/{}", remaining() - offset, size); return 0; } size_t cursor = readOffset + offset; // if(cursor + size <= buffer.size()) { std::memcpy(dst, buffer.data() + cursor, size); // } else { // size_t firstPart = buffer.size() - cursor; // std::memcpy(dst, buffer.data() + cursor, firstPart); // std::memcpy((std::byte*)dst + firstPart, buffer.data(), size - firstPart); // } return size; } template size_t pop_bytes(T* dst) { return pop_bytes(dst, sizeof(T)); } size_t pop_bytes(void* dst, size_t size) { size_t peeked = peek_bytes(dst, size); if(peeked < size) { spdlog::warn("Could not read entire frame, peeked only: {}/{}", peeked, size); return 0; } skip(size); return size; } size_t pop_bytes(std::span dst) { return pop_bytes(dst.data(), dst.size()); } size_t position() const { return readOffset; } size_t remaining() const { return buffer.size() - readOffset; } void reset() { readOffset = 0; } void skip(size_t bytes) { readOffset = (readOffset + std::min(bytes, remaining())); } private: std::span buffer; size_t readOffset = 0; }; } // namespace tw::net