#pragma once #include #include struct RingBuffer { std::span buffer; std::atomic read_ptr = 0; std::atomic write_ptr = 0; std::atomic full = 0; bool Store(std::span data) { 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) { 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) { if (amount > FreeSpace()) { return false; } write_ptr = (write_ptr + amount) % buffer.size(); if (read_ptr == write_ptr) { full = true; } return true; } bool Pop(size_t amount) { if (amount > AvailableData()) { return false; } read_ptr = (read_ptr + amount) % buffer.size(); if (amount > 0) { full = false; } return true; } size_t FreeSpace() const { return buffer.size() - AvailableData(); } size_t AvailableData() const { if (read_ptr == write_ptr) { return full ? buffer.size() : 0; } return (buffer.size() + write_ptr - read_ptr) % buffer.size(); } uint8_t* RawReadPointer() const { return reinterpret_cast(buffer.data() + read_ptr); } size_t ContiguousAvailableData() const { if (read_ptr < write_ptr) { return AvailableData(); } if (full) { return 0; } return buffer.size() - read_ptr; } };