summaryrefslogtreecommitdiff
path: root/src/core/buffer.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/buffer.h')
-rw-r--r--src/core/buffer.h195
1 files changed, 195 insertions, 0 deletions
diff --git a/src/core/buffer.h b/src/core/buffer.h
new file mode 100644
index 0000000..4485ff1
--- /dev/null
+++ b/src/core/buffer.h
@@ -0,0 +1,195 @@
+#pragma once
+
+#include "error.h"
+
+#include <array>
+#include <cstdint>
+#include <deque>
+#include <list>
+#include <string>
+#include <vector>
+
+namespace saw {
+/*
+ * Access class to reduce templated BufferSegments bloat
+ */
+class buffer {
+protected:
+ ~buffer() = default;
+
+public:
+ virtual size_t read_position() const = 0;
+ virtual size_t read_composite_length() const = 0;
+ virtual size_t read_segment_length(size_t offset = 0) const = 0;
+ virtual void read_advance(size_t bytes) = 0;
+
+ virtual uint8_t &read(size_t i = 0) = 0;
+ virtual const uint8_t &read(size_t i = 0) const = 0;
+
+ virtual size_t write_position() const = 0;
+ virtual size_t write_composite_length() const = 0;
+ virtual size_t write_segment_length(size_t offset = 0) const = 0;
+ virtual void write_advance(size_t bytes) = 0;
+
+ virtual uint8_t &write(size_t i = 0) = 0;
+ virtual const uint8_t &write(size_t i = 0) const = 0;
+
+ /*
+ * Sometime buffers need to grow with a little more control
+ * than with push and pop for more efficient calls.
+ * There is nothing you can do if read hasn't been filled, but at
+ * least write can be increased if it is demanded.
+ */
+ virtual error write_require_length(size_t bytes) = 0;
+
+ error push(const uint8_t &value);
+ error push(const uint8_t &buffer, size_t size);
+ error pop(uint8_t &value);
+ error pop(uint8_t &buffer, size_t size);
+
+ /*
+ * Subject to change
+ */
+ std::string to_string() const;
+ std::string to_hex() const;
+};
+
+/*
+ * A viewer class for buffers.
+ * Working on the reference buffer invalidates the buffer view
+ */
+class buffer_view : public buffer {
+private:
+ buffer &buffer_;
+ size_t read_offset_;
+ size_t write_offset_;
+
+public:
+ buffer_view(buffer &);
+
+ size_t read_position() const override;
+ size_t read_composite_length() const override;
+ size_t read_segment_length(size_t offset = 0) const override;
+ void read_advance(size_t bytes) override;
+
+ uint8_t &read(size_t i = 0) override;
+ const uint8_t &read(size_t i = 0) const override;
+
+ size_t write_position() const override;
+ size_t write_composite_length() const override;
+ size_t write_segment_length(size_t offset = 0) const override;
+ void write_advance(size_t bytes) override;
+
+ uint8_t &write(size_t i = 0) override;
+ const uint8_t &write(size_t i = 0) const override;
+
+ error write_require_length(size_t bytes) override;
+
+ size_t read_offset() const;
+ size_t write_offset() const;
+};
+
+/*
+ * Buffer size meant for default allocation size of the ringbuffer since
+ * this class currently doesn't support proper resizing
+ */
+constexpr size_t RING_BUFFER_MAX_SIZE = 4096;
+/*
+ * Buffer wrapping around if read caught up
+ */
+class ring_buffer final : public buffer {
+private:
+ std::vector<uint8_t> buffer_;
+ size_t read_position_;
+ size_t write_position_;
+ bool write_reached_read_ = false;
+
+public:
+ ring_buffer();
+ ring_buffer(size_t size);
+
+ inline size_t size() const { return buffer_.size(); }
+
+ inline uint8_t &operator[](size_t i) { return buffer_[i]; }
+ inline const uint8_t &operator[](size_t i) const { return buffer_[i]; }
+
+ size_t read_position() const override;
+ size_t read_composite_length() const override;
+ size_t read_segment_length(size_t offset = 0) const override;
+ void read_advance(size_t bytes) override;
+
+ uint8_t &read(size_t i = 0) override;
+ const uint8_t &read(size_t i = 0) const override;
+
+ size_t write_position() const override;
+ size_t write_composite_length() const override;
+ size_t write_segment_length(size_t offset = 0) const override;
+ void write_advance(size_t bytes) override;
+
+ uint8_t &write(size_t i = 0) override;
+ const uint8_t &write(size_t i = 0) const override;
+
+ error write_require_length(size_t bytes) override;
+};
+
+/*
+ * One time buffer
+ */
+class array_buffer : public buffer {
+private:
+ std::vector<uint8_t> buffer_;
+
+ size_t read_position_;
+ size_t write_position_;
+
+public:
+ array_buffer(size_t size);
+
+ size_t read_position() const override;
+ size_t read_composite_length() const override;
+ size_t read_segment_length(size_t offset = 0) const override;
+ void read_advance(size_t bytes) override;
+
+ uint8_t &read(size_t i = 0) override;
+ const uint8_t &read(size_t i = 0) const override;
+
+ size_t write_position() const override;
+ size_t write_composite_length() const override;
+ size_t write_segment_length(size_t offset = 0) const override;
+ void write_advance(size_t bytes) override;
+
+ uint8_t &write(size_t i = 0) override;
+ const uint8_t &write(size_t i = 0) const override;
+
+ error write_require_length(size_t bytes) override;
+};
+
+class chain_array_buffer : public buffer {
+private:
+ std::deque<array_buffer> buffer_;
+
+ size_t read_position_;
+ size_t write_position_;
+
+public:
+ chain_array_buffer();
+
+ size_t read_position() const override;
+ size_t read_composite_length() const override;
+ size_t read_segment_length(size_t offset = 0) const override;
+ void read_advance(size_t bytes) override;
+
+ uint8_t &read(size_t i = 0) override;
+ const uint8_t &read(size_t i = 0) const override;
+
+ size_t write_position() const override;
+ size_t write_composite_length() const override;
+ size_t write_segment_length(size_t offset = 0) const override;
+ void write_advance(size_t bytes) override;
+
+ uint8_t &write(size_t i = 0) override;
+ const uint8_t &write(size_t i = 0) const override;
+
+ error write_require_length(size_t bytes) override;
+};
+} // namespace saw