diff 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
line wrap: on
line diff
--- a/ext/json11/json11.cpp	Tue Jun 13 16:24:24 2017 +0100
+++ b/ext/json11/json11.cpp	Tue Jun 13 17:16:03 2017 +0100
@@ -37,11 +37,20 @@
 using std::initializer_list;
 using std::move;
 
+/* Helper for representing null - just a do-nothing struct, plus comparison
+ * operators so the helpers in JsonValue work. We can't use nullptr_t because
+ * it may not be orderable.
+ */
+struct NullStruct {
+    bool operator==(NullStruct) const { return true; }
+    bool operator<(NullStruct) const { return false; }
+};
+
 /* * * * * * * * * * * * * * * * * * * *
  * Serialization
  */
 
-static void dump(std::nullptr_t, string &out) {
+static void dump(NullStruct, string &out) {
     out += "null";
 }
 
@@ -208,9 +217,9 @@
     explicit JsonObject(Json::object &&value)      : Value(move(value)) {}
 };
 
-class JsonNull final : public Value<Json::NUL, std::nullptr_t> {
+class JsonNull final : public Value<Json::NUL, NullStruct> {
 public:
-    JsonNull() : Value(nullptr) {}
+    JsonNull() : Value({}) {}
 };
 
 /* * * * * * * * * * * * * * * * * * * *
@@ -291,6 +300,8 @@
  */
 
 bool Json::operator== (const Json &other) const {
+    if (m_ptr == other.m_ptr)
+        return true;
     if (m_ptr->type() != other.m_ptr->type())
         return false;
 
@@ -298,6 +309,8 @@
 }
 
 bool Json::operator< (const Json &other) const {
+    if (m_ptr == other.m_ptr)
+        return false;
     if (m_ptr->type() != other.m_ptr->type())
         return m_ptr->type() < other.m_ptr->type();
 
@@ -326,11 +339,12 @@
     return (x >= lower && x <= upper);
 }
 
+namespace {
 /* JsonParser
  *
  * Object that tracks all state of an in-progress parse.
  */
-struct JsonParser {
+struct JsonParser final {
 
     /* State
      */
@@ -374,38 +388,31 @@
       if (str[i] == '/') {
         i++;
         if (i == str.size())
-          return fail("unexpected end of input inside comment", 0);
+          return fail("unexpected end of input after start of comment", false);
         if (str[i] == '/') { // inline comment
           i++;
-          if (i == str.size())
-            return fail("unexpected end of input inside inline comment", 0);
-          // advance until next line
-          while (str[i] != '\n') {
+          // advance until next line, or end of input
+          while (i < str.size() && str[i] != '\n') {
             i++;
-            if (i == str.size())
-              return fail("unexpected end of input inside inline comment", 0);
           }
           comment_found = true;
         }
         else if (str[i] == '*') { // multiline comment
           i++;
           if (i > str.size()-2)
-            return fail("unexpected end of input inside multi-line comment", 0);
+            return fail("unexpected end of input inside multi-line comment", false);
           // advance until closing tokens
           while (!(str[i] == '*' && str[i+1] == '/')) {
             i++;
             if (i > str.size()-2)
               return fail(
-                "unexpected end of input inside multi-line comment", 0);
+                "unexpected end of input inside multi-line comment", false);
           }
           i += 2;
-          if (i == str.size())
-            return fail(
-              "unexpected end of input inside multi-line comment", 0);
           comment_found = true;
         }
         else
-          return fail("malformed comment", 0);
+          return fail("malformed comment", false);
       }
       return comment_found;
     }
@@ -420,6 +427,7 @@
         bool comment_found = false;
         do {
           comment_found = consume_comment();
+          if (failed) return;
           consume_whitespace();
         }
         while(comment_found);
@@ -433,8 +441,9 @@
      */
     char get_next_token() {
         consume_garbage();
+        if (failed) return (char)0;
         if (i == str.size())
-            return fail("unexpected end of input", 0);
+            return fail("unexpected end of input", (char)0);
 
         return str[i++];
     }
@@ -508,7 +517,7 @@
                 if (esc.length() < 4) {
                     return fail("bad \\u escape: " + esc, "");
                 }
-                for (int j = 0; j < 4; j++) {
+                for (size_t j = 0; j < 4; j++) {
                     if (!in_range(esc[j], 'a', 'f') && !in_range(esc[j], 'A', 'F')
                             && !in_range(esc[j], '0', '9'))
                         return fail("bad \\u escape: " + esc, "");
@@ -718,6 +727,7 @@
         return fail("expected value, got " + esc(ch));
     }
 };
+}//namespace {
 
 Json Json::parse(const string &in, string &err, JsonParse strategy) {
     JsonParser parser { in, 0, err, false, strategy };
@@ -725,6 +735,8 @@
 
     // Check for any trailing garbage
     parser.consume_garbage();
+    if (parser.failed)
+        return Json();
     if (parser.i != in.size())
         return parser.fail("unexpected trailing " + esc(in[parser.i]));
 
@@ -733,15 +745,22 @@
 
 // Documented in json11.hpp
 vector<Json> Json::parse_multi(const string &in,
+                               std::string::size_type &parser_stop_pos,
                                string &err,
                                JsonParse strategy) {
     JsonParser parser { in, 0, err, false, strategy };
-
+    parser_stop_pos = 0;
     vector<Json> json_vec;
     while (parser.i != in.size() && !parser.failed) {
         json_vec.push_back(parser.parse_json(0));
+        if (parser.failed)
+            break;
+
         // Check for another object
         parser.consume_garbage();
+        if (parser.failed)
+            break;
+        parser_stop_pos = parser.i;
     }
     return json_vec;
 }