2 #include <unordered_set>
10 Json::Json(
const initializer_list<Json>& data) : m_type(NONE) {
11 if (data.begin() == data.end())
return;
12 bool is_object = all_of(data.begin(), data.end(), [](
const Json& elem) {
13 return elem.is_array() && elem.size() == 2 && elem[0].is_string();
17 m_obj =
new JsonObject;
18 for (
auto& pair : data) {
19 (*m_obj)[pair[0].as_string()] = pair[1];
23 m_arr =
new JsonArray(data.begin(), data.end());
26 Json::Json(
const Json& other) {
29 Json::Json(Json&& other) {
30 operator=(move(other));
32 Json& Json::operator=(
const Json& other) {
33 m_type = other.m_type;
34 switch(other.m_type) {
36 m_str = strdup(other.m_str);
42 m_obj =
new JsonObject(other.m_obj->begin(), other.m_obj->end());
45 m_arr =
new JsonArray(other.m_arr->begin(), other.m_arr->end());
48 m_bool = other.m_bool;
53 Json& Json::operator=(Json&& other) {
54 m_type = other.m_type;
55 switch(other.m_type) {
58 other.m_str =
nullptr;
65 other.m_obj =
nullptr;
69 other.m_arr =
nullptr;
72 m_bool = other.m_bool;
80 case STRING: free(m_str);
break;
81 case OBJECT:
if (m_obj)
delete m_obj;
break;
82 case ARRAY:
if (m_arr)
delete m_arr;
break;
85 Json& Json::operator[](
const std::string& key) {
88 m_obj =
new JsonObject;
93 Json& Json::operator[](
const std::string& key)
const {
97 Json& Json::operator[](
size_t idx) {
100 m_arr =
new JsonArray;
104 return (*m_arr)[idx];
106 Json& Json::operator[](
size_t idx)
const {
109 return (*m_arr)[idx];
111 size_t Json::size()
const {
113 case OBJECT:
return m_obj->size();
114 case ARRAY:
return m_arr->size();
118 bool Json::has_key(
const std::string& key)
const {
119 return m_type == OBJECT ? m_obj->find(key) != m_obj->end() :
false;
121 bool Json::resize(
size_t size) {
122 if (m_type == NONE) {
124 m_arr =
new JsonArray;
127 case ARRAY: m_arr->resize(size);
129 return m_type == ARRAY;
131 bool Json::push_back(
const Json& val) {
132 if (m_type == NONE) {
134 m_arr =
new JsonArray;
136 if (m_type == ARRAY) m_arr->push_back(val);
137 return m_type == ARRAY;
141 case OBJECT:
return m_obj->begin()->second;
142 case ARRAY:
return m_arr->front();
143 default:
return *
this;
148 case OBJECT:
return m_obj->rbegin()->second;
149 case ARRAY:
return m_arr->back();
150 default:
return *
this;
154 if (m_type != other.m_type)
return *
this;
157 m_obj->insert(other.m_obj->begin(), other.m_obj->end());
160 m_arr->insert(m_arr->end(), other.m_arr->begin(), other.m_arr->end());
165 std::string Json::as_string()
const {
167 case STRING:
return m_str;
168 case NUMBER:
return m_num.to_string();
169 case BOOLEAN:
return m_bool ?
"true" :
"false";
170 case NONE:
return "null";
174 JsonNum Json::as_number()
const {
176 case NUMBER:
return m_num;
177 case BOOLEAN:
return m_bool;
181 bool Json::as_bool()
const {
183 case NONE:
return false;
184 case BOOLEAN:
return m_bool;
185 default:
return true;
189 std::string Json::dump(
size_t indent,
size_t offset)
const {
191 case STRING:
return "\"" + as_string() +
"\"";
192 case NUMBER:
return m_num.dump();
194 if (is_empty())
return indent > 0 ?
"{\n}" :
"{}";
195 std::string ret =
"{";
196 std::string offset_str(offset,
' ');
197 std::string indent_str(offset + indent,
' ');
199 for (
auto it = cbegin(); it != cend(); ++it) {
200 ret += indent == 0 ?
"" :
"\n" + indent_str;
201 ret +=
"\"" + it.key() +
"\": " +
202 it.value().dump(indent, offset+indent) +
", ";
204 ret.replace(ret.size()-2, 2, indent == 0 ?
"}" :
205 "\n" + offset_str +
"}");
209 if (is_empty())
return "[]";
210 std::string ret =
"[";
211 for (
auto it = cbegin(); it != cend(); ++it) {
212 ret += it->dump(indent, offset) +
", ";
214 ret.replace(ret.size()-2, 2,
"]");
217 case BOOLEAN:
return m_bool ?
"true" :
"false";
218 case NONE:
return "null";
221 bool Json::lex_string(std::string& str,
JsonToken& ret) {
222 if (str[0] !=
'\"' || str.size() < 2)
return false;
224 while (pos == 0 || str[pos-1] ==
'\\') {
225 if (pos != 0) str.replace(pos-1, 1,
"");
226 pos = str.find(
'\"', pos+1);
227 if (pos == std::string::npos)
return false;
230 ret.str = strdup(str.substr(0, pos+1).c_str());
231 str = str.substr(pos+1);
234 bool Json::lex_number(std::string& str,
JsonToken& ret) {
235 static const unordered_set<char> FLOAT_CHARS{
240 long vall = strtol(str.c_str(), &end, 10);
241 if (end != str.c_str() && FLOAT_CHARS.find(*end) == FLOAT_CHARS.end()) {
243 ret.num = vall >= 0 ?
JsonNum((uint64_t)vall) :
JsonNum((int64_t)vall);
244 str = str.substr(end - str.c_str());
248 double vald = strtod(str.c_str(), &end);
249 if (end != str.c_str()) {
252 str = str.substr(end - str.c_str());
259 if (str.size() >= 4 && str.substr(0, 4) ==
"true") {
261 ret.str = strdup(
"true");
264 }
if (str.size() >= 5 && str.substr(0, 5) ==
"false") {
266 ret.str = strdup(
"false");
273 if (str.size() >= 4 && str.substr(0, 4) ==
"null") {
275 ret.str = strdup(
"null");
281 queue<Json::JsonToken> Json::tokenize(std::string curr) {
282 static const unordered_set<char> JSON_SYNTAX{
283 '{',
'}',
'[',
']',
':',
','
286 queue<JsonToken> tokens;
287 while (!curr.empty()) {
289 if (lex_string(curr, tkn)) {
291 }
else if (lex_number(curr, tkn)) {
293 }
else if (lex_bool(curr, tkn)) {
295 }
else if (lex_null(curr, tkn)) {
297 }
else if (isspace(curr[0])) {
298 curr = curr.substr(1);
299 }
else if (JSON_SYNTAX.find(curr[0]) != JSON_SYNTAX.end()) {
300 tokens.emplace(curr[0]);
301 curr = curr.substr(1);
304 assert(
false &&
"Invalid JSON token");
309 Json Json::parse_tokens(queue<JsonToken>& tokens) {
310 if (tokens.empty())
return Json::null();
313 if (tkn.type == NUMTKN) {
314 return Json::number(tkn.num);
315 }
else if (strcmp(tkn.str,
"{") == 0) {
317 while (tokens.front() !=
JsonToken(
'}')) {
318 Json key = parse_tokens(tokens);
319 if (!key.is_string())
return Json::null();
320 if (tokens.front() !=
JsonToken(
':'))
return Json::null();
323 obj[key.as_string()] = parse_tokens(tokens);
324 if (tokens.front() ==
JsonToken(
',')) tokens.pop();
328 }
else if (strcmp(tkn.str,
"[") == 0) {
330 while (tokens.front() !=
JsonToken(
']')) {
332 if (tokens.front() ==
JsonToken(
',')) tokens.pop();
336 }
else if (starts_with(tkn.str,
"\"")) {
337 int len = strlen(tkn.str);
338 tkn.str[len-1] =
'\0';
339 return Json::string(tkn.str+1);
340 }
else if (strcmp(tkn.str,
"true") == 0) {
341 return Json::boolean(
true);
342 }
else if (strcmp(tkn.str,
"false") == 0) {
343 return Json::boolean(
false);
344 }
else if (strcmp(tkn.str,
"null") == 0) {
347 assert(
false &&
"Invalid JSON syntax");
350 Json Json::parse(
const std::string& json) {
351 if (json.empty())
return Json::null();
352 if (isspace(json[0]))
return parse(trim(json));
354 auto tokens = tokenize(json);
355 return parse_tokens(tokens);
357 Json Json::from_file(
const std::string& path) {
358 std::string contents;
361 ifstream file(path.c_str(), ios::binary);
362 if (file.fail())
return Json::null();
363 file.seekg(0, ios::end);
364 unsigned int file_size = file.tellg();
365 file.seekg(0, ios::beg);
366 file_size -= file.tellg();
368 contents.resize(file_size);
369 file.read((
char*)&contents[0], file_size);
372 return Json::parse(contents);
374 bool Json::operator==(
const Json& other)
const {
375 if (m_type != other.m_type)
return false;
377 case STRING:
return strcmp(m_str, other.m_str) == 0;
378 case NUMBER:
return m_num == other.m_num;
379 case OBJECT:
return m_obj ? (other.m_obj && *m_obj == *other.m_obj) : !other.m_obj;
380 case ARRAY:
return m_arr ? (other.m_arr && *m_arr == *other.m_arr) : !other.m_arr;
381 case BOOLEAN:
return m_bool == other.m_bool;
382 case NONE:
return true;