#pragma once #include #include "lock.h" struct RingBuffer { std::span buffer; size_t read_ptr = 0; size_t write_ptr = 0; size_t used = 0; bool Store(std::span data) { InterruptLock lock; if (data.size() > FreeSpace()) { return false; } const size_t to_copy = std::min(buffer.size() - write_ptr, data.size()); std::copy(data.begin(), data.begin() + to_copy, buffer.begin() + write_ptr); if (to_copy < data.size()) { std::copy(data.begin() + to_copy, data.end(), buffer.begin()); } Push(data.size()); return true; } bool Load(std::span out) { InterruptLock lock; if (out.size() > AvailableData()) { return false; } const size_t to_copy = std::min(buffer.size() - read_ptr, out.size()); std::copy(buffer.begin() + read_ptr, buffer.begin() + read_ptr + to_copy, out.begin()); if (to_copy < out.size()) { std::copy(buffer.begin(), buffer.begin() + out.size() - to_copy, out.begin() + to_copy); } Pop(out.size()); return true; } bool Push(size_t amount) { InterruptLock lock; if (amount > FreeSpace()) { return false; } write_ptr = (write_ptr + amount) % buffer.size(); used = used + amount; return true; } bool Pop(size_t amount) { InterruptLock lock; if (amount > AvailableData()) { return false; } read_ptr = (read_ptr + amount) % buffer.size(); used = used - amount; return true; } size_t FreeSpace() const { InterruptLock lock; return buffer.size() - used; } size_t AvailableData() const { InterruptLock lock; return used; } uint8_t* RawReadPointer() const { InterruptLock lock; return reinterpret_cast(buffer.data() + read_ptr); } uint8_t* RawWritePointer() const { InterruptLock lock; return reinterpret_cast(buffer.data() + write_ptr); } size_t ContiguousFreeSpace() const { InterruptLock lock; return std::min(FreeSpace(), buffer.size() - write_ptr); } size_t ContiguousAvailableData() const { InterruptLock lock; return std::min(AvailableData(), buffer.size() - read_ptr); } };