json_common.hpp 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  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. namespace json {
  13. using string_jt = std::string;
  14. using double_jt = double;
  15. using int_jt = int32_t;
  16. using uint_jt = uint32_t;
  17. using bool_jt = bool;
  18. class value;
  19. class malformed_json_exception :
  20. public std::domain_error {
  21. using std::domain_error::domain_error;
  22. };
  23. namespace {
  24. const constexpr json::int_jt INT_JT_MAX_LAST_DIGIT = (0x7FFFFFFF % 10);
  25. const constexpr json::int_jt INT_JT_MAX = json::uint_jt(-1) - 1;
  26. const constexpr json::int_jt INT_JT_MIN = json::int_jt(~(json::uint_jt(-1) / 2));
  27. const constexpr json::uint_jt INT_JT_OVER = json::uint_jt(INT_JT_MAX) + 1;
  28. const constexpr json::uint_jt UINT_JT_MAX = json::uint_jt(0) - 1;
  29. // const constexpr json::uint_jt UINT_JT_MIN = 0;
  30. }
  31. }
  32. namespace json {
  33. namespace helper {
  34. const char get_next_element(char const*& data);
  35. char const * get_numeric_token_end(char const * start);
  36. /**
  37. * @throws json::malformed_json_exception
  38. */
  39. void advance_to_boundary(char const endtok, char const *& data);
  40. /**
  41. * @throws json::malformed_json_exception
  42. */
  43. std::string parse_string(char const * & data);
  44. template <typename T>
  45. void parse_string(T& json, char const * & data) {
  46. json = parse_string(data);
  47. }
  48. template <typename T>
  49. void parse_double(T& json, char const * & data) {
  50. json = atof(data);
  51. while (isdigit(*data)) { ++data; }
  52. if (*data == '.' || *data == 'e') { ++data; }
  53. while (isdigit(*data)) { ++data; }
  54. }
  55. // template <typename T>
  56. // void parse_integer(T& json, char const * & data) {
  57. // json = atoi(data);
  58. // while (isdigit(*data)) { ++data; }
  59. // }
  60. template <typename J>
  61. void parse_numeric(J & json, char const * & data) {
  62. char const * start = data;
  63. char const * const end = get_numeric_token_end(start);
  64. if (end == start) {
  65. throw malformed_json_exception("Expected any token, got nothing");
  66. }
  67. bool const negative = *start == '-';
  68. if (negative) ++start;
  69. uint_jt const threshold = (UINT_JT_MAX / 10);
  70. uint_jt val = 0;
  71. for (; start != end; ++start) {
  72. if (!isdigit(*start)) {
  73. helper::parse_double(json, data);
  74. return;
  75. }
  76. int_jt digit = static_cast<int_jt>(*start - '0');
  77. if (val >= threshold) {
  78. if (val > threshold || (start + 1) < end || digit > INT_JT_MAX_LAST_DIGIT) {
  79. helper::parse_double(json, data);
  80. return;
  81. }
  82. }
  83. val = (10 * val) + digit;
  84. }
  85. if (negative && val == INT_JT_OVER) {
  86. json = INT_JT_MIN;
  87. } else if (negative) {
  88. json = -int_jt(val);
  89. } else if (val <= uint_jt(INT_JT_MAX)) {
  90. json = int_jt(val);
  91. } else {
  92. json = val;
  93. }
  94. data = start;
  95. }
  96. }
  97. }