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 /* * * * * * * * * * * * * * * * * * * *