11 using namespace Internal;
16 void SkipSpaces(std::string_view::const_iterator& iter,
size_t& length);
17 Value
NumberFromString(
const std::string& s,
const bool is_scientific,
const bool is_double);
18 Value
ParseNumber(std::string_view::const_iterator& iter,
size_t& length);
19 Value
ParseString(std::string_view::const_iterator& iter,
size_t& length);
20 Value
ParseObject(std::string_view::const_iterator& iter,
size_t& length);
21 Value
ParseArray(std::string_view::const_iterator& iter,
size_t& length);
22 Value
ParseValue(std::string_view::const_iterator& iter,
size_t& length);
76 if (init.size() == 2 && init.begin()->is_string())
78 val =
Object({ { init.begin()->get<std::string>(), *(init.begin() + 1) } });
84 for (
const auto& j : init)
96 for (
const auto& j : init)
98 new_val.insert(*j.get_object().begin());
101 val = std::move(new_val);
111 return get<Object>();
121 return get<std::string>();
126 return get<Object>();
136 return get<std::string>();
141 return is<std::monostate>();
146 return is<std::string>();
151 return is<Json::Object>();
156 return is<Json::Array>();
166 return std::holds_alternative<long long int>(
val)
167 || std::holds_alternative<unsigned long long int>(
val);
172 return std::holds_alternative<long long int>(
val)
173 || std::holds_alternative<unsigned long long int>(
val)
174 || std::holds_alternative<double>(
val);
179 if (std::holds_alternative<std::monostate>(
val))
186 throw std::runtime_error(
"Json::Value is not an object");
189 return get<Object>()[s];
196 throw std::runtime_error(
"Json::Value is not an object");
199 return get<Object>().at(s);
206 throw std::runtime_error(
"Json::Value is not an array");
209 return get<Array>()[i];
216 throw std::runtime_error(
"Json::Value is not an array");
219 return get<Array>().at(i);
225 std::istreambuf_iterator<char>(is),
226 std::istreambuf_iterator<char>()
234 return is<Object>() && get<Object>().count(s);
239 if (std::holds_alternative<std::monostate>(
val))
246 return get<Object>().size();
251 return get<Array>().size();
254 throw std::runtime_error(
"Json::Value is neither an array nor an object");
259 if (std::holds_alternative<std::monostate>(
val))
266 throw std::runtime_error(
"Can't push_back in a non-array Json::Value");
269 get<Array>().push_back(value);
274 if (std::holds_alternative<std::monostate>(
val))
281 throw std::runtime_error(
"Can't push_back in a non-array Json::Value");
284 get<Array>().push_back(std::move(value));
287 std::string
Value::Dump(
const int indent,
const char indent_char)
const
289 return Dump(0, indent, indent_char);
292 std::string
Value::Dump(
const size_t depth_level,
const int indent,
const char indent_char)
const
294 std::ostringstream oss;
296 std::visit([&](
auto&& arg)
298 using T = std::decay_t<
decltype(arg)>;
300 if constexpr (std::is_same_v<T, std::monostate>)
304 else if constexpr (std::is_same_v<T, RecursiveWrapper<Object>>)
306 const Object& o = arg.get();
313 const std::string new_line = (indent == -1 ?
"" :
"\n");
314 const std::string line_indentation = indent > -1 ? std::string(depth_level * indent, indent_char) :
"";
315 const std::string value_indentation = indent > -1 ? std::string(indent, indent_char) :
"";
317 oss <<
"{" << new_line;
319 for (
const auto& [k, v] : o)
323 oss <<
"," << new_line;
329 oss << line_indentation << value_indentation <<
"\"" << k <<
"\"" << (indent == -1 ?
":" :
": ") << v.Dump(depth_level + 1, indent, indent_char);
331 oss << new_line << line_indentation <<
"}";
333 else if constexpr (std::is_same_v<T, RecursiveWrapper<Array>>)
335 const Array& a = arg.get();
341 const std::string new_line = (indent == -1 ?
"" :
"\n");
342 const std::string line_indentation = indent > -1 ? std::string(depth_level * indent, indent_char) :
"";
343 const std::string value_indentation = indent > -1 ? std::string(indent, indent_char) :
"";
345 oss <<
'[' << new_line;
347 for (
const auto& v : a)
351 oss <<
',' << new_line;
357 oss << line_indentation << value_indentation << v.Dump(depth_level + 1, indent, indent_char);
359 oss << new_line << line_indentation <<
']';
361 else if constexpr (std::is_same_v<T, std::string>)
365 else if constexpr (std::is_same_v<T, bool>)
367 oss << (arg ?
"true" :
"false");
369 else if constexpr (std::is_same_v<T, double>)
371 if (arg == std::floor(arg))
373 oss << std::setprecision(1) << std::fixed << arg;
390 Value Parse(std::string_view::const_iterator iter,
size_t length,
bool no_except)
392 const size_t init_length = length;
398 throw std::runtime_error(std::to_string(length) +
" unread characters remaining after parsing");
402 catch (
const std::runtime_error& e)
408 throw std::runtime_error(e.what() + std::string(
" (at pos ") + std::to_string(init_length - length) +
')');
419 size_t length = s.size();
420 std::string_view sview(s.begin().operator->(), s.end() - s.begin());
423 return Parse(sview.begin(), length);
425 catch (
const std::runtime_error& e)
431 throw std::runtime_error(e.what() + std::string(
" (at pos ") + std::to_string(s.size() - length) +
')');
437 std::ostringstream out;
439 while (it != s.end())
478 void SkipSpaces(std::string_view::const_iterator& iter,
size_t& length)
500 const size_t s_size = s.size();
502 for (
size_t i = 0; i < s_size; ++i)
507 if ((i == 0 && s_size > 1 && s[1] !=
'.' && s[1] !=
'e' && s[1] !=
'E') ||
508 (i == 1 && s_size > 2 && s[0] ==
'-' && s[2] !=
'.' && s[2] !=
'e' && s[2] !=
'E'))
510 throw std::runtime_error(
"Unexpected leading 0 when parsing number");
514 if (i == s_size - 1 ||
515 (i != 0 && (s[i - 1] ==
'.' || s[i - 1] ==
'+'))
518 throw std::runtime_error(
"Unexpected - character when parsing number");
522 if (i == 0 || i == s_size - 1 || (s[i - 1] !=
'e' && s[i - 1] !=
'E'))
524 throw std::runtime_error(
"Unexpected + character when parsing number");
535 throw std::runtime_error(
"Unexpected exponent sign found when parsing a number");
546 throw std::runtime_error(
"Unexpected . sign found when parsing a number");
559 throw std::runtime_error(
"Trying to convert empty string to number");
564 if (is_scientific || is_double)
572 if (s.size() > 20 || (s.size() == 20 && s >
"-9223372036854775808"))
576 return std::stoll(s);
580 if (s.size() > 20 || (s.size() == 20 && s >
"18446744073709551615"))
584 return std::stoull(s);
589 std::string_view::const_iterator start = iter;
591 bool is_scientific =
false;
592 bool is_double =
false;
602 throw std::runtime_error(
"Multiple exponent char encountered while parsing number");
604 is_scientific =
true;
611 throw std::runtime_error(
"Multiple decimal separator encountered while parsing number");
633 return NumberFromString(std::string(start, iter), is_scientific, is_double);
638 return NumberFromString(std::string(start, iter), is_scientific, is_double);
644 return cp <= 0x0010ffffu && !(cp >= 0xd800u && cp <= 0xdfffu);
649 const unsigned long codepoint = std::stoul(hex_chars,
nullptr, 16);
653 throw std::runtime_error(
"Trying to parse an invalid codepoint to UTF8 while reading string");
656 if (codepoint < 0x80)
659 +
static_cast<char>(codepoint);
661 else if (codepoint < 0x800)
664 +
static_cast<char>((codepoint >> 6) | 0xc0)
665 +
static_cast<char>((codepoint & 0x3f) | 0x80);
667 else if (codepoint < 0x10000)
670 +
static_cast<char>((codepoint >> 12) | 0xe0)
671 +
static_cast<char>(((codepoint >> 6) & 0x3f) | 0x80)
672 +
static_cast<char>((codepoint & 0x3f) | 0x80);
677 +
static_cast<char>((codepoint >> 18) | 0xf0)
678 +
static_cast<char>(((codepoint >> 12) & 0x3f) | 0x80)
679 +
static_cast<char>(((codepoint >> 6) & 0x3f) | 0x80)
680 +
static_cast<char>((codepoint & 0x3f) | 0x80);
688 throw std::runtime_error(
"Not enough input when reading string");
692 throw std::runtime_error(std::string(
"Unexpected char found at beginning of string \"") + *iter +
"\"");
697 std::ostringstream output;
707 throw std::runtime_error(
"Unexpected unescaped special character encountered when parsing string");
715 throw std::runtime_error(
"Missing data after escape character when parsing string");
722 output << *iter << *(iter + 1);
764 throw std::runtime_error(
"Missing data after \\u character when parsing string");
771 throw std::runtime_error(
"Unexpected escape character encountered when parsing string");
777 if (*iter > -1 && *iter < 32)
780 throw std::runtime_error(
"Unexpected control character encountered when parsing string");
789 throw std::runtime_error(
"Not enough input when reading string");
796 throw std::runtime_error(
"Not enough input when reading Json::Object");
800 throw std::runtime_error(std::string(
"Unexpected char found at beginning of Json::Object \"") + *iter +
"\"");
809 throw std::runtime_error(
"Not enough input when reading Json::Object");
830 throw std::runtime_error(std::string(
"Unexpected char \"") + *iter +
"\" when reading Json::Object while expecting :");
848 else if (*iter !=
',')
850 throw std::runtime_error(std::string(
"Unexpected char \"") + *iter +
"\" when reading Json::Object while expecting ,");
857 throw std::runtime_error(
"Not enough input when reading Json::Object");
864 throw std::runtime_error(
"Not enough input when reading Json::Array");
868 throw std::runtime_error(std::string(
"Unexpected char found at beginning of Json::Array \"") + *iter +
"\"");
879 throw std::runtime_error(
"Not enough input when reading Json::Array");
894 output.push_back(value);
904 else if (*iter !=
',')
906 throw std::runtime_error(std::string(
"Unexpected char \"") + *iter +
"\" when reading Json::Array while expecting ,");
913 throw std::runtime_error(
"Not enough input when reading Json::Array");
935 || *(iter + 1) !=
'u'
936 || *(iter + 2) !=
'l'
937 || *(iter + 3) !=
'l')
939 throw std::runtime_error(
"Unexpected char \"n\"");
949 || *(iter + 1) !=
'r'
950 || *(iter + 2) !=
'u'
951 || *(iter + 3) !=
'e')
953 throw std::runtime_error(
"Unexpected char \"t\"");
964 || *(iter + 1) !=
'a'
965 || *(iter + 2) !=
'l'
966 || *(iter + 3) !=
's'
967 || *(iter + 4) !=
'e')
969 throw std::runtime_error(
"Unexpected char \"f\"");
992 throw std::runtime_error(std::string(
"Unexpected char \"") + *iter +
"\"");
Template magic to have a full type instead of an incomplete one as required for example by std::varia...
Real class declaration, just a derived class of std::vector<Value>
Real class declaration, just a derived class of std::map<std::string, Value>
Main class, basically a JsonVariant with extra utility functions it doesn't inherit JsonVariant direc...
Internal::JsonVariant val
std::string Dump(const int indent=-1, const char indent_char=' ') const
public dump interface
void push_back(const Value &value)
Value & operator[](const std::string &s)
Value(std::nullptr_t=nullptr)
bool contains(const std::string &s) const
std::string & get_string()
Value ParseString(std::string_view::const_iterator &iter, size_t &length)
Value ParseObject(std::string_view::const_iterator &iter, size_t &length)
Value ParseNumber(std::string_view::const_iterator &iter, size_t &length)
bool IsValidCodepoint(const unsigned long cp)
Value ParseValue(std::string_view::const_iterator &iter, size_t &length)
std::string CodepointToUtf8(const std::string &hex_chars)
Value ParseArray(std::string_view::const_iterator &iter, size_t &length)
Value NumberFromString(const std::string &s, const bool is_scientific, const bool is_double)
Value Parse(std::string_view::const_iterator iter, size_t length, bool no_except=false)
Parse a string_view from iter for at most length characters.
void SkipSpaces(std::string_view::const_iterator &iter, size_t &length)
std::istream & operator>>(std::istream &is, Value &v)
void ValidateStringNumber(const std::string &s)
std::string EscapeChars(const std::string &s)