25 std::vector<std::pair<std::string, Node>>
members;
37 explicit Parser(
const std::string& text) : s_(text) {}
39 bool parse(
Node& out, std::string*
error) {
41 if (!parseValue(out)) {
42 if (
error) *
error =
"invalid JSON near offset " + std::to_string(pos_);
46 if (pos_ != s_.size()) {
47 if (
error) *
error =
"trailing data at offset " + std::to_string(pos_);
54 const std::string& s_;
58 while (pos_ < s_.size() &&
59 (s_[pos_] ==
' ' || s_[pos_] ==
'\t' || s_[pos_] ==
'\n' || s_[pos_] ==
'\r'))
63 bool peek(
char c)
const {
return pos_ < s_.size() && s_[pos_] ==
c; }
65 bool parseValue(
Node& out) {
66 if (pos_ >= s_.size())
return false;
68 case '{':
return parseObject(out);
69 case '[':
return parseArray(out);
71 if (!parseString(out.
stringVal))
return false;
74 case 't':
return parseLiteral(
"true", out,
true);
75 case 'f':
return parseLiteral(
"false", out,
false);
76 case 'n':
return parseNull(out);
77 default:
return parseNumber(out);
81 bool parseLiteral(
const char* lit,
Node& out,
bool value) {
82 const size_t n = std::char_traits<char>::length(lit);
83 if (s_.compare(pos_,
n, lit) != 0)
return false;
90 bool parseNull(
Node& out) {
91 if (s_.compare(pos_, 4,
"null") != 0)
return false;
97 bool parseNumber(
Node& out) {
98 const size_t start = pos_;
99 if (pos_ < s_.size() && (s_[pos_] ==
'-' || s_[pos_] ==
'+')) ++pos_;
100 bool hasDigit =
false;
101 while (pos_ < s_.size() && s_[pos_] >=
'0' && s_[pos_] <=
'9') {
105 bool integral =
true;
106 if (pos_ < s_.size() && s_[pos_] ==
'.') {
109 while (pos_ < s_.size() && s_[pos_] >=
'0' && s_[pos_] <=
'9') ++pos_;
111 if (pos_ < s_.size() && (s_[pos_] ==
'e' || s_[pos_] ==
'E')) {
114 if (pos_ < s_.size() && (s_[pos_] ==
'-' || s_[pos_] ==
'+')) ++pos_;
115 while (pos_ < s_.size() && s_[pos_] >=
'0' && s_[pos_] <=
'9') ++pos_;
117 if (!hasDigit)
return false;
118 const std::string num = s_.substr(start, pos_ - start);
122 out.
intVal = std::stoll(num);
128 if (!integral)
return false;
140 bool parseString(std::string& out) {
141 if (!peek(
'"'))
return false;
144 while (pos_ < s_.size()) {
145 const char c = s_[pos_++];
146 if (
c ==
'"')
return true;
151 if (pos_ >= s_.size())
return false;
152 const char esc = s_[pos_++];
154 case '"': out +=
'"';
break;
155 case '\\': out +=
'\\';
break;
156 case '/': out +=
'/';
break;
157 case 'b': out +=
'\b';
break;
158 case 'f': out +=
'\f';
break;
159 case 'n': out +=
'\n';
break;
160 case 'r': out +=
'\r';
break;
161 case 't': out +=
'\t';
break;
163 if (pos_ + 4 > s_.size())
return false;
164 const char hex[5] = {s_[pos_], s_[pos_ + 1], s_[pos_ + 2], s_[pos_ + 3],
'\0'};
167 const unsigned cp =
static_cast<unsigned>(std::strtoul(hex, &end, 16));
168 if (!end || *end !=
'\0')
return false;
170 if (cp >= 0xD800 && cp <= 0xDBFF && pos_ + 6 <= s_.size() && s_[pos_] ==
'\\' &&
171 s_[pos_ + 1] ==
'u') {
172 const char lohex[5] = {s_[pos_ + 2], s_[pos_ + 3], s_[pos_ + 4],
175 char* loEnd =
nullptr;
176 const unsigned lo =
static_cast<unsigned>(std::strtoul(lohex, &loEnd, 16));
177 if (loEnd && *loEnd ==
'\0' && lo >= 0xDC00 && lo <= 0xDFFF)
178 appendUtf8(out, 0x10000 + ((cp - 0xD800) << 10) + (lo - 0xDC00));
186 default:
return false;
192 static void appendUtf8(std::string& out,
unsigned cp) {
194 out +=
static_cast<char>(cp);
195 }
else if (cp < 0x800) {
196 out +=
static_cast<char>(0xC0 | (cp >> 6));
197 out +=
static_cast<char>(0x80 | (cp & 0x3F));
198 }
else if (cp < 0x10000) {
199 out +=
static_cast<char>(0xE0 | (cp >> 12));
200 out +=
static_cast<char>(0x80 | ((cp >> 6) & 0x3F));
201 out +=
static_cast<char>(0x80 | (cp & 0x3F));
203 out +=
static_cast<char>(0xF0 | (cp >> 18));
204 out +=
static_cast<char>(0x80 | ((cp >> 12) & 0x3F));
205 out +=
static_cast<char>(0x80 | ((cp >> 6) & 0x3F));
206 out +=
static_cast<char>(0x80 | (cp & 0x3F));
210 bool parseObject(
Node& out) {
221 if (!parseString(key))
return false;
223 if (!peek(
':'))
return false;
227 if (!parseValue(val))
return false;
228 out.
members.emplace_back(std::move(key), std::move(val));
235 if (!peek(
','))
return false;
240 bool parseArray(
Node& out) {
251 if (!parseValue(val))
return false;
252 out.
elements.push_back(std::move(val));
259 if (!peek(
','))
return false;
266std::string numberToString(
const Node&
n) {
267 if (
n.integral)
return std::to_string(
n.intVal);
268 std::ostringstream
os;
273bool stringToDouble(
const std::string&
s,
double& out) {
276 const double v = std::stod(
s, &used);
277 while (used <
s.size() && (
s[used] ==
' ' ||
s[used] ==
'\t')) ++used;
278 if (used !=
s.size())
return false;
299bool Value::has(
const char* key)
const {
return static_cast<bool>(
get(key)); }
303 for (
const auto&
m : node_->
members)
304 if (
m.first == key)
return Value(&
m.second);
309 std::vector<std::string> out;
311 out.reserve(node_->
members.size());
312 for (
const auto&
m : node_->
members) out.push_back(
m.first);
317 if (!node_)
return 0;
330 if (!node_)
return fallback;
331 switch (node_->
kind) {
335 if (node_->
stringVal ==
"true")
return true;
336 if (node_->
stringVal ==
"false")
return false;
338 default:
return fallback;
343 if (!node_)
return fallback;
344 switch (node_->
kind) {
349 return stringToDouble(node_->
stringVal,
v) ?
v : fallback;
351 default:
return fallback;
356 if (!node_)
return fallback;
358 if (node_->
intVal < std::numeric_limits<int>::min() ||
359 node_->
intVal > std::numeric_limits<int>::max())
361 return static_cast<int>(node_->
intVal);
363 const double d =
asDouble(
static_cast<double>(fallback));
364 if (!std::isfinite(
d) ||
d <
static_cast<double>(std::numeric_limits<int>::min()) ||
365 d >
static_cast<double>(std::numeric_limits<int>::max()))
367 return static_cast<int>(
d);
371 return static_cast<float>(
asDouble(
static_cast<double>(fallback)));
375 if (!node_)
return fallback;
376 switch (node_->
kind) {
380 default:
return fallback;
395 std::vector<std::string> out;
397 out.reserve(node_->
elements.size());
407 std::vector<int> out;
411 for (
size_t i = 0; i <
n; ++i) out.push_back(arr.
at(i).
asInt(0));
416 std::vector<float> out;
420 for (
size_t i = 0; i <
n; ++i) out.push_back(arr.
at(i).
asFloat(0.f));
425 std::unordered_map<std::string, std::string> out;
433 std::unordered_map<std::string, int> out;
451 auto node = std::make_unique<Node>();
453 if (!parser.parse(*node,
error))
return doc;
454 doc.root_ = std::move(node);