Support dynamically sized buffers (std::vector)
This commit is contained in:
parent
b65c700c29
commit
c3278e807b
3 changed files with 360 additions and 290 deletions
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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 ¤t, 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 ¤t, 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 ¤t, 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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue