ソースを参照

Decode mostly done, endianness issue to fix

cbor
Ludovic 'Archivist' Lagouardette 3年前
コミット
e84f64c689
2個のファイルの変更187行の追加16行の削除
  1. +152
    -14
      include/gp/enveloppe/cbor.hpp
  2. +35
    -2
      tests/cbor_test.cpp

+ 152
- 14
include/gp/enveloppe/cbor.hpp ファイルの表示

@ -80,13 +80,68 @@ namespace gp {
uint16_t sign : 1;
uint16_t exponent : 5;
uint16_t mantissa : 10;
// TODO: support for denormalized values and NaNs
operator float() {
auto a = (uint32_t)((sign<<16) | ((exponent+0x1C000)<<13) | (mantissa<<13));
return *(float*)&a;
}
operator double() {
return (float)*this;
}
};
using cbor_floating_point = gp::fixed_variant<
ieee754_hf,
float,
double
>;
struct cbor_floating_point final {
using backing = gp::fixed_variant<
ieee754_hf,
float,
double
>;
backing contents;
cbor_floating_point(backing& p)
: contents{p}{}
cbor_floating_point(ieee754_hf p)
: contents{p}{}
cbor_floating_point(float p)
: contents{p}{}
cbor_floating_point(double p)
: contents{p}{}
operator ieee754_hf() {
return contents.value<ieee754_hf>();
}
operator float() {
switch(contents.type()) {
case backing::alt<ieee754_hf>():
return contents.value<ieee754_hf>();
case backing::alt<float>():
return contents.value<float>();
default:
gp_config::assertion(false,"this code should never be reached");
return std::numeric_limits<float>::quiet_NaN();
}
}
operator double() {
switch(contents.type()) {
case backing::alt<ieee754_hf>():
return contents.value<ieee754_hf>();
case backing::alt<float>():
return contents.value<float>();
case backing::alt<double>():
return contents.value<double>();
default:
gp_config::assertion(false,"this code should never be reached");
return std::numeric_limits<double>::quiet_NaN();
}
}
};
struct undefined_t final {};
@ -109,7 +164,7 @@ namespace gp {
public:
cbor_value(allocator& alloc_v)
: contents(n">cbor_composite<cbor_value>(undefined_t{}))
: contents()
, alloc(alloc_v)
{}
@ -213,8 +268,91 @@ namespace gp {
#undef ERROR
}
template<typename U>
U& value() {
}
template<typename U>
bool is_a() {
if constexpr (
std::is_same_v<U, uint8_t>
|| std::is_same_v<U, uint16_t>
|| std::is_same_v<U, uint32_t>
|| std::is_same_v<U, uint64_t>
|| std::is_same_v<U, int8_t>
|| std::is_same_v<U, int16_t>
|| std::is_same_v<U, int32_t>
|| std::is_same_v<U, int64_t>
) {
if(contents.is_a<cbor_number>())
{
auto& v = contents.value<cbor_number>();
if(!std::is_signed_v<U> && v.is_negative()) return false;
if(
std::numeric_limits<int64_t>::max()<v.value
&& (
!std::is_same_v<U, uint64_t>
|| v.is_negative()
)
) return false;
int64_t signed_v = (v.is_negative() ? -1 : 1 ) * v.value;
if(
std::numeric_limits<U>::min() <= signed_v
&& std::numeric_limits<U>::max() >= signed_v
) return true;
return false;
} else return false;
} else if constexpr (
std::is_same_v<U, ieee754_hf>
|| std::is_same_v<U, float>
|| std::is_same_v<U, double>
) {
auto& v = contents.value<cbor_floating_point>();
switch(v.contents.type()) {
case cbor_floating_point::backing::alt<ieee754_hf>():
return std::is_same_v<U, ieee754_hf>;
case cbor_floating_point::backing::alt<float>():
return std::is_same_v<U, float> || std::is_same_v<U, ieee754_hf>;
case cbor_floating_point::backing::alt<double>():
return std::is_same_v<U, double> || std::is_same_v<U, float> || std::is_same_v<U, ieee754_hf>;
default:
return false;
}
} else {
return contents.is_a<U>();
}
}
template<typename U>
U get_value() {
gp_config::assertion(is_a<U>(), "can't convert value legally");
if constexpr (
std::is_same_v<U, uint8_t>
|| std::is_same_v<U, uint16_t>
|| std::is_same_v<U, uint32_t>
|| std::is_same_v<U, uint64_t>
|| std::is_same_v<U, int8_t>
|| std::is_same_v<U, int16_t>
|| std::is_same_v<U, int32_t>
|| std::is_same_v<U, int64_t>
) {
auto& v = contents.value<cbor_number>();
return (v.is_negative() ? -1 : 1 ) * v.value;
} else if constexpr (
std::is_same_v<U, ieee754_hf>
|| std::is_same_v<U, float>
|| std::is_same_v<U, double>
) {
auto& v = contents.value<cbor_floating_point>();
return v;
} else {
return contents.value<U>();
}
}
static gp::pair<cbor_value, gp::buffer<std::byte>::associated_iterator> decode(allocator& alloc, gp::buffer<std::byte> src) {
#define ERROR return {cbor_value{undefined_t{}, alloc}, src.begin()}
#define ERROR return {cbor_value{alloc}, src.begin()}
if(src.size()==0) ERROR;
auto discriminant = (cbor_type)(((uint8_t)*src.begin()) >> 5);
auto local = uint8_t(((uint8_t)*src.begin()) & 0b00011111);
@ -375,23 +513,23 @@ namespace gp {
}
static auto encode_float(buffer<std::byte> dest, cbor_floating_point& value) {
switch(value.type()) {
case cbor_floating_point::alt<ieee754_hf>():{
switch(value.contents.type()) {
case cbor_floating_point::backing::alt<ieee754_hf>():{
if(dest.size() < 3) return dest.begin();
dest[0] = std::byte(((uint8_t)cbor_type::oths << 5u) + (uint8_t)cbor_oths::word);
(dest.slice_start(3).slice_end(2).cast<gp::endian_wrapper<ieee754_hf, gp::endian::big>>())[0] = value.value<ieee754_hf>();
(dest.slice_start(3).slice_end(2).cast<gp::endian_wrapper<ieee754_hf, gp::endian::big>>())[0] = value.contents.value<ieee754_hf>();
return dest.begin()+3;
}
case cbor_floating_point::alt<float>():{
case cbor_floating_point::backing::alt<float>():{
if(dest.size() < 5) return dest.begin();
dest[0] = std::byte(((uint8_t)cbor_type::oths << 5u) + (uint8_t)cbor_oths::dword);
(dest.slice_start(5).slice_end(4).cast<gp::endian_wrapper<float, gp::endian::big>>())[0] = value.value<float>();
(dest.slice_start(5).slice_end(4).cast<gp::endian_wrapper<float, gp::endian::big>>())[0] = value.contents.value<float>();
return dest.begin()+5;
}
case cbor_floating_point::alt<double>():{
case cbor_floating_point::backing::alt<double>():{
if(dest.size() < 9) return dest.begin();
dest[0] = std::byte(((uint8_t)cbor_type::oths << 5u) + (uint8_t)cbor_oths::qword);
(dest.slice_start(9).slice_end(8).cast<gp::endian_wrapper<double, gp::endian::big>>())[0] = value.value<double>();
(dest.slice_start(9).slice_end(8).cast<gp::endian_wrapper<double, gp::endian::big>>())[0] = value.contents.value<double>();
return dest.begin()+9;
}
default: return dest.begin();

+ 35
- 2
tests/cbor_test.cpp ファイルの表示

@ -1,4 +1,5 @@
#include <gp/algorithm/foreach.hpp>
#include <gp/allocator/arena.hpp>
#include <gp/array.hpp>
#include <gp/enveloppe/cbor.hpp>
@ -10,8 +11,8 @@ struct cbor_test : public test_scaffold {
}
virtual int run() {
gp::array<char, 4096> store;
gp::arena alloc{&*storep">.begin(), storep">.size()};
k">auto store = std::make_unique<gp::array<char, 4096*4>>();
gp::arena alloc{&*storeo">->begin(), storeo">->size()};
using some_int = gp::fixed_variant<int, unsigned int, long long>;
{
@ -73,6 +74,14 @@ struct cbor_test : public test_scaffold {
gp_config::assertion(serialized.begin() != ret_it, "could not encode");
gp_config::assertion(serialized == serialized_manual, "data did not serialize correctly");
gp::fill(serialized,(std::byte)0);
auto decoded = gp::cbor_value::decode(alloc, serialized_manual.as_buffer());
ret_it = decoded.first.encode(serialized.as_buffer());
gp_config::assertion(serialized.begin() != ret_it, "could not encode");
gp_config::assertion(serialized == serialized_manual, "data did not serialize correctly");
}
{
gp::cbor_value data{alloc};
@ -87,6 +96,14 @@ struct cbor_test : public test_scaffold {
gp_config::assertion(serialized.begin() != ret_it, "could not encode");
gp_config::assertion(serialized == serialized_manual, "data did not serialize correctly");
gp::fill(serialized,(std::byte)0);
auto decoded = gp::cbor_value::decode(alloc, serialized_manual.as_buffer());
ret_it = decoded.first.encode(serialized.as_buffer());
gp_config::assertion(serialized.begin() != ret_it, "could not encode");
gp_config::assertion(serialized == serialized_manual, "data did not serialize correctly");
}
{
gp::cbor_value data{alloc};
@ -105,6 +122,14 @@ struct cbor_test : public test_scaffold {
gp_config::assertion(serialized.begin() != ret_it, "could not encode");
gp_config::assertion(serialized == serialized_manual, "data did not serialize correctly");
gp::fill(serialized,(std::byte)0);
auto decoded = gp::cbor_value::decode(alloc, serialized_manual.as_buffer());
ret_it = decoded.first.encode(serialized.as_buffer());
gp_config::assertion(serialized.begin() != ret_it, "could not encode");
gp_config::assertion(serialized == serialized_manual, "data did not serialize correctly");
}
{
gp::vector<std::byte> str{alloc};
@ -128,6 +153,14 @@ struct cbor_test : public test_scaffold {
gp_config::assertion(serialized.begin() != ret_it, "could not encode");
gp_config::assertion(serialized == serialized_manual, "data did not serialize correctly");
gp::fill(serialized,(std::byte)0);
auto decoded = gp::cbor_value::decode(alloc, serialized_manual.as_buffer());
ret_it = decoded.first.encode(serialized.as_buffer());
gp_config::assertion(serialized.begin() != ret_it, "could not encode");
gp_config::assertion(serialized == serialized_manual, "data did not serialize correctly");
}
return 0;

読み込み中…
キャンセル
保存