nostalgia/deps/ox/src/ox/logconn/circularbuff.hpp

100 lines
2.5 KiB
C++

/*
* Copyright 2015 - 2022 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <ox/std/assert.hpp>
#include <ox/std/buffer.hpp>
#include <ox/std/units.hpp>
namespace ox::detail {
class CirculerBuffer {
private:
std::size_t m_readPt = 0;
std::size_t m_writePt = 0;
ox::Buffer m_buff = ox::Buffer(ox::units::MB);
private:
[[nodiscard]]
constexpr auto avail() const noexcept {
if (m_writePt >= m_readPt) {
return m_buff.size() - (m_writePt - m_readPt);
} else {
return (m_buff.size() - m_writePt) - (m_buff.size() - m_readPt);
}
}
public:
constexpr ox::Error put(char v) noexcept {
return write(&v, 1);
if (1 > avail()) {
return OxError(1, "Insufficient space in buffer");
}
m_buff[m_writePt] = v;
++m_writePt;
return {};
}
constexpr ox::Error write(const char *buff, std::size_t sz) noexcept {
if (sz > avail()) {
return OxError(1, "Insufficient space in buffer");
}
// write seg 1
const auto seg1Sz = ox::min(sz, m_buff.size() - m_writePt);
ox_memcpy(&m_buff[m_writePt], &buff[0], seg1Sz);
m_writePt += sz;
if (seg1Sz != sz) {
m_writePt -= m_buff.size();
// write seg 2
const auto seg2Sz = sz - seg1Sz;
ox_memcpy(&m_buff[0], &buff[seg1Sz], seg2Sz);
oxAssert(m_buff[0] == buff[seg1Sz], "break");
}
return {};
}
constexpr ox::Error seekp(std::size_t bytesFwd) noexcept {
if (bytesFwd > avail()) {
return OxError(1, "Insufficient space in buffer to seek that far ahead");
}
m_writePt += bytesFwd;
if (m_writePt > m_buff.size()) {
m_writePt -= m_buff.size();
}
return {};
}
constexpr ox::Error seekp(int, ios_base::seekdir) {
return OxError(1, "Unimplemented");
}
[[nodiscard]]
constexpr std::size_t tellp() const noexcept {
return m_buff.size() - avail();
}
[[nodiscard]]
constexpr std::size_t read(char *out, std::size_t outSize) noexcept {
const auto bytesRead = ox::min(outSize, m_buff.size() - avail());
// read seg 1
const auto seg1Sz = ox::min(bytesRead, m_buff.size() - m_readPt);
ox_memcpy(&out[0], &m_buff[m_readPt], seg1Sz);
m_readPt += bytesRead;
if (seg1Sz != bytesRead) {
m_readPt -= m_buff.size();
// read seg 2
const auto seg2Sz = bytesRead - seg1Sz;
ox_memcpy(&out[seg1Sz], &m_buff[0], seg2Sz);
}
return bytesRead;
}
};
}