Support dynamically sized buffers (std::vector)

This commit is contained in:
TennesseeTrash 2025-09-22 02:54:13 +02:00
parent b65c700c29
commit c3278e807b
3 changed files with 360 additions and 290 deletions

View file

@ -3,9 +3,12 @@
#include "Core.hpp" #include "Core.hpp"
#include <array>
#include <cstdint> #include <cstdint>
#include <span> #include <span>
#include <string_view> #include <string_view>
#include <variant>
#include <vector>
namespace CBOR namespace CBOR
{ {
@ -15,6 +18,68 @@ namespace CBOR
using Error::Error; using Error::Error;
}; };
class EncoderBuffer
{
public:
EncoderBuffer(std::span<std::uint8_t> buffer);
EncoderBuffer(std::vector<std::uint8_t> &buffer);
template <std::size_t N>
EncoderBuffer(std::array<std::uint8_t, N> &buffer)
: EncoderBuffer(std::span(buffer))
{}
EncoderBuffer(const EncoderBuffer &) = delete;
EncoderBuffer &operator=(const EncoderBuffer &) = delete;
EncoderBuffer(EncoderBuffer &&other);
EncoderBuffer &operator=(EncoderBuffer &&other);
~EncoderBuffer() = default;
void Write(std::uint8_t value);
void Write(std::uint16_t value);
void Write(std::uint32_t value);
void Write(std::uint64_t value);
void Write(std::span<std::uint8_t> value);
void Write(std::string_view value);
std::size_t Size() const;
private:
struct FixedBuffer
{
void Write(std::uint8_t value);
void Write(std::uint16_t value);
void Write(std::uint32_t value);
void Write(std::uint64_t value);
void Write(std::span<std::uint8_t> value);
void Write(std::string_view value);
std::size_t Size() const;
void EnsureSpace(std::size_t size) const;
std::size_t Current;
std::span<std::uint8_t> Buffer;
};
struct DynamicBuffer
{
void Write(std::uint8_t value);
void Write(std::uint16_t value);
void Write(std::uint32_t value);
void Write(std::uint64_t value);
void Write(std::span<std::uint8_t> value);
void Write(std::string_view value);
std::size_t Size() const;
std::vector<std::uint8_t> *Buffer;
};
using BufferType = std::variant<FixedBuffer, DynamicBuffer>;
BufferType mBuffer;
};
// Note(3011): This is the basic CBOR encoder implementation. It will encode just about any // Note(3011): This is the basic CBOR encoder implementation. It will encode just about any
// data into a valid CBOR representation (with the exception of half precision floating point // data into a valid CBOR representation (with the exception of half precision floating point
// numbers). It will also select the optimal storage for data item arguments, with the exception // numbers). It will also select the optimal storage for data item arguments, with the exception
@ -24,7 +89,7 @@ namespace CBOR
class BasicEncoder class BasicEncoder
{ {
public: public:
BasicEncoder(std::span<std::uint8_t> buffer); BasicEncoder(EncoderBuffer buffer);
void Encode(bool value); void Encode(bool value);
void Encode(Special value); void Encode(Special value);
@ -59,10 +124,9 @@ namespace CBOR
void EncodeTag(std::uint64_t value); void EncodeTag(std::uint64_t value);
std::size_t EncodedSize() const; std::size_t Size() const;
private: private:
std::size_t mCurrent; EncoderBuffer mBuffer;
std::span<std::uint8_t> mBuffer;
}; };
} }

View file

@ -5,6 +5,8 @@
#include <cstring> #include <cstring>
#include <format> #include <format>
#include <span>
#include <string_view>
#include <utility> #include <utility>
namespace CBOR namespace CBOR
@ -29,99 +31,262 @@ namespace CBOR
namespace namespace
{ {
std::size_t ArgumentSize(std::size_t value) template <typename... Funcs>
struct Overload: public Funcs...
{ {
if (value <= 23) { using Funcs::operator()...;
return 0; };
std::uint8_t EncodeHeader(MajorType type, ArgumentPosition pos)
{
return std::to_underlying(type) | std::to_underlying(pos);
}
std::uint8_t EncodeHeader(MajorType type, MinorType minor)
{
return std::to_underlying(type) | std::to_underlying(minor);
}
std::uint8_t EncodeHeaderDirect(MajorType type, std::uint8_t value)
{
return std::to_underlying(type) | value;
}
void WriteHeader(EncoderBuffer &buffer, MajorType type, std::uint64_t argument)
{
if (argument <= 23) {
buffer.Write(EncodeHeaderDirect(type, std::uint8_t(argument)));
} }
if (value <= 255) { else if (argument <= 255) {
return 1; buffer.Write(EncodeHeader(type, ArgumentPosition::Next1B));
buffer.Write(std::uint8_t(argument));
} }
else if (value <= 65535) { else if (argument <= 65535) {
return 2; buffer.Write(EncodeHeader(type, ArgumentPosition::Next2B));
buffer.Write(std::uint16_t(argument));
} }
else if (value <= 4294967295) { else if (argument <= 4294967295) {
return 4; buffer.Write(EncodeHeader(type, ArgumentPosition::Next4B));
buffer.Write(std::uint32_t(argument));
} }
else { else {
return 8; buffer.Write(EncodeHeader(type, ArgumentPosition::Next8B));
buffer.Write(std::uint64_t(argument));
} }
} }
std::size_t SpaceLeft(std::span<std::uint8_t> buffer, std::size_t offset)
{
return buffer.size() - offset;
}
void EnsureEnoughSpace(std::span<std::uint8_t> buffer, std::size_t offset,
std::size_t spaceRequired)
{
if (SpaceLeft(buffer, offset) < spaceRequired) {
throw NotEnoughSpace(SpaceLeft(buffer, offset), spaceRequired);
}
}
void Write(std::span<std::uint8_t> &buffer, std::size_t &current, std::uint16_t value)
{
static constexpr std::uint16_t mask = 0x00'FF;
std::uint16_t network = HostToNetwork(value);
buffer[current++] = static_cast<std::uint8_t>((network ) & mask);
buffer[current++] = static_cast<std::uint8_t>((network >> 8) & mask);
}
void Write(std::span<std::uint8_t> &buffer, std::size_t &current, std::uint32_t value)
{
static constexpr std::uint32_t mask = 0x00'00'00'FF;
std::uint32_t network = HostToNetwork(value);
buffer[current++] = static_cast<std::uint8_t>((network ) & mask);
buffer[current++] = static_cast<std::uint8_t>((network >> 8) & mask);
buffer[current++] = static_cast<std::uint8_t>((network >> 16) & mask);
buffer[current++] = static_cast<std::uint8_t>((network >> 24) & mask);
}
void Write(std::span<std::uint8_t> &buffer, std::size_t &current, std::uint64_t value)
{
static constexpr std::uint64_t mask = 0x00'00'00'00'00'00'00'FF;
std::uint64_t network = HostToNetwork(value);
buffer[current++] = static_cast<std::uint8_t>((network ) & mask);
buffer[current++] = static_cast<std::uint8_t>((network >> 8) & mask);
buffer[current++] = static_cast<std::uint8_t>((network >> 16) & mask);
buffer[current++] = static_cast<std::uint8_t>((network >> 24) & mask);
buffer[current++] = static_cast<std::uint8_t>((network >> 32) & mask);
buffer[current++] = static_cast<std::uint8_t>((network >> 40) & mask);
buffer[current++] = static_cast<std::uint8_t>((network >> 48) & mask);
buffer[current++] = static_cast<std::uint8_t>((network >> 56) & mask);
}
} }
BasicEncoder::BasicEncoder(std::span<std::uint8_t> buffer) EncoderBuffer::EncoderBuffer(std::span<std::uint8_t> buffer)
: mCurrent(0), mBuffer(buffer) : mBuffer(FixedBuffer { .Current = 0, .Buffer = buffer, })
{}
EncoderBuffer::EncoderBuffer(std::vector<std::uint8_t> &buffer)
: mBuffer(DynamicBuffer { .Buffer = &buffer })
{}
EncoderBuffer::EncoderBuffer(EncoderBuffer &&other)
: mBuffer(std::exchange(other.mBuffer, FixedBuffer { .Current = 0, .Buffer = {}, }))
{}
void EncoderBuffer::Write(std::uint8_t value)
{
std::visit(Overload {
[value] (FixedBuffer &buffer) { buffer.Write(value); },
[value] (DynamicBuffer &buffer) { buffer.Write(value); },
}, mBuffer);
}
void EncoderBuffer::Write(std::uint16_t value)
{
std::visit(Overload {
[value] (FixedBuffer &buffer) { buffer.Write(value); },
[value] (DynamicBuffer &buffer) { buffer.Write(value); },
}, mBuffer);
}
void EncoderBuffer::Write(std::uint32_t value)
{
std::visit(Overload {
[value] (FixedBuffer &buffer) { buffer.Write(value); },
[value] (DynamicBuffer &buffer) { buffer.Write(value); },
}, mBuffer);
}
void EncoderBuffer::Write(std::uint64_t value)
{
std::visit(Overload {
[value] (FixedBuffer &buffer) { buffer.Write(value); },
[value] (DynamicBuffer &buffer) { buffer.Write(value); },
}, mBuffer);
}
void EncoderBuffer::Write(std::span<std::uint8_t> value)
{
std::visit(Overload {
[value] (FixedBuffer &buffer) { buffer.Write(value); },
[value] (DynamicBuffer &buffer) { buffer.Write(value); },
}, mBuffer);
}
void EncoderBuffer::Write(std::string_view value)
{
std::visit(Overload {
[value] (FixedBuffer &buffer) { buffer.Write(value); },
[value] (DynamicBuffer &buffer) { buffer.Write(value); },
}, mBuffer);
}
std::size_t EncoderBuffer::Size() const
{
return std::visit(Overload {
[] (const FixedBuffer &buffer) { return buffer.Size(); },
[] (const DynamicBuffer &buffer) { return buffer.Size(); },
}, mBuffer);
}
void EncoderBuffer::FixedBuffer::Write(std::uint8_t value)
{
EnsureSpace(1);
Buffer[Current++] = value;
}
void EncoderBuffer::FixedBuffer::Write(std::uint16_t value)
{
EnsureSpace(2);
static constexpr std::uint16_t mask = 0x00'FF;
std::uint16_t network = HostToNetwork(value);
Buffer[Current++] = static_cast<std::uint8_t>((network ) & mask);
Buffer[Current++] = static_cast<std::uint8_t>((network >> 8) & mask);
}
void EncoderBuffer::FixedBuffer::Write(std::uint32_t value)
{
EnsureSpace(4);
static constexpr std::uint32_t mask = 0x00'00'00'FF;
std::uint32_t network = HostToNetwork(value);
Buffer[Current++] = static_cast<std::uint8_t>((network ) & mask);
Buffer[Current++] = static_cast<std::uint8_t>((network >> 8) & mask);
Buffer[Current++] = static_cast<std::uint8_t>((network >> 16) & mask);
Buffer[Current++] = static_cast<std::uint8_t>((network >> 24) & mask);
}
void EncoderBuffer::FixedBuffer::Write(std::uint64_t value)
{
EnsureSpace(8);
static constexpr std::uint64_t mask = 0x00'00'00'00'00'00'00'FF;
std::uint64_t network = HostToNetwork(value);
Buffer[Current++] = static_cast<std::uint8_t>((network ) & mask);
Buffer[Current++] = static_cast<std::uint8_t>((network >> 8) & mask);
Buffer[Current++] = static_cast<std::uint8_t>((network >> 16) & mask);
Buffer[Current++] = static_cast<std::uint8_t>((network >> 24) & mask);
Buffer[Current++] = static_cast<std::uint8_t>((network >> 32) & mask);
Buffer[Current++] = static_cast<std::uint8_t>((network >> 40) & mask);
Buffer[Current++] = static_cast<std::uint8_t>((network >> 48) & mask);
Buffer[Current++] = static_cast<std::uint8_t>((network >> 56) & mask);
}
void EncoderBuffer::FixedBuffer::Write(std::span<std::uint8_t> value)
{
EnsureSpace(value.size());
std::memcpy(Buffer.data() + Current, value.data(), value.size());
Current += value.size();
}
void EncoderBuffer::FixedBuffer::Write(std::string_view value)
{
EnsureSpace(value.size());
std::memcpy(Buffer.data() + Current, value.data(), value.size());
Current += value.size();
}
void EncoderBuffer::FixedBuffer::EnsureSpace(std::size_t size) const
{
std::size_t spaceLeft = Current > Buffer.size() ? 0 : Buffer.size() - Current;
if (size > spaceLeft) {
throw NotEnoughSpace(spaceLeft, size);
}
}
std::size_t EncoderBuffer::FixedBuffer::Size() const
{
return Current;
}
void EncoderBuffer::DynamicBuffer::Write(std::uint8_t value)
{
Buffer->push_back(value);
}
void EncoderBuffer::DynamicBuffer::Write(std::uint16_t value)
{
static constexpr std::uint16_t mask = 0x00'FF;
std::uint16_t network = HostToNetwork(value);
Buffer->push_back(static_cast<std::uint8_t>((network ) & mask));
Buffer->push_back(static_cast<std::uint8_t>((network >> 8) & mask));
}
void EncoderBuffer::DynamicBuffer::Write(std::uint32_t value)
{
static constexpr std::uint32_t mask = 0x00'00'00'FF;
std::uint32_t network = HostToNetwork(value);
Buffer->push_back(static_cast<std::uint8_t>((network ) & mask));
Buffer->push_back(static_cast<std::uint8_t>((network >> 8) & mask));
Buffer->push_back(static_cast<std::uint8_t>((network >> 16) & mask));
Buffer->push_back(static_cast<std::uint8_t>((network >> 24) & mask));
}
void EncoderBuffer::DynamicBuffer::Write(std::uint64_t value)
{
static constexpr std::uint64_t mask = 0x00'00'00'00'00'00'00'FF;
std::uint64_t network = HostToNetwork(value);
Buffer->push_back(static_cast<std::uint8_t>((network ) & mask));
Buffer->push_back(static_cast<std::uint8_t>((network >> 8) & mask));
Buffer->push_back(static_cast<std::uint8_t>((network >> 16) & mask));
Buffer->push_back(static_cast<std::uint8_t>((network >> 24) & mask));
Buffer->push_back(static_cast<std::uint8_t>((network >> 32) & mask));
Buffer->push_back(static_cast<std::uint8_t>((network >> 40) & mask));
Buffer->push_back(static_cast<std::uint8_t>((network >> 48) & mask));
Buffer->push_back(static_cast<std::uint8_t>((network >> 56) & mask));
}
void EncoderBuffer::DynamicBuffer::Write(std::span<std::uint8_t> value)
{
Buffer->append_range(value);
}
void EncoderBuffer::DynamicBuffer::Write(std::string_view value)
{
Buffer->append_range(value);
}
std::size_t EncoderBuffer::DynamicBuffer::Size() const
{
return Buffer->size();
}
BasicEncoder::BasicEncoder(EncoderBuffer buffer)
: mBuffer(std::move(buffer))
{} {}
void BasicEncoder::Encode(bool value) void BasicEncoder::Encode(bool value)
{ {
EnsureEnoughSpace(mBuffer, mCurrent, 1);
if (value) { if (value) {
mBuffer[mCurrent++] = std::to_underlying(MajorType::Other) mBuffer.Write(EncodeHeader(MajorType::Other, MinorType::True));
| std::to_underlying(MinorType::True);
} }
else { else {
mBuffer[mCurrent++] = std::to_underlying(MajorType::Other) mBuffer.Write(EncodeHeader(MajorType::Other, MinorType::False));
| std::to_underlying(MinorType::False);
} }
} }
void BasicEncoder::Encode(Special value) void BasicEncoder::Encode(Special value)
{ {
EnsureEnoughSpace(mBuffer, mCurrent, 1);
switch (value) { switch (value) {
case Special::Null: case Special::Null:
mBuffer[mCurrent++] = std::to_underlying(MajorType::Other) mBuffer.Write(EncodeHeader(MajorType::Other, MinorType::Null));
| std::to_underlying(MinorType::Null);
break; break;
case Special::Undefined: case Special::Undefined:
mBuffer[mCurrent++] = std::to_underlying(MajorType::Other) mBuffer.Write(EncodeHeader(MajorType::Other, MinorType::Undefined));
| std::to_underlying(MinorType::Undefined);
break; break;
default: default:
throw UnknownValue(); throw UnknownValue();
@ -132,27 +297,21 @@ namespace CBOR
{ {
if (value >= 0) { if (value >= 0) {
if (value <= 23) { if (value <= 23) {
EnsureEnoughSpace(mBuffer, mCurrent, 1); mBuffer.Write(EncodeHeaderDirect(MajorType::Unsigned, std::uint8_t(value)));
mBuffer[mCurrent++] = static_cast<std::uint8_t>(std::to_underlying(MajorType::Unsigned) | value);
} }
else { else {
EnsureEnoughSpace(mBuffer, mCurrent, 2); mBuffer.Write(EncodeHeader(MajorType::Unsigned, ArgumentPosition::Next1B));
mBuffer[mCurrent++] = std::to_underlying(MajorType::Unsigned) mBuffer.Write(static_cast<std::uint8_t>(value));
| std::to_underlying(ArgumentPosition::Next1B);
mBuffer[mCurrent++] = static_cast<std::uint8_t>(value);
} }
} }
else { else {
std::int8_t actual = -(value + 1); std::int8_t actual = -(value + 1);
if (actual <= 23) { if (actual <= 23) {
EnsureEnoughSpace(mBuffer, mCurrent, 1); mBuffer.Write(EncodeHeaderDirect(MajorType::Negative, std::uint8_t(actual)));
mBuffer[mCurrent++] = static_cast<std::uint8_t>(std::to_underlying(MajorType::Negative) | actual);
} }
else { else {
EnsureEnoughSpace(mBuffer, mCurrent, 2); mBuffer.Write(EncodeHeader(MajorType::Negative, ArgumentPosition::Next1B));
mBuffer[mCurrent++] = std::to_underlying(MajorType::Negative) mBuffer.Write(static_cast<std::uint8_t>(actual));
| std::to_underlying(ArgumentPosition::Next1B);
mBuffer[mCurrent++] = static_cast<std::uint8_t>(actual);
} }
} }
} }
@ -167,23 +326,17 @@ namespace CBOR
} }
else if (value >= -256 && value <= -1) { else if (value >= -256 && value <= -1) {
std::uint8_t actual = static_cast<std::uint8_t>(-(value + 1)); std::uint8_t actual = static_cast<std::uint8_t>(-(value + 1));
EnsureEnoughSpace(mBuffer, mCurrent, 2); mBuffer.Write(EncodeHeader(MajorType::Negative, ArgumentPosition::Next1B));
mBuffer[mCurrent++] = std::to_underlying(MajorType::Negative) mBuffer.Write(actual);
| std::to_underlying(ArgumentPosition::Next1B);
mBuffer[mCurrent++] = actual;
} }
else if (value >= 0) { else if (value >= 0) {
EnsureEnoughSpace(mBuffer, mCurrent, 3); mBuffer.Write(EncodeHeader(MajorType::Unsigned, ArgumentPosition::Next2B));
mBuffer[mCurrent++] = std::to_underlying(MajorType::Unsigned) mBuffer.Write(static_cast<std::uint16_t>(value));
| std::to_underlying(ArgumentPosition::Next2B);
Write(mBuffer, mCurrent, static_cast<std::uint16_t>(value));
} }
else { else {
EnsureEnoughSpace(mBuffer, mCurrent, 3);
std::int16_t actual = -(value + 1); std::int16_t actual = -(value + 1);
mBuffer[mCurrent++] = std::to_underlying(MajorType::Negative) mBuffer.Write(EncodeHeader(MajorType::Negative, ArgumentPosition::Next2B));
| std::to_underlying(ArgumentPosition::Next2B); mBuffer.Write(static_cast<std::uint16_t>(actual));
Write(mBuffer, mCurrent, static_cast<std::uint16_t>(actual));
} }
} }
@ -197,21 +350,16 @@ namespace CBOR
} }
else if (value >= -65536 && value <= -1) { else if (value >= -65536 && value <= -1) {
std::uint16_t actual = static_cast<std::uint16_t>(std::abs(value + 1)); std::uint16_t actual = static_cast<std::uint16_t>(std::abs(value + 1));
EnsureEnoughSpace(mBuffer, mCurrent, 3); mBuffer.Write(actual);
Write(mBuffer, mCurrent, actual);
} }
else if (value >= 0) { else if (value >= 0) {
EnsureEnoughSpace(mBuffer, mCurrent, 5); mBuffer.Write(EncodeHeader(MajorType::Unsigned, ArgumentPosition::Next4B));
mBuffer[mCurrent++] = std::to_underlying(MajorType::Unsigned) mBuffer.Write(static_cast<std::uint32_t>(value));
| std::to_underlying(ArgumentPosition::Next4B);
Write(mBuffer, mCurrent, static_cast<std::uint32_t>(value));
} }
else { else {
EnsureEnoughSpace(mBuffer, mCurrent, 5);
std::int32_t actual = std::abs(value + 1); std::int32_t actual = std::abs(value + 1);
mBuffer[mCurrent++] = std::to_underlying(MajorType::Negative) mBuffer.Write(EncodeHeader(MajorType::Negative, ArgumentPosition::Next4B));
| std::to_underlying(ArgumentPosition::Next4B); mBuffer.Write(static_cast<std::uint32_t>(actual));
Write(mBuffer, mCurrent, static_cast<std::uint32_t>(actual));
} }
} }
@ -225,35 +373,28 @@ namespace CBOR
} }
else if (value >= -2147483648 && value <= -1) { else if (value >= -2147483648 && value <= -1) {
std::uint32_t actual = static_cast<std::uint32_t>(std::abs(value + 1)); std::uint32_t actual = static_cast<std::uint32_t>(std::abs(value + 1));
EnsureEnoughSpace(mBuffer, mCurrent, 5); mBuffer.Write(EncodeHeader(MajorType::Negative, ArgumentPosition::Next4B));
Write(mBuffer, mCurrent, actual); mBuffer.Write(actual);
} }
else if (value >= 0) { else if (value >= 0) {
EnsureEnoughSpace(mBuffer, mCurrent, 9); mBuffer.Write(EncodeHeader(MajorType::Unsigned, ArgumentPosition::Next8B));
mBuffer[mCurrent++] = std::to_underlying(MajorType::Unsigned) mBuffer.Write(static_cast<std::uint64_t>(value));
| std::to_underlying(ArgumentPosition::Next8B);
Write(mBuffer, mCurrent, static_cast<std::uint64_t>(value));
} }
else { else {
EnsureEnoughSpace(mBuffer, mCurrent, 9);
std::int64_t actual = std::abs(value + 1); std::int64_t actual = std::abs(value + 1);
mBuffer[mCurrent++] = std::to_underlying(MajorType::Negative) mBuffer.Write(EncodeHeader(MajorType::Negative, ArgumentPosition::Next8B));
| std::to_underlying(ArgumentPosition::Next8B); mBuffer.Write(static_cast<std::uint64_t>(actual));
Write(mBuffer, mCurrent, static_cast<std::uint64_t>(actual));
} }
} }
void BasicEncoder::Encode(std::uint8_t value) void BasicEncoder::Encode(std::uint8_t value)
{ {
if (value <= 23) { if (value <= 23) {
EnsureEnoughSpace(mBuffer, mCurrent, 1); mBuffer.Write(EncodeHeaderDirect(MajorType::Unsigned, value));
mBuffer[mCurrent++] = std::to_underlying(MajorType::Unsigned) | value;
} }
else { else {
EnsureEnoughSpace(mBuffer, mCurrent, 2); mBuffer.Write(EncodeHeader(MajorType::Unsigned, ArgumentPosition::Next1B));
mBuffer[mCurrent++] = std::to_underlying(MajorType::Unsigned) mBuffer.Write(value);
| std::to_underlying(ArgumentPosition::Next1B);
mBuffer[mCurrent++] = value;
} }
} }
@ -263,10 +404,8 @@ namespace CBOR
Encode(static_cast<std::uint8_t>(value)); Encode(static_cast<std::uint8_t>(value));
} }
else { else {
EnsureEnoughSpace(mBuffer, mCurrent, 3); mBuffer.Write(EncodeHeader(MajorType::Unsigned, ArgumentPosition::Next2B));
mBuffer[mCurrent++] = std::to_underlying(MajorType::Unsigned) mBuffer.Write(value);
| std::to_underlying(ArgumentPosition::Next2B);
Write(mBuffer, mCurrent, value);
} }
} }
@ -276,10 +415,8 @@ namespace CBOR
Encode(static_cast<std::uint16_t>(value)); Encode(static_cast<std::uint16_t>(value));
} }
else { else {
EnsureEnoughSpace(mBuffer, mCurrent, 5); mBuffer.Write(EncodeHeader(MajorType::Unsigned, ArgumentPosition::Next4B));
mBuffer[mCurrent++] = std::to_underlying(MajorType::Unsigned) mBuffer.Write(value);
| std::to_underlying(ArgumentPosition::Next4B);
Write(mBuffer, mCurrent, value);
} }
} }
@ -289,10 +426,8 @@ namespace CBOR
Encode(static_cast<std::uint32_t>(value)); Encode(static_cast<std::uint32_t>(value));
} }
else { else {
EnsureEnoughSpace(mBuffer, mCurrent, 9); mBuffer.Write(EncodeHeader(MajorType::Unsigned, ArgumentPosition::Next8B));
mBuffer[mCurrent++] = std::to_underlying(MajorType::Unsigned) mBuffer.Write(value);
| std::to_underlying(ArgumentPosition::Next8B);
Write(mBuffer, mCurrent, value);
} }
} }
@ -300,51 +435,22 @@ namespace CBOR
{ {
// Note(3011): This is suboptimal, but dealing with IEEE 754 numbers correctly // Note(3011): This is suboptimal, but dealing with IEEE 754 numbers correctly
// is difficult, and has been left for later. // is difficult, and has been left for later.
EnsureEnoughSpace(mBuffer, mCurrent, 5); mBuffer.Write(EncodeHeader(MajorType::Other, MinorType::Float));
mBuffer[mCurrent++] = std::to_underlying(MajorType::Other) mBuffer.Write(std::bit_cast<std::uint32_t>(value));
| std::to_underlying(MinorType::Float);
Write(mBuffer, mCurrent, std::bit_cast<std::uint32_t>(value));
} }
void BasicEncoder::Encode(double value) void BasicEncoder::Encode(double value)
{ {
// Note(3011): This is suboptimal, but dealing with IEEE 754 numbers correctly // Note(3011): This is suboptimal, but dealing with IEEE 754 numbers correctly
// is difficult, and has been left for later. // is difficult, and has been left for later.
EnsureEnoughSpace(mBuffer, mCurrent, 9); mBuffer.Write(EncodeHeader(MajorType::Other, MinorType::Double));
mBuffer[mCurrent++] = std::to_underlying(MajorType::Other) mBuffer.Write(std::bit_cast<std::uint64_t>(value));
| std::to_underlying(MinorType::Double);
Write(mBuffer, mCurrent, std::bit_cast<std::uint64_t>(value));
} }
void BasicEncoder::Encode(std::span<std::uint8_t> value) void BasicEncoder::Encode(std::span<std::uint8_t> value)
{ {
EnsureEnoughSpace(mBuffer, mCurrent, 1 + ArgumentSize(value.size()) + value.size()); WriteHeader(mBuffer, MajorType::Binary, value.size());
if (value.size() <= 23) { mBuffer.Write(value);
mBuffer[mCurrent++] = std::to_underlying(MajorType::Binary)
| static_cast<std::uint8_t>(value.size());
}
else if (value.size() <= 255) {
mBuffer[mCurrent++] = std::to_underlying(MajorType::Binary)
| std::to_underlying(ArgumentPosition::Next1B);
mBuffer[mCurrent++] = static_cast<std::uint8_t>(value.size());
}
else if (value.size() <= 65535) {
mBuffer[mCurrent++] = std::to_underlying(MajorType::Binary)
| std::to_underlying(ArgumentPosition::Next2B);
Write(mBuffer, mCurrent, static_cast<std::uint16_t>(value.size()));
}
else if (value.size() <= 4294967295) {
mBuffer[mCurrent++] = std::to_underlying(MajorType::Binary)
| std::to_underlying(ArgumentPosition::Next4B);
Write(mBuffer, mCurrent, static_cast<std::uint32_t>(value.size()));
}
else {
mBuffer[mCurrent++] = std::to_underlying(MajorType::Binary)
| std::to_underlying(ArgumentPosition::Next8B);
Write(mBuffer, mCurrent, static_cast<std::uint64_t>(value.size()));
}
std::memcpy(mBuffer.data() + mCurrent, value.data(), value.size());
mCurrent += value.size();
} }
void BasicEncoder::Encode(const char *value) void BasicEncoder::Encode(const char *value)
@ -354,159 +460,52 @@ namespace CBOR
void BasicEncoder::Encode(std::string_view value) void BasicEncoder::Encode(std::string_view value)
{ {
EnsureEnoughSpace(mBuffer, mCurrent, 1 + ArgumentSize(value.size()) + value.size()); WriteHeader(mBuffer, MajorType::String, value.size());
if (value.size() <= 23) { mBuffer.Write(value);
mBuffer[mCurrent++] = std::to_underlying(MajorType::String)
| static_cast<std::uint8_t>(value.size());
}
else if (value.size() <= 255) {
mBuffer[mCurrent++] = std::to_underlying(MajorType::String)
| std::to_underlying(ArgumentPosition::Next1B);
mBuffer[mCurrent++] = static_cast<std::uint8_t>(value.size());
}
else if (value.size() <= 65535) {
mBuffer[mCurrent++] = std::to_underlying(MajorType::String)
| std::to_underlying(ArgumentPosition::Next2B);
Write(mBuffer, mCurrent, static_cast<std::uint16_t>(value.size()));
}
else if (value.size() <= 4294967295) {
mBuffer[mCurrent++] = std::to_underlying(MajorType::String)
| std::to_underlying(ArgumentPosition::Next4B);
Write(mBuffer, mCurrent, static_cast<std::uint32_t>(value.size()));
}
else {
mBuffer[mCurrent++] = std::to_underlying(MajorType::String)
| std::to_underlying(ArgumentPosition::Next8B);
Write(mBuffer, mCurrent, static_cast<std::uint64_t>(value.size()));
}
std::memcpy(mBuffer.data() + mCurrent, value.data(), value.size());
mCurrent += value.size();
} }
void BasicEncoder::BeginArray(std::size_t size) void BasicEncoder::BeginArray(std::size_t size)
{ {
EnsureEnoughSpace(mBuffer, mCurrent, 1 + ArgumentSize(size)); WriteHeader(mBuffer, MajorType::Array, size);
if (size <= 23) {
mBuffer[mCurrent++] = std::to_underlying(MajorType::Array)
| static_cast<std::uint8_t>(size);
}
else if (size <= 255) {
mBuffer[mCurrent++] = std::to_underlying(MajorType::Array)
| std::to_underlying(ArgumentPosition::Next1B);
mBuffer[mCurrent++] = static_cast<std::uint8_t>(size);
}
else if (size <= 65535) {
mBuffer[mCurrent++] = std::to_underlying(MajorType::Array)
| std::to_underlying(ArgumentPosition::Next2B);
Write(mBuffer, mCurrent, static_cast<std::uint16_t>(size));
}
else if (size <= 4294967295) {
mBuffer[mCurrent++] = std::to_underlying(MajorType::Array)
| std::to_underlying(ArgumentPosition::Next4B);
Write(mBuffer, mCurrent, static_cast<std::uint32_t>(size));
}
else {
mBuffer[mCurrent++] = std::to_underlying(MajorType::Array)
| std::to_underlying(ArgumentPosition::Next8B);
Write(mBuffer, mCurrent, static_cast<std::uint64_t>(size));
}
} }
void BasicEncoder::BeginMap(std::size_t size) void BasicEncoder::BeginMap(std::size_t size)
{ {
EnsureEnoughSpace(mBuffer, mCurrent, 1 + ArgumentSize(size)); WriteHeader(mBuffer, MajorType::Map, size);
if (size <= 23) {
mBuffer[mCurrent++] = std::to_underlying(MajorType::Map)
| static_cast<std::uint8_t>(size);
}
else if (size <= 255) {
mBuffer[mCurrent++] = std::to_underlying(MajorType::Map)
| std::to_underlying(ArgumentPosition::Next1B);
mBuffer[mCurrent++] = static_cast<std::uint8_t>(size);
}
else if (size <= 65535) {
mBuffer[mCurrent++] = std::to_underlying(MajorType::Map)
| std::to_underlying(ArgumentPosition::Next2B);
Write(mBuffer, mCurrent, static_cast<std::uint16_t>(size));
}
else if (size <= 4294967295) {
mBuffer[mCurrent++] = std::to_underlying(MajorType::Map)
| std::to_underlying(ArgumentPosition::Next4B);
Write(mBuffer, mCurrent, static_cast<std::uint32_t>(size));
}
else {
mBuffer[mCurrent++] = std::to_underlying(MajorType::Map)
| std::to_underlying(ArgumentPosition::Next8B);
Write(mBuffer, mCurrent, static_cast<std::uint64_t>(size));
}
} }
void BasicEncoder::BeginIndefiniteBinary() void BasicEncoder::BeginIndefiniteBinary()
{ {
EnsureEnoughSpace(mBuffer, mCurrent, 1); mBuffer.Write(EncodeHeader(MajorType::Binary, ArgumentPosition::Indefinite));
mBuffer[mCurrent++] = std::to_underlying(MajorType::Binary)
| std::to_underlying(ArgumentPosition::Indefinite);
} }
void BasicEncoder::BeginIndefiniteString() void BasicEncoder::BeginIndefiniteString()
{ {
EnsureEnoughSpace(mBuffer, mCurrent, 1); mBuffer.Write(EncodeHeader(MajorType::String, ArgumentPosition::Indefinite));
mBuffer[mCurrent++] = std::to_underlying(MajorType::String)
| std::to_underlying(ArgumentPosition::Indefinite);
} }
void BasicEncoder::BeginIndefiniteArray() void BasicEncoder::BeginIndefiniteArray()
{ {
EnsureEnoughSpace(mBuffer, mCurrent, 1); mBuffer.Write(EncodeHeader(MajorType::Array, ArgumentPosition::Indefinite));
mBuffer[mCurrent++] = std::to_underlying(MajorType::Array)
| std::to_underlying(ArgumentPosition::Indefinite);
} }
void BasicEncoder::BeginIndefiniteMap() void BasicEncoder::BeginIndefiniteMap()
{ {
EnsureEnoughSpace(mBuffer, mCurrent, 1); mBuffer.Write(EncodeHeader(MajorType::Map, ArgumentPosition::Indefinite));
mBuffer[mCurrent++] = std::to_underlying(MajorType::Map)
| std::to_underlying(ArgumentPosition::Indefinite);
} }
void BasicEncoder::End() void BasicEncoder::End()
{ {
EnsureEnoughSpace(mBuffer, mCurrent, 1); mBuffer.Write(EncodeHeader(MajorType::Other, MinorType::Break));
mBuffer[mCurrent++] = std::to_underlying(MajorType::Other)
| std::to_underlying(MinorType::Break);
} }
void BasicEncoder::EncodeTag(std::uint64_t value) void BasicEncoder::EncodeTag(std::uint64_t value)
{ {
EnsureEnoughSpace(mBuffer, mCurrent, 1 + ArgumentSize(value)); WriteHeader(mBuffer, MajorType::Tag, value);
if (value <= 23) {
mBuffer[mCurrent++] = std::to_underlying(MajorType::Tag)
| static_cast<std::uint8_t>(value);
}
else if (value <= 255) {
mBuffer[mCurrent++] = std::to_underlying(MajorType::Tag)
| std::to_underlying(ArgumentPosition::Next1B);
mBuffer[mCurrent++] = static_cast<std::uint8_t>(value);
}
else if (value <= 65535) {
mBuffer[mCurrent++] = std::to_underlying(MajorType::Tag)
| std::to_underlying(ArgumentPosition::Next2B);
Write(mBuffer, mCurrent, static_cast<std::uint16_t>(value));
}
else if (value <= 4294967295) {
mBuffer[mCurrent++] = std::to_underlying(MajorType::Tag)
| std::to_underlying(ArgumentPosition::Next4B);
Write(mBuffer, mCurrent, static_cast<std::uint32_t>(value));
}
else {
mBuffer[mCurrent++] = std::to_underlying(MajorType::Tag)
| std::to_underlying(ArgumentPosition::Next8B);
Write(mBuffer, mCurrent, static_cast<std::uint64_t>(value));
}
} }
std::size_t BasicEncoder::EncodedSize() const std::size_t BasicEncoder::Size() const
{ {
return mBuffer.size() - (mBuffer.size() - mCurrent); return mBuffer.Size();
} }
} }

View file

@ -18,7 +18,7 @@ struct SomeStruct
std::vector<std::string> tools; std::vector<std::string> tools;
}; };
std::size_t Encode(const SomeStruct &value, std::span<std::uint8_t> buffer) std::size_t Encode(const SomeStruct &value, auto &buffer)
{ {
CBOR::BasicEncoder enc(buffer); CBOR::BasicEncoder enc(buffer);
enc.EncodeTag(15'000); enc.EncodeTag(15'000);
@ -50,7 +50,7 @@ std::size_t Encode(const SomeStruct &value, std::span<std::uint8_t> buffer)
} }
enc.End(); enc.End();
return enc.EncodedSize(); return enc.Size();
} }
SomeStruct Decode1(std::span<std::uint8_t> buffer) SomeStruct Decode1(std::span<std::uint8_t> buffer)
@ -174,7 +174,8 @@ int main()
{ {
using namespace std::string_view_literals; using namespace std::string_view_literals;
std::array<std::uint8_t, 1024> buffer {}; //std::array<std::uint8_t, 1024> buffer {};
std::vector<std::uint8_t> buffer;
SomeStruct expected { SomeStruct expected {
.name = "Player1", .name = "Player1",
@ -196,6 +197,12 @@ int main()
std::size_t encodedSize = Encode(expected, buffer); std::size_t encodedSize = Encode(expected, buffer);
std::println("Encoded size: {}", encodedSize); std::println("Encoded size: {}", encodedSize);
std::print("Encoded hex: ");
for (std::size_t i = 0; i < encodedSize; ++i) {
std::print("{:02X} ", buffer[i]);
}
std::println();
SomeStruct result1 = Decode1(std::span<std::uint8_t>(buffer.data(), encodedSize)); SomeStruct result1 = Decode1(std::span<std::uint8_t>(buffer.data(), encodedSize));
SomeStruct result2 = Decode2(std::span<std::uint8_t>(buffer.data(), encodedSize)); SomeStruct result2 = Decode2(std::span<std::uint8_t>(buffer.data(), encodedSize));