瀏覽代碼

More work on CBOR refactoring

channel
Ludovic 'Archivist' Lagouardette 3 年之前
父節點
當前提交
9defdda3c5
共有 3 個檔案被更改,包括 263 行新增1 行删除
  1. +5
    -0
      include/gp/containers/buffer.hpp
  2. +252
    -0
      include/gp/ipc/envelope/cbor.hpp
  3. +6
    -1
      include/gp/math/boolean/bitops.hpp

+ 5
- 0
include/gp/containers/buffer.hpp 查看文件

@ -25,6 +25,11 @@ namespace gp{
, end_elem{end_ptr}
{}
constexpr buffer(associated_iterator beg_ptr, associated_iterator end_ptr)
: begin_elem{beg_ptr}
, end_elem{end_ptr}
{}
constexpr buffer(T* beg_ptr, std::size_t sz)
: begin_elem{beg_ptr}
, end_elem{beg_ptr+sz}

+ 252
- 0
include/gp/ipc/envelope/cbor.hpp 查看文件

@ -93,6 +93,258 @@ namespace gp {
return (float)*this;
}
};
template<typename T>
vector<char>& push_as_cbor(vector<char>&, T);
template<typename T>
vector<char>& push_as_cbor(vector<char>&, T&);
inline vector<char>& push_integer_with_header_as_cbor(vector<char>& src, uint8_t header, uint64_t value) {
auto norm_v = (value<0) ? -value : value;
if(norm_v <= 23) {
src.push_back(header+norm_v);
} else if(norm_v < (1ll<<8ll)) {
src.push_back(header+24);
src.push_back(norm_v);
} else if(norm_v < (1ll<<16ll)) {
endian_wrapper<uint16_t, endian::big> wrapper = norm_v;
src.push_back(header+25);
for(auto byte : wrapper.bytes) {
src.push_back(byte);
}
} else if(norm_v < (1ll<<32ll)) {
endian_wrapper<uint32_t, endian::big> wrapper = norm_v;
src.push_back(header+26);
for(auto byte : wrapper.bytes) {
src.push_back(byte);
}
} else {
endian_wrapper<uint64_t, endian::big> wrapper = norm_v;
src.push_back(header+27);
for(auto byte : wrapper.bytes) {
src.push_back(byte);
}
}
return src;
}
/**
* @brief Pushes an integer as CBOR on the vector
*
* @param src the vector on which the push happens
* @param value the value to push, can be signed
* @return vector<char>& the same reference that was received for the source
*/
template<>
vector<char>& push_as_cbor<int64_t>(vector<char>& src, int64_t& value) {
uint8_t sign = (value<0) ? 0b00100000 : 0;
auto norm_v = (value<0) ? -value : value;
return push_integer_with_header_as_cbor(src, sign, norm_v);
}
/**
* @brief Pushes an unsigned integer as CBOR on the vector
*
* @param src the vector on which the push happens
* @param value the value to push, cannot be signed
* @return vector<char>& the same reference that was received for the source
*/
template<>
vector<char>& push_as_cbor<uint64_t>(vector<char>& src, uint64_t& value) {
return push_integer_with_header_as_cbor(src, 0, value);
}
template<>
vector<char>& push_as_cbor<std::nullptr_t>(vector<char>& src, std::nullptr_t) {
src.push_back(0b11110110);
return src;
}
struct cbor_undefined{};
template<>
vector<char>& push_as_cbor<cbor_undefined>(vector<char>& src, cbor_undefined) {
src.push_back(0b11110111);
return src;
}
template<>
vector<char>& push_as_cbor<bool>(vector<char>& src, bool value) {
src.push_back(0b11110100+(value ? 1 : 0));
return src;
}
template<>
vector<char>& push_as_cbor<gp::buffer<char>>(vector<char>& src, gp::buffer<char> value) {
push_integer_with_header_as_cbor(src, (uint8_t)0b01000000, value.size());
for(auto byte : value) {
src.push_back(byte);
}
return src;
}
struct cbor_array_initiator {
size_t size;
};
struct cbor_associative_array_initiator {
size_t size;
};
template<>
vector<char>& push_as_cbor<cbor_array_initiator>(vector<char>& src, cbor_array_initiator value) {
return push_integer_with_header_as_cbor(src, (uint8_t)0b10000000, value.size);
}
template<>
vector<char>& push_as_cbor<cbor_associative_array_initiator>(vector<char>& src, cbor_associative_array_initiator value) {
return push_integer_with_header_as_cbor(src, (uint8_t)0b10100000, value.size);
}
template<typename First, typename Second>
vector<char>& push_as_cbor(vector<char>& src, gp::pair<First, Second>& value) {
push_as_cbor<First>(src,value.first);
return push_as_cbor<Second>(src,value.second);
}
struct cbor_tag_initiator {
union {
size_t as_integer;
cbor_tags tag;
};
};
template<>
vector<char>& push_as_cbor<cbor_tag_initiator>(vector<char>& src, cbor_tag_initiator value) {
return push_integer_with_header_as_cbor(src, (uint8_t)0b11000000, value.as_integer);
}
using parsing_state = gp::buffer<char>;
template<typename T>
gp::pair<gp::optional<T>, parsing_state> read_cbor(parsing_state state);
inline gp::pair<gp::optional<uint64_t>, parsing_state> pull_arbitrary_integer_from_cbor(parsing_state state) {
auto local = (uint8_t)0b00011111 & (uint8_t)*state.begin();
if(local <= 23) {
return {*state.begin(), {state.begin()+1, state.end()}};
} else {
switch((cbor_oths)local) {
case cbor_oths::byte: {
if(state.size() < 2) return {nullopt, state};
return {*(state.begin()+1), {state.begin()+2, state.end()}};
}
case cbor_oths::word: {
if(state.size() < 3) return {nullopt, state};
return {
uint16_t(*(state.slice_start(3).slice_end(2).cast<gp::endian_wrapper<uint16_t, endian::big>>().begin().data)),
{state.begin()+3, state.end()}
};
}
case cbor_oths::dword: {
if(state.size() < 5) return {nullopt, state};
return {
uint32_t(*(state.slice_start(5).slice_end(4).cast<gp::endian_wrapper<uint32_t, endian::big>>().begin().data)),
{state.begin()+5, state.end()}
};
}
case cbor_oths::qword: {
if(state.size() < 9) return {nullopt, state};
return {
uint64_t(*(state.slice_start(9).slice_end(8).cast<gp::endian_wrapper<uint64_t, endian::big>>().begin().data)),
{state.begin()+9, state.end()}
};
}
default: {
return {nullopt, state};
}
}
}
}
template<>
gp::pair<gp::optional<int64_t>, parsing_state> read_cbor<int64_t>(parsing_state state) {
if(state.size()) return {nullopt, state};
auto type = cbor_type(((uint8_t)0b11100000 & (uint8_t)*state.begin()) >> 5);
int64_t sign = type == cbor_type::nint ? -1 : 1;
switch(type) {
case cbor_type::uint:
case cbor_type::nint:
{
auto[value, new_state] = pull_arbitrary_integer_from_cbor(state);
if(value.has_value()) return {value.value() * sign, new_state};
break;
}
default:
break;
}
return {nullopt, state};
}
template<>
gp::pair<gp::optional<uint64_t>, parsing_state> read_cbor<uint64_t>(parsing_state state) {
if(state.size()) return {nullopt, state};
auto type = cbor_type(((uint8_t)0b11100000 & (uint8_t)*state.begin()) >> 5);
switch(type) {
case cbor_type::uint:
{
auto[value, new_state] = pull_arbitrary_integer_from_cbor(state);
if(value.has_value()) return {value.value(), new_state};
break;
}
default:
break;
}
return {nullopt, state};
}
struct cbor_floating_point final {
using backing = gp::fixed_variant<

+ 6
- 1
include/gp/math/boolean/bitops.hpp 查看文件

@ -1,5 +1,7 @@
#pragma once
#include "gp/containers/array.hpp"
#include <stddef.h>
#include <stdint.h>
@ -54,7 +56,10 @@ namespace gp{
template<typename T, endian mode = endian::big>
struct endian_wrapper {
T value;
union{
T value;
gp::array<uint8_t, sizeof(T)> bytes;
};
endian_wrapper(){};
endian_wrapper(T v) : value{
mode == endian::native ? v : swap_endian(v)

Loading…
取消
儲存