Zero-copy TX: span_writer packer, static buffers, no vector returns
This commit is contained in:
@@ -6,11 +6,11 @@
|
||||
#include <expected>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include "span_writer.h"
|
||||
|
||||
namespace msgpack {
|
||||
|
||||
@@ -163,26 +163,23 @@ inline result<body_info> get_body_info(const uint8_t *p, int size) {
|
||||
}
|
||||
|
||||
class packer {
|
||||
public:
|
||||
using buffer = std::vector<std::uint8_t>;
|
||||
|
||||
private:
|
||||
std::shared_ptr<buffer> m_buffer;
|
||||
span_writer m_buf;
|
||||
|
||||
template <typename T> void push_big_endian(T n) {
|
||||
auto p = reinterpret_cast<std::uint8_t *>(&n) + (sizeof(T) - 1);
|
||||
for (size_t i = 0; i < sizeof(T); ++i, --p) {
|
||||
m_buffer->push_back(*p);
|
||||
m_buf.push_back(*p);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Range> void push(const Range &r) {
|
||||
m_buffer->insert(m_buffer->end(), std::begin(r), std::end(r));
|
||||
m_buf.insert(m_buf.end(), std::begin(r), std::end(r));
|
||||
}
|
||||
|
||||
public:
|
||||
packer() : m_buffer(std::make_shared<buffer>()) {}
|
||||
packer(const std::shared_ptr<buffer> &buf) : m_buffer(buf) {}
|
||||
packer(uint8_t *data, size_t capacity) : m_buf(data, capacity) {}
|
||||
packer(span_writer buf) : m_buf(buf) {}
|
||||
|
||||
packer(const packer &) = delete;
|
||||
packer &operator=(const packer &) = delete;
|
||||
@@ -190,12 +187,12 @@ public:
|
||||
using pack_result = result<std::reference_wrapper<packer>>;
|
||||
|
||||
pack_result pack_nil() {
|
||||
m_buffer->push_back(format::NIL);
|
||||
m_buf.push_back(format::NIL);
|
||||
return *this;
|
||||
}
|
||||
|
||||
pack_result pack_bool(bool v) {
|
||||
m_buffer->push_back(v ? format::TRUE : format::FALSE);
|
||||
m_buf.push_back(v ? format::TRUE : format::FALSE);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -203,36 +200,36 @@ public:
|
||||
pack_result pack_integer(T n) {
|
||||
if constexpr (std::is_signed_v<T>) {
|
||||
if (n >= 0 && n <= 0x7F) {
|
||||
m_buffer->push_back(static_cast<uint8_t>(n));
|
||||
m_buf.push_back(static_cast<uint8_t>(n));
|
||||
} else if (n >= -32 && n < 0) {
|
||||
m_buffer->push_back(static_cast<uint8_t>(n)); // negative fixint
|
||||
m_buf.push_back(static_cast<uint8_t>(n)); // negative fixint
|
||||
} else if (n >= std::numeric_limits<int8_t>::min() && n <= std::numeric_limits<int8_t>::max()) {
|
||||
m_buffer->push_back(format::INT8);
|
||||
m_buffer->push_back(static_cast<uint8_t>(n));
|
||||
m_buf.push_back(format::INT8);
|
||||
m_buf.push_back(static_cast<uint8_t>(n));
|
||||
} else if (n >= std::numeric_limits<int16_t>::min() && n <= std::numeric_limits<int16_t>::max()) {
|
||||
m_buffer->push_back(format::INT16);
|
||||
m_buf.push_back(format::INT16);
|
||||
push_big_endian(static_cast<int16_t>(n));
|
||||
} else if (n >= std::numeric_limits<int32_t>::min() && n <= std::numeric_limits<int32_t>::max()) {
|
||||
m_buffer->push_back(format::INT32);
|
||||
m_buf.push_back(format::INT32);
|
||||
push_big_endian(static_cast<int32_t>(n));
|
||||
} else {
|
||||
m_buffer->push_back(format::INT64);
|
||||
m_buf.push_back(format::INT64);
|
||||
push_big_endian(static_cast<int64_t>(n));
|
||||
}
|
||||
} else {
|
||||
if (n <= 0x7F) {
|
||||
m_buffer->push_back(static_cast<uint8_t>(n));
|
||||
m_buf.push_back(static_cast<uint8_t>(n));
|
||||
} else if (n <= std::numeric_limits<uint8_t>::max()) {
|
||||
m_buffer->push_back(format::UINT8);
|
||||
m_buffer->push_back(static_cast<uint8_t>(n));
|
||||
m_buf.push_back(format::UINT8);
|
||||
m_buf.push_back(static_cast<uint8_t>(n));
|
||||
} else if (n <= std::numeric_limits<uint16_t>::max()) {
|
||||
m_buffer->push_back(format::UINT16);
|
||||
m_buf.push_back(format::UINT16);
|
||||
push_big_endian(static_cast<uint16_t>(n));
|
||||
} else if (n <= std::numeric_limits<uint32_t>::max()) {
|
||||
m_buffer->push_back(format::UINT32);
|
||||
m_buf.push_back(format::UINT32);
|
||||
push_big_endian(static_cast<uint32_t>(n));
|
||||
} else {
|
||||
m_buffer->push_back(format::UINT64);
|
||||
m_buf.push_back(format::UINT64);
|
||||
push_big_endian(static_cast<uint64_t>(n));
|
||||
}
|
||||
}
|
||||
@@ -240,13 +237,13 @@ public:
|
||||
}
|
||||
|
||||
pack_result pack_float(float n) {
|
||||
m_buffer->push_back(format::FLOAT32);
|
||||
m_buf.push_back(format::FLOAT32);
|
||||
push_big_endian(n);
|
||||
return *this;
|
||||
}
|
||||
|
||||
pack_result pack_double(double n) {
|
||||
m_buffer->push_back(format::FLOAT64);
|
||||
m_buf.push_back(format::FLOAT64);
|
||||
push_big_endian(n);
|
||||
return *this;
|
||||
}
|
||||
@@ -255,15 +252,15 @@ public:
|
||||
pack_result pack_str(const Range &r) {
|
||||
auto sz = static_cast<size_t>(std::distance(std::begin(r), std::end(r)));
|
||||
if (sz < 32) {
|
||||
m_buffer->push_back(format::FIXSTR_MIN | static_cast<uint8_t>(sz));
|
||||
m_buf.push_back(format::FIXSTR_MIN | static_cast<uint8_t>(sz));
|
||||
} else if (sz <= std::numeric_limits<uint8_t>::max()) {
|
||||
m_buffer->push_back(format::STR8);
|
||||
m_buffer->push_back(static_cast<uint8_t>(sz));
|
||||
m_buf.push_back(format::STR8);
|
||||
m_buf.push_back(static_cast<uint8_t>(sz));
|
||||
} else if (sz <= std::numeric_limits<uint16_t>::max()) {
|
||||
m_buffer->push_back(format::STR16);
|
||||
m_buf.push_back(format::STR16);
|
||||
push_big_endian(static_cast<uint16_t>(sz));
|
||||
} else if (sz <= std::numeric_limits<uint32_t>::max()) {
|
||||
m_buffer->push_back(format::STR32);
|
||||
m_buf.push_back(format::STR32);
|
||||
push_big_endian(static_cast<uint32_t>(sz));
|
||||
} else {
|
||||
return std::unexpected(error_code::overflow);
|
||||
@@ -280,13 +277,13 @@ public:
|
||||
pack_result pack_bin(const Range &r) {
|
||||
auto sz = static_cast<size_t>(std::distance(std::begin(r), std::end(r)));
|
||||
if (sz <= std::numeric_limits<uint8_t>::max()) {
|
||||
m_buffer->push_back(format::BIN8);
|
||||
m_buffer->push_back(static_cast<uint8_t>(sz));
|
||||
m_buf.push_back(format::BIN8);
|
||||
m_buf.push_back(static_cast<uint8_t>(sz));
|
||||
} else if (sz <= std::numeric_limits<uint16_t>::max()) {
|
||||
m_buffer->push_back(format::BIN16);
|
||||
m_buf.push_back(format::BIN16);
|
||||
push_big_endian(static_cast<uint16_t>(sz));
|
||||
} else if (sz <= std::numeric_limits<uint32_t>::max()) {
|
||||
m_buffer->push_back(format::BIN32);
|
||||
m_buf.push_back(format::BIN32);
|
||||
push_big_endian(static_cast<uint32_t>(sz));
|
||||
} else {
|
||||
return std::unexpected(error_code::overflow);
|
||||
@@ -297,12 +294,12 @@ public:
|
||||
|
||||
pack_result pack_array(size_t n) {
|
||||
if (n <= 15) {
|
||||
m_buffer->push_back(format::FIXARRAY_MIN | static_cast<uint8_t>(n));
|
||||
m_buf.push_back(format::FIXARRAY_MIN | static_cast<uint8_t>(n));
|
||||
} else if (n <= std::numeric_limits<uint16_t>::max()) {
|
||||
m_buffer->push_back(format::ARRAY16);
|
||||
m_buf.push_back(format::ARRAY16);
|
||||
push_big_endian(static_cast<uint16_t>(n));
|
||||
} else if (n <= std::numeric_limits<uint32_t>::max()) {
|
||||
m_buffer->push_back(format::ARRAY32);
|
||||
m_buf.push_back(format::ARRAY32);
|
||||
push_big_endian(static_cast<uint32_t>(n));
|
||||
} else {
|
||||
return std::unexpected(error_code::overflow);
|
||||
@@ -312,12 +309,12 @@ public:
|
||||
|
||||
pack_result pack_map(size_t n) {
|
||||
if (n <= 15) {
|
||||
m_buffer->push_back(format::FIXMAP_MIN | static_cast<uint8_t>(n));
|
||||
m_buf.push_back(format::FIXMAP_MIN | static_cast<uint8_t>(n));
|
||||
} else if (n <= std::numeric_limits<uint16_t>::max()) {
|
||||
m_buffer->push_back(format::MAP16);
|
||||
m_buf.push_back(format::MAP16);
|
||||
push_big_endian(static_cast<uint16_t>(n));
|
||||
} else if (n <= std::numeric_limits<uint32_t>::max()) {
|
||||
m_buffer->push_back(format::MAP32);
|
||||
m_buf.push_back(format::MAP32);
|
||||
push_big_endian(static_cast<uint32_t>(n));
|
||||
} else {
|
||||
return std::unexpected(error_code::overflow);
|
||||
@@ -330,26 +327,26 @@ public:
|
||||
auto sz = static_cast<size_t>(std::distance(std::begin(r), std::end(r)));
|
||||
|
||||
switch (sz) {
|
||||
case 1: m_buffer->push_back(format::FIXEXT1); break;
|
||||
case 2: m_buffer->push_back(format::FIXEXT2); break;
|
||||
case 4: m_buffer->push_back(format::FIXEXT4); break;
|
||||
case 8: m_buffer->push_back(format::FIXEXT8); break;
|
||||
case 16: m_buffer->push_back(format::FIXEXT16); break;
|
||||
case 1: m_buf.push_back(format::FIXEXT1); break;
|
||||
case 2: m_buf.push_back(format::FIXEXT2); break;
|
||||
case 4: m_buf.push_back(format::FIXEXT4); break;
|
||||
case 8: m_buf.push_back(format::FIXEXT8); break;
|
||||
case 16: m_buf.push_back(format::FIXEXT16); break;
|
||||
default:
|
||||
if (sz <= std::numeric_limits<uint8_t>::max()) {
|
||||
m_buffer->push_back(format::EXT8);
|
||||
m_buffer->push_back(static_cast<uint8_t>(sz));
|
||||
m_buf.push_back(format::EXT8);
|
||||
m_buf.push_back(static_cast<uint8_t>(sz));
|
||||
} else if (sz <= std::numeric_limits<uint16_t>::max()) {
|
||||
m_buffer->push_back(format::EXT16);
|
||||
m_buf.push_back(format::EXT16);
|
||||
push_big_endian(static_cast<uint16_t>(sz));
|
||||
} else if (sz <= std::numeric_limits<uint32_t>::max()) {
|
||||
m_buffer->push_back(format::EXT32);
|
||||
m_buf.push_back(format::EXT32);
|
||||
push_big_endian(static_cast<uint32_t>(sz));
|
||||
} else {
|
||||
return std::unexpected(error_code::overflow);
|
||||
}
|
||||
}
|
||||
m_buffer->push_back(static_cast<uint8_t>(type));
|
||||
m_buf.push_back(static_cast<uint8_t>(type));
|
||||
push(r);
|
||||
return *this;
|
||||
}
|
||||
@@ -392,7 +389,8 @@ public:
|
||||
template <typename T>
|
||||
requires requires(const T &v) { { T::ext_id } -> std::convertible_to<int8_t>; v.as_tuple(); }
|
||||
pack_result pack(const T &v) {
|
||||
packer inner;
|
||||
uint8_t ext_buf[256];
|
||||
packer inner(ext_buf, sizeof(ext_buf));
|
||||
auto r = inner.pack(v.as_tuple());
|
||||
if (!r) return r;
|
||||
return pack_ext(T::ext_id, inner.get_payload());
|
||||
@@ -413,7 +411,7 @@ private:
|
||||
}
|
||||
|
||||
public:
|
||||
const buffer &get_payload() const { return *m_buffer; }
|
||||
const span_writer &get_payload() const { return m_buf; }
|
||||
};
|
||||
|
||||
class parser {
|
||||
|
||||
Reference in New Issue
Block a user