100 lines
2.5 KiB
C++
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;
|
|
}
|
|
};
|
|
|
|
}
|