LCOV - code coverage report
Current view: top level - core/data - SPDataCbor.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 111 139 79.9 %
Date: 2024-05-12 00:16:13 Functions: 45 75 60.0 %

          Line data    Source code
       1             : /**
       2             : Copyright (c) 2016-2022 Roman Katuntsev <sbkarr@stappler.org>
       3             : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
       4             : 
       5             : Permission is hereby granted, free of charge, to any person obtaining a copy
       6             : of this software and associated documentation files (the "Software"), to deal
       7             : in the Software without restriction, including without limitation the rights
       8             : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       9             : copies of the Software, and to permit persons to whom the Software is
      10             : furnished to do so, subject to the following conditions:
      11             : 
      12             : The above copyright notice and this permission notice shall be included in
      13             : all copies or substantial portions of the Software.
      14             : 
      15             : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      16             : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      17             : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      18             : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      19             : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      20             : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      21             : THE SOFTWARE.
      22             : **/
      23             : 
      24             : #ifndef STAPPLER_DATA_SPDATACBOR_H_
      25             : #define STAPPLER_DATA_SPDATACBOR_H_
      26             : 
      27             : #include "SPBytesView.h"
      28             : #include "SPHalfFloat.h"
      29             : 
      30             : namespace STAPPLER_VERSIONIZED stappler::data::cbor {
      31             : 
      32             : enum class MajorType : uint8_t {
      33             :         Unsigned        = 0,
      34             :         Negative        = 1,
      35             :         ByteString      = 2,
      36             :         CharString      = 3,
      37             :         Array           = 4,
      38             :         Map                     = 5,
      39             :         Tag                     = 6,
      40             :         Simple          = 7
      41             : };
      42             : 
      43             : enum class SimpleValue : uint8_t {
      44             :         False                           = 20,
      45             :         True                            = 21,
      46             :         Null                            = 22,
      47             :         Undefined                       = 23,
      48             : };
      49             : 
      50             : enum class Flags : uint8_t {
      51             :         Null = 0,
      52             :         Interrupt = 0xFF,
      53             : 
      54             :         MajorTypeShift = 5, // bitshift for major type id
      55             : 
      56             :         MajorTypeMask = 7, // mask for major type id
      57             :         MajorTypeMaskEncoded = 7 << 5, // mask for major type id
      58             : 
      59             :         AdditionalInfoMask = 31, // mask for additional info
      60             : 
      61             :         MaxAdditionalNumber = 24,
      62             :         AdditionalNumber8Bit = 24,
      63             :         AdditionalNumber16Bit = 25,
      64             :         AdditionalNumber32Bit = 26,
      65             :         AdditionalNumber64Bit = 27,
      66             : 
      67             :         Simple8Bit = 24,
      68             :         AdditionalFloat16Bit = 25,
      69             :         AdditionalFloat32Bit = 26,
      70             :         AdditionalFloat64Bit = 27,
      71             : 
      72             :         Unassigned1 = 28,
      73             :         Unassigned2 = 29,
      74             :         Unassigned3 = 30,
      75             : 
      76             :         UndefinedLength = 31,
      77             : };
      78             : 
      79             : enum class MajorTypeEncoded : uint8_t {
      80             :         Unsigned        = toInt(MajorType::Unsigned) << toInt(Flags::MajorTypeShift),
      81             :         Negative        = toInt(MajorType::Negative) << toInt(Flags::MajorTypeShift),
      82             :         ByteString      = toInt(MajorType::ByteString) << toInt(Flags::MajorTypeShift),
      83             :         CharString      = toInt(MajorType::CharString) << toInt(Flags::MajorTypeShift),
      84             :         Array           = toInt(MajorType::Array) << toInt(Flags::MajorTypeShift),
      85             :         Map                     = toInt(MajorType::Map) << toInt(Flags::MajorTypeShift),
      86             :         Tag                     = toInt(MajorType::Tag) << toInt(Flags::MajorTypeShift),
      87             :         Simple          = toInt(MajorType::Simple) << toInt(Flags::MajorTypeShift)
      88             : };
      89             : 
      90             : enum class Tag : uint16_t {
      91             :         DateTime = 0,   // string - Standard date/time string
      92             :         EpochTime = 1,  // multiple - Epoch-based date/time
      93             :         PositiveBignum = 2, // byte string
      94             :         NegativeBignum = 3, // byte string
      95             :         DecimalFraction = 4, // array - Decimal fraction;
      96             :         BigFloat = 5, // array
      97             :         /* 6-20 - Unassigned */
      98             :         ExpectedBase64Url = 21, // multiple - Expected conversion to base64url encoding;
      99             :         ExpectedBase64 = 22, // multiple - Expected conversion to base64 encoding;
     100             :         ExpectedBase16 = 23, // multiple - Expected conversion to base16 encoding;
     101             :         EmbeddedCbor = 24, // byte string - Encoded CBOR data item;
     102             : 
     103             :         StringReference = 25, // unsigned integer - reference the nth previously seen string
     104             :         // [http://cbor.schmorp.de/stringref][Marc_A._Lehmann]
     105             : 
     106             :         SerializedPerl = 26, // array - Serialised Perl object with classname and constructor arguments
     107             :         // [http://cbor.schmorp.de/perl-object][Marc_A._Lehmann]
     108             : 
     109             :         SerializedObject = 27, // array - Serialised language-independent object with type name and constructor arguments
     110             :         // [http://cbor.schmorp.de/generic-object][Marc_A._Lehmann]
     111             : 
     112             :         SharedValue = 28, // multiple - mark value as (potentially) shared
     113             :         // [http://cbor.schmorp.de/value-sharing][Marc_A._Lehmann]
     114             : 
     115             :         ValueReference = 29, // unsigned integer - reference nth marked value
     116             :         // [http://cbor.schmorp.de/value-sharing][Marc_A._Lehmann]
     117             : 
     118             :         RationalNumber = 30, // array - Rational number
     119             :         // [http://peteroupc.github.io/CBOR/rational.html][Peter_Occil]
     120             : 
     121             :         /* 31 - Unassigned */
     122             :         HintHintUri = 32, // UTF-8 string;
     123             :         HintBase64Url = 33, // UTF-8 string;
     124             :         HintBase64 = 34, // UTF-8 string;
     125             :         HintRegularExpression = 35, // UTF-8 string;
     126             :         HintMimeMessage = 36, // UTF-8 string;
     127             : 
     128             :         BinaryUuid = 37, // byte string - Binary UUID [RFC4122] section 4.1.2;
     129             :         // [https://github.com/lucas-clemente/cbor-specs/blob/master/uuid.md][Lucas_Clemente]
     130             : 
     131             :         LanguageTaggedString = 38, // byte string - [http://peteroupc.github.io/CBOR/langtags.html][Peter_Occil]
     132             :         Identifier = 39, // multiple - [https://github.com/lucas-clemente/cbor-specs/blob/master/id.md][Lucas_Clemente]
     133             : 
     134             :         /* 40-255 - Unassigned */
     135             : 
     136             :         StringMark = 256, // multiple - mark value as having string references
     137             :         // [http://cbor.schmorp.de/stringref][Marc_A._Lehmann]
     138             : 
     139             :         BinaryMimeMessage = 257, // byte string - Binary MIME message
     140             :         // [http://peteroupc.github.io/CBOR/binarymime.html][Peter_Occil]
     141             : 
     142             :         /* 258-263 - Unassigned */
     143             :         DecimalFractionFixed = 264, // array - Decimal fraction with arbitrary exponent
     144             :         // [http://peteroupc.github.io/CBOR/bigfrac.html][Peter_Occil]
     145             : 
     146             :         BigFloatFixed = 265, // array - Bigfloat with arbitrary exponent
     147             :         // [http://peteroupc.github.io/CBOR/bigfrac.html][Peter_Occil]
     148             : 
     149             :         /* 266-22097 - Unassigned */
     150             :         HintIndirection = 22098, // multiple - hint that indicates an additional level of indirection
     151             :         // [http://cbor.schmorp.de/indirection][Marc_A._Lehmann]
     152             : 
     153             :         /* 22099-55798 - Unassigned */
     154             : 
     155             :         CborMagick = 55799, // multiple - Self-describe CBOR;
     156             :         /* 55800-18446744073709551615 - Unassigned */
     157             : };
     158             : 
     159             : constexpr MajorTypeEncoded operator << (MajorType t, Flags f) {
     160             :         return MajorTypeEncoded(toInt(t) << toInt(f));
     161             : }
     162             : 
     163             : constexpr bool operator == (uint8_t v, MajorTypeEncoded enc) {
     164             :         return (v & toInt(Flags::MajorTypeMaskEncoded)) == toInt(enc);
     165             : }
     166             : 
     167             : constexpr bool operator == (uint8_t v, MajorType t) {
     168             :         return (v & toInt(Flags::MajorTypeMaskEncoded)) == (t << Flags::MajorTypeShift);
     169             : }
     170             : 
     171             : constexpr bool operator == (uint8_t v, Flags f) {
     172             :         return (v & toInt(Flags::AdditionalInfoMask)) == (toInt(f));
     173             : }
     174             : 
     175             : constexpr MajorType type(uint8_t v) {
     176             :         switch (MajorTypeEncoded(v & 0b11100000)) {
     177             :         case MajorTypeEncoded::Unsigned: return MajorType::Unsigned; break;
     178             :         case MajorTypeEncoded::Negative: return MajorType::Negative; break;
     179             :         case MajorTypeEncoded::ByteString: return MajorType::ByteString; break;
     180             :         case MajorTypeEncoded::CharString: return MajorType::CharString; break;
     181             :         case MajorTypeEncoded::Array: return MajorType::Array; break;
     182             :         case MajorTypeEncoded::Map: return MajorType::Map; break;
     183             :         case MajorTypeEncoded::Tag: return MajorType::Tag; break;
     184             :         case MajorTypeEncoded::Simple: return MajorType::Simple; break;
     185             :         }
     186             :         return MajorType::Unsigned;
     187             : }
     188             : 
     189             : constexpr uint8_t data(uint8_t v) {
     190             :         return v & toInt(Flags::AdditionalInfoMask);
     191             : }
     192             : 
     193             : constexpr Flags flags(uint8_t v) {
     194             :         return Flags(v & toInt(Flags::AdditionalInfoMask));
     195             : }
     196             : 
     197             : // writer: some class with implementation of:
     198             : //  emplace(uint8_t byte)
     199             : //  emplace(uint8_t *bytes, size_t nbytes)
     200             : 
     201             : template <class Writer>
     202       16600 : inline void _writeId(Writer &w) {
     203             :         // write CBOR id ( 0xd9d9f7 )
     204       16600 :         w.emplace(0xd9);
     205       16600 :         w.emplace(0xd9);
     206       16600 :         w.emplace(0xf7);
     207       16600 : }
     208             : 
     209             : template <class Writer, class T>
     210     4959661 : inline void _writeNumeric(Writer &w, T value, MajorTypeEncoded m, Flags f) {
     211     4959661 :         value = byteorder::HostToNetwork(value);
     212     4959661 :         w.emplace(toInt(m) | toInt(f));
     213     4959661 :         w.emplace((uint8_t *)&value, sizeof(T));
     214     4959661 : }
     215             : 
     216             : template <class Writer>
     217    22549456 : inline void _writeInt(Writer &w, uint64_t value, MajorTypeEncoded type) {
     218    22549456 :         if (value < toInt(Flags::MaxAdditionalNumber)) {
     219    19335379 :                 w.emplace(toInt(type) | (uint8_t)value);
     220     3214077 :         } else if (value <= maxOf<uint8_t>()) {
     221     1539684 :                 w.emplace(toInt(type) | toInt(Flags::AdditionalNumber8Bit));
     222     1539684 :                 w.emplace((uint8_t)value);
     223     1674393 :         } else if (value <= maxOf<uint16_t>()) {
     224     1177843 :                 _writeNumeric(w, (uint16_t)value, type, Flags::AdditionalNumber16Bit);
     225      496550 :         } else if (value <= maxOf<uint32_t>()) {
     226      496325 :                 _writeNumeric(w, (uint32_t)value, type, Flags::AdditionalNumber32Bit);
     227         225 :         } else if (value <= maxOf<uint64_t>()) {
     228         225 :                 _writeNumeric(w, (uint64_t)value, type, Flags::AdditionalNumber64Bit);
     229             :         }
     230    22549456 : }
     231             : 
     232             : template <class Writer>
     233           0 : inline void _writeFloatNaN(Writer &w) {
     234           0 :         _writeNumeric(w, halffloat::nan(), MajorTypeEncoded::Simple, Flags::AdditionalFloat16Bit);  // write nan from IEEE 754
     235           0 : }
     236             : 
     237             : template <class Writer>
     238           0 : inline void _writeFloatPositiveInf(Writer &w) {
     239           0 :         _writeNumeric(w, halffloat::posinf(), MajorTypeEncoded::Simple, Flags::AdditionalFloat16Bit);  // write +inf from IEEE 754
     240           0 : }
     241             : 
     242             : template <class Writer>
     243           0 : inline void _writeFloatNegativeInf(Writer &w) {
     244           0 :         _writeNumeric(w, halffloat::neginf(), MajorTypeEncoded::Simple, Flags::AdditionalFloat16Bit);  // write -inf from IEEE 754
     245           0 : }
     246             : 
     247             : template <class Writer>
     248      857168 : inline void _writeFloat16(Writer &w, uint16_t value) {
     249      857168 :         _writeNumeric(w, value, MajorTypeEncoded::Simple, Flags::AdditionalFloat16Bit);
     250      857168 : }
     251             : 
     252             : template <class Writer>
     253     2428100 : inline void _writeFloat32(Writer &w, float value) {
     254     2428100 :         _writeNumeric(w, value, MajorTypeEncoded::Simple, Flags::AdditionalFloat32Bit);
     255     2428100 : }
     256             : 
     257             : template <class Writer>
     258           0 : inline void _writeFloat64(Writer &w, double value) {
     259           0 :         _writeNumeric(w, value, MajorTypeEncoded::Simple, Flags::AdditionalFloat64Bit);
     260           0 : }
     261             : 
     262             : template <class Writer>
     263      497700 : inline void _writeArrayStart(Writer &w, size_t len) {
     264      497700 :         _writeInt(w, len, MajorTypeEncoded::Array);
     265      497700 : }
     266             : 
     267             : template <class Writer>
     268     1377209 : inline void _writeMapStart(Writer &w, size_t len) {
     269     1377209 :         _writeInt(w, len, MajorTypeEncoded::Map);
     270     1377209 : }
     271             : 
     272             : template <class Writer>
     273        3825 : inline void _writeNull(Writer &w, nullptr_t = nullptr) {
     274        3825 :         w.emplace(toInt(MajorTypeEncoded::Simple) | toInt(SimpleValue::Null));
     275        3825 : }
     276             : 
     277             : template <class Writer>
     278      921250 : inline void _writeBool(Writer &w, bool value) {
     279      921250 :         w.emplace(toInt(MajorTypeEncoded::Simple) | toInt(value ? SimpleValue::True : SimpleValue::False));
     280      921250 : }
     281             : 
     282             : template <class Writer>
     283     6755000 : inline void _writeInt(Writer &w, int64_t value) {
     284     6755000 :         if (value == 0) {
     285      330575 :                 w.emplace(toInt(MajorTypeEncoded::Unsigned));
     286             :         } else {
     287     6424425 :                 if (value > 0) {
     288     6418975 :                         _writeInt(w, (uint64_t)value, MajorTypeEncoded::Unsigned);
     289             :                 } else {
     290        5450 :                         _writeInt(w, (uint64_t)std::abs(value + 1), MajorTypeEncoded::Negative);
     291             :                 }
     292             :         }
     293     6755000 : }
     294             : 
     295             : template <class Writer>
     296     3285268 : inline void _writeFloat(Writer &w, double value) {
     297             :         // calculate optimal size to store value
     298             :         // some code from https://github.com/cabo/cn-cbor/blob/master/src/cn-encoder.c
     299     3285268 :         float fvalue = value;
     300     3285268 :         if (isnan(value)) { // NaN -- we always write a half NaN
     301           0 :                 _writeFloatNaN(w);
     302     3285268 :         } else if (value == NumericLimits<double>::infinity()) {
     303           0 :                 _writeFloatPositiveInf(w);
     304     3285268 :         } else if (value == - NumericLimits<double>::infinity()) {
     305           0 :                 _writeFloatNegativeInf(w);
     306     3285268 :         } else if (fvalue == value) { // 32 bits is enough and we aren't NaN
     307             :                 union {
     308             :                         float f;
     309             :                         uint32_t u;
     310             :                 } u32;
     311             : 
     312     3285268 :                 u32.f = fvalue;
     313     3285268 :                 if ((u32.u & 0x1FFF) == 0) { // worth trying half
     314      857168 :                         int s16 = (u32.u >> 16) & 0x8000;
     315      857168 :                         int exp = (u32.u >> 23) & 0xff;
     316      857168 :                         int mant = u32.u & 0x7fffff;
     317      857168 :                         if (exp == 0 && mant == 0) {
     318             :                                 ; // 0.0, -0.0
     319      857168 :                         } else if (exp >= 113 && exp <= 142) { // normalized
     320      857168 :                                 s16 += ((exp - 112) << 10) + (mant >> 13);
     321           0 :                         } else if (exp >= 103 && exp < 113) { // denorm, exp16 = 0
     322           0 :                                 if (mant & ((1 << (126 - exp)) - 1)) {
     323           0 :                                         _writeFloat32(w, fvalue);
     324           0 :                                         return;
     325             :                                 }
     326           0 :                                 s16 += ((mant + 0x800000) >> (126 - exp));
     327           0 :                         } else if (exp == 255 && mant == 0) { // Inf
     328           0 :                                 s16 += 0x7c00;
     329             :                         } else {
     330           0 :                                 _writeFloat32(w, fvalue);
     331           0 :                                 return;
     332             :                         }
     333             : 
     334      857168 :                         _writeFloat16(w, s16);
     335             :                 } else {
     336     2428100 :                         _writeFloat32(w, fvalue);
     337             :                 }
     338             :         } else  {
     339           0 :                 _writeFloat64(w, value);
     340             :         }
     341             : }
     342             : 
     343             : template <class Writer>
     344    13824029 : inline void _writeString(Writer &w, const StringView &str) {
     345    13824029 :         auto size = str.size();
     346    13824029 :         _writeInt(w, size, MajorTypeEncoded::CharString);
     347    13824029 :         w.emplace((uint8_t *)str.data(), size);
     348    13824029 : }
     349             : 
     350             : template <class Writer>
     351      426093 : inline void _writeBytes(Writer &w, const BytesViewTemplate<Endian::Network> &data) {
     352      426093 :         auto size = data.size();
     353      426093 :         _writeInt(w, size, MajorTypeEncoded::ByteString);
     354      426093 :         w.emplace(data.data(), size);
     355      426093 : }
     356             : 
     357             : template <class Writer>
     358     6471200 : inline void _writeNumber(Writer &w, float n) {
     359     6471200 :         if (n == roundf(n)) {
     360     3613350 :                 _writeInt(w, int64_t(n));
     361             :         } else {
     362     2857850 :                 _writeFloat(w, n);
     363             :         }
     364     6471200 : };
     365             : 
     366    56074458 : inline uint64_t _readIntValue(BytesViewTemplate<Endian::Network> &r, uint8_t type) {
     367    56074458 :         if (type < toInt(Flags::MaxAdditionalNumber)) {
     368    53323111 :                 return type;
     369     2751345 :         } else if (type == toInt(Flags::AdditionalNumber8Bit)) {
     370     1719790 :                 return r.readUnsigned();
     371     1031574 :         } else if (type == toInt(Flags::AdditionalNumber16Bit)) {
     372      790228 :                 return r.readUnsigned16();
     373      241348 :         } else if (type == toInt(Flags::AdditionalNumber32Bit)) {
     374      240475 :                 return r.readUnsigned32();
     375         875 :         } else if (type == toInt(Flags::AdditionalNumber64Bit)) {
     376         775 :                 return r.readUnsigned64();
     377             :         } else {
     378         100 :                 return 0;
     379             :         }
     380             : }
     381             : 
     382    19435932 : inline int64_t _readInt(BytesViewTemplate<Endian::Network> &r) {
     383    19435932 :         uint8_t type = r.readUnsigned();
     384    19435932 :         MajorTypeEncoded majorType = (MajorTypeEncoded)(type & toInt(Flags::MajorTypeMaskEncoded));;
     385    19435932 :         type = type & toInt(Flags::AdditionalInfoMask);
     386             : 
     387    19435932 :         switch(majorType) {
     388    19435932 :         case MajorTypeEncoded::Unsigned: return _readIntValue(r, type); break;
     389           0 :         case MajorTypeEncoded::Negative: return (-1 - _readIntValue(r, type)); break;
     390             :         default: break;
     391             :         }
     392             :         return 0;
     393             : }
     394             : 
     395    49319739 : inline double _readNumber(BytesViewTemplate<Endian::Network> &r) {
     396    49319739 :         uint8_t type = r.readUnsigned();
     397    49319739 :         MajorTypeEncoded majorType = (MajorTypeEncoded)(type & toInt(Flags::MajorTypeMaskEncoded));;
     398    49319739 :         type = type & toInt(Flags::AdditionalInfoMask);
     399             : 
     400    49319739 :         switch(majorType) {
     401    27462952 :         case MajorTypeEncoded::Unsigned:
     402    27462952 :                 return _readIntValue(r, type);
     403             :                 break;
     404       15990 :         case MajorTypeEncoded::Negative:
     405       15990 :                 return (-1 - static_cast<int64_t>(_readIntValue(r, type)));
     406             :                 break;
     407    21840797 :         case MajorTypeEncoded::Simple:
     408    21840797 :                 if (type == toInt(Flags::AdditionalFloat16Bit)) {
     409     3288149 :                         return r.readFloat16();
     410    18552648 :                 } else if (type == toInt(Flags::AdditionalFloat32Bit)) {
     411    18552648 :                         return r.readFloat32();
     412           0 :                 } else if (type == toInt(Flags::AdditionalFloat64Bit)) {
     413           0 :                         return r.readFloat64();
     414             :                 }
     415             :                 break;
     416             :         default: break;
     417             :         }
     418             :         return 0.0;
     419             : }
     420             : 
     421             : }
     422             : 
     423             : #endif /* STAPPLER_DATA_SPDATACBOR_H_ */

Generated by: LCOV version 1.14