[WIP] Buffers interface

This commit is contained in:
alejo committed 2026-09-19 23:00:15 -03:00
1 parent 7fd475c9a9
commit 9a5b56729b
11 files changed
+348

No files matched your search

+20
View File
@@ -0,0 +1,20 @@
#include <cstdint>
#include <acrux/memory/Endian.hpp>
#include "acrux/format/Print.hpp"
using namespace acrux::memory;
using namespace acrux::fmt;
int main()
{
uint32_t number = 10;
println(number);
Endian newEndian = !hostEndianness();
fromHostEndianness(number, newEndian);
println(number);
toHostEndianness(number, newEndian);
println(number);
return 0;
}
+14
View File
@@ -0,0 +1,14 @@
#pragma once
#include <memory>
#include "BufferBase.hpp"
namespace acrux::buffers
{
template<typename TWriter, typename TReader>
class Buffer : public IBuffer
{
public:
virtual TWriter* getWriter() = 0;
virtual std::unique_ptr<TReader> makeReader() = 0;
};
}
+40
View File
@@ -0,0 +1,40 @@
#pragma once
#include <cstddef>
#include <istream>
#include <ostream>
#include "acrux/memory/Endian.hpp"
namespace acrux::buffers
{
class IBuffer
{
public:
[[nodiscard]] virtual size_t byteLength() const = 0;
[[nodiscard]] virtual size_t bitLength() const = 0;
[[nodiscard]] virtual size_t byteCapacity() const = 0;
[[nodiscard]] virtual size_t bitCapacity() const = 0;
virtual bool copyTo(std::ostream& stream) const = 0;
virtual bool copyFrom(std::istream& stream) = 0;
[[nodiscard]] virtual bool hasBytesLeft(size_t count) const = 0;
[[nodiscard]] virtual bool hasBitsLeft(size_t count) const = 0;
void setendianness(acrux::memory::Endian endianness);
acrux::memory::Endian endianness();
~IBuffer() = default;
IBuffer(const IBuffer&) = default;
IBuffer(IBuffer&&) noexcept = default;
IBuffer& operator=(IBuffer&&) noexcept = default;
IBuffer& operator=(const IBuffer&) = default;
private:
acrux::memory::Endian m_endianness{acrux::memory::Endian::None};
};
}
+33
View File
@@ -0,0 +1,33 @@
#pragma once
#include <cstddef>
#include "BufferBase.hpp"
#include "acrux/memory/Endian.hpp"
namespace acrux::buffers
{
class BufferReader : public IBuffer
{
public:
[[nodiscard]] virtual bool read(void* s, size_t bitCount) = 0;
template <typename T>
[[nodiscard]] bool read(T& value, acrux::memory::Endian endianness);
[[nodiscard]] const IBuffer* getBuffer() const;
IBuffer* getBuffer();
BufferReader(IBuffer* buffer);
~BufferReader() = default;
BufferReader(const BufferReader&) = default;
BufferReader(BufferReader&&) noexcept = default;
BufferReader& operator=(BufferReader&&) noexcept = default;
BufferReader& operator=(const BufferReader&) = default;
private:
IBuffer* m_buffer{nullptr};
};
}
+32
View File
@@ -0,0 +1,32 @@
#pragma once
#include <cstddef>
#include "BufferBase.hpp"
#include "acrux/memory/Endian.hpp"
namespace acrux::buffers
{
class BufferWriter : public IBuffer
{
public:
[[nodiscard]] virtual bool write(const void* s, size_t bitCount) = 0;
template <typename T>
[[nodiscard]] bool write(const T& value, acrux::memory::Endian endianness);
[[nodiscard]] const IBuffer* getBuffer() const;
IBuffer* getBuffer();
BufferWriter(IBuffer* buffer);
~BufferWriter() = default;
BufferWriter(const BufferWriter&) = default;
BufferWriter(BufferWriter&&) noexcept = default;
BufferWriter& operator=(BufferWriter&&) noexcept = default;
BufferWriter& operator=(const BufferWriter&) = default;
private:
IBuffer* m_buffer{nullptr};
};
}
@@ -0,0 +1,21 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include <array>
#include "acrux/buffers/fixed/FixedBufferBase.hpp"
namespace acrux::buffers
{
template <size_t ByteCapacity> class FixedBuffer : FixedBufferBase
{
public:
[[nodiscard]] const uint8_t* data() const override;
private:
uint8_t* data() override;
std::array<uint8_t, ByteCapacity> m_data{0};
};
}
@@ -0,0 +1,31 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include "acrux/buffers/Buffer.hpp"
#include "acrux/buffers/fixed/FixedBufferReader.hpp"
#include "acrux/buffers/fixed/FixedBufferWriter.hpp"
namespace acrux::buffers
{
class FixedBufferBase : Buffer<FixedBufferWriter, FixedBufferReader>
{
public:
FixedBufferWriter* getWriter() override;
std::unique_ptr<FixedBufferReader> makeReader() override;
~FixedBufferBase() = default;
FixedBufferBase(const FixedBufferBase&) = default;
FixedBufferBase(FixedBufferBase&&) noexcept = default;
FixedBufferBase& operator=(FixedBufferBase&&) noexcept = default;
FixedBufferBase& operator=(const FixedBufferBase&) = default;
[[nodiscard]] virtual const uint8_t* data() const = 0;
private:
virtual uint8_t* data() = 0;
size_t m_byteCursor{0};
uint8_t m_bitCursor{0};
};
}
@@ -0,0 +1,14 @@
#pragma once
#include "acrux/buffers/BufferBase.hpp"
#include "acrux/buffers/BufferReader.hpp"
namespace acrux::buffers
{
class FixedBufferReader final : public BufferReader
{
public:
[[nodiscard]] bool read(void* s, size_t bitCount) override;
FixedBufferReader(IBuffer* buffer);
};
}
@@ -0,0 +1,14 @@
#pragma once
#include "acrux/buffers/BufferBase.hpp"
#include "acrux/buffers/BufferWriter.hpp"
namespace acrux::buffers
{
class FixedBufferWriter final : public BufferWriter
{
public:
[[nodiscard]] bool write(const void* s, size_t bitCount) override;
FixedBufferWriter(IBuffer* buffer);
};
}
+103
View File
@@ -0,0 +1,103 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include <type_traits>
namespace acrux::memory
{
enum class Endian : uint8_t
{
None,
Little,
Big
};
/**
* @param endian The endianness to get the opposite of.
* @return Gets the opposite endiannes, unchanged if `endian` is `None`.
*/
Endian operator!(const Endian& endian);
/**
* @return The host's endianness
*/
Endian hostEndianness();
/**
* @brief Swaps the bytes of `value` if `source` and `target` are different,
* results in a no-op if `source` or `target` is `None`.
*
* @tparam T The type of the value to modify.
* @param value The value to modify.
* @param source The value's source endianness.
* @param target The value's target endianness.
*/
template <typename T> void convertEndianness(T& value, Endian source, Endian target);
/**
* @brief Swaps the bytes of `value` if `source` is different than the host's endianness.
* results in a no-op if `source` is `None`
*
* @tparam T The type of the value to convert.
* @param value The value to convert.
* @param source The value's source endianness
*/
template <typename T> void toHostEndianness(T& value, Endian source);
/**
* @brief Swaps the bytes of `value` if `target` is different than the host's endianness.
* results in a no-op if `target` is `None`
*
* @tparam T The type of the value to convert.
* @param value The value to convert.
* @param target The value's target endianness
*/
template <typename T> void fromHostEndianness(T& value, Endian target);
/**
* @brief Swaps the bytes of a given value.
*
* @tparam T The type of the value.
* @param value The value to modify.
*/
template <typename T> void swapBytes(T& value);
template <typename T> void convertEndianness(T& value, Endian source, Endian target)
{
// Cannot operate on an unknown or invariant endianness
if (source == Endian::None || target == Endian::None)
return;
// Already in target order
if (source == target)
return;
swapBytes(value);
}
template <typename T> void toHostEndianness(T& value, Endian source)
{
convertEndianness(value, source, hostEndianness());
}
template <typename T> void fromHostEndianness(T& value, Endian target)
{
convertEndianness(value, hostEndianness(), target);
}
template <typename T> void swapBytes(T& value)
{
static_assert(std::is_trivially_copyable<T>::value, "Type must be trivially copyable");
uint8_t* bytes = reinterpret_cast<uint8_t*>(&value);
uint8_t temp;
for (std::size_t i = 0; i < sizeof(T) / 2; ++i)
{
temp = bytes[i];
bytes[i] = bytes[sizeof(T) - 1 - i];
bytes[sizeof(T) - 1 - i] = temp;
}
}
}
+26
View File
@@ -0,0 +1,26 @@
#include "acrux/memory/Endian.hpp"
namespace acrux::memory
{
Endian operator!(const Endian& endian)
{
switch (endian)
{
case Endian::Little:
return Endian::Big;
case Endian::Big:
return Endian::Little;
default:
return Endian::None;
}
}
Endian hostEndianness()
{
const uint16_t number = 0x1;
const uint8_t* firstByte = reinterpret_cast<const uint8_t*>(&number);
return (*firstByte == 1) ? Endian::Little : Endian::Big;
}
}