json_common.hpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. //
  2. // json_common.h
  3. // json
  4. //
  5. // Created by Sam Jaffe on 4/22/16.
  6. //
  7. #pragma once
  8. #include <cstdint>
  9. #include <cstdlib>
  10. #include <stdexcept>
  11. #include <string>
  12. #include <errno.h>
  13. namespace json {
  14. using string_jt = std::string;
  15. using double_jt = double;
  16. using int_jt = int32_t;
  17. using uint_jt = uint32_t;
  18. using bool_jt = bool;
  19. class value;
  20. class malformed_json_exception :
  21. public std::domain_error {
  22. using std::domain_error::domain_error;
  23. };
  24. class unterminated_json_exception :
  25. public malformed_json_exception {
  26. using malformed_json_exception::malformed_json_exception;
  27. };
  28. class json_numeric_exception :
  29. public std::domain_error {
  30. using std::domain_error::domain_error;
  31. };
  32. class json_numeric_width_exception :
  33. public json_numeric_exception {
  34. using json_numeric_exception::json_numeric_exception;
  35. };
  36. template <typename T = json::int_jt>
  37. struct numeric_limits {
  38. static constexpr const T max{std::numeric_limits<T>::max()};
  39. static constexpr const T min{std::numeric_limits<T>::min()};
  40. static constexpr const uint_jt over{uint_jt{max}+1};
  41. };
  42. namespace {
  43. const constexpr json::int_jt INT_JT_MAX = std::numeric_limits<json::int_jt>::max();
  44. const constexpr json::int_jt INT_JT_MAX_LAST_DIGIT = (INT_JT_MAX % 10);
  45. const constexpr json::int_jt INT_JT_MIN = std::numeric_limits<json::int_jt>::min();
  46. const constexpr json::uint_jt INT_JT_OVER = json::uint_jt(INT_JT_MAX) + 1;
  47. const constexpr json::uint_jt UINT_JT_MAX = json::uint_jt(0) - 1;
  48. // const constexpr json::uint_jt UINT_JT_MIN = 0;
  49. }
  50. }
  51. namespace json { namespace parser {
  52. enum options {
  53. allow_all = 0x00,
  54. disable_unknown_keys = 0x01,
  55. disable_missing_keys = 0x02,
  56. disable_concatenated_json_bodies = 0x04,
  57. disable_all = 0xFF,
  58. };
  59. } }
  60. namespace json { namespace helper {
  61. const char get_next_element(char const*& data);
  62. enum numeric_state {
  63. DOUBLE, INTEGER
  64. };
  65. struct numeric_token_info {
  66. enum parse_state { decimal, octal, hexadecimal };
  67. numeric_token_info(char const * start);
  68. numeric_state parse_numeric();
  69. uint_jt val;
  70. parse_state base;
  71. char const * it;
  72. char const * end;
  73. bool is_double;
  74. bool is_negative;
  75. };
  76. numeric_token_info get_numeric_token_info(char const * it);
  77. /**
  78. * @throws json::malformed_json_exception
  79. */
  80. void advance_to_boundary(char const endtok, char const *& data);
  81. /**
  82. * @throws json::malformed_json_exception
  83. */
  84. std::string parse_string(char const * & data);
  85. std::string replace_all(std::string str, std::string const & from, std::string const & to);
  86. template <typename T>
  87. void parse_string(T& json, char const * & data) {
  88. json::helper::get_next_element(data);
  89. json = parse_string(data);
  90. }
  91. template <typename T>
  92. T parse_double_impl(char const * begin, char const * & end) {
  93. return std::strtod(begin, const_cast<char**>(&end));
  94. }
  95. template <>
  96. inline float parse_double_impl<float>(char const * begin, char const * & end) {
  97. return std::strtof(begin, const_cast<char**>(&end));
  98. }
  99. template <>
  100. inline long double parse_double_impl<long double>(char const * begin, char const * & end) {
  101. return std::strtold(begin, const_cast<char**>(&end));
  102. }
  103. template <typename T>
  104. void parse_double(T& json, char const * & data) {
  105. json::helper::get_next_element(data);
  106. char const * begin = data;
  107. errno = 0;
  108. T tmp = parse_double_impl<T>(begin, data);
  109. if (errno != 0) {
  110. throw json::json_numeric_width_exception{"Number is out-of-range for floating-point type"};
  111. } else if ( begin == data ) {
  112. throw json::json_numeric_exception{"Expected numeric data"};
  113. }
  114. errno = 0;
  115. json = std::move(tmp);
  116. }
  117. template <typename J>
  118. void parse_numeric(J & json, char const * & data) {
  119. json::helper::get_next_element(data);
  120. numeric_token_info info = data;
  121. if ( info.is_negative && !std::is_signed<J>::value ) {
  122. throw json_numeric_exception{"Expected signed integer"};
  123. } else if ( info.is_double || info.parse_numeric() == DOUBLE ) {
  124. throw json_numeric_exception{"Expected integer, got double"};
  125. } else if (info.base == numeric_token_info::decimal &&
  126. (fls(info.val) > std::numeric_limits<J>::digits + info.is_negative
  127. || info.val > json::numeric_limits<J>::over)) {
  128. throw json_numeric_width_exception{"Integer width too small for parsed value"};
  129. } else if (info.is_negative) {
  130. if (info.val == json::numeric_limits<J>::over) {
  131. json = json::numeric_limits<J>::min;
  132. } else {
  133. json = -int_jt(info.val);
  134. }
  135. } else if (info.val <= uint_jt(INT_JT_MAX)) {
  136. json = int_jt(info.val);
  137. } else if (std::is_signed<J>::value &&
  138. info.base == numeric_token_info::decimal) {
  139. throw json_numeric_exception{"Expected unsigned integer"};
  140. } else {
  141. json = info.val;
  142. }
  143. data = info.it;
  144. }
  145. } }