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 <array>
#include <cstdint>
#include <span>
#include <string_view>
#include <variant>
#include <vector>
namespace CBOR
{
@ -15,6 +18,68 @@ namespace CBOR
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
// 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
@ -24,7 +89,7 @@ namespace CBOR
class BasicEncoder
{
public:
BasicEncoder(std::span<std::uint8_t> buffer);
BasicEncoder(EncoderBuffer buffer);
void Encode(bool value);
void Encode(Special value);
@ -59,10 +124,9 @@ namespace CBOR
void EncodeTag(std::uint64_t value);
std::size_t EncodedSize() const;
std::size_t Size() const;
private:
std::size_t mCurrent;
std::span<std::uint8_t> mBuffer;
EncoderBuffer mBuffer;
};
}

View file

@ -5,6 +5,8 @@
#include <cstring>
#include <format>
#include <span>
#include <string_view>
#include <utility>
namespace CBOR
@ -29,99 +31,262 @@ namespace CBOR
namespace
{
std::size_t ArgumentSize(std::size_t value)
template <typename... Funcs>
struct Overload: public Funcs...
{
if (value <= 23) {
return 0;
using Funcs::operator()...;
};
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) {
return 1;
else if (argument <= 255) {
buffer.Write(EncodeHeader(type, ArgumentPosition::Next1B));
buffer.Write(std::uint8_t(argument));
}
else if (value <= 65535) {
return 2;
else if (argument <= 65535) {
buffer.Write(EncodeHeader(type, ArgumentPosition::Next2B));
buffer.Write(std::uint16_t(argument));
}
else if (value <= 4294967295) {
return 4;
else if (argument <= 4294967295) {
buffer.Write(EncodeHeader(type, ArgumentPosition::Next4B));
buffer.Write(std::uint32_t(argument));
}
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)
: mCurrent(0), mBuffer(buffer)
EncoderBuffer::EncoderBuffer(std::span<std::uint8_t> 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)
{
EnsureEnoughSpace(mBuffer, mCurrent, 1);
if (value) {
mBuffer[mCurrent++] = std::to_underlying(MajorType::Other)
| std::to_underlying(MinorType::True);
mBuffer.Write(EncodeHeader(MajorType::Other, MinorType::True));
}
else {
mBuffer[mCurrent++] = std::to_underlying(MajorType::Other)
| std::to_underlying(MinorType::False);
mBuffer.Write(EncodeHeader(MajorType::Other, MinorType::False));
}
}
void BasicEncoder::Encode(Special value)
{
EnsureEnoughSpace(mBuffer, mCurrent, 1);
switch (value) {
case Special::Null:
mBuffer[mCurrent++] = std::to_underlying(MajorType::Other)
| std::to_underlying(MinorType::Null);
mBuffer.Write(EncodeHeader(MajorType::Other, MinorType::Null));
break;
case Special::Undefined:
mBuffer[mCurrent++] = std::to_underlying(MajorType::Other)
| std::to_underlying(MinorType::Undefined);
mBuffer.Write(EncodeHeader(MajorType::Other, MinorType::Undefined));
break;
default:
throw UnknownValue();
@ -132,27 +297,21 @@ namespace CBOR
{
if (value >= 0) {
if (value <= 23) {
EnsureEnoughSpace(mBuffer, mCurrent, 1);
mBuffer[mCurrent++] = static_cast<std::uint8_t>(std::to_underlying(MajorType::Unsigned) | value);
mBuffer.Write(EncodeHeaderDirect(MajorType::Unsigned, std::uint8_t(value)));
}
else {
EnsureEnoughSpace(mBuffer, mCurrent, 2);
mBuffer[mCurrent++] = std::to_underlying(MajorType::Unsigned)
| std::to_underlying(ArgumentPosition::Next1B);
mBuffer[mCurrent++] = static_cast<std::uint8_t>(value);
mBuffer.Write(EncodeHeader(MajorType::Unsigned, ArgumentPosition::Next1B));
mBuffer.Write(static_cast<std::uint8_t>(value));
}
}
else {
std::int8_t actual = -(value + 1);
if (actual <= 23) {
EnsureEnoughSpace(mBuffer, mCurrent, 1);
mBuffer[mCurrent++] = static_cast<std::uint8_t>(std::to_underlying(MajorType::Negative) | actual);
mBuffer.Write(EncodeHeaderDirect(MajorType::Negative, std::uint8_t(actual)));
}
else {
EnsureEnoughSpace(mBuffer, mCurrent, 2);
mBuffer[mCurrent++] = std::to_underlying(MajorType::Negative)
| std::to_underlying(ArgumentPosition::Next1B);
mBuffer[mCurrent++] = static_cast<std::uint8_t>(actual);
mBuffer.Write(EncodeHeader(MajorType::Negative, ArgumentPosition::Next1B));
mBuffer.Write(static_cast<std::uint8_t>(actual));
}
}
}
@ -167,23 +326,17 @@ namespace CBOR
}
else if (value >= -256 && value <= -1) {
std::uint8_t actual = static_cast<std::uint8_t>(-(value + 1));
EnsureEnoughSpace(mBuffer, mCurrent, 2);
mBuffer[mCurrent++] = std::to_underlying(MajorType::Negative)
| std::to_underlying(ArgumentPosition::Next1B);
mBuffer[mCurrent++] = actual;
mBuffer.Write(EncodeHeader(MajorType::Negative, ArgumentPosition::Next1B));
mBuffer.Write(actual);
}
else if (value >= 0) {
EnsureEnoughSpace(mBuffer, mCurrent, 3);
mBuffer[mCurrent++] = std::to_underlying(MajorType::Unsigned)
| std::to_underlying(ArgumentPosition::Next2B);
Write(mBuffer, mCurrent, static_cast<std::uint16_t>(value));
mBuffer.Write(EncodeHeader(MajorType::Unsigned, ArgumentPosition::Next2B));
mBuffer.Write(static_cast<std::uint16_t>(value));
}
else {
EnsureEnoughSpace(mBuffer, mCurrent, 3);
std::int16_t actual = -(value + 1);
mBuffer[mCurrent++] = std::to_underlying(MajorType::Negative)
| std::to_underlying(ArgumentPosition::Next2B);
Write(mBuffer, mCurrent, static_cast<std::uint16_t>(actual));
mBuffer.Write(EncodeHeader(MajorType::Negative, ArgumentPosition::Next2B));
mBuffer.Write(static_cast<std::uint16_t>(actual));
}
}
@ -197,21 +350,16 @@ namespace CBOR
}
else if (value >= -65536 && value <= -1) {
std::uint16_t actual = static_cast<std::uint16_t>(std::abs(value + 1));
EnsureEnoughSpace(mBuffer, mCurrent, 3);
Write(mBuffer, mCurrent, actual);
mBuffer.Write(actual);
}
else if (value >= 0) {
EnsureEnoughSpace(mBuffer, mCurrent, 5);
mBuffer[mCurrent++] = std::to_underlying(MajorType::Unsigned)
| std::to_underlying(ArgumentPosition::Next4B);
Write(mBuffer, mCurrent, static_cast<std::uint32_t>(value));
mBuffer.Write(EncodeHeader(MajorType::Unsigned, ArgumentPosition::Next4B));
mBuffer.Write(static_cast<std::uint32_t>(value));
}
else {
EnsureEnoughSpace(mBuffer, mCurrent, 5);
std::int32_t actual = std::abs(value + 1);
mBuffer[mCurrent++] = std::to_underlying(MajorType::Negative)
| std::to_underlying(ArgumentPosition::Next4B);
Write(mBuffer, mCurrent, static_cast<std::uint32_t>(actual));
mBuffer.Write(EncodeHeader(MajorType::Negative, ArgumentPosition::Next4B));
mBuffer.Write(static_cast<std::uint32_t>(actual));
}
}
@ -225,35 +373,28 @@ namespace CBOR
}
else if (value >= -2147483648 && value <= -1) {
std::uint32_t actual = static_cast<std::uint32_t>(std::abs(value + 1));
EnsureEnoughSpace(mBuffer, mCurrent, 5);
Write(mBuffer, mCurrent, actual);
mBuffer.Write(EncodeHeader(MajorType::Negative, ArgumentPosition::Next4B));
mBuffer.Write(actual);
}
else if (value >= 0) {
EnsureEnoughSpace(mBuffer, mCurrent, 9);
mBuffer[mCurrent++] = std::to_underlying(MajorType::Unsigned)
| std::to_underlying(ArgumentPosition::Next8B);
Write(mBuffer, mCurrent, static_cast<std::uint64_t>(value));
mBuffer.Write(EncodeHeader(MajorType::Unsigned, ArgumentPosition::Next8B));
mBuffer.Write(static_cast<std::uint64_t>(value));
}
else {
EnsureEnoughSpace(mBuffer, mCurrent, 9);
std::int64_t actual = std::abs(value + 1);
mBuffer[mCurrent++] = std::to_underlying(MajorType::Negative)
| std::to_underlying(ArgumentPosition::Next8B);
Write(mBuffer, mCurrent, static_cast<std::uint64_t>(actual));
mBuffer.Write(EncodeHeader(MajorType::Negative, ArgumentPosition::Next8B));
mBuffer.Write(static_cast<std::uint64_t>(actual));
}
}
void BasicEncoder::Encode(std::uint8_t value)
{
if (value <= 23) {
EnsureEnoughSpace(mBuffer, mCurrent, 1);
mBuffer[mCurrent++] = std::to_underlying(MajorType::Unsigned) | value;
mBuffer.Write(EncodeHeaderDirect(MajorType::Unsigned, value));
}
else {
EnsureEnoughSpace(mBuffer, mCurrent, 2);
mBuffer[mCurrent++] = std::to_underlying(MajorType::Unsigned)
| std::to_underlying(ArgumentPosition::Next1B);
mBuffer[mCurrent++] = value;
mBuffer.Write(EncodeHeader(MajorType::Unsigned, ArgumentPosition::Next1B));
mBuffer.Write(value);
}
}
@ -263,10 +404,8 @@ namespace CBOR
Encode(static_cast<std::uint8_t>(value));
}
else {
EnsureEnoughSpace(mBuffer, mCurrent, 3);
mBuffer[mCurrent++] = std::to_underlying(MajorType::Unsigned)
| std::to_underlying(ArgumentPosition::Next2B);
Write(mBuffer, mCurrent, value);
mBuffer.Write(EncodeHeader(MajorType::Unsigned, ArgumentPosition::Next2B));
mBuffer.Write(value);
}
}
@ -276,10 +415,8 @@ namespace CBOR
Encode(static_cast<std::uint16_t>(value));
}
else {
EnsureEnoughSpace(mBuffer, mCurrent, 5);
mBuffer[mCurrent++] = std::to_underlying(MajorType::Unsigned)
| std::to_underlying(ArgumentPosition::Next4B);
Write(mBuffer, mCurrent, value);
mBuffer.Write(EncodeHeader(MajorType::Unsigned, ArgumentPosition::Next4B));
mBuffer.Write(value);
}
}
@ -289,10 +426,8 @@ namespace CBOR
Encode(static_cast<std::uint32_t>(value));
}
else {
EnsureEnoughSpace(mBuffer, mCurrent, 9);
mBuffer[mCurrent++] = std::to_underlying(MajorType::Unsigned)
| std::to_underlying(ArgumentPosition::Next8B);
Write(mBuffer, mCurrent, value);
mBuffer.Write(EncodeHeader(MajorType::Unsigned, ArgumentPosition::Next8B));
mBuffer.Write(value);
}
}
@ -300,51 +435,22 @@ namespace CBOR
{
// Note(3011): This is suboptimal, but dealing with IEEE 754 numbers correctly
// is difficult, and has been left for later.
EnsureEnoughSpace(mBuffer, mCurrent, 5);
mBuffer[mCurrent++] = std::to_underlying(MajorType::Other)
| std::to_underlying(MinorType::Float);
Write(mBuffer, mCurrent, std::bit_cast<std::uint32_t>(value));
mBuffer.Write(EncodeHeader(MajorType::Other, MinorType::Float));
mBuffer.Write(std::bit_cast<std::uint32_t>(value));
}
void BasicEncoder::Encode(double value)
{
// Note(3011): This is suboptimal, but dealing with IEEE 754 numbers correctly
// is difficult, and has been left for later.
EnsureEnoughSpace(mBuffer, mCurrent, 9);
mBuffer[mCurrent++] = std::to_underlying(MajorType::Other)
| std::to_underlying(MinorType::Double);
Write(mBuffer, mCurrent, std::bit_cast<std::uint64_t>(value));
mBuffer.Write(EncodeHeader(MajorType::Other, MinorType::Double));
mBuffer.Write(std::bit_cast<std::uint64_t>(value));
}
void BasicEncoder::Encode(std::span<std::uint8_t> value)
{
EnsureEnoughSpace(mBuffer, mCurrent, 1 + ArgumentSize(value.size()) + value.size());
if (value.size() <= 23) {
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();
WriteHeader(mBuffer, MajorType::Binary, value.size());
mBuffer.Write(value);
}
void BasicEncoder::Encode(const char *value)
@ -354,159 +460,52 @@ namespace CBOR
void BasicEncoder::Encode(std::string_view value)
{
EnsureEnoughSpace(mBuffer, mCurrent, 1 + ArgumentSize(value.size()) + value.size());
if (value.size() <= 23) {
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();
WriteHeader(mBuffer, MajorType::String, value.size());
mBuffer.Write(value);
}
void BasicEncoder::BeginArray(std::size_t size)
{
EnsureEnoughSpace(mBuffer, mCurrent, 1 + ArgumentSize(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));
}
WriteHeader(mBuffer, MajorType::Array, size);
}
void BasicEncoder::BeginMap(std::size_t size)
{
EnsureEnoughSpace(mBuffer, mCurrent, 1 + ArgumentSize(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));
}
WriteHeader(mBuffer, MajorType::Map, size);
}
void BasicEncoder::BeginIndefiniteBinary()
{
EnsureEnoughSpace(mBuffer, mCurrent, 1);
mBuffer[mCurrent++] = std::to_underlying(MajorType::Binary)
| std::to_underlying(ArgumentPosition::Indefinite);
mBuffer.Write(EncodeHeader(MajorType::Binary, ArgumentPosition::Indefinite));
}
void BasicEncoder::BeginIndefiniteString()
{
EnsureEnoughSpace(mBuffer, mCurrent, 1);
mBuffer[mCurrent++] = std::to_underlying(MajorType::String)
| std::to_underlying(ArgumentPosition::Indefinite);
mBuffer.Write(EncodeHeader(MajorType::String, ArgumentPosition::Indefinite));
}
void BasicEncoder::BeginIndefiniteArray()
{
EnsureEnoughSpace(mBuffer, mCurrent, 1);
mBuffer[mCurrent++] = std::to_underlying(MajorType::Array)
| std::to_underlying(ArgumentPosition::Indefinite);
mBuffer.Write(EncodeHeader(MajorType::Array, ArgumentPosition::Indefinite));
}
void BasicEncoder::BeginIndefiniteMap()
{
EnsureEnoughSpace(mBuffer, mCurrent, 1);
mBuffer[mCurrent++] = std::to_underlying(MajorType::Map)
| std::to_underlying(ArgumentPosition::Indefinite);
mBuffer.Write(EncodeHeader(MajorType::Map, ArgumentPosition::Indefinite));
}
void BasicEncoder::End()
{
EnsureEnoughSpace(mBuffer, mCurrent, 1);
mBuffer[mCurrent++] = std::to_underlying(MajorType::Other)
| std::to_underlying(MinorType::Break);
mBuffer.Write(EncodeHeader(MajorType::Other, MinorType::Break));
}
void BasicEncoder::EncodeTag(std::uint64_t value)
{
EnsureEnoughSpace(mBuffer, mCurrent, 1 + ArgumentSize(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));
}
WriteHeader(mBuffer, MajorType::Tag, 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::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);
enc.EncodeTag(15'000);
@ -50,7 +50,7 @@ std::size_t Encode(const SomeStruct &value, std::span<std::uint8_t> buffer)
}
enc.End();
return enc.EncodedSize();
return enc.Size();
}
SomeStruct Decode1(std::span<std::uint8_t> buffer)
@ -174,7 +174,8 @@ int main()
{
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 {
.name = "Player1",
@ -196,6 +197,12 @@ int main()
std::size_t encodedSize = Encode(expected, buffer);
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 result2 = Decode2(std::span<std::uint8_t>(buffer.data(), encodedSize));