|
@ -80,13 +80,68 @@ namespace gp { |
|
|
uint16_t sign : 1; |
|
|
uint16_t sign : 1; |
|
|
uint16_t exponent : 5; |
|
|
uint16_t exponent : 5; |
|
|
uint16_t mantissa : 10; |
|
|
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 {}; |
|
|
struct undefined_t final {}; |
|
|
|
|
|
|
|
@ -109,7 +164,7 @@ namespace gp { |
|
|
public: |
|
|
public: |
|
|
|
|
|
|
|
|
cbor_value(allocator& alloc_v) |
|
|
cbor_value(allocator& alloc_v) |
|
|
: contents(n">cbor_composite<cbor_value>(undefined_t{})) |
|
|
|
|
|
|
|
|
: contents() |
|
|
, alloc(alloc_v) |
|
|
, alloc(alloc_v) |
|
|
{} |
|
|
{} |
|
|
|
|
|
|
|
@ -213,8 +268,91 @@ namespace gp { |
|
|
#undef ERROR
|
|
|
#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) { |
|
|
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; |
|
|
if(src.size()==0) ERROR; |
|
|
auto discriminant = (cbor_type)(((uint8_t)*src.begin()) >> 5); |
|
|
auto discriminant = (cbor_type)(((uint8_t)*src.begin()) >> 5); |
|
|
auto local = uint8_t(((uint8_t)*src.begin()) & 0b00011111); |
|
|
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) { |
|
|
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(); |
|
|
if(dest.size() < 3) return dest.begin(); |
|
|
dest[0] = std::byte(((uint8_t)cbor_type::oths << 5u) + (uint8_t)cbor_oths::word); |
|
|
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; |
|
|
return dest.begin()+3; |
|
|
} |
|
|
} |
|
|
case cbor_floating_point::alt<float>():{ |
|
|
|
|
|
|
|
|
case cbor_floating_point::backing::alt<float>():{ |
|
|
if(dest.size() < 5) return dest.begin(); |
|
|
if(dest.size() < 5) return dest.begin(); |
|
|
dest[0] = std::byte(((uint8_t)cbor_type::oths << 5u) + (uint8_t)cbor_oths::dword); |
|
|
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; |
|
|
return dest.begin()+5; |
|
|
} |
|
|
} |
|
|
case cbor_floating_point::alt<double>():{ |
|
|
|
|
|
|
|
|
case cbor_floating_point::backing::alt<double>():{ |
|
|
if(dest.size() < 9) return dest.begin(); |
|
|
if(dest.size() < 9) return dest.begin(); |
|
|
dest[0] = std::byte(((uint8_t)cbor_type::oths << 5u) + (uint8_t)cbor_oths::qword); |
|
|
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; |
|
|
return dest.begin()+9; |
|
|
} |
|
|
} |
|
|
default: return dest.begin(); |
|
|
default: return dest.begin(); |
|
|