✨ CBOR support for half-precision floats
This commit is contained in:
		
							parent
							
								
									17c9b17a7e
								
							
						
					
					
						commit
						b7e0c12966
					
				
					 3 changed files with 62 additions and 10 deletions
				
			
		
							
								
								
									
										25
									
								
								src/json.hpp
									
										
									
									
									
								
							
							
						
						
									
										25
									
								
								src/json.hpp
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -34,7 +34,7 @@ SOFTWARE.
 | 
			
		|||
#include <cassert> // assert
 | 
			
		||||
#include <cctype> // isdigit
 | 
			
		||||
#include <ciso646> // and, not, or
 | 
			
		||||
#include <cmath> // isfinite, signbit
 | 
			
		||||
#include <cmath> // isfinite, ldexp, signbit
 | 
			
		||||
#include <cstddef> // nullptr_t, ptrdiff_t, size_t
 | 
			
		||||
#include <cstdint> // int64_t, uint64_t
 | 
			
		||||
#include <cstdlib> // strtod, strtof, strtold, strtoul
 | 
			
		||||
| 
						 | 
				
			
			@ -7169,6 +7169,29 @@ class basic_json
 | 
			
		|||
        {
 | 
			
		||||
            return value_t::null;
 | 
			
		||||
        }
 | 
			
		||||
        else if (v[current_idx] == 0xf9) // Half-Precision Float
 | 
			
		||||
        {
 | 
			
		||||
            idx += 2; // skip two content bytes
 | 
			
		||||
 | 
			
		||||
            // code from RFC 7049, Appendix D
 | 
			
		||||
            const int half = (v[current_idx + 1] << 8) + v[current_idx + 2];
 | 
			
		||||
            const int exp = (half >> 10) & 0x1f;
 | 
			
		||||
            const int mant = half & 0x3ff;
 | 
			
		||||
            double val;
 | 
			
		||||
            if (exp == 0)
 | 
			
		||||
            {
 | 
			
		||||
                val = std::ldexp(mant, -24);
 | 
			
		||||
            }
 | 
			
		||||
            else if (exp != 31)
 | 
			
		||||
            {
 | 
			
		||||
                val = std::ldexp(mant + 1024, exp - 25);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                val = mant == 0 ? INFINITY : NAN;
 | 
			
		||||
            }
 | 
			
		||||
            return half & 0x8000 ? -val : val;
 | 
			
		||||
        }
 | 
			
		||||
        else if (v[current_idx] == 0xfa) // Single-Precision Float
 | 
			
		||||
        {
 | 
			
		||||
            // copy bytes in reverse order into the float variable
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,7 +34,7 @@ SOFTWARE.
 | 
			
		|||
#include <cassert> // assert
 | 
			
		||||
#include <cctype> // isdigit
 | 
			
		||||
#include <ciso646> // and, not, or
 | 
			
		||||
#include <cmath> // isfinite, signbit
 | 
			
		||||
#include <cmath> // isfinite, ldexp, signbit
 | 
			
		||||
#include <cstddef> // nullptr_t, ptrdiff_t, size_t
 | 
			
		||||
#include <cstdint> // int64_t, uint64_t
 | 
			
		||||
#include <cstdlib> // strtod, strtof, strtold, strtoul
 | 
			
		||||
| 
						 | 
				
			
			@ -7169,6 +7169,35 @@ class basic_json
 | 
			
		|||
        {
 | 
			
		||||
            return value_t::null;
 | 
			
		||||
        }
 | 
			
		||||
        else if (v[current_idx] == 0xf9) // Half-Precision Float
 | 
			
		||||
        {
 | 
			
		||||
            idx += 2; // skip two content bytes
 | 
			
		||||
 | 
			
		||||
            // code from RFC 7049, Appendix D, Figure 3:
 | 
			
		||||
            // As half-precision floating-point numbers were only added to IEEE
 | 
			
		||||
            // 754 in 2008, today's programming platforms often still only have
 | 
			
		||||
            // limited support for them. It is very easy to include at least
 | 
			
		||||
            // decoding support for them even without such support. An example
 | 
			
		||||
            // of a small decoder for half-precision floating-point numbers in
 | 
			
		||||
            // the C language is shown in Figure 3.
 | 
			
		||||
            const int half = (v[current_idx + 1] << 8) + v[current_idx + 2];
 | 
			
		||||
            const int exp = (half >> 10) & 0x1f;
 | 
			
		||||
            const int mant = half & 0x3ff;
 | 
			
		||||
            double val;
 | 
			
		||||
            if (exp == 0)
 | 
			
		||||
            {
 | 
			
		||||
                val = std::ldexp(mant, -24);
 | 
			
		||||
            }
 | 
			
		||||
            else if (exp != 31)
 | 
			
		||||
            {
 | 
			
		||||
                val = std::ldexp(mant + 1024, exp - 25);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                val = mant == 0 ? INFINITY : NAN;
 | 
			
		||||
            }
 | 
			
		||||
            return half & 0x8000 ? -val : val;
 | 
			
		||||
        }
 | 
			
		||||
        else if (v[current_idx] == 0xfa) // Single-Precision Float
 | 
			
		||||
        {
 | 
			
		||||
            // copy bytes in reverse order into the float variable
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1102,26 +1102,26 @@ TEST_CASE("examples from RFC 7049 Appendix A")
 | 
			
		|||
 | 
			
		||||
        // half-precision float
 | 
			
		||||
        //CHECK(json::to_cbor(json::parse("0.0")) == std::vector<uint8_t>({0xf9, 0x00, 0x00}));
 | 
			
		||||
        //CHECK(json::parse("0.0") == json::from_cbor(std::vector<uint8_t>({0xf9, 0x00, 0x00})));
 | 
			
		||||
        CHECK(json::parse("0.0") == json::from_cbor(std::vector<uint8_t>({0xf9, 0x00, 0x00})));
 | 
			
		||||
 | 
			
		||||
        // half-precision float
 | 
			
		||||
        //CHECK(json::to_cbor(json::parse("-0.0")) == std::vector<uint8_t>({0xf9, 0x80, 0x00}));
 | 
			
		||||
        //CHECK(json::parse("-0.0") == json::from_cbor(std::vector<uint8_t>({0xf9, 0x80, 0x00})));
 | 
			
		||||
        CHECK(json::parse("-0.0") == json::from_cbor(std::vector<uint8_t>({0xf9, 0x80, 0x00})));
 | 
			
		||||
 | 
			
		||||
        // half-precision float
 | 
			
		||||
        //CHECK(json::to_cbor(json::parse("1.0")) == std::vector<uint8_t>({0xf9, 0x3c, 0x00}));
 | 
			
		||||
        //CHECK(json::parse("1.0") == json::from_cbor(std::vector<uint8_t>({0xf9, 0x3c, 0x00})));
 | 
			
		||||
        CHECK(json::parse("1.0") == json::from_cbor(std::vector<uint8_t>({0xf9, 0x3c, 0x00})));
 | 
			
		||||
 | 
			
		||||
        CHECK(json::to_cbor(json::parse("1.1")) == std::vector<uint8_t>({0xfb, 0x3f, 0xf1, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a}));
 | 
			
		||||
        CHECK(json::parse("1.1") == json::from_cbor(std::vector<uint8_t>({0xfb, 0x3f, 0xf1, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a})));
 | 
			
		||||
 | 
			
		||||
        // half-precision float
 | 
			
		||||
        //CHECK(json::to_cbor(json::parse("1.5")) == std::vector<uint8_t>({0xf9, 0x3e, 0x00}));
 | 
			
		||||
        //CHECK(json::parse("1.5") == json::from_cbor(std::vector<uint8_t>({0xf9, 0x3e, 0x00})));
 | 
			
		||||
        CHECK(json::parse("1.5") == json::from_cbor(std::vector<uint8_t>({0xf9, 0x3e, 0x00})));
 | 
			
		||||
 | 
			
		||||
        // half-precision float
 | 
			
		||||
        //CHECK(json::to_cbor(json::parse("65504.0")) == std::vector<uint8_t>({0xf9, 0x7b, 0xff}));
 | 
			
		||||
        //CHECK(json::parse("65504.0") == json::from_cbor(std::vector<uint8_t>({0xf9, 0x7b, 0xff})));
 | 
			
		||||
        CHECK(json::parse("65504.0") == json::from_cbor(std::vector<uint8_t>({0xf9, 0x7b, 0xff})));
 | 
			
		||||
 | 
			
		||||
        //CHECK(json::to_cbor(json::parse("100000.0")) == std::vector<uint8_t>({0xfa, 0x47, 0xc3, 0x50, 0x00}));
 | 
			
		||||
        CHECK(json::parse("100000.0") == json::from_cbor(std::vector<uint8_t>({0xfa, 0x47, 0xc3, 0x50, 0x00})));
 | 
			
		||||
| 
						 | 
				
			
			@ -1134,15 +1134,15 @@ TEST_CASE("examples from RFC 7049 Appendix A")
 | 
			
		|||
 | 
			
		||||
        // half-precision float
 | 
			
		||||
        //CHECK(json::to_cbor(json::parse("5.960464477539063e-8")) == std::vector<uint8_t>({0xf9, 0x00, 0x01}));
 | 
			
		||||
        //CHECK(json::parse("-4.0") == json::from_cbor(std::vector<uint8_t>({0xf9, 0xc4, 0x00})));
 | 
			
		||||
        CHECK(json::parse("-4.0") == json::from_cbor(std::vector<uint8_t>({0xf9, 0xc4, 0x00})));
 | 
			
		||||
 | 
			
		||||
        // half-precision float
 | 
			
		||||
        //CHECK(json::to_cbor(json::parse("0.00006103515625")) == std::vector<uint8_t>({0xf9, 0x04, 0x00}));
 | 
			
		||||
        //CHECK(json::parse("-4.0") == json::from_cbor(std::vector<uint8_t>({0xf9, 0xc4, 0x00})));
 | 
			
		||||
        CHECK(json::parse("-4.0") == json::from_cbor(std::vector<uint8_t>({0xf9, 0xc4, 0x00})));
 | 
			
		||||
 | 
			
		||||
        // half-precision float
 | 
			
		||||
        //CHECK(json::to_cbor(json::parse("-4.0")) == std::vector<uint8_t>({0xf9, 0xc4, 0x00}));
 | 
			
		||||
        //CHECK(json::parse("-4.0") == json::from_cbor(std::vector<uint8_t>({0xf9, 0xc4, 0x00})));
 | 
			
		||||
        CHECK(json::parse("-4.0") == json::from_cbor(std::vector<uint8_t>({0xf9, 0xc4, 0x00})));
 | 
			
		||||
 | 
			
		||||
        CHECK(json::to_cbor(json::parse("-4.1")) == std::vector<uint8_t>({0xfb, 0xc0, 0x10, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66}));
 | 
			
		||||
        CHECK(json::parse("-4.1") == json::from_cbor(std::vector<uint8_t>({0xfb, 0xc0, 0x10, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66})));
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue