summaryrefslogtreecommitdiff
path: root/fastbuffer.hpp
diff options
context:
space:
mode:
authorToni Uhlig <matzeton@googlemail.com>2025-03-18 16:23:01 +0100
committerToni Uhlig <matzeton@googlemail.com>2025-03-19 12:03:29 +0100
commitc652e22dd1cfe059a30604e772529f1d86a1a28d (patch)
treea6ecd392f5f45c1434f78697fd3e64bffaaf1a5b /fastbuffer.hpp
initial commitHEADmain
Signed-off-by: Toni Uhlig <matzeton@googlemail.com>
Diffstat (limited to 'fastbuffer.hpp')
-rw-r--r--fastbuffer.hpp157
1 files changed, 157 insertions, 0 deletions
diff --git a/fastbuffer.hpp b/fastbuffer.hpp
new file mode 100644
index 0000000..d6ac8d5
--- /dev/null
+++ b/fastbuffer.hpp
@@ -0,0 +1,157 @@
+#ifndef FASTBUFFER_H
+#define FASTBUFFER_H 1
+
+#include <boost/asio/buffer.hpp>
+#include <boost/format.hpp>
+#include <boost/noncopyable.hpp>
+#include <exception>
+#include <string>
+
+class BufferException : public std::exception {
+public:
+ explicit BufferException(const char *what) : m_what(what) {}
+ explicit BufferException(const std::string &what) : m_what(what) {}
+ virtual ~BufferException() noexcept {}
+ virtual const char *what() const noexcept { return m_what.c_str(); }
+
+private:
+ std::string m_what;
+};
+
+class BufferBase {
+public:
+ explicit BufferBase(std::size_t size)
+ : m_bufferOffset{0}, m_bufferUsed{0}, m_bufferSize{size} {
+ m_buffer = new std::uint8_t[size];
+ }
+ BufferBase(BufferBase &&moveable) {
+ m_bufferOffset = std::move(moveable.m_bufferOffset);
+ m_bufferUsed = std::move(moveable.m_bufferUsed);
+ m_bufferSize = std::move(moveable.m_bufferSize);
+ m_buffer = std::move(moveable.m_buffer);
+ moveable.m_buffer = nullptr;
+ moveable.m_bufferOffset = moveable.m_bufferUsed = moveable.m_bufferSize = 0;
+ }
+ ~BufferBase() { delete[] m_buffer; }
+ void operator+=(std::size_t commit_size) {
+ checkFreeSpace(commit_size);
+ m_bufferUsed += commit_size;
+ }
+ void operator+=(const std::initializer_list<uint8_t> &to_add) {
+ checkFreeSpace(to_add.size());
+ std::copy(to_add.begin(), to_add.end(), &m_buffer[m_bufferUsed]);
+ m_bufferUsed += to_add.size();
+ }
+ void operator-=(std::size_t consume_size) {
+ const auto unconsumed_space = unconsumed();
+ checkConsumableSpace(consume_size);
+ if (consume_size == unconsumed_space) {
+ m_bufferUsed = m_bufferOffset = 0;
+ return;
+ }
+ m_bufferOffset += consume_size;
+ }
+ auto operator+() {
+ return boost::asio::buffer(&m_buffer[m_bufferUsed], unused());
+ }
+ auto operator-() {
+ return boost::asio::buffer(&m_buffer[m_bufferOffset], m_bufferUsed);
+ }
+ auto operator[](std::size_t index) const { return m_buffer[index]; }
+ const auto *operator()(std::size_t index) const { return &m_buffer[index]; }
+ auto *operator()() { return &m_buffer[m_bufferUsed]; }
+ auto size() const { return m_bufferUsed; }
+ auto capacity() const { return m_bufferSize; }
+ std::size_t unused() const { return m_bufferSize - m_bufferUsed; }
+ std::size_t unconsumed() const { return m_bufferUsed - m_bufferOffset; }
+ void checkFreeSpace(std::size_t commit_size) const {
+ const auto free_space = unused();
+ if (commit_size > free_space)
+ throw BufferException(
+ (boost::format(
+ "Buffer overflow: %1% bytes free, %1% bytes required") %
+ free_space % commit_size)
+ .str());
+ }
+ void checkConsumableSpace(std::size_t consume_size) const {
+ const auto unconsumed_space = unconsumed();
+ if (consume_size > unconsumed_space)
+ throw BufferException(
+ (boost::format(
+ "Buffer underflow: %1% bytes used, %1% bytes consumed") %
+ unconsumed_space % consume_size)
+ .str());
+ };
+ auto getHealth() const {
+ return (static_cast<float>(m_bufferUsed) /
+ static_cast<float>(m_bufferSize));
+ }
+ auto getConsumeHealth() const {
+ return (static_cast<float>(unconsumed()) /
+ static_cast<float>(m_bufferSize));
+ }
+
+private:
+ std::size_t m_bufferOffset;
+ std::size_t m_bufferUsed;
+ std::size_t m_bufferSize;
+ std::uint8_t *m_buffer;
+};
+
+using ContiguousStreamBuffer = BufferBase;
+
+class ContiguousPacketQueue : public boost::noncopyable {
+public:
+ struct Element {
+ std::size_t size;
+ };
+ explicit ContiguousPacketQueue(std::size_t max_packets,
+ std::size_t max_queue_size)
+ : m_buffer(max_queue_size), m_packetsOffset{0}, m_packetsUsed{0},
+ m_packetsSize{max_packets} {
+ m_packets = new Element[max_packets];
+ }
+ ContiguousPacketQueue(ContiguousPacketQueue &&moveable)
+ : m_buffer(std::move(moveable.m_buffer)) {
+ m_packetsOffset = std::move(moveable.m_packetsOffset);
+ m_packetsUsed = std::move(moveable.m_packetsUsed);
+ m_packetsSize = std::move(moveable.m_packetsSize);
+ m_packets = std::move(moveable.m_packets);
+ moveable.m_packets = nullptr;
+ moveable.m_packetsOffset = moveable.m_packetsUsed = moveable.m_packetsSize =
+ 0;
+ }
+ ~ContiguousPacketQueue() { delete[] m_packets; }
+ void operator+=(std::size_t commit_size) {
+ m_packets[m_packetsUsed++].size = commit_size;
+ m_buffer += commit_size;
+ }
+ void operator+=(const std::initializer_list<uint8_t> &to_add) {
+ m_packets[m_packetsUsed++].size = to_add.size();
+ m_buffer += to_add;
+ }
+ void operator--() {
+ const auto consume_size = m_packets[m_packetsOffset].size;
+ m_buffer -= consume_size;
+ if (++m_packetsOffset == m_packetsUsed) {
+ m_packetsOffset = m_packetsUsed = 0;
+ return;
+ }
+ }
+ auto operator+() { return +m_buffer; }
+ auto operator-() { return -m_buffer; }
+ auto size() const { return m_packetsUsed; }
+ auto capacity() const { return m_packetsSize; }
+ std::size_t unused() const { return m_packetsSize - m_packetsUsed; }
+ std::size_t unconsumed() const { return m_packetsUsed - m_packetsOffset; }
+ const auto *GetBuffer() const { return &m_buffer; }
+
+private:
+ BufferBase m_buffer;
+ std::size_t m_packetsOffset;
+ std::size_t m_packetsUsed;
+ std::size_t m_packetsSize;
+ Element *m_packets;
+};
+
+#endif