Mercurial > hg > piper-cpp
comparison ext/json11/json11.cpp @ 242:d607ae858682
Update json11 code
author | Chris Cannam <cannam@all-day-breakfast.com> |
---|---|
date | Tue, 13 Jun 2017 17:16:03 +0100 |
parents | bf8e3e7dd7de |
children | de5dc40f1830 |
comparison
equal
deleted
inserted
replaced
241:fdab0a246298 | 242:d607ae858682 |
---|---|
35 using std::map; | 35 using std::map; |
36 using std::make_shared; | 36 using std::make_shared; |
37 using std::initializer_list; | 37 using std::initializer_list; |
38 using std::move; | 38 using std::move; |
39 | 39 |
40 /* Helper for representing null - just a do-nothing struct, plus comparison | |
41 * operators so the helpers in JsonValue work. We can't use nullptr_t because | |
42 * it may not be orderable. | |
43 */ | |
44 struct NullStruct { | |
45 bool operator==(NullStruct) const { return true; } | |
46 bool operator<(NullStruct) const { return false; } | |
47 }; | |
48 | |
40 /* * * * * * * * * * * * * * * * * * * * | 49 /* * * * * * * * * * * * * * * * * * * * |
41 * Serialization | 50 * Serialization |
42 */ | 51 */ |
43 | 52 |
44 static void dump(std::nullptr_t, string &out) { | 53 static void dump(NullStruct, string &out) { |
45 out += "null"; | 54 out += "null"; |
46 } | 55 } |
47 | 56 |
48 static void dump(double value, string &out) { | 57 static void dump(double value, string &out) { |
49 if (std::isfinite(value)) { | 58 if (std::isfinite(value)) { |
206 public: | 215 public: |
207 explicit JsonObject(const Json::object &value) : Value(value) {} | 216 explicit JsonObject(const Json::object &value) : Value(value) {} |
208 explicit JsonObject(Json::object &&value) : Value(move(value)) {} | 217 explicit JsonObject(Json::object &&value) : Value(move(value)) {} |
209 }; | 218 }; |
210 | 219 |
211 class JsonNull final : public Value<Json::NUL, std::nullptr_t> { | 220 class JsonNull final : public Value<Json::NUL, NullStruct> { |
212 public: | 221 public: |
213 JsonNull() : Value(nullptr) {} | 222 JsonNull() : Value({}) {} |
214 }; | 223 }; |
215 | 224 |
216 /* * * * * * * * * * * * * * * * * * * * | 225 /* * * * * * * * * * * * * * * * * * * * |
217 * Static globals - static-init-safe | 226 * Static globals - static-init-safe |
218 */ | 227 */ |
289 /* * * * * * * * * * * * * * * * * * * * | 298 /* * * * * * * * * * * * * * * * * * * * |
290 * Comparison | 299 * Comparison |
291 */ | 300 */ |
292 | 301 |
293 bool Json::operator== (const Json &other) const { | 302 bool Json::operator== (const Json &other) const { |
303 if (m_ptr == other.m_ptr) | |
304 return true; | |
294 if (m_ptr->type() != other.m_ptr->type()) | 305 if (m_ptr->type() != other.m_ptr->type()) |
295 return false; | 306 return false; |
296 | 307 |
297 return m_ptr->equals(other.m_ptr.get()); | 308 return m_ptr->equals(other.m_ptr.get()); |
298 } | 309 } |
299 | 310 |
300 bool Json::operator< (const Json &other) const { | 311 bool Json::operator< (const Json &other) const { |
312 if (m_ptr == other.m_ptr) | |
313 return false; | |
301 if (m_ptr->type() != other.m_ptr->type()) | 314 if (m_ptr->type() != other.m_ptr->type()) |
302 return m_ptr->type() < other.m_ptr->type(); | 315 return m_ptr->type() < other.m_ptr->type(); |
303 | 316 |
304 return m_ptr->less(other.m_ptr.get()); | 317 return m_ptr->less(other.m_ptr.get()); |
305 } | 318 } |
324 | 337 |
325 static inline bool in_range(long x, long lower, long upper) { | 338 static inline bool in_range(long x, long lower, long upper) { |
326 return (x >= lower && x <= upper); | 339 return (x >= lower && x <= upper); |
327 } | 340 } |
328 | 341 |
342 namespace { | |
329 /* JsonParser | 343 /* JsonParser |
330 * | 344 * |
331 * Object that tracks all state of an in-progress parse. | 345 * Object that tracks all state of an in-progress parse. |
332 */ | 346 */ |
333 struct JsonParser { | 347 struct JsonParser final { |
334 | 348 |
335 /* State | 349 /* State |
336 */ | 350 */ |
337 const string &str; | 351 const string &str; |
338 size_t i; | 352 size_t i; |
372 bool consume_comment() { | 386 bool consume_comment() { |
373 bool comment_found = false; | 387 bool comment_found = false; |
374 if (str[i] == '/') { | 388 if (str[i] == '/') { |
375 i++; | 389 i++; |
376 if (i == str.size()) | 390 if (i == str.size()) |
377 return fail("unexpected end of input inside comment", 0); | 391 return fail("unexpected end of input after start of comment", false); |
378 if (str[i] == '/') { // inline comment | 392 if (str[i] == '/') { // inline comment |
379 i++; | 393 i++; |
380 if (i == str.size()) | 394 // advance until next line, or end of input |
381 return fail("unexpected end of input inside inline comment", 0); | 395 while (i < str.size() && str[i] != '\n') { |
382 // advance until next line | |
383 while (str[i] != '\n') { | |
384 i++; | 396 i++; |
385 if (i == str.size()) | |
386 return fail("unexpected end of input inside inline comment", 0); | |
387 } | 397 } |
388 comment_found = true; | 398 comment_found = true; |
389 } | 399 } |
390 else if (str[i] == '*') { // multiline comment | 400 else if (str[i] == '*') { // multiline comment |
391 i++; | 401 i++; |
392 if (i > str.size()-2) | 402 if (i > str.size()-2) |
393 return fail("unexpected end of input inside multi-line comment", 0); | 403 return fail("unexpected end of input inside multi-line comment", false); |
394 // advance until closing tokens | 404 // advance until closing tokens |
395 while (!(str[i] == '*' && str[i+1] == '/')) { | 405 while (!(str[i] == '*' && str[i+1] == '/')) { |
396 i++; | 406 i++; |
397 if (i > str.size()-2) | 407 if (i > str.size()-2) |
398 return fail( | 408 return fail( |
399 "unexpected end of input inside multi-line comment", 0); | 409 "unexpected end of input inside multi-line comment", false); |
400 } | 410 } |
401 i += 2; | 411 i += 2; |
402 if (i == str.size()) | |
403 return fail( | |
404 "unexpected end of input inside multi-line comment", 0); | |
405 comment_found = true; | 412 comment_found = true; |
406 } | 413 } |
407 else | 414 else |
408 return fail("malformed comment", 0); | 415 return fail("malformed comment", false); |
409 } | 416 } |
410 return comment_found; | 417 return comment_found; |
411 } | 418 } |
412 | 419 |
413 /* consume_garbage() | 420 /* consume_garbage() |
418 consume_whitespace(); | 425 consume_whitespace(); |
419 if(strategy == JsonParse::COMMENTS) { | 426 if(strategy == JsonParse::COMMENTS) { |
420 bool comment_found = false; | 427 bool comment_found = false; |
421 do { | 428 do { |
422 comment_found = consume_comment(); | 429 comment_found = consume_comment(); |
430 if (failed) return; | |
423 consume_whitespace(); | 431 consume_whitespace(); |
424 } | 432 } |
425 while(comment_found); | 433 while(comment_found); |
426 } | 434 } |
427 } | 435 } |
431 * Return the next non-whitespace character. If the end of the input is reached, | 439 * Return the next non-whitespace character. If the end of the input is reached, |
432 * flag an error and return 0. | 440 * flag an error and return 0. |
433 */ | 441 */ |
434 char get_next_token() { | 442 char get_next_token() { |
435 consume_garbage(); | 443 consume_garbage(); |
444 if (failed) return (char)0; | |
436 if (i == str.size()) | 445 if (i == str.size()) |
437 return fail("unexpected end of input", 0); | 446 return fail("unexpected end of input", (char)0); |
438 | 447 |
439 return str[i++]; | 448 return str[i++]; |
440 } | 449 } |
441 | 450 |
442 /* encode_utf8(pt, out) | 451 /* encode_utf8(pt, out) |
506 // relies on std::string returning the terminating NUL when | 515 // relies on std::string returning the terminating NUL when |
507 // accessing str[length]. Checking here reduces brittleness. | 516 // accessing str[length]. Checking here reduces brittleness. |
508 if (esc.length() < 4) { | 517 if (esc.length() < 4) { |
509 return fail("bad \\u escape: " + esc, ""); | 518 return fail("bad \\u escape: " + esc, ""); |
510 } | 519 } |
511 for (int j = 0; j < 4; j++) { | 520 for (size_t j = 0; j < 4; j++) { |
512 if (!in_range(esc[j], 'a', 'f') && !in_range(esc[j], 'A', 'F') | 521 if (!in_range(esc[j], 'a', 'f') && !in_range(esc[j], 'A', 'F') |
513 && !in_range(esc[j], '0', '9')) | 522 && !in_range(esc[j], '0', '9')) |
514 return fail("bad \\u escape: " + esc, ""); | 523 return fail("bad \\u escape: " + esc, ""); |
515 } | 524 } |
516 | 525 |
716 } | 725 } |
717 | 726 |
718 return fail("expected value, got " + esc(ch)); | 727 return fail("expected value, got " + esc(ch)); |
719 } | 728 } |
720 }; | 729 }; |
730 }//namespace { | |
721 | 731 |
722 Json Json::parse(const string &in, string &err, JsonParse strategy) { | 732 Json Json::parse(const string &in, string &err, JsonParse strategy) { |
723 JsonParser parser { in, 0, err, false, strategy }; | 733 JsonParser parser { in, 0, err, false, strategy }; |
724 Json result = parser.parse_json(0); | 734 Json result = parser.parse_json(0); |
725 | 735 |
726 // Check for any trailing garbage | 736 // Check for any trailing garbage |
727 parser.consume_garbage(); | 737 parser.consume_garbage(); |
738 if (parser.failed) | |
739 return Json(); | |
728 if (parser.i != in.size()) | 740 if (parser.i != in.size()) |
729 return parser.fail("unexpected trailing " + esc(in[parser.i])); | 741 return parser.fail("unexpected trailing " + esc(in[parser.i])); |
730 | 742 |
731 return result; | 743 return result; |
732 } | 744 } |
733 | 745 |
734 // Documented in json11.hpp | 746 // Documented in json11.hpp |
735 vector<Json> Json::parse_multi(const string &in, | 747 vector<Json> Json::parse_multi(const string &in, |
748 std::string::size_type &parser_stop_pos, | |
736 string &err, | 749 string &err, |
737 JsonParse strategy) { | 750 JsonParse strategy) { |
738 JsonParser parser { in, 0, err, false, strategy }; | 751 JsonParser parser { in, 0, err, false, strategy }; |
739 | 752 parser_stop_pos = 0; |
740 vector<Json> json_vec; | 753 vector<Json> json_vec; |
741 while (parser.i != in.size() && !parser.failed) { | 754 while (parser.i != in.size() && !parser.failed) { |
742 json_vec.push_back(parser.parse_json(0)); | 755 json_vec.push_back(parser.parse_json(0)); |
756 if (parser.failed) | |
757 break; | |
758 | |
743 // Check for another object | 759 // Check for another object |
744 parser.consume_garbage(); | 760 parser.consume_garbage(); |
761 if (parser.failed) | |
762 break; | |
763 parser_stop_pos = parser.i; | |
745 } | 764 } |
746 return json_vec; | 765 return json_vec; |
747 } | 766 } |
748 | 767 |
749 /* * * * * * * * * * * * * * * * * * * * | 768 /* * * * * * * * * * * * * * * * * * * * |