// // json_common.h // json // // Created by Sam Jaffe on 4/22/16. // #pragma once #include #include #include #include namespace json { using string_jt = std::string; using double_jt = double; using int_jt = int32_t; using uint_jt = uint32_t; using bool_jt = bool; class value; class malformed_json_exception : public std::domain_error { using std::domain_error::domain_error; }; namespace { const constexpr json::int_jt INT_JT_MAX_LAST_DIGIT = (0x7FFFFFFF % 10); const constexpr json::int_jt INT_JT_MAX = json::uint_jt(-1) - 1; const constexpr json::int_jt INT_JT_MIN = json::int_jt(~(json::uint_jt(-1) / 2)); const constexpr json::uint_jt INT_JT_OVER = json::uint_jt(INT_JT_MAX) + 1; const constexpr json::uint_jt UINT_JT_MAX = json::uint_jt(0) - 1; // const constexpr json::uint_jt UINT_JT_MIN = 0; } } namespace json { namespace helper { const char get_next_element(char const*& data); char const * get_numeric_token_end(char const * start); /** * @throws json::malformed_json_exception */ void advance_to_boundary(char const endtok, char const *& data); /** * @throws json::malformed_json_exception */ std::string parse_string(char const * & data); template void parse_string(T& json, char const * & data) { json = parse_string(data); } template void parse_double(T& json, char const * & data) { json = atof(data); while (isdigit(*data)) { ++data; } if (*data == '.' || *data == 'e') { ++data; } while (isdigit(*data)) { ++data; } } // template // void parse_integer(T& json, char const * & data) { // json = atoi(data); // while (isdigit(*data)) { ++data; } // } template void parse_numeric(J & json, char const * & data) { char const * start = data; char const * const end = get_numeric_token_end(start); if (end == start) { throw malformed_json_exception("Expected any token, got nothing"); } bool const negative = *start == '-'; if (negative) ++start; uint_jt const threshold = (UINT_JT_MAX / 10); uint_jt val = 0; for (; start != end; ++start) { if (!isdigit(*start)) { helper::parse_double(json, data); return; } int_jt digit = static_cast(*start - '0'); if (val >= threshold) { if (val > threshold || (start + 1) < end || digit > INT_JT_MAX_LAST_DIGIT) { helper::parse_double(json, data); return; } } val = (10 * val) + digit; } if (negative && val == INT_JT_OVER) { json = INT_JT_MIN; } else if (negative) { json = -int_jt(val); } else if (val <= uint_jt(INT_JT_MAX)) { json = int_jt(val); } else { json = val; } data = start; } } }