diff --git a/LibCBOR/Include/CBOR/Encoder.hpp b/LibCBOR/Include/CBOR/Encoder.hpp index efb115d..ac63692 100644 --- a/LibCBOR/Include/CBOR/Encoder.hpp +++ b/LibCBOR/Include/CBOR/Encoder.hpp @@ -3,9 +3,12 @@ #include "Core.hpp" +#include #include #include #include +#include +#include namespace CBOR { @@ -15,6 +18,68 @@ namespace CBOR using Error::Error; }; + class EncoderBuffer + { + public: + EncoderBuffer(std::span buffer); + EncoderBuffer(std::vector &buffer); + + template + EncoderBuffer(std::array &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 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 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 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 value); + void Write(std::string_view value); + + std::size_t Size() const; + + std::vector *Buffer; + }; + + using BufferType = std::variant; + + 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 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 mBuffer; + EncoderBuffer mBuffer; }; } diff --git a/LibCBOR/Source/Encoder.cpp b/LibCBOR/Source/Encoder.cpp index 7c7ae08..e61a8ac 100644 --- a/LibCBOR/Source/Encoder.cpp +++ b/LibCBOR/Source/Encoder.cpp @@ -5,6 +5,8 @@ #include #include +#include +#include #include namespace CBOR @@ -29,99 +31,262 @@ namespace CBOR namespace { - std::size_t ArgumentSize(std::size_t value) + template + 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 buffer, std::size_t offset) - { - return buffer.size() - offset; - } - - void EnsureEnoughSpace(std::span buffer, std::size_t offset, - std::size_t spaceRequired) - { - if (SpaceLeft(buffer, offset) < spaceRequired) { - throw NotEnoughSpace(SpaceLeft(buffer, offset), spaceRequired); - } - } - - void Write(std::span &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((network ) & mask); - buffer[current++] = static_cast((network >> 8) & mask); - } - - void Write(std::span &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((network ) & mask); - buffer[current++] = static_cast((network >> 8) & mask); - buffer[current++] = static_cast((network >> 16) & mask); - buffer[current++] = static_cast((network >> 24) & mask); - } - - void Write(std::span &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((network ) & mask); - buffer[current++] = static_cast((network >> 8) & mask); - buffer[current++] = static_cast((network >> 16) & mask); - buffer[current++] = static_cast((network >> 24) & mask); - buffer[current++] = static_cast((network >> 32) & mask); - buffer[current++] = static_cast((network >> 40) & mask); - buffer[current++] = static_cast((network >> 48) & mask); - buffer[current++] = static_cast((network >> 56) & mask); - } } - BasicEncoder::BasicEncoder(std::span buffer) - : mCurrent(0), mBuffer(buffer) + EncoderBuffer::EncoderBuffer(std::span buffer) + : mBuffer(FixedBuffer { .Current = 0, .Buffer = buffer, }) + {} + + EncoderBuffer::EncoderBuffer(std::vector &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 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((network ) & mask); + Buffer[Current++] = static_cast((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((network ) & mask); + Buffer[Current++] = static_cast((network >> 8) & mask); + Buffer[Current++] = static_cast((network >> 16) & mask); + Buffer[Current++] = static_cast((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((network ) & mask); + Buffer[Current++] = static_cast((network >> 8) & mask); + Buffer[Current++] = static_cast((network >> 16) & mask); + Buffer[Current++] = static_cast((network >> 24) & mask); + Buffer[Current++] = static_cast((network >> 32) & mask); + Buffer[Current++] = static_cast((network >> 40) & mask); + Buffer[Current++] = static_cast((network >> 48) & mask); + Buffer[Current++] = static_cast((network >> 56) & mask); + } + + void EncoderBuffer::FixedBuffer::Write(std::span 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((network ) & mask)); + Buffer->push_back(static_cast((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((network ) & mask)); + Buffer->push_back(static_cast((network >> 8) & mask)); + Buffer->push_back(static_cast((network >> 16) & mask)); + Buffer->push_back(static_cast((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((network ) & mask)); + Buffer->push_back(static_cast((network >> 8) & mask)); + Buffer->push_back(static_cast((network >> 16) & mask)); + Buffer->push_back(static_cast((network >> 24) & mask)); + Buffer->push_back(static_cast((network >> 32) & mask)); + Buffer->push_back(static_cast((network >> 40) & mask)); + Buffer->push_back(static_cast((network >> 48) & mask)); + Buffer->push_back(static_cast((network >> 56) & mask)); + } + + void EncoderBuffer::DynamicBuffer::Write(std::span 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::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(value); + mBuffer.Write(EncodeHeader(MajorType::Unsigned, ArgumentPosition::Next1B)); + mBuffer.Write(static_cast(value)); } } else { std::int8_t actual = -(value + 1); if (actual <= 23) { - EnsureEnoughSpace(mBuffer, mCurrent, 1); - mBuffer[mCurrent++] = static_cast(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(actual); + mBuffer.Write(EncodeHeader(MajorType::Negative, ArgumentPosition::Next1B)); + mBuffer.Write(static_cast(actual)); } } } @@ -167,23 +326,17 @@ namespace CBOR } else if (value >= -256 && value <= -1) { std::uint8_t actual = static_cast(-(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(value)); + mBuffer.Write(EncodeHeader(MajorType::Unsigned, ArgumentPosition::Next2B)); + mBuffer.Write(static_cast(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(actual)); + mBuffer.Write(EncodeHeader(MajorType::Negative, ArgumentPosition::Next2B)); + mBuffer.Write(static_cast(actual)); } } @@ -197,21 +350,16 @@ namespace CBOR } else if (value >= -65536 && value <= -1) { std::uint16_t actual = static_cast(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(value)); + mBuffer.Write(EncodeHeader(MajorType::Unsigned, ArgumentPosition::Next4B)); + mBuffer.Write(static_cast(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(actual)); + mBuffer.Write(EncodeHeader(MajorType::Negative, ArgumentPosition::Next4B)); + mBuffer.Write(static_cast(actual)); } } @@ -225,35 +373,28 @@ namespace CBOR } else if (value >= -2147483648 && value <= -1) { std::uint32_t actual = static_cast(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(value)); + mBuffer.Write(EncodeHeader(MajorType::Unsigned, ArgumentPosition::Next8B)); + mBuffer.Write(static_cast(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(actual)); + mBuffer.Write(EncodeHeader(MajorType::Negative, ArgumentPosition::Next8B)); + mBuffer.Write(static_cast(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(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(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(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(value)); + mBuffer.Write(EncodeHeader(MajorType::Other, MinorType::Float)); + mBuffer.Write(std::bit_cast(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(value)); + mBuffer.Write(EncodeHeader(MajorType::Other, MinorType::Double)); + mBuffer.Write(std::bit_cast(value)); } void BasicEncoder::Encode(std::span value) { - EnsureEnoughSpace(mBuffer, mCurrent, 1 + ArgumentSize(value.size()) + value.size()); - if (value.size() <= 23) { - mBuffer[mCurrent++] = std::to_underlying(MajorType::Binary) - | static_cast(value.size()); - } - else if (value.size() <= 255) { - mBuffer[mCurrent++] = std::to_underlying(MajorType::Binary) - | std::to_underlying(ArgumentPosition::Next1B); - mBuffer[mCurrent++] = static_cast(value.size()); - } - else if (value.size() <= 65535) { - mBuffer[mCurrent++] = std::to_underlying(MajorType::Binary) - | std::to_underlying(ArgumentPosition::Next2B); - Write(mBuffer, mCurrent, static_cast(value.size())); - } - else if (value.size() <= 4294967295) { - mBuffer[mCurrent++] = std::to_underlying(MajorType::Binary) - | std::to_underlying(ArgumentPosition::Next4B); - Write(mBuffer, mCurrent, static_cast(value.size())); - } - else { - mBuffer[mCurrent++] = std::to_underlying(MajorType::Binary) - | std::to_underlying(ArgumentPosition::Next8B); - Write(mBuffer, mCurrent, static_cast(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(value.size()); - } - else if (value.size() <= 255) { - mBuffer[mCurrent++] = std::to_underlying(MajorType::String) - | std::to_underlying(ArgumentPosition::Next1B); - mBuffer[mCurrent++] = static_cast(value.size()); - } - else if (value.size() <= 65535) { - mBuffer[mCurrent++] = std::to_underlying(MajorType::String) - | std::to_underlying(ArgumentPosition::Next2B); - Write(mBuffer, mCurrent, static_cast(value.size())); - } - else if (value.size() <= 4294967295) { - mBuffer[mCurrent++] = std::to_underlying(MajorType::String) - | std::to_underlying(ArgumentPosition::Next4B); - Write(mBuffer, mCurrent, static_cast(value.size())); - } - else { - mBuffer[mCurrent++] = std::to_underlying(MajorType::String) - | std::to_underlying(ArgumentPosition::Next8B); - Write(mBuffer, mCurrent, static_cast(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(size); - } - else if (size <= 255) { - mBuffer[mCurrent++] = std::to_underlying(MajorType::Array) - | std::to_underlying(ArgumentPosition::Next1B); - mBuffer[mCurrent++] = static_cast(size); - } - else if (size <= 65535) { - mBuffer[mCurrent++] = std::to_underlying(MajorType::Array) - | std::to_underlying(ArgumentPosition::Next2B); - Write(mBuffer, mCurrent, static_cast(size)); - } - else if (size <= 4294967295) { - mBuffer[mCurrent++] = std::to_underlying(MajorType::Array) - | std::to_underlying(ArgumentPosition::Next4B); - Write(mBuffer, mCurrent, static_cast(size)); - } - else { - mBuffer[mCurrent++] = std::to_underlying(MajorType::Array) - | std::to_underlying(ArgumentPosition::Next8B); - Write(mBuffer, mCurrent, static_cast(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(size); - } - else if (size <= 255) { - mBuffer[mCurrent++] = std::to_underlying(MajorType::Map) - | std::to_underlying(ArgumentPosition::Next1B); - mBuffer[mCurrent++] = static_cast(size); - } - else if (size <= 65535) { - mBuffer[mCurrent++] = std::to_underlying(MajorType::Map) - | std::to_underlying(ArgumentPosition::Next2B); - Write(mBuffer, mCurrent, static_cast(size)); - } - else if (size <= 4294967295) { - mBuffer[mCurrent++] = std::to_underlying(MajorType::Map) - | std::to_underlying(ArgumentPosition::Next4B); - Write(mBuffer, mCurrent, static_cast(size)); - } - else { - mBuffer[mCurrent++] = std::to_underlying(MajorType::Map) - | std::to_underlying(ArgumentPosition::Next8B); - Write(mBuffer, mCurrent, static_cast(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(value); - } - else if (value <= 255) { - mBuffer[mCurrent++] = std::to_underlying(MajorType::Tag) - | std::to_underlying(ArgumentPosition::Next1B); - mBuffer[mCurrent++] = static_cast(value); - } - else if (value <= 65535) { - mBuffer[mCurrent++] = std::to_underlying(MajorType::Tag) - | std::to_underlying(ArgumentPosition::Next2B); - Write(mBuffer, mCurrent, static_cast(value)); - } - else if (value <= 4294967295) { - mBuffer[mCurrent++] = std::to_underlying(MajorType::Tag) - | std::to_underlying(ArgumentPosition::Next4B); - Write(mBuffer, mCurrent, static_cast(value)); - } - else { - mBuffer[mCurrent++] = std::to_underlying(MajorType::Tag) - | std::to_underlying(ArgumentPosition::Next8B); - Write(mBuffer, mCurrent, static_cast(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(); } } diff --git a/Tests/Main.cpp b/Tests/Main.cpp index 0819924..5b51912 100644 --- a/Tests/Main.cpp +++ b/Tests/Main.cpp @@ -18,7 +18,7 @@ struct SomeStruct std::vector tools; }; -std::size_t Encode(const SomeStruct &value, std::span 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 buffer) } enc.End(); - return enc.EncodedSize(); + return enc.Size(); } SomeStruct Decode1(std::span buffer) @@ -174,7 +174,8 @@ int main() { using namespace std::string_view_literals; - std::array buffer {}; + //std::array buffer {}; + std::vector 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(buffer.data(), encodedSize)); SomeStruct result2 = Decode2(std::span(buffer.data(), encodedSize));