| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155 |
- //
- // json_common.h
- // json
- //
- // Created by Sam Jaffe on 4/22/16.
- //
- #pragma once
- #include <cstdint>
- #include <cstdlib>
- #include <errno.h>
- #include <limits>
- #include <stdexcept>
- #include <string>
- #include <strings.h>
- #include "json_exception.h"
- 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;
- template <typename T = json::int_jt> struct numeric_limits {
- static constexpr const T max{std::numeric_limits<T>::max()};
- static constexpr const T min{std::numeric_limits<T>::min()};
- static constexpr const uint_jt over{uint_jt{max} + 1};
- };
- namespace {
- const constexpr int_jt INT_JT_MAX = std::numeric_limits<int_jt>::max();
- const constexpr int_jt INT_JT_MAX_LAST_DIGIT = (INT_JT_MAX % 10);
- const constexpr int_jt INT_JT_MIN = std::numeric_limits<int_jt>::min();
- const constexpr uint_jt INT_JT_OVER = uint_jt(INT_JT_MAX) + 1;
- const constexpr uint_jt UINT_JT_MAX = uint_jt(0) - 1;
- // const constexpr uint_jt UINT_JT_MIN = 0;
- }
- }
- namespace json { namespace parser {
- enum options {
- allow_all = 0x00,
- disable_unknown_keys = 0x01,
- disable_missing_keys = 0x02,
- disable_concatenated_json_bodies = 0x04,
- disable_all = 0xFF,
- };
- }}
- namespace json { namespace helper {
- const char get_next_element(char const *& data);
- enum numeric_state { DOUBLE, INTEGER };
- struct numeric_token_info {
- enum parse_state { decimal, octal, hexadecimal };
- numeric_token_info(char const * start);
- numeric_state parse_numeric();
- uint_jt val;
- parse_state base;
- char const * it;
- char const * end;
- bool is_double;
- bool is_negative;
- };
- numeric_token_info get_numeric_token_info(char const * it);
- /**
- * @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);
- std::string replace_all(std::string str, std::string const & from,
- std::string const & to);
- template <typename T> void parse_string(T & json, char const *& data) {
- json::helper::get_next_element(data);
- json = parse_string(data);
- }
- template <typename T>
- T parse_double_impl(char const * begin, char const *& end) {
- return std::strtod(begin, const_cast<char **>(&end));
- }
- template <>
- inline float parse_double_impl<float>(char const * begin, char const *& end) {
- return std::strtof(begin, const_cast<char **>(&end));
- }
- template <>
- inline long double parse_double_impl<long double>(char const * begin,
- char const *& end) {
- return std::strtold(begin, const_cast<char **>(&end));
- }
- template <typename T> void parse_double(T & json, char const *& data) {
- json::helper::get_next_element(data);
- char const * begin = data;
- errno = 0;
- T tmp = parse_double_impl<T>(begin, data);
- if (errno != 0) {
- throw json::json_numeric_width_exception{
- "Number is out-of-range for floating-point type"};
- } else if (begin == data) {
- throw json::json_numeric_exception("Expected numeric data");
- }
- errno = 0;
- json = std::move(tmp);
- }
- template <typename J>
- bool has_too_many_digits(numeric_token_info const & info) {
- return fls(static_cast<int_jt>(info.val)) >
- std::numeric_limits<J>::digits + info.is_negative;
- }
- template <typename J> void parse_numeric(J & json, char const *& data) {
- json::helper::get_next_element(data);
- numeric_token_info info = data;
- if (info.is_negative && !std::is_signed<J>::value) {
- throw json_numeric_exception("Expected signed integer");
- } else if (info.is_double || info.parse_numeric() == DOUBLE) {
- throw json_numeric_exception("Expected integer, got double");
- } else if (info.base == numeric_token_info::decimal &&
- (has_too_many_digits<J>(info) ||
- info.val > json::numeric_limits<J>::over)) {
- throw json_numeric_width_exception{
- "Integer width too small for parsed value"};
- } else if (info.is_negative) {
- if (info.val == json::numeric_limits<J>::over) {
- json = json::numeric_limits<J>::min;
- } else {
- json = static_cast<J>(-int_jt(info.val));
- }
- } else if (info.val <= uint_jt(INT_JT_MAX)) {
- json = static_cast<J>(int_jt(info.val));
- } else if (std::is_signed<J>::value &&
- info.base == numeric_token_info::decimal) {
- throw json_numeric_exception("Expected unsigned integer");
- } else {
- json = static_cast<J>(info.val);
- }
- data = info.it;
- }
- }}
|