| 1 | /* json11
 | 
| 2 |  *
 | 
| 3 |  * json11 is a tiny JSON library for C++11, providing JSON parsing and serialization.
 | 
| 4 |  *
 | 
| 5 |  * The core object provided by the library is json11::Json. A Json object represents any JSON
 | 
| 6 |  * value: null, bool, number (int or double), string (std::string), array (std::vector), or
 | 
| 7 |  * object (std::map).
 | 
| 8 |  *
 | 
| 9 |  * Json objects act like values: they can be assigned, copied, moved, compared for equality or
 | 
| 10 |  * order, etc. There are also helper methods Json::dump, to serialize a Json to a string, and
 | 
| 11 |  * Json::parse (static) to parse a std::string as a Json object.
 | 
| 12 |  *
 | 
| 13 |  * Internally, the various types of Json object are represented by the JsonValue class
 | 
| 14 |  * hierarchy.
 | 
| 15 |  *
 | 
| 16 |  * A note on numbers - JSON specifies the syntax of number formatting but not its semantics,
 | 
| 17 |  * so some JSON implementations distinguish between integers and floating-point numbers, while
 | 
| 18 |  * some don't. In json11, we choose the latter. Because some JSON implementations (namely
 | 
| 19 |  * Javascript itself) treat all numbers as the same type, distinguishing the two leads
 | 
| 20 |  * to JSON that will be *silently* changed by a round-trip through those implementations.
 | 
| 21 |  * Dangerous! To avoid that risk, json11 stores all numbers as double internally, but also
 | 
| 22 |  * provides integer helpers.
 | 
| 23 |  *
 | 
| 24 |  * Fortunately, double-precision IEEE754 ('double') can precisely store any integer in the
 | 
| 25 |  * range +/-2^53, which includes every 'int' on most systems. (Timestamps often use int64
 | 
| 26 |  * or long long to avoid the Y2038K problem; a double storing microseconds since some epoch
 | 
| 27 |  * will be exact for +/- 275 years.)
 | 
| 28 |  */
 | 
| 29 | 
 | 
| 30 | /* Copyright (c) 2013 Dropbox, Inc.
 | 
| 31 |  *
 | 
| 32 |  * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
| 33 |  * of this software and associated documentation files (the "Software"), to deal
 | 
| 34 |  * in the Software without restriction, including without limitation the rights
 | 
| 35 |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
| 36 |  * copies of the Software, and to permit persons to whom the Software is
 | 
| 37 |  * furnished to do so, subject to the following conditions:
 | 
| 38 |  *
 | 
| 39 |  * The above copyright notice and this permission notice shall be included in
 | 
| 40 |  * all copies or substantial portions of the Software.
 | 
| 41 |  *
 | 
| 42 |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
| 43 |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
| 44 |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
| 45 |  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
| 46 |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
| 47 |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
| 48 |  * THE SOFTWARE.
 | 
| 49 |  */
 | 
| 50 | 
 | 
| 51 | #pragma once
 | 
| 52 | 
 | 
| 53 | #include <cassert>
 | 
| 54 | #include <cmath>
 | 
| 55 | #include <cstdint>
 | 
| 56 | #include <cstdio>
 | 
| 57 | #include <cstdlib>
 | 
| 58 | #include <initializer_list>
 | 
| 59 | #include <iosfwd>
 | 
| 60 | #include <limits>
 | 
| 61 | #include <map>
 | 
| 62 | #include <memory>
 | 
| 63 | #include <string>
 | 
| 64 | #include <type_traits>
 | 
| 65 | #include <utility>
 | 
| 66 | #include <vector>
 | 
| 67 | 
 | 
| 68 | #ifdef _MSC_VER
 | 
| 69 | #pragma warning(push)
 | 
| 70 | #pragma warning(disable : 4244)
 | 
| 71 | #if _MSC_VER <= 1800  // VS 2013
 | 
| 72 | #ifndef noexcept
 | 
| 73 | #define noexcept throw()
 | 
| 74 | #endif
 | 
| 75 | 
 | 
| 76 | #ifndef snprintf
 | 
| 77 | #define snprintf _snprintf_s
 | 
| 78 | #endif
 | 
| 79 | #endif
 | 
| 80 | #endif
 | 
| 81 | 
 | 
| 82 | #if defined(__GNUC__) && (__GNUC__ >= 7)
 | 
| 83 | #pragma GCC diagnostic push
 | 
| 84 | #pragma GCC diagnostic ignored "-Woverloaded-virtual"
 | 
| 85 | #endif
 | 
| 86 | 
 | 
| 87 | namespace json11 {
 | 
| 88 | 
 | 
| 89 | enum JsonParse { STANDARD, COMMENTS };
 | 
| 90 | 
 | 
| 91 | class JsonValue;
 | 
| 92 | 
 | 
| 93 | class Json final {
 | 
| 94 | public:
 | 
| 95 |     // Types
 | 
| 96 |     enum Type { NUL, NUMBER, BOOL, STRING, ARRAY, OBJECT };
 | 
| 97 | 
 | 
| 98 |     // Array and object typedefs
 | 
| 99 |     using array = std::vector<Json>;
 | 
| 100 |     using object = std::map<std::string, Json>;
 | 
| 101 | 
 | 
| 102 |     // Constructors for the various types of JSON value.
 | 
| 103 |     Json() noexcept;                 // NUL
 | 
| 104 |     Json(std::nullptr_t) noexcept;   // NUL
 | 
| 105 |     Json(double value);              // NUMBER
 | 
| 106 |     Json(long long value);           // NUMBER
 | 
| 107 |     Json(bool value);                // BOOL
 | 
| 108 |     Json(const std::string& value);  // STRING
 | 
| 109 |     Json(std::string&& value);       // STRING
 | 
| 110 |     Json(const char* value);         // STRING
 | 
| 111 |     Json(const array& values);       // ARRAY
 | 
| 112 |     Json(array&& values);            // ARRAY
 | 
| 113 |     Json(const object& values);      // OBJECT
 | 
| 114 |     Json(object&& values);           // OBJECT
 | 
| 115 | 
 | 
| 116 |     // Implicit constructor: anything with a to_json() function.
 | 
| 117 |     template <class T, class = decltype(&T::to_json)>
 | 
| 118 |     Json(const T& t) : Json(t.to_json()) {}
 | 
| 119 | 
 | 
| 120 |     // Implicit constructor: map-like objects (std::map, std::unordered_map, etc)
 | 
| 121 |     template <class M,
 | 
| 122 |             typename std::enable_if<
 | 
| 123 |                     std::is_constructible<std::string, decltype(std::declval<M>().begin()->first)>::value &&
 | 
| 124 |                             std::is_constructible<Json, decltype(std::declval<M>().begin()->second)>::value,
 | 
| 125 |                     int>::type = 0>
 | 
| 126 |     Json(const M& m) : Json(object(m.begin(), m.end())) {}
 | 
| 127 | 
 | 
| 128 |     // Implicit constructor: vector-like objects (std::list, std::vector, std::set, etc)
 | 
| 129 |     template <class V,
 | 
| 130 |             typename std::enable_if<std::is_constructible<Json, decltype(*std::declval<V>().begin())>::value,
 | 
| 131 |                     int>::type = 0>
 | 
| 132 |     Json(const V& v) : Json(array(v.begin(), v.end())) {}
 | 
| 133 | 
 | 
| 134 |     // This prevents Json(some_pointer) from accidentally producing a bool. Use
 | 
| 135 |     // Json(bool(some_pointer)) if that behavior is desired.
 | 
| 136 |     Json(void*) = delete;
 | 
| 137 | 
 | 
| 138 |     // Accessors
 | 
| 139 |     Type type() const;
 | 
| 140 | 
 | 
| 141 |     bool is_null() const {
 | 
| 142 |         return type() == NUL;
 | 
| 143 |     }
 | 
| 144 |     bool is_number() const {
 | 
| 145 |         return type() == NUMBER;
 | 
| 146 |     }
 | 
| 147 |     bool is_bool() const {
 | 
| 148 |         return type() == BOOL;
 | 
| 149 |     }
 | 
| 150 |     bool is_string() const {
 | 
| 151 |         return type() == STRING;
 | 
| 152 |     }
 | 
| 153 |     bool is_array() const {
 | 
| 154 |         return type() == ARRAY;
 | 
| 155 |     }
 | 
| 156 |     bool is_object() const {
 | 
| 157 |         return type() == OBJECT;
 | 
| 158 |     }
 | 
| 159 | 
 | 
| 160 |     // Return the enclosed value if this is a number, 0 otherwise. Note that json11 does not
 | 
| 161 |     // distinguish between integer and non-integer numbers - number_value() and int_value()
 | 
| 162 |     // can both be applied to a NUMBER-typed object.
 | 
| 163 |     double number_value() const;
 | 
| 164 |     int int_value() const;
 | 
| 165 |     long long long_value() const;
 | 
| 166 | 
 | 
| 167 |     // Return the enclosed value if this is a boolean, false otherwise.
 | 
| 168 |     bool bool_value() const;
 | 
| 169 |     // Return the enclosed string if this is a string, "" otherwise.
 | 
| 170 |     const std::string& string_value() const;
 | 
| 171 |     // Return the enclosed std::vector if this is an array, or an empty vector otherwise.
 | 
| 172 |     const array& array_items() const;
 | 
| 173 |     // Return the enclosed std::map if this is an object, or an empty map otherwise.
 | 
| 174 |     const object& object_items() const;
 | 
| 175 | 
 | 
| 176 |     // Return a reference to arr[i] if this is an array, Json() otherwise.
 | 
| 177 |     const Json& operator[](std::size_t i) const;
 | 
| 178 |     // Return a reference to obj[key] if this is an object, Json() otherwise.
 | 
| 179 |     const Json& operator[](const std::string& key) const;
 | 
| 180 | 
 | 
| 181 |     // Serialize.
 | 
| 182 |     void dump(std::string& out) const;
 | 
| 183 |     std::string dump() const {
 | 
| 184 |         std::string out;
 | 
| 185 |         dump(out);
 | 
| 186 |         return out;
 | 
| 187 |     }
 | 
| 188 | 
 | 
| 189 |     // Parse. If parse fails, return Json() and assign an error message to err.
 | 
| 190 |     static Json parse(const std::string& in, std::string& err, JsonParse strategy = JsonParse::STANDARD);
 | 
| 191 | 
 | 
| 192 |     static Json parse(const char* in, std::string& err, JsonParse strategy = JsonParse::STANDARD) {
 | 
| 193 |         if (in == nullptr) {
 | 
| 194 |             err = "null input";
 | 
| 195 |             return nullptr;
 | 
| 196 |         }
 | 
| 197 |         return parse(std::string(in), err, strategy);
 | 
| 198 |     }
 | 
| 199 |     // Parse multiple objects, concatenated or separated by whitespace
 | 
| 200 |     static std::vector<Json> parse_multi(const std::string& in, std::string::size_type& parser_stop_pos,
 | 
| 201 |             std::string& err, JsonParse strategy = JsonParse::STANDARD);
 | 
| 202 | 
 | 
| 203 |     static inline std::vector<Json> parse_multi(
 | 
| 204 |             const std::string& in, std::string& err, JsonParse strategy = JsonParse::STANDARD) {
 | 
| 205 |         std::string::size_type parser_stop_pos;
 | 
| 206 |         return parse_multi(in, parser_stop_pos, err, strategy);
 | 
| 207 |     }
 | 
| 208 | 
 | 
| 209 |     bool operator==(const Json& rhs) const;
 | 
| 210 |     bool operator<(const Json& rhs) const;
 | 
| 211 |     bool operator!=(const Json& rhs) const {
 | 
| 212 |         return !(*this == rhs);
 | 
| 213 |     }
 | 
| 214 |     bool operator<=(const Json& rhs) const {
 | 
| 215 |         return !(rhs < *this);
 | 
| 216 |     }
 | 
| 217 |     bool operator>(const Json& rhs) const {
 | 
| 218 |         return (rhs < *this);
 | 
| 219 |     }
 | 
| 220 |     bool operator>=(const Json& rhs) const {
 | 
| 221 |         return !(*this < rhs);
 | 
| 222 |     }
 | 
| 223 | 
 | 
| 224 |     /* has_shape(types, err)
 | 
| 225 |      *
 | 
| 226 |      * Return true if this is a JSON object and, for each item in types, has a field of
 | 
| 227 |      * the given type. If not, return false and set err to a descriptive message.
 | 
| 228 |      */
 | 
| 229 |     using shape = std::initializer_list<std::pair<std::string, Type>>;
 | 
| 230 |     bool has_shape(const shape& types, std::string& err) const {
 | 
| 231 |         if (!is_object()) {
 | 
| 232 |             err = "expected JSON object, got " + dump();
 | 
| 233 |             return false;
 | 
| 234 |         }
 | 
| 235 | 
 | 
| 236 |         for (auto& item : types) {
 | 
| 237 |             if ((*this)[item.first].type() != item.second) {
 | 
| 238 |                 err = "bad type for " + item.first + " in " + dump();
 | 
| 239 |                 return false;
 | 
| 240 |             }
 | 
| 241 |         }
 | 
| 242 | 
 | 
| 243 |         return true;
 | 
| 244 |     }
 | 
| 245 | 
 | 
| 246 | private:
 | 
| 247 |     std::shared_ptr<JsonValue> m_ptr;
 | 
| 248 | };
 | 
| 249 | 
 | 
| 250 | // Internal class hierarchy - JsonValue objects are not exposed to users of this API.
 | 
| 251 | class JsonValue {
 | 
| 252 | protected:
 | 
| 253 |     friend class Json;
 | 
| 254 |     friend class JsonInt;
 | 
| 255 |     friend class JsonDouble;
 | 
| 256 |     virtual Json::Type type() const = 0;
 | 
| 257 |     virtual bool equals(const JsonValue* other) const = 0;
 | 
| 258 |     virtual bool less(const JsonValue* other) const = 0;
 | 
| 259 |     virtual void dump(std::string& out) const = 0;
 | 
| 260 |     virtual double number_value() const;
 | 
| 261 |     virtual int int_value() const;
 | 
| 262 |     virtual long long long_value() const;
 | 
| 263 |     virtual bool bool_value() const;
 | 
| 264 |     virtual const std::string& string_value() const;
 | 
| 265 |     virtual const Json::array& array_items() const;
 | 
| 266 |     virtual const Json& operator[](std::size_t i) const;
 | 
| 267 |     virtual const Json::object& object_items() const;
 | 
| 268 |     virtual const Json& operator[](const std::string& key) const;
 | 
| 269 |     virtual ~JsonValue() = default;
 | 
| 270 | };
 | 
| 271 | 
 | 
| 272 | static const int max_depth = 200;
 | 
| 273 | 
 | 
| 274 | /* Helper for representing null - just a do-nothing struct, plus comparison
 | 
| 275 |  * operators so the helpers in JsonValue work. We can't use nullptr_t because
 | 
| 276 |  * it may not be orderable.
 | 
| 277 |  */
 | 
| 278 | struct NullStruct {
 | 
| 279 |     bool operator==(NullStruct) const {
 | 
| 280 |         return true;
 | 
| 281 |     }
 | 
| 282 |     bool operator<(NullStruct) const {
 | 
| 283 |         return false;
 | 
| 284 |     }
 | 
| 285 | };
 | 
| 286 | 
 | 
| 287 | /* * * * * * * * * * * * * * * * * * * *
 | 
| 288 |  * Serialization
 | 
| 289 |  */
 | 
| 290 | 
 | 
| 291 | static void dump(NullStruct, std::string& out) {
 | 
| 292 |     out += "null";
 | 
| 293 | }
 | 
| 294 | 
 | 
| 295 | static void dump(double value, std::string& out) {
 | 
| 296 |     if (std::isfinite(value)) {
 | 
| 297 |         char buf[32];
 | 
| 298 |         snprintf(buf, sizeof buf, "%.17g", value);
 | 
| 299 |         out += buf;
 | 
| 300 |     } else {
 | 
| 301 |         out += "null";
 | 
| 302 |     }
 | 
| 303 | }
 | 
| 304 | 
 | 
| 305 | static void dump(long long value, std::string& out) {
 | 
| 306 |     char buf[32];
 | 
| 307 |     snprintf(buf, sizeof buf, "%lld", value);
 | 
| 308 |     out += buf;
 | 
| 309 | }
 | 
| 310 | 
 | 
| 311 | static void dump(bool value, std::string& out) {
 | 
| 312 |     out += value ? "true" : "false";
 | 
| 313 | }
 | 
| 314 | 
 | 
| 315 | static void dump(const std::string& value, std::string& out) {
 | 
| 316 |     out += '"';
 | 
| 317 |     for (std::size_t i = 0; i < value.length(); i++) {
 | 
| 318 |         const char ch = value[i];
 | 
| 319 |         if (ch == '\\') {
 | 
| 320 |             out += "\\\\";
 | 
| 321 |         } else if (ch == '"') {
 | 
| 322 |             out += "\\\"";
 | 
| 323 |         } else if (ch == '\b') {
 | 
| 324 |             out += "\\b";
 | 
| 325 |         } else if (ch == '\f') {
 | 
| 326 |             out += "\\f";
 | 
| 327 |         } else if (ch == '\n') {
 | 
| 328 |             out += "\\n";
 | 
| 329 |         } else if (ch == '\r') {
 | 
| 330 |             out += "\\r";
 | 
| 331 |         } else if (ch == '\t') {
 | 
| 332 |             out += "\\t";
 | 
| 333 |         } else if (static_cast<uint8_t>(ch) <= 0x1f) {
 | 
| 334 |             char buf[8];
 | 
| 335 |             snprintf(buf, sizeof buf, "\\u%04x", ch);
 | 
| 336 |             out += buf;
 | 
| 337 |         } else if (static_cast<uint8_t>(ch) == 0xe2 && static_cast<uint8_t>(value[i + 1]) == 0x80 &&
 | 
| 338 |                    static_cast<uint8_t>(value[i + 2]) == 0xa8) {
 | 
| 339 |             out += "\\u2028";
 | 
| 340 |             i += 2;
 | 
| 341 |         } else if (static_cast<uint8_t>(ch) == 0xe2 && static_cast<uint8_t>(value[i + 1]) == 0x80 &&
 | 
| 342 |                    static_cast<uint8_t>(value[i + 2]) == 0xa9) {
 | 
| 343 |             out += "\\u2029";
 | 
| 344 |             i += 2;
 | 
| 345 |         } else {
 | 
| 346 |             out += ch;
 | 
| 347 |         }
 | 
| 348 |     }
 | 
| 349 |     out += '"';
 | 
| 350 | }
 | 
| 351 | 
 | 
| 352 | static void dump(const Json::array& values, std::string& out) {
 | 
| 353 |     bool first = true;
 | 
| 354 |     out += "[";
 | 
| 355 |     for (const auto& value : values) {
 | 
| 356 |         if (!first) out += ", ";
 | 
| 357 |         value.dump(out);
 | 
| 358 |         first = false;
 | 
| 359 |     }
 | 
| 360 |     out += "]";
 | 
| 361 | }
 | 
| 362 | 
 | 
| 363 | static void dump(const Json::object& values, std::string& out) {
 | 
| 364 |     bool first = true;
 | 
| 365 |     out += "{";
 | 
| 366 |     for (const auto& kv : values) {
 | 
| 367 |         if (!first) out += ", ";
 | 
| 368 |         dump(kv.first, out);
 | 
| 369 |         out += ": ";
 | 
| 370 |         kv.second.dump(out);
 | 
| 371 |         first = false;
 | 
| 372 |     }
 | 
| 373 |     out += "}";
 | 
| 374 | }
 | 
| 375 | 
 | 
| 376 | inline void Json::dump(std::string& out) const {
 | 
| 377 |     m_ptr->dump(out);
 | 
| 378 | }
 | 
| 379 | 
 | 
| 380 | /* * * * * * * * * * * * * * * * * * * *
 | 
| 381 |  * Value wrappers
 | 
| 382 |  */
 | 
| 383 | 
 | 
| 384 | template <Json::Type tag, typename T>
 | 
| 385 | class Value : public JsonValue {
 | 
| 386 | protected:
 | 
| 387 |     // Constructors
 | 
| 388 |     explicit Value(T value) : m_value(std::move(value)) {}
 | 
| 389 | 
 | 
| 390 |     // Get type tag
 | 
| 391 |     Json::Type type() const override {
 | 
| 392 |         return tag;
 | 
| 393 |     }
 | 
| 394 | 
 | 
| 395 |     // Comparisons
 | 
| 396 |     bool equals(const JsonValue* other) const override {
 | 
| 397 |         return m_value == static_cast<const Value<tag, T>*>(other)->m_value;
 | 
| 398 |     }
 | 
| 399 |     bool less(const JsonValue* other) const override {
 | 
| 400 |         return m_value < static_cast<const Value<tag, T>*>(other)->m_value;
 | 
| 401 |     }
 | 
| 402 | 
 | 
| 403 |     const T m_value;
 | 
| 404 |     void dump(std::string& out) const override {
 | 
| 405 |         json11::dump(m_value, out);
 | 
| 406 |     }
 | 
| 407 | };
 | 
| 408 | 
 | 
| 409 | class JsonDouble final : public Value<Json::NUMBER, double> {
 | 
| 410 |     double number_value() const override {
 | 
| 411 |         return m_value;
 | 
| 412 |     }
 | 
| 413 |     int int_value() const override {
 | 
| 414 |         return static_cast<int>(m_value);
 | 
| 415 |     }
 | 
| 416 |     long long long_value() const override {
 | 
| 417 |         return static_cast<long long>(m_value);
 | 
| 418 |     }
 | 
| 419 |     bool equals(const JsonValue* other) const override {
 | 
| 420 |         return m_value == other->number_value();
 | 
| 421 |     }
 | 
| 422 |     bool less(const JsonValue* other) const override {
 | 
| 423 |         return m_value < other->number_value();
 | 
| 424 |     }
 | 
| 425 | 
 | 
| 426 | public:
 | 
| 427 |     explicit JsonDouble(double value) : Value(value) {}
 | 
| 428 | };
 | 
| 429 | 
 | 
| 430 | class JsonInt final : public Value<Json::NUMBER, long long> {
 | 
| 431 |     double number_value() const override {
 | 
| 432 |         return m_value;
 | 
| 433 |     }
 | 
| 434 |     int int_value() const override {
 | 
| 435 |         return m_value;
 | 
| 436 |     }
 | 
| 437 |     long long long_value() const override {
 | 
| 438 |         return static_cast<long long>(m_value);
 | 
| 439 |     }
 | 
| 440 |     bool equals(const JsonValue* other) const override {
 | 
| 441 |         return m_value == other->number_value();
 | 
| 442 |     }
 | 
| 443 |     bool less(const JsonValue* other) const override {
 | 
| 444 |         return m_value < other->number_value();
 | 
| 445 |     }
 | 
| 446 | 
 | 
| 447 | public:
 | 
| 448 |     explicit JsonInt(int value) : Value(value) {}
 | 
| 449 | };
 | 
| 450 | 
 | 
| 451 | class JsonBoolean final : public Value<Json::BOOL, bool> {
 | 
| 452 |     bool bool_value() const override {
 | 
| 453 |         return m_value;
 | 
| 454 |     }
 | 
| 455 | 
 | 
| 456 | public:
 | 
| 457 |     explicit JsonBoolean(bool value) : Value(value) {}
 | 
| 458 | };
 | 
| 459 | 
 | 
| 460 | class JsonString final : public Value<Json::STRING, std::string> {
 | 
| 461 |     const std::string& string_value() const override {
 | 
| 462 |         return m_value;
 | 
| 463 |     }
 | 
| 464 | 
 | 
| 465 | public:
 | 
| 466 |     explicit JsonString(const std::string& value) : Value(value) {}
 | 
| 467 |     explicit JsonString(std::string&& value) : Value(std::move(value)) {}
 | 
| 468 | };
 | 
| 469 | 
 | 
| 470 | class JsonArray final : public Value<Json::ARRAY, Json::array> {
 | 
| 471 |     const Json::array& array_items() const override {
 | 
| 472 |         return m_value;
 | 
| 473 |     }
 | 
| 474 |     const Json& operator[](std::size_t i) const override;
 | 
| 475 | 
 | 
| 476 | public:
 | 
| 477 |     explicit JsonArray(const Json::array& value) : Value(value) {}
 | 
| 478 |     explicit JsonArray(Json::array&& value) : Value(std::move(value)) {}
 | 
| 479 | };
 | 
| 480 | 
 | 
| 481 | class JsonObject final : public Value<Json::OBJECT, Json::object> {
 | 
| 482 |     const Json::object& object_items() const override {
 | 
| 483 |         return m_value;
 | 
| 484 |     }
 | 
| 485 |     const Json& operator[](const std::string& key) const override;
 | 
| 486 | 
 | 
| 487 | public:
 | 
| 488 |     explicit JsonObject(const Json::object& value) : Value(value) {}
 | 
| 489 |     explicit JsonObject(Json::object&& value) : Value(std::move(value)) {}
 | 
| 490 | };
 | 
| 491 | 
 | 
| 492 | class JsonNull final : public Value<Json::NUL, NullStruct> {
 | 
| 493 | public:
 | 
| 494 |     JsonNull() : Value({}) {}
 | 
| 495 | };
 | 
| 496 | 
 | 
| 497 | /* * * * * * * * * * * * * * * * * * * *
 | 
| 498 |  * Static globals - static-init-safe
 | 
| 499 |  */
 | 
| 500 | struct Statics {
 | 
| 501 |     const std::shared_ptr<JsonValue> null = std::make_shared<JsonNull>();
 | 
| 502 |     const std::shared_ptr<JsonValue> t = std::make_shared<JsonBoolean>(true);
 | 
| 503 |     const std::shared_ptr<JsonValue> f = std::make_shared<JsonBoolean>(false);
 | 
| 504 |     const std::string empty_string{};
 | 
| 505 |     const std::vector<Json> empty_vector{};
 | 
| 506 |     const std::map<std::string, Json> empty_map{};
 | 
| 507 |     Statics() = default;
 | 
| 508 | };
 | 
| 509 | 
 | 
| 510 | static const Statics& statics() {
 | 
| 511 |     static const Statics s{};
 | 
| 512 |     return s;
 | 
| 513 | }
 | 
| 514 | 
 | 
| 515 | static const Json& static_null() {
 | 
| 516 |     // This has to be separate, not in Statics, because Json() accesses statics().null.
 | 
| 517 |     static const Json json_null;
 | 
| 518 |     return json_null;
 | 
| 519 | }
 | 
| 520 | 
 | 
| 521 | /* * * * * * * * * * * * * * * * * * * *
 | 
| 522 |  * Constructors
 | 
| 523 |  */
 | 
| 524 | 
 | 
| 525 | inline Json::Json() noexcept : m_ptr(statics().null) {}
 | 
| 526 | inline Json::Json(std::nullptr_t) noexcept : m_ptr(statics().null) {}
 | 
| 527 | inline Json::Json(double value) : m_ptr(std::make_shared<JsonDouble>(value)) {}
 | 
| 528 | inline Json::Json(long long value) : m_ptr(std::make_shared<JsonInt>(value)) {}
 | 
| 529 | inline Json::Json(bool value) : m_ptr(value ? statics().t : statics().f) {}
 | 
| 530 | inline Json::Json(const std::string& value) : m_ptr(std::make_shared<JsonString>(value)) {}
 | 
| 531 | inline Json::Json(std::string&& value) : m_ptr(std::make_shared<JsonString>(std::move(value))) {}
 | 
| 532 | inline Json::Json(const char* value) : m_ptr(std::make_shared<JsonString>(value)) {}
 | 
| 533 | inline Json::Json(const Json::array& values) : m_ptr(std::make_shared<JsonArray>(values)) {}
 | 
| 534 | inline Json::Json(Json::array&& values) : m_ptr(std::make_shared<JsonArray>(std::move(values))) {}
 | 
| 535 | inline Json::Json(const Json::object& values) : m_ptr(std::make_shared<JsonObject>(values)) {}
 | 
| 536 | inline Json::Json(Json::object&& values) : m_ptr(std::make_shared<JsonObject>(std::move(values))) {}
 | 
| 537 | 
 | 
| 538 | /* * * * * * * * * * * * * * * * * * * *
 | 
| 539 |  * Accessors
 | 
| 540 |  */
 | 
| 541 | 
 | 
| 542 | inline Json::Type Json::type() const {
 | 
| 543 |     return m_ptr->type();
 | 
| 544 | }
 | 
| 545 | inline double Json::number_value() const {
 | 
| 546 |     return m_ptr->number_value();
 | 
| 547 | }
 | 
| 548 | inline int Json::int_value() const {
 | 
| 549 |     return m_ptr->int_value();
 | 
| 550 | }
 | 
| 551 | inline long long Json::long_value() const {
 | 
| 552 |     return m_ptr->long_value();
 | 
| 553 | }
 | 
| 554 | inline bool Json::bool_value() const {
 | 
| 555 |     return m_ptr->bool_value();
 | 
| 556 | }
 | 
| 557 | inline const std::string& Json::string_value() const {
 | 
| 558 |     return m_ptr->string_value();
 | 
| 559 | }
 | 
| 560 | inline const std::vector<Json>& Json::array_items() const {
 | 
| 561 |     return m_ptr->array_items();
 | 
| 562 | }
 | 
| 563 | inline const std::map<std::string, Json>& Json::object_items() const {
 | 
| 564 |     return m_ptr->object_items();
 | 
| 565 | }
 | 
| 566 | inline const Json& Json::operator[](std::size_t i) const {
 | 
| 567 |     return (*m_ptr)[i];
 | 
| 568 | }
 | 
| 569 | inline const Json& Json::operator[](const std::string& key) const {
 | 
| 570 |     return (*m_ptr)[key];
 | 
| 571 | }
 | 
| 572 | 
 | 
| 573 | inline double JsonValue::number_value() const {
 | 
| 574 |     return 0;
 | 
| 575 | }
 | 
| 576 | inline int JsonValue::int_value() const {
 | 
| 577 |     return 0;
 | 
| 578 | }
 | 
| 579 | inline long long JsonValue::long_value() const {
 | 
| 580 |     return 0;
 | 
| 581 | }
 | 
| 582 | inline bool JsonValue::bool_value() const {
 | 
| 583 |     return false;
 | 
| 584 | }
 | 
| 585 | inline const std::string& JsonValue::string_value() const {
 | 
| 586 |     return statics().empty_string;
 | 
| 587 | }
 | 
| 588 | inline const std::vector<Json>& JsonValue::array_items() const {
 | 
| 589 |     return statics().empty_vector;
 | 
| 590 | }
 | 
| 591 | inline const std::map<std::string, Json>& JsonValue::object_items() const {
 | 
| 592 |     return statics().empty_map;
 | 
| 593 | }
 | 
| 594 | inline const Json& JsonValue::operator[](std::size_t) const {
 | 
| 595 |     return static_null();
 | 
| 596 | }
 | 
| 597 | inline const Json& JsonValue::operator[](const std::string&) const {
 | 
| 598 |     return static_null();
 | 
| 599 | }
 | 
| 600 | 
 | 
| 601 | inline const Json& JsonObject::operator[](const std::string& key) const {
 | 
| 602 |     auto iter = m_value.find(key);
 | 
| 603 |     return (iter == m_value.end()) ? static_null() : iter->second;
 | 
| 604 | }
 | 
| 605 | inline const Json& JsonArray::operator[](std::size_t i) const {
 | 
| 606 |     if (i >= m_value.size()) {
 | 
| 607 |         return static_null();
 | 
| 608 |     }
 | 
| 609 |     return m_value[i];
 | 
| 610 | }
 | 
| 611 | 
 | 
| 612 | /* * * * * * * * * * * * * * * * * * * *
 | 
| 613 |  * Comparison
 | 
| 614 |  */
 | 
| 615 | 
 | 
| 616 | inline bool Json::operator==(const Json& other) const {
 | 
| 617 |     if (m_ptr == other.m_ptr) {
 | 
| 618 |         return true;
 | 
| 619 |     }
 | 
| 620 |     if (m_ptr->type() != other.m_ptr->type()) {
 | 
| 621 |         return false;
 | 
| 622 |     }
 | 
| 623 | 
 | 
| 624 |     return m_ptr->equals(other.m_ptr.get());
 | 
| 625 | }
 | 
| 626 | 
 | 
| 627 | inline bool Json::operator<(const Json& other) const {
 | 
| 628 |     if (m_ptr == other.m_ptr) {
 | 
| 629 |         return false;
 | 
| 630 |     }
 | 
| 631 |     if (m_ptr->type() != other.m_ptr->type()) {
 | 
| 632 |         return m_ptr->type() < other.m_ptr->type();
 | 
| 633 |     }
 | 
| 634 | 
 | 
| 635 |     return m_ptr->less(other.m_ptr.get());
 | 
| 636 | }
 | 
| 637 | 
 | 
| 638 | /* * * * * * * * * * * * * * * * * * * *
 | 
| 639 |  * Parsing
 | 
| 640 |  */
 | 
| 641 | 
 | 
| 642 | /* esc(c)
 | 
| 643 |  *
 | 
| 644 |  * Format char c suitable for printing in an error message.
 | 
| 645 |  */
 | 
| 646 | static inline std::string esc(char c) {
 | 
| 647 |     char buf[12];
 | 
| 648 |     if (static_cast<uint8_t>(c) >= 0x20 && static_cast<uint8_t>(c) <= 0x7f) {
 | 
| 649 |         snprintf(buf, sizeof buf, "'%c' (%d)", c, c);
 | 
| 650 |     } else {
 | 
| 651 |         snprintf(buf, sizeof buf, "(%d)", c);
 | 
| 652 |     }
 | 
| 653 |     return std::string(buf);
 | 
| 654 | }
 | 
| 655 | 
 | 
| 656 | static inline bool in_range(long x, long lower, long upper) {
 | 
| 657 |     return (x >= lower && x <= upper);
 | 
| 658 | }
 | 
| 659 | 
 | 
| 660 | namespace {
 | 
| 661 | /* JsonParser
 | 
| 662 |  *
 | 
| 663 |  * Object that tracks all state of an in-progress parse.
 | 
| 664 |  */
 | 
| 665 | struct JsonParser final {
 | 
| 666 |     /* State
 | 
| 667 |      */
 | 
| 668 |     const std::string& str;
 | 
| 669 |     std::size_t i;
 | 
| 670 |     std::string& err;
 | 
| 671 |     bool failed;
 | 
| 672 |     const JsonParse strategy;
 | 
| 673 | 
 | 
| 674 |     /* fail(msg, err_ret = Json())
 | 
| 675 |      *
 | 
| 676 |      * Mark this parse as failed.
 | 
| 677 |      */
 | 
| 678 |     Json fail(std::string&& msg) {
 | 
| 679 |         return fail(std::move(msg), Json());
 | 
| 680 |     }
 | 
| 681 | 
 | 
| 682 |     template <typename T>
 | 
| 683 |     T fail(std::string&& msg, T err_ret) {
 | 
| 684 |         if (!failed) {
 | 
| 685 |             err = std::move(msg);
 | 
| 686 |         }
 | 
| 687 |         failed = true;
 | 
| 688 |         return err_ret;
 | 
| 689 |     }
 | 
| 690 | 
 | 
| 691 |     /* consume_whitespace()
 | 
| 692 |      *
 | 
| 693 |      * Advance until the current character is non-whitespace.
 | 
| 694 |      */
 | 
| 695 |     void consume_whitespace() {
 | 
| 696 |         while (str[i] == ' ' || str[i] == '\r' || str[i] == '\n' || str[i] == '\t') {
 | 
| 697 |             i++;
 | 
| 698 |         }
 | 
| 699 |     }
 | 
| 700 | 
 | 
| 701 |     /* consume_comment()
 | 
| 702 |      *
 | 
| 703 |      * Advance comments (c-style inline and multiline).
 | 
| 704 |      */
 | 
| 705 |     bool consume_comment() {
 | 
| 706 |         bool comment_found = false;
 | 
| 707 |         if (str[i] == '/') {
 | 
| 708 |             i++;
 | 
| 709 |             if (i == str.size()) {
 | 
| 710 |                 return fail("unexpected end of input after start of comment", false);
 | 
| 711 |             }
 | 
| 712 |             if (str[i] == '/') {  // inline comment
 | 
| 713 |                 i++;
 | 
| 714 |                 // advance until next line, or end of input
 | 
| 715 |                 while (i < str.size() && str[i] != '\n') {
 | 
| 716 |                     i++;
 | 
| 717 |                 }
 | 
| 718 |                 comment_found = true;
 | 
| 719 |             } else if (str[i] == '*') {  // multiline comment
 | 
| 720 |                 i++;
 | 
| 721 |                 if (i > str.size() - 2)
 | 
| 722 |                     return fail("unexpected end of input inside multi-line comment", false);
 | 
| 723 |                 // advance until closing tokens
 | 
| 724 |                 while (!(str[i] == '*' && str[i + 1] == '/')) {
 | 
| 725 |                     i++;
 | 
| 726 |                     if (i > str.size() - 2)
 | 
| 727 |                         return fail("unexpected end of input inside multi-line comment", false);
 | 
| 728 |                 }
 | 
| 729 |                 i += 2;
 | 
| 730 |                 comment_found = true;
 | 
| 731 |             } else {
 | 
| 732 |                 return fail("malformed comment", false);
 | 
| 733 |             }
 | 
| 734 |         }
 | 
| 735 |         return comment_found;
 | 
| 736 |     }
 | 
| 737 | 
 | 
| 738 |     /* consume_garbage()
 | 
| 739 |      *
 | 
| 740 |      * Advance until the current character is non-whitespace and non-comment.
 | 
| 741 |      */
 | 
| 742 |     void consume_garbage() {
 | 
| 743 |         consume_whitespace();
 | 
| 744 |         if (strategy == JsonParse::COMMENTS) {
 | 
| 745 |             bool comment_found = false;
 | 
| 746 |             do {
 | 
| 747 |                 comment_found = consume_comment();
 | 
| 748 |                 if (failed) {
 | 
| 749 |                     return;
 | 
| 750 |                 }
 | 
| 751 |                 consume_whitespace();
 | 
| 752 |             } while (comment_found);
 | 
| 753 |         }
 | 
| 754 |     }
 | 
| 755 | 
 | 
| 756 |     /* get_next_token()
 | 
| 757 |      *
 | 
| 758 |      * Return the next non-whitespace character. If the end of the input is reached,
 | 
| 759 |      * flag an error and return 0.
 | 
| 760 |      */
 | 
| 761 |     char get_next_token() {
 | 
| 762 |         consume_garbage();
 | 
| 763 |         if (failed) {
 | 
| 764 |             return static_cast<char>(0);
 | 
| 765 |         }
 | 
| 766 |         if (i == str.size()) {
 | 
| 767 |             return fail("unexpected end of input", static_cast<char>(0));
 | 
| 768 |         }
 | 
| 769 | 
 | 
| 770 |         return str[i++];
 | 
| 771 |     }
 | 
| 772 | 
 | 
| 773 |     /* encode_utf8(pt, out)
 | 
| 774 |      *
 | 
| 775 |      * Encode pt as UTF-8 and add it to out.
 | 
| 776 |      */
 | 
| 777 |     void encode_utf8(long pt, std::string& out) {
 | 
| 778 |         if (pt < 0) {
 | 
| 779 |             return;
 | 
| 780 |         }
 | 
| 781 | 
 | 
| 782 |         if (pt < 0x80) {
 | 
| 783 |             out += static_cast<char>(pt);
 | 
| 784 |         } else if (pt < 0x800) {
 | 
| 785 |             out += static_cast<char>((pt >> 6) | 0xC0);
 | 
| 786 |             out += static_cast<char>((pt & 0x3F) | 0x80);
 | 
| 787 |         } else if (pt < 0x10000) {
 | 
| 788 |             out += static_cast<char>((pt >> 12) | 0xE0);
 | 
| 789 |             out += static_cast<char>(((pt >> 6) & 0x3F) | 0x80);
 | 
| 790 |             out += static_cast<char>((pt & 0x3F) | 0x80);
 | 
| 791 |         } else {
 | 
| 792 |             out += static_cast<char>((pt >> 18) | 0xF0);
 | 
| 793 |             out += static_cast<char>(((pt >> 12) & 0x3F) | 0x80);
 | 
| 794 |             out += static_cast<char>(((pt >> 6) & 0x3F) | 0x80);
 | 
| 795 |             out += static_cast<char>((pt & 0x3F) | 0x80);
 | 
| 796 |         }
 | 
| 797 |     }
 | 
| 798 | 
 | 
| 799 |     /* parse_string()
 | 
| 800 |      *
 | 
| 801 |      * Parse a std::string, starting at the current position.
 | 
| 802 |      */
 | 
| 803 |     std::string parse_string() {
 | 
| 804 |         std::string out;
 | 
| 805 |         long last_escaped_codepoint = -1;
 | 
| 806 |         while (true) {
 | 
| 807 |             if (i == str.size()) return fail("unexpected end of input in std::string", "");
 | 
| 808 | 
 | 
| 809 |             char ch = str[i++];
 | 
| 810 | 
 | 
| 811 |             if (ch == '"') {
 | 
| 812 |                 encode_utf8(last_escaped_codepoint, out);
 | 
| 813 |                 return out;
 | 
| 814 |             }
 | 
| 815 | 
 | 
| 816 |             if (in_range(ch, 0, 0x1f)) {
 | 
| 817 |                 return fail("unescaped " + esc(ch) + " in std::string", "");
 | 
| 818 |             }
 | 
| 819 | 
 | 
| 820 |             // The usual case: non-escaped characters
 | 
| 821 |             if (ch != '\\') {
 | 
| 822 |                 encode_utf8(last_escaped_codepoint, out);
 | 
| 823 |                 last_escaped_codepoint = -1;
 | 
| 824 |                 out += ch;
 | 
| 825 |                 continue;
 | 
| 826 |             }
 | 
| 827 | 
 | 
| 828 |             // Handle escapes
 | 
| 829 |             if (i == str.size()) {
 | 
| 830 |                 return fail("unexpected end of input in std::string", "");
 | 
| 831 |             }
 | 
| 832 | 
 | 
| 833 |             ch = str[i++];
 | 
| 834 | 
 | 
| 835 |             if (ch == 'u') {
 | 
| 836 |                 // Extract 4-byte escape sequence
 | 
| 837 |                 std::string esc = str.substr(i, 4);
 | 
| 838 |                 // Explicitly check length of the substring. The following loop
 | 
| 839 |                 // relies on std::string returning the terminating NUL when
 | 
| 840 |                 // accessing str[length]. Checking here reduces brittleness.
 | 
| 841 |                 if (esc.length() < 4) {
 | 
| 842 |                     return fail("bad \\u escape: " + esc, "");
 | 
| 843 |                 }
 | 
| 844 |                 for (std::size_t j = 0; j < 4; j++) {
 | 
| 845 |                     if (!in_range(esc[j], 'a', 'f') && !in_range(esc[j], 'A', 'F') &&
 | 
| 846 |                             !in_range(esc[j], '0', '9'))
 | 
| 847 |                         return fail("bad \\u escape: " + esc, "");
 | 
| 848 |                 }
 | 
| 849 | 
 | 
| 850 |                 long codepoint = strtol(esc.data(), nullptr, 16);
 | 
| 851 | 
 | 
| 852 |                 // JSON specifies that characters outside the BMP shall be encoded as a pair
 | 
| 853 |                 // of 4-hex-digit \u escapes encoding their surrogate pair components. Check
 | 
| 854 |                 // whether we're in the middle of such a beast: the previous codepoint was an
 | 
| 855 |                 // escaped lead (high) surrogate, and this is a trail (low) surrogate.
 | 
| 856 |                 if (in_range(last_escaped_codepoint, 0xD800, 0xDBFF) && in_range(codepoint, 0xDC00, 0xDFFF)) {
 | 
| 857 |                     // Reassemble the two surrogate pairs into one astral-plane character, per
 | 
| 858 |                     // the UTF-16 algorithm.
 | 
| 859 |                     encode_utf8((((last_escaped_codepoint - 0xD800) << 10) | (codepoint - 0xDC00)) + 0x10000,
 | 
| 860 |                             out);
 | 
| 861 |                     last_escaped_codepoint = -1;
 | 
| 862 |                 } else {
 | 
| 863 |                     encode_utf8(last_escaped_codepoint, out);
 | 
| 864 |                     last_escaped_codepoint = codepoint;
 | 
| 865 |                 }
 | 
| 866 | 
 | 
| 867 |                 i += 4;
 | 
| 868 |                 continue;
 | 
| 869 |             }
 | 
| 870 | 
 | 
| 871 |             encode_utf8(last_escaped_codepoint, out);
 | 
| 872 |             last_escaped_codepoint = -1;
 | 
| 873 | 
 | 
| 874 |             if (ch == 'b') {
 | 
| 875 |                 out += '\b';
 | 
| 876 |             } else if (ch == 'f') {
 | 
| 877 |                 out += '\f';
 | 
| 878 |             } else if (ch == 'n') {
 | 
| 879 |                 out += '\n';
 | 
| 880 |             } else if (ch == 'r') {
 | 
| 881 |                 out += '\r';
 | 
| 882 |             } else if (ch == 't') {
 | 
| 883 |                 out += '\t';
 | 
| 884 |             } else if (ch == '"' || ch == '\\' || ch == '/') {
 | 
| 885 |                 out += ch;
 | 
| 886 |             } else {
 | 
| 887 |                 return fail("invalid escape character " + esc(ch), "");
 | 
| 888 |             }
 | 
| 889 |         }
 | 
| 890 |     }
 | 
| 891 | 
 | 
| 892 |     /* parse_number()
 | 
| 893 |      *
 | 
| 894 |      * Parse a double.
 | 
| 895 |      */
 | 
| 896 |     Json parse_number() {
 | 
| 897 |         std::size_t start_pos = i;
 | 
| 898 | 
 | 
| 899 |         if (str[i] == '-') {
 | 
| 900 |             i++;
 | 
| 901 |         }
 | 
| 902 | 
 | 
| 903 |         // Integer part
 | 
| 904 |         if (str[i] == '0') {
 | 
| 905 |             i++;
 | 
| 906 |             if (in_range(str[i], '0', '9')) {
 | 
| 907 |                 return fail("leading 0s not permitted in numbers");
 | 
| 908 |             }
 | 
| 909 |         } else if (in_range(str[i], '1', '9')) {
 | 
| 910 |             i++;
 | 
| 911 |             while (in_range(str[i], '0', '9')) {
 | 
| 912 |                 i++;
 | 
| 913 |             }
 | 
| 914 |         } else {
 | 
| 915 |             return fail("invalid " + esc(str[i]) + " in number");
 | 
| 916 |         }
 | 
| 917 | 
 | 
| 918 |         if (str[i] != '.' && str[i] != 'e' && str[i] != 'E' &&
 | 
| 919 |                 (i - start_pos) <= static_cast<std::size_t>(std::numeric_limits<int>::digits10)) {
 | 
| 920 |             return std::atoll(str.c_str() + start_pos);
 | 
| 921 |         }
 | 
| 922 | 
 | 
| 923 |         // Decimal part
 | 
| 924 |         if (str[i] == '.') {
 | 
| 925 |             i++;
 | 
| 926 |             if (!in_range(str[i], '0', '9')) {
 | 
| 927 |                 return fail("at least one digit required in fractional part");
 | 
| 928 |             }
 | 
| 929 | 
 | 
| 930 |             while (in_range(str[i], '0', '9')) {
 | 
| 931 |                 i++;
 | 
| 932 |             }
 | 
| 933 |         }
 | 
| 934 | 
 | 
| 935 |         // Exponent part
 | 
| 936 |         if (str[i] == 'e' || str[i] == 'E') {
 | 
| 937 |             i++;
 | 
| 938 | 
 | 
| 939 |             if (str[i] == '+' || str[i] == '-') {
 | 
| 940 |                 i++;
 | 
| 941 |             }
 | 
| 942 | 
 | 
| 943 |             if (!in_range(str[i], '0', '9')) {
 | 
| 944 |                 return fail("at least one digit required in exponent");
 | 
| 945 |             }
 | 
| 946 | 
 | 
| 947 |             while (in_range(str[i], '0', '9')) {
 | 
| 948 |                 i++;
 | 
| 949 |             }
 | 
| 950 |         }
 | 
| 951 | 
 | 
| 952 |         return std::strtod(str.c_str() + start_pos, nullptr);
 | 
| 953 |     }
 | 
| 954 | 
 | 
| 955 |     /* expect(str, res)
 | 
| 956 |      *
 | 
| 957 |      * Expect that 'str' starts at the character that was just read. If it does, advance
 | 
| 958 |      * the input and return res. If not, flag an error.
 | 
| 959 |      */
 | 
| 960 |     Json expect(const std::string& expected, Json res) {
 | 
| 961 |         assert(i != 0);
 | 
| 962 |         i--;
 | 
| 963 |         if (str.compare(i, expected.length(), expected) == 0) {
 | 
| 964 |             i += expected.length();
 | 
| 965 |             return res;
 | 
| 966 |         } else {
 | 
| 967 |             return fail("parse error: expected " + expected + ", got " + str.substr(i, expected.length()));
 | 
| 968 |         }
 | 
| 969 |     }
 | 
| 970 | 
 | 
| 971 |     /* parse_json()
 | 
| 972 |      *
 | 
| 973 |      * Parse a JSON object.
 | 
| 974 |      */
 | 
| 975 |     Json parse_json(int depth) {
 | 
| 976 |         if (depth > max_depth) {
 | 
| 977 |             return fail("exceeded maximum nesting depth");
 | 
| 978 |         }
 | 
| 979 | 
 | 
| 980 |         char ch = get_next_token();
 | 
| 981 |         if (failed) {
 | 
| 982 |             return Json();
 | 
| 983 |         }
 | 
| 984 | 
 | 
| 985 |         if (ch == '-' || (ch >= '0' && ch <= '9')) {
 | 
| 986 |             i--;
 | 
| 987 |             return parse_number();
 | 
| 988 |         }
 | 
| 989 | 
 | 
| 990 |         if (ch == 't') {
 | 
| 991 |             return expect("true", true);
 | 
| 992 |         }
 | 
| 993 | 
 | 
| 994 |         if (ch == 'f') {
 | 
| 995 |             return expect("false", false);
 | 
| 996 |         }
 | 
| 997 | 
 | 
| 998 |         if (ch == 'n') {
 | 
| 999 |             return expect("null", Json());
 | 
| 1000 |         }
 | 
| 1001 | 
 | 
| 1002 |         if (ch == '"') {
 | 
| 1003 |             return parse_string();
 | 
| 1004 |         }
 | 
| 1005 | 
 | 
| 1006 |         if (ch == '{') {
 | 
| 1007 |             std::map<std::string, Json> data;
 | 
| 1008 |             ch = get_next_token();
 | 
| 1009 |             if (ch == '}') {
 | 
| 1010 |                 return data;
 | 
| 1011 |             }
 | 
| 1012 | 
 | 
| 1013 |             while (true) {
 | 
| 1014 |                 if (ch != '"') return fail("expected '\"' in object, got " + esc(ch));
 | 
| 1015 | 
 | 
| 1016 |                 std::string key = parse_string();
 | 
| 1017 |                 if (failed) {
 | 
| 1018 |                     return Json();
 | 
| 1019 |                 }
 | 
| 1020 | 
 | 
| 1021 |                 ch = get_next_token();
 | 
| 1022 |                 if (ch != ':') {
 | 
| 1023 |                     return fail("expected ':' in object, got " + esc(ch));
 | 
| 1024 |                 }
 | 
| 1025 | 
 | 
| 1026 |                 data[std::move(key)] = parse_json(depth + 1);
 | 
| 1027 |                 if (failed) {
 | 
| 1028 |                     return Json();
 | 
| 1029 |                 }
 | 
| 1030 | 
 | 
| 1031 |                 ch = get_next_token();
 | 
| 1032 |                 if (ch == '}') {
 | 
| 1033 |                     break;
 | 
| 1034 |                 }
 | 
| 1035 |                 if (ch != ',') {
 | 
| 1036 |                     return fail("expected ',' in object, got " + esc(ch));
 | 
| 1037 |                 }
 | 
| 1038 | 
 | 
| 1039 |                 ch = get_next_token();
 | 
| 1040 |             }
 | 
| 1041 |             return data;
 | 
| 1042 |         }
 | 
| 1043 | 
 | 
| 1044 |         if (ch == '[') {
 | 
| 1045 |             std::vector<Json> data;
 | 
| 1046 |             ch = get_next_token();
 | 
| 1047 |             if (ch == ']') {
 | 
| 1048 |                 return data;
 | 
| 1049 |             }
 | 
| 1050 | 
 | 
| 1051 |             while (true) {
 | 
| 1052 |                 i--;
 | 
| 1053 |                 data.push_back(parse_json(depth + 1));
 | 
| 1054 |                 if (failed) {
 | 
| 1055 |                     return Json();
 | 
| 1056 |                 }
 | 
| 1057 | 
 | 
| 1058 |                 ch = get_next_token();
 | 
| 1059 |                 if (ch == ']') {
 | 
| 1060 |                     break;
 | 
| 1061 |                 }
 | 
| 1062 |                 if (ch != ',') {
 | 
| 1063 |                     return fail("expected ',' in list, got " + esc(ch));
 | 
| 1064 |                 }
 | 
| 1065 | 
 | 
| 1066 |                 ch = get_next_token();
 | 
| 1067 |                 (void)ch;
 | 
| 1068 |             }
 | 
| 1069 |             return data;
 | 
| 1070 |         }
 | 
| 1071 | 
 | 
| 1072 |         return fail("expected value, got " + esc(ch));
 | 
| 1073 |     }
 | 
| 1074 | };
 | 
| 1075 | }  // namespace
 | 
| 1076 | 
 | 
| 1077 | inline Json Json::parse(const std::string& in, std::string& err, JsonParse strategy) {
 | 
| 1078 |     JsonParser parser{in, 0, err, false, strategy};
 | 
| 1079 |     Json result = parser.parse_json(0);
 | 
| 1080 | 
 | 
| 1081 |     // Check for any trailing garbage
 | 
| 1082 |     parser.consume_garbage();
 | 
| 1083 |     if (parser.failed) {
 | 
| 1084 |         return Json();
 | 
| 1085 |     }
 | 
| 1086 |     if (parser.i != in.size()) {
 | 
| 1087 |         return parser.fail("unexpected trailing " + esc(in[parser.i]));
 | 
| 1088 |     }
 | 
| 1089 | 
 | 
| 1090 |     return result;
 | 
| 1091 | }
 | 
| 1092 | 
 | 
| 1093 | inline std::vector<Json> parse_multi(const std::string& in, std::string::size_type& parser_stop_pos,
 | 
| 1094 |         std::string& err, JsonParse strategy) {
 | 
| 1095 |     JsonParser parser{in, 0, err, false, strategy};
 | 
| 1096 |     parser_stop_pos = 0;
 | 
| 1097 |     std::vector<Json> json_vec;
 | 
| 1098 |     while (parser.i != in.size() && !parser.failed) {
 | 
| 1099 |         json_vec.push_back(parser.parse_json(0));
 | 
| 1100 |         if (parser.failed) {
 | 
| 1101 |             break;
 | 
| 1102 |         }
 | 
| 1103 | 
 | 
| 1104 |         // Check for another object
 | 
| 1105 |         parser.consume_garbage();
 | 
| 1106 |         if (parser.failed) {
 | 
| 1107 |             break;
 | 
| 1108 |         }
 | 
| 1109 |         parser_stop_pos = parser.i;
 | 
| 1110 |     }
 | 
| 1111 |     return json_vec;
 | 
| 1112 | }
 | 
| 1113 | 
 | 
| 1114 | #ifdef _MSC_VER
 | 
| 1115 | #pragma warning(pop)
 | 
| 1116 | #endif  // _MSC_VER
 | 
| 1117 | 
 | 
| 1118 | }  // namespace json11
 | 
| 1119 | 
 | 
| 1120 | #if defined(__GNUC__) && (__GNUC__ >= 7)
 | 
| 1121 | #pragma GCC diagnostic pop
 | 
| 1122 | #endif |