LCOV - code coverage report
Current view: top level - core/data - SPDataDecodeJson.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 129 146 88.4 %
Date: 2024-05-12 00:16:13 Functions: 21 21 100.0 %

          Line data    Source code
       1             : /**
       2             : Copyright (c) 2017-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_SPDATADECODEJSON_H_
      25             : #define STAPPLER_DATA_SPDATADECODEJSON_H_
      26             : 
      27             : #include "SPDataValue.h"
      28             : 
      29             : namespace STAPPLER_VERSIONIZED stappler::data::json {
      30             : 
      31     5091150 : inline StringView decodeNumber(StringView &r, bool &isFloat) {
      32     5091150 :         auto tmp = r;
      33     5091150 :         if (r.is('-')) {
      34       16275 :                 ++ r;
      35             :         }
      36     5091150 :         r.skipChars<StringView::CharGroup<CharGroupId::Numbers>>();
      37     5091150 :         if (r.is('.')) {
      38       29100 :                 isFloat = true;
      39       29100 :                 ++ r;
      40       29100 :                 r.skipChars<StringView::CharGroup<CharGroupId::Numbers>>();
      41             :         }
      42     5091150 :         if (r.is('E') || r.is('e')) {
      43        7275 :                 isFloat = true;
      44        7275 :                 ++ r;
      45        7275 :                 if (r.is('+') || r.is('-')) {
      46        7225 :                         ++ r;
      47             :                 }
      48        7275 :                 r.skipChars<StringView::CharGroup<CharGroupId::Numbers>>();
      49             :         }
      50             : 
      51     5091150 :         return StringView(tmp.data(), tmp.size() - r.size());
      52             : }
      53             : 
      54             : template <typename Interface>
      55             : struct Decoder : public Interface::AllocBaseType {
      56             :         using InterfaceType = Interface;
      57             :         using ValueType = ValueTemplate<Interface>;
      58             :         using StringType = typename InterfaceType::StringType;
      59             : 
      60             :         enum BackType {
      61             :                 BackIsArray,
      62             :                 BackIsDict,
      63             :                 BackIsEmpty
      64             :         };
      65             : 
      66       17775 :         Decoder(StringView &r, bool v) : validate(v), backType(BackIsEmpty), r(r), back(nullptr) {
      67       17775 :                 stack.reserve(10);
      68       17775 :         }
      69             : 
      70             :         inline void parseBufferString(StringType &ref);
      71             :         inline void parseJsonNumber(ValueType &ref) SPINLINE;
      72             : 
      73             :         inline void parseValue(ValueType &current);
      74             :         void parseJson(ValueType &val);
      75             : 
      76    15252800 :         inline void push(BackType t, ValueType *v) {
      77    15252800 :                 ++ r;
      78    15252800 :                 back = v;
      79    15252800 :                 stack.push_back(v);
      80    15252800 :                 backType = t;
      81    15252800 :         }
      82             : 
      83    15252800 :         inline void pop() {
      84    15252800 :                 r ++;
      85    15252800 :                 stack.pop_back();
      86    15252800 :                 if (stack.empty()) {
      87       15925 :                         back = nullptr;
      88       15925 :                         backType = BackIsEmpty;
      89             :                 } else {
      90    15236875 :                         back = stack.back();
      91    15236875 :                         backType = (back->isArray())?BackIsArray:BackIsDict;
      92             :                 }
      93    15252800 :         }
      94             : 
      95             :         bool validate;
      96             :         bool stop = false;
      97             :         BackType backType;
      98             :         StringView r;
      99             :         ValueType *back;
     100             :         StringType buf;
     101             :         typename InterfaceType::template ArrayType<ValueType *> stack;
     102             : };
     103             : 
     104             : template <typename Interface>
     105   108472250 : inline void Decoder<Interface>::parseBufferString(StringType &ref) {
     106             : #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
     107             :         static const char escape[256] = {
     108             :                 Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, '\'', 0, 0, 0, 0, 0, 0, 0,'/',
     109             :                 Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0,
     110             :                 0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0,
     111             :                 0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     112             :                 Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16
     113             :         };
     114             : #undef Z16
     115   108472250 :         if (r.is('"')) { r ++; }
     116   108472250 :         auto s = r.readUntil<StringView::Chars<'\\', '"'>>();
     117   108472250 :         ref.assign(s.data(), s.size());
     118   109777650 :         while (!r.empty() && !r.is('"')) {
     119     1305400 :                 if (r.is('\\')) {
     120     1305400 :                         ++ r;
     121     1305400 :                         if (r.is('u')) {
     122           0 :                                 ++ r;
     123           0 :                                 if (r >= 4) {
     124           0 :                                         unicode::utf8Encode(ref, char16_t(base16::hexToChar(r[0], r[1]) << 8 | base16::hexToChar(r[2], r[3]) ));
     125           0 :                                         r += 4;
     126             :                                 } else {
     127           0 :                                         r.clear();
     128             :                                 }
     129             :                         } else {
     130     1305400 :                                 ref.push_back(escape[(uint8_t)r[0]]);
     131     1305400 :                                 ++ r;
     132             :                         }
     133             :                 }
     134     1305400 :                 auto s = r.readUntil<StringView::Chars<'\\', '"'>>();
     135     1305400 :                 ref.append(s.data(), s.size());
     136             :         }
     137   108472250 :         if (r.is('"')) { ++ r; }
     138   108472250 : }
     139             : 
     140             : template <typename Interface>
     141             : inline void Decoder<Interface>::parseJsonNumber(ValueType &result) {
     142     5090500 :         bool isFloat = false;
     143     5090500 :         auto value = decodeNumber(r, isFloat);
     144     5090500 :         if (value.empty()) {
     145           0 :                 return;
     146             :         } else {
     147     5090500 :                 if (isFloat) {
     148       58250 :                         value.readDouble().unwrap([&] (double v) {
     149       29125 :                                 result._type = ValueType::Type::DOUBLE;
     150       29125 :                                 result.doubleVal = v;
     151             :                         });
     152             :                 } else {
     153    10122750 :                         value.readInteger().unwrap([&] (int64_t v) {
     154     5061375 :                                 result._type = ValueType::Type::INTEGER;
     155     5061375 :                                 result.intVal = v;
     156             :                         });
     157             :                 }
     158             :         }
     159             : }
     160             : 
     161             : template <typename Interface>
     162    71959100 : inline void Decoder<Interface>::parseValue(ValueType &current) {
     163    71959100 :         switch(r[0]) {
     164    42758575 :         case '"':
     165    42758575 :                 current._type = ValueType::Type::CHARSTRING;
     166    42758575 :                 parseBufferString(buf);
     167    42758575 :                 current.strVal = new StringType(std::move(buf));
     168    42758575 :                 break;
     169     2665150 :         case 't':
     170     2665150 :                 current._type = ValueType::Type::BOOLEAN;
     171     2665150 :                 current.boolVal = true;
     172     2665150 :                 r += 4;
     173     2665150 :                 break;
     174     6171175 :         case 'f':
     175     6171175 :                 current._type = ValueType::Type::BOOLEAN;
     176     6171175 :                 current.boolVal = false;
     177     6171175 :                 r += 5;
     178     6171175 :                 break;
     179     5090500 :         case '0': case '1': case '2': case '3': case '4': case '5':
     180             :         case '6': case '7': case '8': case '9': case '+': case '-':
     181             :                 parseJsonNumber(current);
     182     5090500 :                 break;
     183     3639700 :         case '[':
     184     3639700 :                 current._type = ValueType::Type::ARRAY;
     185     3851325 :                 current.arrayVal = new typename ValueType::ArrayType();
     186             :                 //current.arrayVal->reserve(10);
     187     3639700 :                 push(BackIsArray, &current);
     188     3639700 :                 break;
     189    11613100 :         case '{':
     190    11613100 :                 current._type = ValueType::Type::DICTIONARY;
     191    12149975 :                 current.dictVal = new typename ValueType::DictionaryType();
     192    11613100 :                 push(BackIsDict, &current);
     193    11613100 :                 break;
     194       20900 :         case 'n':
     195       20900 :                 if (r.is("nan")) {
     196           0 :                         current._type = ValueType::Type::DOUBLE;
     197           0 :                         current.doubleVal = nan();
     198           0 :                         r += 3;
     199             :                 } else {
     200       20900 :                         r += 4;
     201             :                 }
     202       20900 :                 break;
     203           0 :         default:
     204           0 :                 r.skipUntil<StringView::Chars<'"', 't', 'f', 'n', '+', '-', '[', '{', ']', '}'>, StringView::Range<'0', '9'>>();
     205           0 :                 break;
     206             :         }
     207    71959100 : }
     208             : 
     209             : template <typename Interface>
     210    87211900 : void Decoder<Interface>::parseJson(ValueType &val) {
     211             :         do {
     212    87211900 :                 switch (backType) {
     213     9867350 :                 case BackIsArray:
     214     9867350 :                         r.skipChars<StringView::Chars<' ', '\n', '\r', '\t', ','>>();
     215     9867350 :                         if (!r.is(']')) {
     216     6227650 :                                 back->arrayVal->emplace_back(ValueType::Type::EMPTY);
     217     6227650 :                                 parseValue(back->arrayVal->back());
     218             :                         } else {
     219     3639700 :                                 back->arrayVal->shrink_to_fit();
     220     3639700 :                                 pop();
     221             :                         }
     222     9867350 :                         break;
     223    77326775 :                 case BackIsDict:
     224    77326775 :                         r.skipUntil<StringView::Chars<'"', '}'>>();
     225    77326775 :                         if (!r.is('}')) {
     226    65713675 :                                 parseBufferString(buf);
     227    65713675 :                                 if (validate) {
     228           0 :                                         auto tmp = r.readChars<StringView::Chars<':', ' ', '\n', '\r', '\t'>>();
     229           0 :                                         tmp.template skipUntil<StringView::Chars<':'>>();
     230           0 :                                         if (!tmp.is(':')) {
     231           0 :                                                 stop = true;
     232           0 :                                                 return;
     233             :                                         }
     234             :                                 } else {
     235    65713675 :                                         r.skipChars<StringView::Chars<':', ' ', '\n', '\r', '\t'>>();
     236             :                                 }
     237    65713675 :                                 parseValue(back->dictVal->emplace(std::move(buf), ValueType::Type::EMPTY).first->second);
     238             :                         } else {
     239    11613100 :                                 pop();
     240             :                         }
     241    77326775 :                         break;
     242       17775 :                 case BackIsEmpty:
     243       17775 :                         parseValue(val);
     244       17775 :                         break;
     245             :                 }
     246    87211900 :         } while (!r.empty() && !stack.empty() && !stop);
     247             : }
     248             : 
     249             : template <typename Interface>
     250       17825 : auto read(StringView &n, bool validate = false) -> ValueTemplate<Interface> {
     251       17825 :         auto r = n;
     252       17825 :         if (r.empty() || r == "null") {
     253          50 :                 return ValueTemplate<Interface>();
     254             :         }
     255             : 
     256       17775 :         r.skipChars<StringView::Chars<' ', '\n', '\r', '\t'>>();
     257       17775 :         Decoder<Interface> dec(r, validate);
     258       17775 :         ValueTemplate<Interface> ret;
     259       17775 :         dec.parseJson(ret);
     260       17775 :         n = dec.r;
     261       17775 :         return ret;
     262       17775 : }
     263             : 
     264             : template <typename Interface>
     265       17825 : auto read(const StringView &r) -> ValueTemplate<Interface> {
     266       17825 :         StringView tmp(r);
     267       35650 :         return read<Interface>(tmp);
     268             : }
     269             : 
     270             : }
     271             : 
     272             : #endif /* STAPPLER_DATA_SPDATADECODEJSON_H_ */

Generated by: LCOV version 1.14