json.cc 48.5 KB
Newer Older
N
tidy up  
Niels 已提交
1 2 3 4 5 6 7 8 9 10 11
/*!
@file
@copyright The code is licensed under the MIT License
           <http://opensource.org/licenses/MIT>,
           Copyright (c) 2013-2014 Niels Lohmann.

@author Niels Lohmann <http://nlohmann.me>

@see https://github.com/nlohmann/json
*/

N
Niels 已提交
12
#include "json.h"
N
Niels 已提交
13

N
Niels 已提交
14
#include <cctype>     // std::isdigit, std::isspace
N
Niels 已提交
15
#include <cstddef>    // std::size_t
N
Niels 已提交
16 17
#include <stdexcept>  // std::runtime_error
#include <utility>    // std::swap, std::move
N
Niels 已提交
18

N
Niels 已提交
19 20
namespace nlohmann
{
N
Niels 已提交
21 22 23 24 25

///////////////////////////////////
// CONSTRUCTORS OF UNION "value" //
///////////////////////////////////

N
Niels 已提交
26
json::value::value(array_t* _array): array(_array) {}
N
Niels 已提交
27
json::value::value(object_t* object_): object(object_) {}
N
Niels 已提交
28 29 30 31
json::value::value(string_t* _string): string(_string) {}
json::value::value(boolean_t _boolean) : boolean(_boolean) {}
json::value::value(number_t _number) : number(_number) {}
json::value::value(number_float_t _number_float) : number_float(_number_float) {}
N
Niels 已提交
32

N
Niels 已提交
33 34 35 36

/////////////////////////////////
// CONSTRUCTORS AND DESTRUCTOR //
/////////////////////////////////
N
Niels 已提交
37

N
Niels 已提交
38 39
/*!
Construct an empty JSON given the type.
N
Niels 已提交
40

N
Niels 已提交
41
@param t  the type from the @ref json::type enumeration.
N
Niels 已提交
42 43 44

@post Memory for array, object, and string are allocated.
*/
45
json::json(const value_type t)
N
Niels 已提交
46
    : type_(t)
N
Niels 已提交
47
{
N
Niels 已提交
48
    switch (type_)
N
Niels 已提交
49 50 51
    {
        case (value_type::array):
        {
N
Niels 已提交
52
            value_.array = new array_t();
N
Niels 已提交
53 54
            break;
        }
N
Niels 已提交
55 56
        case (value_type::object):
        {
N
Niels 已提交
57
            value_.object = new object_t();
N
Niels 已提交
58 59
            break;
        }
N
Niels 已提交
60 61
        case (value_type::string):
        {
N
Niels 已提交
62
            value_.string = new string_t();
N
Niels 已提交
63 64
            break;
        }
N
Niels 已提交
65 66
        case (value_type::boolean):
        {
N
Niels 已提交
67
            value_.boolean = boolean_t();
N
Niels 已提交
68 69
            break;
        }
N
Niels 已提交
70 71
        case (value_type::number):
        {
N
Niels 已提交
72
            value_.number = number_t();
N
Niels 已提交
73 74
            break;
        }
N
Niels 已提交
75 76
        case (value_type::number_float):
        {
N
Niels 已提交
77
            value_.number_float = number_float_t();
N
Niels 已提交
78 79
            break;
        }
N
Niels 已提交
80
        default:
N
Niels 已提交
81
        {
N
Niels 已提交
82 83 84 85 86
            break;
        }
    }
}

N
Niels 已提交
87 88 89
/*!
Construct a null JSON object.
*/
N
Niels 已提交
90
json::json(std::nullptr_t) noexcept : json()
N
Niels 已提交
91 92 93 94 95 96 97
{}

/*!
Construct a string JSON object.

@param s  a string to initialize the JSON object with
*/
98
json::json(const std::string& s)
N
Niels 已提交
99
    : type_(value_type::string), value_(new string_t(s))
N
Niels 已提交
100 101
{}

102
json::json(std::string&& s)
N
Niels 已提交
103
    : type_(value_type::string), value_(new string_t(std::move(s)))
N
Niels 已提交
104 105
{}

106
json::json(const char* s)
N
Niels 已提交
107
    : type_(value_type::string), value_(new string_t(s))
N
Niels 已提交
108 109
{}

N
Niels 已提交
110
json::json(const bool b) noexcept
N
Niels 已提交
111
    : type_(value_type::boolean), value_(b)
N
Niels 已提交
112 113
{}

N
Niels 已提交
114
json::json(const int i) noexcept
N
Niels 已提交
115
    : type_(value_type::number), value_(i)
N
Niels 已提交
116 117
{}

N
Niels 已提交
118
json::json(const double f) noexcept
N
Niels 已提交
119
    : type_(value_type::number_float), value_(f)
N
Niels 已提交
120 121
{}

122
json::json(const array_t& a)
N
Niels 已提交
123
    : type_(value_type::array), value_(new array_t(a))
N
Niels 已提交
124 125
{}

126
json::json(array_t&& a)
N
Niels 已提交
127
    : type_(value_type::array), value_(new array_t(std::move(a)))
N
Niels 已提交
128 129
{}

130
json::json(const object_t& o)
N
Niels 已提交
131
    : type_(value_type::object), value_(new object_t(o))
N
Niels 已提交
132 133
{}

134
json::json(object_t&& o)
N
Niels 已提交
135
    : type_(value_type::object), value_(new object_t(std::move(o)))
N
Niels 已提交
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
{}

/*!
This function is a bit tricky as it uses an initializer list of JSON objects
for both arrays and objects. This is not supported by C++, so we use the
following trick. Both initializer lists for objects and arrays will transform
to a list of JSON objects. The only difference is that in case of an object,
the list will contain JSON array objects with two elements - one for the key
and one for the value. As a result, it is sufficient to check if each element
of the initializer list is an array (1) with two elements (2) whose first
element is of type string (3). If this is the case, we treat the whole
initializer list as list of pairs to construct an object. If not, we pass it
as is to create an array.

@bug With the described approach, we would fail to recognize an array whose
     first element is again an arrays as array.
*/
153
json::json(list_init_t a)
N
Niels 已提交
154 155 156 157 158
{
    // check if each element is an array with two elements whose first element
    // is a string
    for (const auto& element : a)
    {
N
Niels 已提交
159
        if (element.type_ != value_type::array or
N
Niels 已提交
160
                element.size() != 2 or
N
Niels 已提交
161
                element[0].type_ != value_type::string)
N
Niels 已提交
162 163 164
        {

            // the initializer list describes an array
N
Niels 已提交
165 166
            type_ = value_type::array;
            value_ = new array_t(a);
N
Niels 已提交
167 168 169 170 171
            return;
        }
    }

    // the initializer list is a list of pairs
N
Niels 已提交
172 173
    type_ = value_type::object;
    value_ = new object_t();
N
Niels 已提交
174
    for (const json& element : a)
N
Niels 已提交
175 176
    {
        const std::string k = element[0];
N
Niels 已提交
177
        value_.object->emplace(std::make_pair(std::move(k),
N
Niels 已提交
178
                                              std::move(element[1])));
N
Niels 已提交
179 180 181 182 183
    }
}

/*!
A copy constructor for the JSON class.
N
Niels 已提交
184

N
Niels 已提交
185 186
@param o  the JSON object to copy
*/
187
json::json(const json& o)
N
Niels 已提交
188
    : type_(o.type_)
N
Niels 已提交
189
{
N
Niels 已提交
190
    switch (type_)
N
Niels 已提交
191 192 193
    {
        case (value_type::array):
        {
N
Niels 已提交
194
            value_.array = new array_t(*o.value_.array);
N
Niels 已提交
195
            break;
N
Niels 已提交
196
        }
N
Niels 已提交
197 198
        case (value_type::object):
        {
N
Niels 已提交
199
            value_.object = new object_t(*o.value_.object);
N
Niels 已提交
200
            break;
N
Niels 已提交
201
        }
N
Niels 已提交
202 203
        case (value_type::string):
        {
N
Niels 已提交
204
            value_.string = new string_t(*o.value_.string);
N
Niels 已提交
205
            break;
N
Niels 已提交
206
        }
N
Niels 已提交
207 208
        case (value_type::boolean):
        {
N
Niels 已提交
209
            value_.boolean = o.value_.boolean;
N
Niels 已提交
210
            break;
N
Niels 已提交
211
        }
N
Niels 已提交
212 213
        case (value_type::number):
        {
N
Niels 已提交
214
            value_.number = o.value_.number;
N
Niels 已提交
215
            break;
N
Niels 已提交
216
        }
N
Niels 已提交
217 218
        case (value_type::number_float):
        {
N
Niels 已提交
219
            value_.number_float = o.value_.number_float;
N
Niels 已提交
220
            break;
N
Niels 已提交
221
        }
N
Niels 已提交
222
        default:
N
Niels 已提交
223
        {
N
Niels 已提交
224
            break;
N
Niels 已提交
225
        }
N
Niels 已提交
226 227 228
    }
}

N
Niels 已提交
229 230
/*!
A move constructor for the JSON class.
N
Niels 已提交
231

N
Niels 已提交
232 233 234 235
@param o  the JSON object to move

@post The JSON object \p o is invalidated.
*/
N
Niels 已提交
236
json::json(json&& o) noexcept
N
Niels 已提交
237
    : type_(std::move(o.type_)), value_(std::move(o.value_))
N
Niels 已提交
238 239
{
    // invalidate payload
N
Niels 已提交
240 241
    o.type_ = value_type::null;
    o.value_ = {};
N
Niels 已提交
242 243 244 245 246 247 248 249
}

/*!
A copy assignment operator for the JSON class, following the copy-and-swap
idiom.

@param o  A JSON object to assign to this object.
*/
N
Niels 已提交
250
json& json::operator=(json o) noexcept
N
Niels 已提交
251
{
N
Niels 已提交
252 253
    std::swap(type_, o.type_);
    std::swap(value_, o.value_);
N
Niels 已提交
254 255
    return *this;
}
N
Niels 已提交
256

N
Niels 已提交
257
json::~json() noexcept
N
Niels 已提交
258
{
N
Niels 已提交
259
    switch (type_)
N
Niels 已提交
260 261 262
    {
        case (value_type::array):
        {
N
Niels 已提交
263
            delete value_.array;
N
Niels 已提交
264 265
            break;
        }
N
Niels 已提交
266 267
        case (value_type::object):
        {
N
Niels 已提交
268
            delete value_.object;
N
Niels 已提交
269 270
            break;
        }
N
Niels 已提交
271 272
        case (value_type::string):
        {
N
Niels 已提交
273
            delete value_.string;
N
Niels 已提交
274 275
            break;
        }
N
Niels 已提交
276
        default:
N
Niels 已提交
277 278
        {
            // nothing to do for non-pointer types
N
Niels 已提交
279
            break;
N
Niels 已提交
280
        }
N
Niels 已提交
281 282 283
    }
}

N
Niels 已提交
284 285 286 287
/*!
@param s  a string representation of a JSON object
@return a JSON object
*/
N
Niels 已提交
288
json json::parse(const std::string& s)
N
Niels 已提交
289
{
N
Niels 已提交
290
    return parser(s).parse();
N
Niels 已提交
291 292 293 294 295 296
}

/*!
@param s  a string representation of a JSON object
@return a JSON object
*/
N
Niels 已提交
297
json json::parse(const char* s)
N
Niels 已提交
298
{
N
Niels 已提交
299
    return parser(s).parse();
N
Niels 已提交
300 301 302
}


N
Niels 已提交
303
const std::string json::type_name() const noexcept
N
Niels 已提交
304
{
N
Niels 已提交
305
    switch (type_)
N
Niels 已提交
306 307 308 309
    {
        case (value_type::array):
        {
            return "array";
N
Niels 已提交
310
        }
N
Niels 已提交
311 312 313
        case (value_type::object):
        {
            return "object";
N
Niels 已提交
314
        }
N
Niels 已提交
315 316 317
        case (value_type::null):
        {
            return "null";
N
Niels 已提交
318
        }
N
Niels 已提交
319 320 321
        case (value_type::string):
        {
            return "string";
N
Niels 已提交
322
        }
N
Niels 已提交
323 324 325
        case (value_type::boolean):
        {
            return "boolean";
N
Niels 已提交
326
        }
N
Niels 已提交
327
        default:
N
Niels 已提交
328 329
        {
            return "number";
N
Niels 已提交
330
        }
N
Niels 已提交
331 332 333 334
    }
}


N
Niels 已提交
335 336 337
///////////////////////////////
// OPERATORS AND CONVERSIONS //
///////////////////////////////
N
Niels 已提交
338

N
Niels 已提交
339 340 341 342 343
/*!
@exception std::logic_error if the function is called for JSON objects whose
    type is not string
*/
template<>
N
Niels 已提交
344
std::string json::get() const
N
Niels 已提交
345
{
N
Niels 已提交
346
    switch (type_)
N
Niels 已提交
347 348
    {
        case (value_type::string):
N
Niels 已提交
349
            return *value_.string;
N
Niels 已提交
350
        default:
N
Niels 已提交
351
            throw std::logic_error("cannot cast " + type_name() + " to JSON string");
N
Niels 已提交
352 353 354
    }
}

N
Niels 已提交
355 356 357 358 359
/*!
@exception std::logic_error if the function is called for JSON objects whose
    type is not number (int or float)
*/
template<>
N
Niels 已提交
360
int json::get() const
N
Niels 已提交
361
{
N
Niels 已提交
362
    switch (type_)
N
Niels 已提交
363 364
    {
        case (value_type::number):
N
Niels 已提交
365
            return value_.number;
N
Niels 已提交
366
        case (value_type::number_float):
N
Niels 已提交
367
            return static_cast<number_t>(value_.number_float);
N
Niels 已提交
368
        default:
N
Niels 已提交
369
            throw std::logic_error("cannot cast " + type_name() + " to JSON number");
N
Niels 已提交
370 371 372
    }
}

N
Niels 已提交
373 374 375 376 377
/*!
@exception std::logic_error if the function is called for JSON objects whose
    type is not number (int or float)
*/
template<>
N
Niels 已提交
378
double json::get() const
N
Niels 已提交
379
{
N
Niels 已提交
380
    switch (type_)
N
Niels 已提交
381 382
    {
        case (value_type::number):
N
Niels 已提交
383
            return static_cast<number_float_t>(value_.number);
N
Niels 已提交
384
        case (value_type::number_float):
N
Niels 已提交
385
            return value_.number_float;
N
Niels 已提交
386
        default:
N
Niels 已提交
387
            throw std::logic_error("cannot cast " + type_name() + " to JSON number");
N
Niels 已提交
388 389 390
    }
}

N
Niels 已提交
391 392 393 394 395
/*!
@exception std::logic_error if the function is called for JSON objects whose
    type is not boolean
*/
template<>
N
Niels 已提交
396
bool json::get() const
N
Niels 已提交
397
{
N
Niels 已提交
398
    switch (type_)
N
Niels 已提交
399 400
    {
        case (value_type::boolean):
N
Niels 已提交
401
            return value_.boolean;
N
Niels 已提交
402
        default:
N
Niels 已提交
403
            throw std::logic_error("cannot cast " + type_name() + " to JSON Boolean");
N
Niels 已提交
404 405 406
    }
}

N
Niels 已提交
407 408 409 410 411
/*!
@exception std::logic_error if the function is called for JSON objects whose
    type is an object
*/
template<>
N
Niels 已提交
412
json::array_t json::get() const
N
Niels 已提交
413
{
N
Niels 已提交
414
    if (type_ == value_type::array)
N
Niels 已提交
415
    {
N
Niels 已提交
416
        return *value_.array;
N
Niels 已提交
417
    }
N
Niels 已提交
418
    if (type_ == value_type::object)
N
Niels 已提交
419
    {
N
Niels 已提交
420
        throw std::logic_error("cannot cast " + type_name() + " to JSON array");
N
Niels 已提交
421 422
    }

N
Niels 已提交
423
    array_t result;
N
Niels 已提交
424 425 426 427
    result.push_back(*this);
    return result;
}

N
Niels 已提交
428 429 430 431 432
/*!
@exception std::logic_error if the function is called for JSON objects whose
    type is not object
*/
template<>
N
Niels 已提交
433
json::object_t json::get() const
N
Niels 已提交
434
{
N
Niels 已提交
435
    if (type_ == value_type::object)
N
Niels 已提交
436
    {
N
Niels 已提交
437
        return *value_.object;
N
Niels 已提交
438 439 440
    }
    else
    {
N
Niels 已提交
441
        throw std::logic_error("cannot cast " + type_name() + " to JSON object");
N
Niels 已提交
442 443 444
    }
}

N
Niels 已提交
445
json::operator const std::string() const
N
Niels 已提交
446 447 448 449
{
    return get<std::string>();
}

N
Niels 已提交
450
json::operator int() const
N
Niels 已提交
451 452 453 454
{
    return get<int>();
}

N
Niels 已提交
455
json::operator double() const
N
Niels 已提交
456 457 458 459
{
    return get<double>();
}

N
Niels 已提交
460
json::operator bool() const
N
Niels 已提交
461 462 463 464
{
    return get<bool>();
}

N
Niels 已提交
465
json::operator array_t() const
N
Niels 已提交
466 467 468 469
{
    return get<array_t>();
}

N
Niels 已提交
470
json::operator object_t() const
N
Niels 已提交
471 472 473 474
{
    return get<object_t>();
}

N
Niels 已提交
475
const std::string json::to_string() const noexcept
N
Niels 已提交
476
{
N
Niels 已提交
477
    switch (type_)
N
Niels 已提交
478 479 480
    {
        case (value_type::string):
        {
N
Niels 已提交
481
            return std::string("\"") + *value_.string + "\"";
N
Niels 已提交
482 483
        }

N
Niels 已提交
484 485
        case (value_type::boolean):
        {
N
Niels 已提交
486
            return value_.boolean ? "true" : "false";
N
Niels 已提交
487 488
        }

N
Niels 已提交
489 490
        case (value_type::number):
        {
N
Niels 已提交
491
            return std::to_string(value_.number);
N
Niels 已提交
492 493
        }

N
Niels 已提交
494 495
        case (value_type::number_float):
        {
N
Niels 已提交
496
            return std::to_string(value_.number_float);
N
Niels 已提交
497 498
        }

N
Niels 已提交
499 500
        case (value_type::array):
        {
N
Niels 已提交
501 502
            std::string result;

N
Niels 已提交
503
            for (array_t::const_iterator i = value_.array->begin(); i != value_.array->end(); ++i)
N
Niels 已提交
504
            {
N
Niels 已提交
505
                if (i != value_.array->begin())
N
Niels 已提交
506
                {
N
Niels 已提交
507 508
                    result += ", ";
                }
N
Niels 已提交
509
                result += i->to_string();
N
Niels 已提交
510 511 512 513 514
            }

            return "[" + result + "]";
        }

N
Niels 已提交
515 516
        case (value_type::object):
        {
N
Niels 已提交
517 518
            std::string result;

N
Niels 已提交
519
            for (object_t::const_iterator i = value_.object->begin(); i != value_.object->end(); ++i)
N
Niels 已提交
520
            {
N
Niels 已提交
521
                if (i != value_.object->begin())
N
Niels 已提交
522
                {
N
Niels 已提交
523 524
                    result += ", ";
                }
N
Niels 已提交
525
                result += "\"" + i->first + "\": " + i->second.to_string();
N
Niels 已提交
526 527 528 529
            }

            return "{" + result + "}";
        }
N
Niels 已提交
530 531 532 533 534 535

        // actually only value_type::null - but making the compiler happy
        default:
        {
            return "null";
        }
N
Niels 已提交
536 537 538 539
    }
}


N
Niels 已提交
540 541 542
///////////////////////////////////////////
// ADDING ELEMENTS TO OBJECTS AND ARRAYS //
///////////////////////////////////////////
N
Niels 已提交
543

N
Niels 已提交
544
json& json::operator+=(const json& o)
N
Niels 已提交
545
{
N
Niels 已提交
546 547 548 549
    push_back(o);
    return *this;
}

N
Niels 已提交
550
json& json::operator+=(const std::string& s)
N
Niels 已提交
551
{
N
Niels 已提交
552
    push_back(json(s));
N
Niels 已提交
553 554 555
    return *this;
}

N
Niels 已提交
556
json& json::operator+=(const char* s)
N
Niels 已提交
557
{
N
Niels 已提交
558
    push_back(json(s));
N
Niels 已提交
559 560 561
    return *this;
}

N
Niels 已提交
562
json& json::operator+=(std::nullptr_t)
N
Niels 已提交
563
{
N
Niels 已提交
564
    push_back(json());
N
Niels 已提交
565 566 567
    return *this;
}

N
Niels 已提交
568
json& json::operator+=(bool b)
N
Niels 已提交
569
{
N
Niels 已提交
570
    push_back(json(b));
N
Niels 已提交
571 572 573
    return *this;
}

N
Niels 已提交
574 575 576 577 578 579
/*!
Adds a number (int) to the current object. This is done by wrapping the number
into a JSON and call push_back for this.

@param i  A number (int) to add to the array.
*/
N
Niels 已提交
580
json& json::operator+=(int i)
N
Niels 已提交
581
{
N
Niels 已提交
582
    push_back(json(i));
N
Niels 已提交
583 584 585
    return *this;
}

N
Niels 已提交
586 587 588 589 590 591
/*!
Adds a number (float) to the current object. This is done by wrapping the
number into a JSON and call push_back for this.

@param f  A number (float) to add to the array.
*/
N
Niels 已提交
592
json& json::operator+=(double f)
N
Niels 已提交
593
{
N
Niels 已提交
594
    push_back(json(f));
N
Niels 已提交
595 596 597
    return *this;
}

N
Niels 已提交
598
/*!
N
Niels 已提交
599
@todo comment me
N
Niels 已提交
600
*/
N
Niels 已提交
601
json& json::operator+=(const object_t::value_type& p)
N
Niels 已提交
602 603 604 605 606
{
    return operator[](p.first) = p.second;
}

/*!
N
Niels 已提交
607
@todo comment me
N
Niels 已提交
608
*/
N
Niels 已提交
609
json& json::operator+=(list_init_t a)
N
Niels 已提交
610 611 612 613
{
    push_back(a);
    return *this;
}
N
Niels 已提交
614

N
Niels 已提交
615 616 617 618 619 620 621 622 623 624 625 626 627 628
/*!
This function implements the actual "adding to array" function and is called
by all other push_back or operator+= functions. If the function is called for
an array, the passed element is added to the array.

@param o  The element to add to the array.

@pre  The JSON object is an array or null.
@post The JSON object is an array whose last element is the passed element o.
@exception std::runtime_error  The function was called for a JSON type that
             does not support addition to an array (e.g., int or string).

@note Null objects are silently transformed into an array before the addition.
*/
N
Niels 已提交
629
void json::push_back(const json& o)
N
Niels 已提交
630 631
{
    // push_back only works for null objects or arrays
N
Niels 已提交
632
    if (not(type_ == value_type::null or type_ == value_type::array))
N
Niels 已提交
633
    {
N
Niels 已提交
634
        throw std::runtime_error("cannot add element to " + type_name());
N
Niels 已提交
635 636
    }

N
Niels 已提交
637
    // transform null object into an array
N
Niels 已提交
638
    if (type_ == value_type::null)
N
Niels 已提交
639
    {
N
Niels 已提交
640 641
        type_ = value_type::array;
        value_.array = new array_t;
N
Niels 已提交
642 643
    }

N
Niels 已提交
644
    // add element to array
N
Niels 已提交
645
    value_.array->push_back(o);
N
Niels 已提交
646 647
}

N
Niels 已提交
648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663
/*!
This function implements the actual "adding to array" function and is called
by all other push_back or operator+= functions. If the function is called for
an array, the passed element is added to the array using move semantics.

@param o  The element to add to the array.

@pre  The JSON object is an array or null.
@post The JSON object is an array whose last element is the passed element o.
@post The element o is destroyed.
@exception std::runtime_error  The function was called for a JSON type that
             does not support addition to an array (e.g., int or string).

@note Null objects are silently transformed into an array before the addition.
@note This function applies move semantics for the given element.
*/
N
Niels 已提交
664
void json::push_back(json&& o)
N
Niels 已提交
665 666
{
    // push_back only works for null objects or arrays
N
Niels 已提交
667
    if (not(type_ == value_type::null or type_ == value_type::array))
N
Niels 已提交
668
    {
N
Niels 已提交
669
        throw std::runtime_error("cannot add element to " + type_name());
N
Niels 已提交
670 671 672
    }

    // transform null object into an array
N
Niels 已提交
673
    if (type_ == value_type::null)
N
Niels 已提交
674
    {
N
Niels 已提交
675 676
        type_ = value_type::array;
        value_.array = new array_t;
N
Niels 已提交
677 678 679
    }

    // add element to array (move semantics)
N
Niels 已提交
680
    value_.array->emplace_back(std::move(o));
N
Niels 已提交
681
    // invalidate object
N
Niels 已提交
682
    o.type_ = value_type::null;
N
Niels 已提交
683 684
}

N
Niels 已提交
685
void json::push_back(const std::string& s)
N
Niels 已提交
686
{
N
Niels 已提交
687
    push_back(json(s));
N
Niels 已提交
688 689
}

N
Niels 已提交
690
void json::push_back(const char* s)
N
Niels 已提交
691
{
N
Niels 已提交
692
    push_back(json(s));
N
Niels 已提交
693 694
}

N
Niels 已提交
695
void json::push_back(std::nullptr_t)
N
Niels 已提交
696
{
N
Niels 已提交
697
    push_back(json());
N
Niels 已提交
698 699
}

N
Niels 已提交
700
void json::push_back(bool b)
N
Niels 已提交
701
{
N
Niels 已提交
702
    push_back(json(b));
N
Niels 已提交
703 704
}

N
Niels 已提交
705 706 707 708 709 710
/*!
Adds a number (int) to the current object. This is done by wrapping the number
into a JSON and call push_back for this.

@param i  A number (int) to add to the array.
*/
N
Niels 已提交
711
void json::push_back(int i)
N
Niels 已提交
712
{
N
Niels 已提交
713
    push_back(json(i));
N
Niels 已提交
714 715
}

N
Niels 已提交
716 717 718 719 720 721
/*!
Adds a number (float) to the current object. This is done by wrapping the
number into a JSON and call push_back for this.

@param f  A number (float) to add to the array.
*/
N
Niels 已提交
722
void json::push_back(double f)
N
Niels 已提交
723
{
N
Niels 已提交
724
    push_back(json(f));
N
Niels 已提交
725 726
}

N
Niels 已提交
727
/*!
N
Niels 已提交
728
@todo comment me
N
Niels 已提交
729
*/
N
Niels 已提交
730
void json::push_back(const object_t::value_type& p)
N
Niels 已提交
731 732 733 734 735
{
    operator[](p.first) = p.second;
}

/*!
N
Niels 已提交
736
@todo comment me
N
Niels 已提交
737
*/
N
Niels 已提交
738
void json::push_back(list_init_t a)
N
Niels 已提交
739 740 741 742 743 744 745
{
    bool is_array = false;

    // check if each element is an array with two elements whose first element
    // is a string
    for (const auto& element : a)
    {
N
Niels 已提交
746
        if (element.type_ != value_type::array or
N
Niels 已提交
747
                element.size() != 2 or
N
Niels 已提交
748
                element[0].type_ != value_type::string)
N
Niels 已提交
749 750 751 752 753 754 755 756 757
        {
            // the initializer list describes an array
            is_array = true;
            break;
        }
    }

    if (is_array)
    {
N
Niels 已提交
758
        for (const json& element : a)
N
Niels 已提交
759 760 761 762 763 764
        {
            push_back(element);
        }
    }
    else
    {
N
Niels 已提交
765
        for (const json& element : a)
N
Niels 已提交
766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788
        {
            const object_t::value_type tmp {element[0].get<std::string>(), element[1]};
            push_back(tmp);
        }
    }
}

/*!
This operator realizes read/write access to array elements given an integer
index.  Bounds will not be checked.

@note The "index" variable should be of type size_t as it is compared against
      size() and used in the at() function. However, the compiler will have
      problems in case integer literals are used. In this case, an implicit
      conversion to both size_t and JSON is possible. Therefore, we use int as
      type and convert it to size_t where necessary.

@param index  the index of the element to return from the array
@return reference to element for the given index

@pre Object is an array.
@exception std::domain_error if object is not an array
*/
N
Niels 已提交
789
json& json::operator[](const int index)
N
Niels 已提交
790 791
{
    // this [] operator only works for arrays
N
Niels 已提交
792
    if (type_ != value_type::array)
N
Niels 已提交
793 794
    {
        throw std::domain_error("cannot add entry with index " +
N
Niels 已提交
795
                                std::to_string(index) + " to " + type_name());
N
Niels 已提交
796 797
    }

N
Niels 已提交
798
    // return reference to element from array at given index
N
Niels 已提交
799
    return (*value_.array)[static_cast<std::size_t>(index)];
N
Niels 已提交
800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817
}

/*!
This operator realizes read-only access to array elements given an integer
index.  Bounds will not be checked.

@note The "index" variable should be of type size_t as it is compared against
      size() and used in the at() function. However, the compiler will have
      problems in case integer literals are used. In this case, an implicit
      conversion to both size_t and JSON is possible. Therefore, we use int as
      type and convert it to size_t where necessary.

@param index  the index of the element to return from the array
@return read-only reference to element for the given index

@pre Object is an array.
@exception std::domain_error if object is not an array
*/
N
Niels 已提交
818
const json& json::operator[](const int index) const
N
Niels 已提交
819 820
{
    // this [] operator only works for arrays
N
Niels 已提交
821
    if (type_ != value_type::array)
N
Niels 已提交
822 823
    {
        throw std::domain_error("cannot get entry with index " +
N
Niels 已提交
824
                                std::to_string(index) + " from " + type_name());
N
Niels 已提交
825 826
    }

N
Niels 已提交
827
    // return element from array at given index
N
Niels 已提交
828
    return (*value_.array)[static_cast<std::size_t>(index)];
N
Niels 已提交
829 830
}

N
Niels 已提交
831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847
/*!
This function realizes read/write access to array elements given an integer
index. Bounds will be checked.

@note The "index" variable should be of type size_t as it is compared against
      size() and used in the at() function. However, the compiler will have
      problems in case integer literals are used. In this case, an implicit
      conversion to both size_t and JSON is possible. Therefore, we use int as
      type and convert it to size_t where necessary.

@param index  the index of the element to return from the array
@return reference to element for the given index

@pre Object is an array.
@exception std::domain_error if object is not an array
@exception std::out_of_range if index is out of range (via std::vector::at)
*/
N
Niels 已提交
848
json& json::at(const int index)
N
Niels 已提交
849 850
{
    // this function only works for arrays
N
Niels 已提交
851
    if (type_ != value_type::array)
N
Niels 已提交
852 853
    {
        throw std::domain_error("cannot add entry with index " +
N
Niels 已提交
854
                                std::to_string(index) + " to " + type_name());
N
Niels 已提交
855 856
    }

N
Niels 已提交
857
    // return reference to element from array at given index
N
Niels 已提交
858
    return value_.array->at(static_cast<std::size_t>(index));
N
Niels 已提交
859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877
}

/*!
This operator realizes read-only access to array elements given an integer
index. Bounds will be checked.

@note The "index" variable should be of type size_t as it is compared against
      size() and used in the at() function. However, the compiler will have
      problems in case integer literals are used. In this case, an implicit
      conversion to both size_t and JSON is possible. Therefore, we use int as
      type and convert it to size_t where necessary.

@param index  the index of the element to return from the array
@return read-only reference to element for the given index

@pre Object is an array.
@exception std::domain_error if object is not an array
@exception std::out_of_range if index is out of range (via std::vector::at)
*/
N
Niels 已提交
878
const json& json::at(const int index) const
N
Niels 已提交
879 880
{
    // this function only works for arrays
N
Niels 已提交
881
    if (type_ != value_type::array)
N
Niels 已提交
882 883
    {
        throw std::domain_error("cannot get entry with index " +
N
Niels 已提交
884
                                std::to_string(index) + " from " + type_name());
N
Niels 已提交
885 886
    }

N
Niels 已提交
887
    // return element from array at given index
N
Niels 已提交
888
    return value_.array->at(static_cast<std::size_t>(index));
N
Niels 已提交
889 890
}

N
Niels 已提交
891
/*!
N
Niels 已提交
892
@copydoc json::operator[](const char* key)
N
Niels 已提交
893
*/
N
Niels 已提交
894
json& json::operator[](const std::string& key)
N
Niels 已提交
895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911
{
    return operator[](key.c_str());
}

/*!
This operator realizes read/write access to object elements given a string
key.

@param key  the key index of the element to return from the object
@return reference to a JSON object for the given key (null if key does not
        exist)

@pre  Object is an object or a null object.
@post null objects are silently converted to objects.

@exception std::domain_error if object is not an object (or null)
*/
N
Niels 已提交
912
json& json::operator[](const char* key)
N
Niels 已提交
913 914
{
    // implicitly convert null to object
N
Niels 已提交
915
    if (type_ == value_type::null)
N
Niels 已提交
916
    {
N
Niels 已提交
917 918
        type_ = value_type::object;
        value_.object = new object_t;
N
Niels 已提交
919 920
    }

N
Niels 已提交
921
    // this [] operator only works for objects
N
Niels 已提交
922
    if (type_ != value_type::object)
N
Niels 已提交
923 924
    {
        throw std::domain_error("cannot add entry with key " +
N
Niels 已提交
925
                                std::string(key) + " to " + type_name());
N
Niels 已提交
926 927
    }

N
Niels 已提交
928
    // if the key does not exist, create it
N
Niels 已提交
929
    if (value_.object->find(key) == value_.object->end())
N
Niels 已提交
930
    {
N
Niels 已提交
931
        (*value_.object)[key] = json();
N
Niels 已提交
932 933
    }

N
Niels 已提交
934
    // return reference to element from array at given index
N
Niels 已提交
935
    return (*value_.object)[key];
N
Niels 已提交
936 937
}

N
Niels 已提交
938 939 940
/*!
This operator realizes read-only access to object elements given a string
key.
N
Niels 已提交
941

N
Niels 已提交
942 943
@param key  the key index of the element to return from the object
@return read-only reference to element for the given key
N
Niels 已提交
944

N
Niels 已提交
945 946 947 948
@pre Object is an object.
@exception std::domain_error if object is not an object
@exception std::out_of_range if key is not found in object
*/
N
Niels 已提交
949
const json& json::operator[](const std::string& key) const
N
Niels 已提交
950 951
{
    // this [] operator only works for objects
N
Niels 已提交
952
    if (type_ != value_type::object)
N
Niels 已提交
953
    {
N
Niels 已提交
954
        throw std::domain_error("cannot get entry with key " +
N
Niels 已提交
955
                                std::string(key) + " from " + type_name());
N
Niels 已提交
956 957
    }

N
Niels 已提交
958
    // search for the key
N
Niels 已提交
959
    const auto it = value_.object->find(key);
N
Niels 已提交
960 961

    // make sure the key exists in the object
N
Niels 已提交
962
    if (it == value_.object->end())
N
Niels 已提交
963 964
    {
        throw std::out_of_range("key " + key + " not found");
N
Niels 已提交
965 966
    }

N
Niels 已提交
967 968 969 970 971
    // return element from array at given key
    return it->second;
}

/*!
N
Niels 已提交
972
@copydoc json::at(const char* key)
N
Niels 已提交
973
*/
N
Niels 已提交
974
json& json::at(const std::string& key)
N
Niels 已提交
975 976
{
    return at(key.c_str());
N
Niels 已提交
977 978
}

N
Niels 已提交
979 980 981 982 983 984 985 986 987 988 989 990 991
/*!
This function realizes read/write access to object elements given a string
key.

@param key  the key index of the element to return from the object
@return reference to a JSON object for the given key (exception if key does not
        exist)

@pre  Object is an object.

@exception std::domain_error if object is not an object
@exception std::out_of_range if key was not found (via std::map::at)
*/
N
Niels 已提交
992
json& json::at(const char* key)
N
Niels 已提交
993 994
{
    // this function operator only works for objects
N
Niels 已提交
995
    if (type_ != value_type::object)
N
Niels 已提交
996 997
    {
        throw std::domain_error("cannot add entry with key " +
N
Niels 已提交
998
                                std::string(key) + " to " + type_name());
N
Niels 已提交
999 1000
    }

N
Niels 已提交
1001
    // return reference to element from array at given index
N
Niels 已提交
1002
    return value_.object->at(key);
N
Niels 已提交
1003 1004
}

N
Niels 已提交
1005
/*!
N
Niels 已提交
1006
@copydoc json::at(const char *key) const
N
Niels 已提交
1007
*/
N
Niels 已提交
1008
const json& json::at(const std::string& key) const
N
Niels 已提交
1009 1010 1011 1012
{
    return at(key.c_str());
}

N
Niels 已提交
1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023
/*!
This operator realizes read-only access to object elements given a string
key.

@param key  the key index of the element to return from the object
@return read-only reference to element for the given key

@pre Object is an object.
@exception std::domain_error if object is not an object
@exception std::out_of_range if key is not found (via std::map::at)
*/
N
Niels 已提交
1024
const json& json::at(const char* key) const
N
Niels 已提交
1025 1026
{
    // this [] operator only works for objects
N
Niels 已提交
1027
    if (type_ != value_type::object)
N
Niels 已提交
1028 1029
    {
        throw std::domain_error("cannot get entry with key " +
N
Niels 已提交
1030
                                std::string(key) + " from " + type_name());
N
Niels 已提交
1031
    }
N
Niels 已提交
1032 1033

    // return element from array at given key
N
Niels 已提交
1034
    return value_.object->at(key);
N
Niels 已提交
1035 1036
}

N
Niels 已提交
1037

N
Niels 已提交
1038 1039 1040 1041 1042 1043 1044 1045 1046
/*!
Returns the size of the JSON object.

@return the size of the JSON object; the size is the number of elements in
        compounds (array and object), 1 for value types (true, false, number,
        string), and 0 for null.

@invariant The size is reported as 0 if and only if empty() would return true.
*/
N
Niels 已提交
1047
std::size_t json::size() const noexcept
N
Niels 已提交
1048
{
N
Niels 已提交
1049
    switch (type_)
N
Niels 已提交
1050 1051 1052
    {
        case (value_type::array):
        {
N
Niels 已提交
1053
            return value_.array->size();
N
Niels 已提交
1054
        }
N
Niels 已提交
1055 1056
        case (value_type::object):
        {
N
Niels 已提交
1057
            return value_.object->size();
N
Niels 已提交
1058
        }
N
Niels 已提交
1059 1060
        case (value_type::null):
        {
N
Niels 已提交
1061
            return 0;
N
Niels 已提交
1062
        }
N
Niels 已提交
1063
        default:
N
Niels 已提交
1064
        {
N
Niels 已提交
1065
            return 1;
N
Niels 已提交
1066
        }
N
Niels 已提交
1067 1068 1069
    }
}

N
Niels 已提交
1070 1071 1072 1073 1074 1075 1076 1077 1078
/*!
Returns whether a JSON object is empty.

@return true for null objects and empty compounds (array and object); false
        for value types (true, false, number, string) and filled compounds
        (array and object).

@invariant Empty would report true if and only if size() would return 0.
*/
N
Niels 已提交
1079
bool json::empty() const noexcept
N
Niels 已提交
1080
{
N
Niels 已提交
1081
    switch (type_)
N
Niels 已提交
1082 1083 1084
    {
        case (value_type::array):
        {
N
Niels 已提交
1085
            return value_.array->empty();
N
Niels 已提交
1086
        }
N
Niels 已提交
1087 1088
        case (value_type::object):
        {
N
Niels 已提交
1089
            return value_.object->empty();
N
Niels 已提交
1090
        }
N
Niels 已提交
1091 1092
        case (value_type::null):
        {
N
Niels 已提交
1093
            return true;
N
Niels 已提交
1094
        }
N
Niels 已提交
1095
        default:
N
Niels 已提交
1096
        {
N
Niels 已提交
1097
            return false;
N
Niels 已提交
1098
        }
N
Niels 已提交
1099 1100 1101 1102 1103 1104 1105 1106 1107 1108
    }
}

/*!
Removes all elements from compounds and resets values to default.

@invariant Clear will set any value type to its default value which is empty
           for compounds, false for booleans, 0 for integer numbers, and 0.0
           for floating numbers.
*/
N
Niels 已提交
1109
void json::clear() noexcept
N
Niels 已提交
1110
{
N
Niels 已提交
1111
    switch (type_)
N
Niels 已提交
1112 1113 1114
    {
        case (value_type::array):
        {
N
Niels 已提交
1115
            value_.array->clear();
N
Niels 已提交
1116
            break;
N
Niels 已提交
1117
        }
N
Niels 已提交
1118 1119
        case (value_type::object):
        {
N
Niels 已提交
1120
            value_.object->clear();
N
Niels 已提交
1121
            break;
N
Niels 已提交
1122
        }
N
Niels 已提交
1123 1124
        case (value_type::string):
        {
N
Niels 已提交
1125
            value_.string->clear();
N
Niels 已提交
1126 1127 1128 1129
            break;
        }
        case (value_type::boolean):
        {
N
Niels 已提交
1130
            value_.boolean = {};
N
Niels 已提交
1131 1132 1133 1134
            break;
        }
        case (value_type::number):
        {
N
Niels 已提交
1135
            value_.number = {};
N
Niels 已提交
1136 1137 1138 1139
            break;
        }
        case (value_type::number_float):
        {
N
Niels 已提交
1140
            value_.number_float = {};
N
Niels 已提交
1141 1142
            break;
        }
N
Niels 已提交
1143
        default:
N
Niels 已提交
1144 1145
        {
            break;
N
Niels 已提交
1146
        }
N
Niels 已提交
1147 1148 1149
    }
}

N
Niels 已提交
1150
json::value_type json::type() const noexcept
N
Niels 已提交
1151
{
N
Niels 已提交
1152
    return type_;
N
Niels 已提交
1153 1154
}

N
Niels 已提交
1155
json::iterator json::find(const std::string& key)
N
Niels 已提交
1156
{
N
Niels 已提交
1157 1158 1159
    return find(key.c_str());
}

N
Niels 已提交
1160
json::const_iterator json::find(const std::string& key) const
N
Niels 已提交
1161
{
N
Niels 已提交
1162 1163 1164
    return find(key.c_str());
}

N
Niels 已提交
1165
json::iterator json::find(const char* key)
N
Niels 已提交
1166
{
N
Niels 已提交
1167
    if (type_ != value_type::object)
N
Niels 已提交
1168
    {
N
Niels 已提交
1169
        return end();
N
Niels 已提交
1170 1171 1172
    }
    else
    {
N
Niels 已提交
1173 1174
        const object_t::iterator i = value_.object->find(key);
        if (i != value_.object->end())
N
Niels 已提交
1175
        {
N
Niels 已提交
1176
            json::iterator result(this);
N
Niels 已提交
1177 1178
            delete result.oi_;
            result.oi_ = new object_t::iterator(i);
N
Niels 已提交
1179
            return result;
N
Niels 已提交
1180 1181 1182
        }
        else
        {
N
Niels 已提交
1183 1184 1185 1186 1187
            return end();
        }
    }
}

N
Niels 已提交
1188
json::const_iterator json::find(const char* key) const
N
Niels 已提交
1189
{
N
Niels 已提交
1190
    if (type_ != value_type::object)
N
Niels 已提交
1191
    {
N
Niels 已提交
1192
        return end();
N
Niels 已提交
1193 1194 1195
    }
    else
    {
N
Niels 已提交
1196 1197
        const object_t::const_iterator i = value_.object->find(key);
        if (i != value_.object->end())
N
Niels 已提交
1198
        {
N
Niels 已提交
1199
            json::const_iterator result(this);
N
Niels 已提交
1200 1201
            delete result.oi_;
            result.oi_ = new object_t::const_iterator(i);
N
Niels 已提交
1202
            return result;
N
Niels 已提交
1203 1204 1205
        }
        else
        {
N
Niels 已提交
1206 1207 1208 1209 1210
            return end();
        }
    }
}

N
Niels 已提交
1211
bool json::operator==(const json& o) const noexcept
N
Niels 已提交
1212
{
N
Niels 已提交
1213
    switch (type_)
N
Niels 已提交
1214 1215 1216
    {
        case (value_type::array):
        {
N
Niels 已提交
1217
            if (o.type_ == value_type::array)
N
Niels 已提交
1218
            {
N
Niels 已提交
1219
                return *value_.array == *o.value_.array;
N
Niels 已提交
1220
            }
N
Niels 已提交
1221
            break;
N
Niels 已提交
1222
        }
N
Niels 已提交
1223 1224
        case (value_type::object):
        {
N
Niels 已提交
1225
            if (o.type_ == value_type::object)
N
Niels 已提交
1226
            {
N
Niels 已提交
1227
                return *value_.object == *o.value_.object;
N
Niels 已提交
1228
            }
N
Niels 已提交
1229
            break;
N
Niels 已提交
1230
        }
N
Niels 已提交
1231 1232
        case (value_type::null):
        {
N
Niels 已提交
1233
            if (o.type_ == value_type::null)
N
Niels 已提交
1234
            {
N
Niels 已提交
1235 1236
                return true;
            }
N
Niels 已提交
1237
            break;
N
Niels 已提交
1238
        }
N
Niels 已提交
1239 1240
        case (value_type::string):
        {
N
Niels 已提交
1241
            if (o.type_ == value_type::string)
N
Niels 已提交
1242
            {
N
Niels 已提交
1243
                return *value_.string == *o.value_.string;
N
Niels 已提交
1244
            }
N
Niels 已提交
1245
            break;
N
Niels 已提交
1246
        }
N
Niels 已提交
1247 1248
        case (value_type::boolean):
        {
N
Niels 已提交
1249
            if (o.type_ == value_type::boolean)
N
Niels 已提交
1250
            {
N
Niels 已提交
1251
                return value_.boolean == o.value_.boolean;
N
Niels 已提交
1252
            }
N
Niels 已提交
1253
            break;
N
Niels 已提交
1254
        }
N
Niels 已提交
1255 1256
        case (value_type::number):
        {
N
Niels 已提交
1257
            if (o.type_ == value_type::number)
N
Niels 已提交
1258
            {
N
Niels 已提交
1259
                return value_.number == o.value_.number;
1260
            }
N
Niels 已提交
1261
            if (o.type_ == value_type::number_float)
N
Niels 已提交
1262
            {
N
Niels 已提交
1263
                return value_.number == static_cast<number_t>(o.value_.number_float);
N
Niels 已提交
1264
            }
N
Niels 已提交
1265
            break;
N
Niels 已提交
1266
        }
N
Niels 已提交
1267 1268
        case (value_type::number_float):
        {
N
Niels 已提交
1269
            if (o.type_ == value_type::number)
N
Niels 已提交
1270
            {
N
Niels 已提交
1271
                return value_.number_float == static_cast<number_float_t>(o.value_.number);
1272
            }
N
Niels 已提交
1273
            if (o.type_ == value_type::number_float)
N
Niels 已提交
1274
            {
N
Niels 已提交
1275
                return value_.number_float == o.value_.number_float;
N
Niels 已提交
1276
            }
N
Niels 已提交
1277
            break;
N
Niels 已提交
1278 1279 1280 1281 1282 1283
        }
    }

    return false;
}

N
Niels 已提交
1284
bool json::operator!=(const json& o) const noexcept
N
Niels 已提交
1285
{
N
Niels 已提交
1286 1287
    return not operator==(o);
}
N
Niels 已提交
1288 1289


N
Niels 已提交
1290
json::iterator json::begin() noexcept
N
Niels 已提交
1291
{
N
Niels 已提交
1292
    return json::iterator(this);
N
Niels 已提交
1293 1294
}

N
Niels 已提交
1295
json::iterator json::end() noexcept
N
Niels 已提交
1296
{
N
Niels 已提交
1297
    return json::iterator();
N
Niels 已提交
1298 1299
}

N
Niels 已提交
1300
json::const_iterator json::begin() const noexcept
N
Niels 已提交
1301
{
N
Niels 已提交
1302
    return json::const_iterator(this);
N
Niels 已提交
1303 1304
}

N
Niels 已提交
1305
json::const_iterator json::end() const noexcept
N
Niels 已提交
1306
{
N
Niels 已提交
1307
    return json::const_iterator();
N
Niels 已提交
1308 1309
}

N
Niels 已提交
1310
json::const_iterator json::cbegin() const noexcept
N
Niels 已提交
1311
{
N
Niels 已提交
1312
    return json::const_iterator(this);
N
Niels 已提交
1313 1314
}

N
Niels 已提交
1315
json::const_iterator json::cend() const noexcept
N
Niels 已提交
1316
{
N
Niels 已提交
1317
    return json::const_iterator();
N
Niels 已提交
1318 1319 1320
}


N
Niels 已提交
1321
json::iterator::iterator(json* j) : object_(j)
N
Niels 已提交
1322
{
N
Niels 已提交
1323
    if (object_ != nullptr)
N
Niels 已提交
1324
    {
N
Niels 已提交
1325
        if (object_->type_ == value_type::array)
N
Niels 已提交
1326
        {
N
Niels 已提交
1327
            vi_ = new array_t::iterator(object_->value_.array->begin());
N
Niels 已提交
1328
        }
N
Niels 已提交
1329
        if (object_->type_ == value_type::object)
N
Niels 已提交
1330
        {
N
Niels 已提交
1331
            oi_ = new object_t::iterator(object_->value_.object->begin());
N
Niels 已提交
1332 1333
        }
    }
N
Niels 已提交
1334 1335
}

N
Niels 已提交
1336
json::iterator::iterator(const json::iterator& o) : object_(o.object_)
N
Niels 已提交
1337
{
N
Niels 已提交
1338
    if (object_ != nullptr)
N
Niels 已提交
1339
    {
N
Niels 已提交
1340
        if (object_->type_ == value_type::array)
N
Niels 已提交
1341
        {
N
Niels 已提交
1342
            vi_ = new array_t::iterator(*(o.vi_));
N
Niels 已提交
1343
        }
N
Niels 已提交
1344
        if (object_->type_ == value_type::object)
N
Niels 已提交
1345
        {
N
Niels 已提交
1346
            oi_ = new object_t::iterator(*(o.oi_));
N
Niels 已提交
1347
        }
N
Niels 已提交
1348
    }
N
Niels 已提交
1349 1350
}

N
Niels 已提交
1351
json::iterator::~iterator()
N
Niels 已提交
1352
{
N
Niels 已提交
1353 1354
    delete vi_;
    delete oi_;
N
Niels 已提交
1355 1356
}

N
Niels 已提交
1357
json::iterator& json::iterator::operator=(json::iterator o)
N
Niels 已提交
1358
{
N
Niels 已提交
1359 1360 1361
    std::swap(object_, o.object_);
    std::swap(vi_, o.vi_);
    std::swap(oi_, o.oi_);
N
Niels 已提交
1362 1363 1364
    return *this;
}

N
Niels 已提交
1365
bool json::iterator::operator==(const json::iterator& o) const
N
Niels 已提交
1366
{
N
Niels 已提交
1367
    if (object_ != o.object_)
N
Niels 已提交
1368 1369 1370 1371
    {
        return false;
    }

N
Niels 已提交
1372
    if (object_ != nullptr)
N
Niels 已提交
1373
    {
N
Niels 已提交
1374
        if (object_->type_ == value_type::array)
N
Niels 已提交
1375
        {
N
Niels 已提交
1376
            return (vi_ == o.vi_);
N
Niels 已提交
1377
        }
N
Niels 已提交
1378
        if (object_->type_ == value_type::object)
N
Niels 已提交
1379
        {
N
Niels 已提交
1380
            return (oi_ == o.oi_);
N
Niels 已提交
1381 1382
        }
    }
N
Niels 已提交
1383

N
Niels 已提交
1384
    return true;
N
Niels 已提交
1385 1386
}

N
Niels 已提交
1387
bool json::iterator::operator!=(const json::iterator& o) const
N
Niels 已提交
1388 1389
{
    return not operator==(o);
N
Niels 已提交
1390 1391
}

N
Niels 已提交
1392
json::iterator& json::iterator::operator++()
N
Niels 已提交
1393
{
N
Niels 已提交
1394
    // iterator cannot be incremented
N
Niels 已提交
1395
    if (object_ == nullptr)
N
Niels 已提交
1396
    {
N
Niels 已提交
1397 1398 1399
        return *this;
    }

N
Niels 已提交
1400
    switch (object_->type_)
N
Niels 已提交
1401 1402 1403
    {
        case (value_type::array):
        {
N
Niels 已提交
1404
            if (++(*vi_) == object_->value_.array->end())
N
Niels 已提交
1405
            {
N
Niels 已提交
1406
                object_ = nullptr;
N
Niels 已提交
1407 1408 1409
            }
            break;
        }
N
Niels 已提交
1410 1411
        case (value_type::object):
        {
N
Niels 已提交
1412
            if (++(*oi_) == object_->value_.object->end())
N
Niels 已提交
1413
            {
N
Niels 已提交
1414
                object_ = nullptr;
N
Niels 已提交
1415 1416 1417
            }
            break;
        }
N
Niels 已提交
1418
        default:
N
Niels 已提交
1419
        {
N
Niels 已提交
1420
            object_ = nullptr;
N
Niels 已提交
1421 1422 1423 1424 1425
        }
    }
    return *this;
}

N
Niels 已提交
1426
json& json::iterator::operator*() const
N
Niels 已提交
1427
{
N
Niels 已提交
1428
    // dereferencing end() is an error
N
Niels 已提交
1429
    if (object_ == nullptr)
N
Niels 已提交
1430
    {
N
Niels 已提交
1431 1432 1433
        throw std::runtime_error("cannot get value");
    }

N
Niels 已提交
1434
    switch (object_->type_)
N
Niels 已提交
1435 1436 1437
    {
        case (value_type::array):
        {
N
Niels 已提交
1438
            return **vi_;
N
Niels 已提交
1439
        }
N
Niels 已提交
1440 1441
        case (value_type::object):
        {
N
Niels 已提交
1442
            return (*oi_)->second;
N
Niels 已提交
1443
        }
N
Niels 已提交
1444
        default:
N
Niels 已提交
1445
        {
N
Niels 已提交
1446
            return *object_;
N
Niels 已提交
1447
        }
N
Niels 已提交
1448 1449 1450
    }
}

N
Niels 已提交
1451
json* json::iterator::operator->() const
N
Niels 已提交
1452
{
N
Niels 已提交
1453
    // dereferencing end() is an error
N
Niels 已提交
1454
    if (object_ == nullptr)
N
Niels 已提交
1455
    {
N
Niels 已提交
1456 1457 1458
        throw std::runtime_error("cannot get value");
    }

N
Niels 已提交
1459
    switch (object_->type_)
N
Niels 已提交
1460 1461 1462
    {
        case (value_type::array):
        {
N
Niels 已提交
1463
            return &(**vi_);
N
Niels 已提交
1464
        }
N
Niels 已提交
1465 1466
        case (value_type::object):
        {
N
Niels 已提交
1467
            return &((*oi_)->second);
N
Niels 已提交
1468
        }
N
Niels 已提交
1469
        default:
N
Niels 已提交
1470
        {
N
Niels 已提交
1471
            return object_;
N
Niels 已提交
1472
        }
N
Niels 已提交
1473 1474 1475
    }
}

N
Niels 已提交
1476
std::string json::iterator::key() const
N
Niels 已提交
1477
{
N
Niels 已提交
1478
    if (object_ != nullptr and object_->type_ == value_type::object)
N
Niels 已提交
1479
    {
N
Niels 已提交
1480
        return (*oi_)->first;
N
Niels 已提交
1481 1482 1483 1484
    }
    else
    {
        throw std::out_of_range("cannot get key");
N
Niels 已提交
1485 1486 1487
    }
}

N
Niels 已提交
1488
json& json::iterator::value() const
N
Niels 已提交
1489
{
N
Niels 已提交
1490
    // dereferencing end() is an error
N
Niels 已提交
1491
    if (object_ == nullptr)
N
Niels 已提交
1492 1493
    {
        throw std::out_of_range("cannot get value");
N
Niels 已提交
1494 1495
    }

N
Niels 已提交
1496
    switch (object_->type_)
N
Niels 已提交
1497 1498 1499
    {
        case (value_type::array):
        {
N
Niels 已提交
1500
            return **vi_;
N
Niels 已提交
1501
        }
N
Niels 已提交
1502 1503
        case (value_type::object):
        {
N
Niels 已提交
1504
            return (*oi_)->second;
N
Niels 已提交
1505
        }
N
Niels 已提交
1506
        default:
N
Niels 已提交
1507
        {
N
Niels 已提交
1508
            return *object_;
N
Niels 已提交
1509
        }
N
Niels 已提交
1510 1511 1512 1513
    }
}


N
Niels 已提交
1514
json::const_iterator::const_iterator(const json* j) : object_(j)
N
Niels 已提交
1515
{
N
Niels 已提交
1516
    if (object_ != nullptr)
N
Niels 已提交
1517
    {
N
Niels 已提交
1518
        if (object_->type_ == value_type::array)
N
Niels 已提交
1519
        {
N
Niels 已提交
1520
            vi_ = new array_t::const_iterator(object_->value_.array->begin());
N
Niels 已提交
1521
        }
N
Niels 已提交
1522
        if (object_->type_ == value_type::object)
N
Niels 已提交
1523
        {
N
Niels 已提交
1524
            oi_ = new object_t::const_iterator(object_->value_.object->begin());
N
Niels 已提交
1525 1526
        }
    }
N
Niels 已提交
1527 1528
}

N
Niels 已提交
1529
json::const_iterator::const_iterator(const json::const_iterator& o) : object_(o.object_)
N
Niels 已提交
1530
{
N
Niels 已提交
1531
    if (object_ != nullptr)
N
Niels 已提交
1532
    {
N
Niels 已提交
1533
        if (object_->type_ == value_type::array)
N
Niels 已提交
1534
        {
N
Niels 已提交
1535
            vi_ = new array_t::const_iterator(*(o.vi_));
N
Niels 已提交
1536
        }
N
Niels 已提交
1537
        if (object_->type_ == value_type::object)
N
Niels 已提交
1538
        {
N
Niels 已提交
1539
            oi_ = new object_t::const_iterator(*(o.oi_));
N
Niels 已提交
1540 1541
        }
    }
N
Niels 已提交
1542 1543
}

N
Niels 已提交
1544
json::const_iterator::const_iterator(const json::iterator& o) : object_(o.object_)
N
Niels 已提交
1545
{
N
Niels 已提交
1546
    if (object_ != nullptr)
N
Niels 已提交
1547
    {
N
Niels 已提交
1548
        if (object_->type_ == value_type::array)
N
Niels 已提交
1549
        {
N
Niels 已提交
1550
            vi_ = new array_t::const_iterator(*(o.vi_));
N
Niels 已提交
1551
        }
N
Niels 已提交
1552
        if (object_->type_ == value_type::object)
N
Niels 已提交
1553
        {
N
Niels 已提交
1554
            oi_ = new object_t::const_iterator(*(o.oi_));
N
Niels 已提交
1555 1556
        }
    }
N
Niels 已提交
1557 1558
}

N
Niels 已提交
1559
json::const_iterator::~const_iterator()
N
Niels 已提交
1560
{
N
Niels 已提交
1561 1562
    delete vi_;
    delete oi_;
N
Niels 已提交
1563 1564
}

N
Niels 已提交
1565
json::const_iterator& json::const_iterator::operator=(json::const_iterator o)
N
Niels 已提交
1566
{
N
Niels 已提交
1567 1568 1569
    std::swap(object_, o.object_);
    std::swap(vi_, o.vi_);
    std::swap(oi_, o.oi_);
N
Niels 已提交
1570 1571 1572
    return *this;
}

N
Niels 已提交
1573
bool json::const_iterator::operator==(const json::const_iterator& o) const
N
Niels 已提交
1574
{
N
Niels 已提交
1575
    if (object_ != o.object_)
N
Niels 已提交
1576 1577 1578 1579
    {
        return false;
    }

N
Niels 已提交
1580
    if (object_ != nullptr)
N
Niels 已提交
1581
    {
N
Niels 已提交
1582
        if (object_->type_ == value_type::array)
N
Niels 已提交
1583
        {
N
Niels 已提交
1584
            return (vi_ == o.vi_);
N
Niels 已提交
1585
        }
N
Niels 已提交
1586
        if (object_->type_ == value_type::object)
N
Niels 已提交
1587
        {
N
Niels 已提交
1588
            return (oi_ == o.oi_);
N
Niels 已提交
1589
        }
N
Niels 已提交
1590
    }
N
Niels 已提交
1591

N
Niels 已提交
1592
    return true;
N
Niels 已提交
1593 1594
}

N
Niels 已提交
1595
bool json::const_iterator::operator!=(const json::const_iterator& o) const
N
Niels 已提交
1596 1597
{
    return not operator==(o);
N
Niels 已提交
1598 1599
}

N
Niels 已提交
1600
json::const_iterator& json::const_iterator::operator++()
N
Niels 已提交
1601
{
N
Niels 已提交
1602
    // iterator cannot be incremented
N
Niels 已提交
1603
    if (object_ == nullptr)
N
Niels 已提交
1604
    {
N
Niels 已提交
1605 1606 1607
        return *this;
    }

N
Niels 已提交
1608
    switch (object_->type_)
N
Niels 已提交
1609 1610 1611
    {
        case (value_type::array):
        {
N
Niels 已提交
1612
            if (++(*vi_) == object_->value_.array->end())
N
Niels 已提交
1613
            {
N
Niels 已提交
1614
                object_ = nullptr;
N
Niels 已提交
1615 1616 1617
            }
            break;
        }
N
Niels 已提交
1618 1619
        case (value_type::object):
        {
N
Niels 已提交
1620
            if (++(*oi_) == object_->value_.object->end())
N
Niels 已提交
1621
            {
N
Niels 已提交
1622
                object_ = nullptr;
N
Niels 已提交
1623 1624 1625
            }
            break;
        }
N
Niels 已提交
1626
        default:
N
Niels 已提交
1627
        {
N
Niels 已提交
1628
            object_ = nullptr;
N
Niels 已提交
1629 1630 1631 1632 1633
        }
    }
    return *this;
}

N
Niels 已提交
1634
const json& json::const_iterator::operator*() const
N
Niels 已提交
1635
{
N
Niels 已提交
1636
    // dereferencing end() is an error
N
Niels 已提交
1637
    if (object_ == nullptr)
N
Niels 已提交
1638
    {
N
Niels 已提交
1639 1640 1641
        throw std::runtime_error("cannot get value");
    }

N
Niels 已提交
1642
    switch (object_->type_)
N
Niels 已提交
1643 1644 1645
    {
        case (value_type::array):
        {
N
Niels 已提交
1646
            return **vi_;
N
Niels 已提交
1647
        }
N
Niels 已提交
1648 1649
        case (value_type::object):
        {
N
Niels 已提交
1650
            return (*oi_)->second;
N
Niels 已提交
1651
        }
N
Niels 已提交
1652
        default:
N
Niels 已提交
1653
        {
N
Niels 已提交
1654
            return *object_;
N
Niels 已提交
1655
        }
N
Niels 已提交
1656 1657 1658
    }
}

N
Niels 已提交
1659
const json* json::const_iterator::operator->() const
N
Niels 已提交
1660
{
N
Niels 已提交
1661
    // dereferencing end() is an error
N
Niels 已提交
1662
    if (object_ == nullptr)
N
Niels 已提交
1663
    {
N
Niels 已提交
1664 1665 1666
        throw std::runtime_error("cannot get value");
    }

N
Niels 已提交
1667
    switch (object_->type_)
N
Niels 已提交
1668 1669 1670
    {
        case (value_type::array):
        {
N
Niels 已提交
1671
            return &(**vi_);
N
Niels 已提交
1672
        }
N
Niels 已提交
1673 1674
        case (value_type::object):
        {
N
Niels 已提交
1675
            return &((*oi_)->second);
N
Niels 已提交
1676
        }
N
Niels 已提交
1677
        default:
N
Niels 已提交
1678
        {
N
Niels 已提交
1679
            return object_;
N
Niels 已提交
1680
        }
N
Niels 已提交
1681 1682 1683
    }
}

N
Niels 已提交
1684
std::string json::const_iterator::key() const
N
Niels 已提交
1685
{
N
Niels 已提交
1686
    if (object_ != nullptr and object_->type_ == value_type::object)
N
Niels 已提交
1687
    {
N
Niels 已提交
1688
        return (*oi_)->first;
N
Niels 已提交
1689 1690 1691 1692
    }
    else
    {
        throw std::out_of_range("cannot get key");
N
Niels 已提交
1693 1694 1695
    }
}

N
Niels 已提交
1696
const json& json::const_iterator::value() const
N
Niels 已提交
1697
{
N
Niels 已提交
1698
    // dereferencing end() is an error
N
Niels 已提交
1699
    if (object_ == nullptr)
N
Niels 已提交
1700 1701
    {
        throw std::out_of_range("cannot get value");
N
Niels 已提交
1702 1703
    }

N
Niels 已提交
1704
    switch (object_->type_)
N
Niels 已提交
1705 1706 1707
    {
        case (value_type::array):
        {
N
Niels 已提交
1708
            return **vi_;
N
Niels 已提交
1709
        }
N
Niels 已提交
1710 1711
        case (value_type::object):
        {
N
Niels 已提交
1712
            return (*oi_)->second;
N
Niels 已提交
1713
        }
N
Niels 已提交
1714
        default:
N
Niels 已提交
1715
        {
N
Niels 已提交
1716
            return *object_;
N
Niels 已提交
1717
        }
N
Niels 已提交
1718 1719
    }
}
N
Niels 已提交
1720 1721 1722 1723 1724 1725 1726 1727 1728


/*!
Initialize the JSON parser given a string \p s.

@note After initialization, the function @ref parse has to be called manually.

@param s  string to parse

N
Niels 已提交
1729
@post \p s is copied to the buffer @ref buffer_ and the first character is
N
Niels 已提交
1730 1731
      read. Whitespace is skipped.
*/
N
Niels 已提交
1732
json::parser::parser(const char* s)
N
Niels 已提交
1733
    :  buffer_(s)
N
Niels 已提交
1734 1735 1736 1737 1738 1739
{
    // read first character
    next();
}

/*!
N
Niels 已提交
1740
@copydoc json::parser::parser(const char* s)
N
Niels 已提交
1741
*/
N
Niels 已提交
1742
json::parser::parser(const std::string& s)
N
Niels 已提交
1743
    : buffer_(s)
N
Niels 已提交
1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755
{
    // read first character
    next();
}

/*!
Initialize the JSON parser given an input stream \p _is.

@note After initialization, the function @ref parse has to be called manually.

\param _is input stream to parse

N
Niels 已提交
1756
@post \p _is is copied to the buffer @ref buffer_ and the firsr character is
N
Niels 已提交
1757 1758 1759
      read. Whitespace is skipped.

*/
N
Niels 已提交
1760
json::parser::parser(std::istream& _is)
N
Niels 已提交
1761
{
N
Niels 已提交
1762 1763
    while (_is)
    {
N
Niels 已提交
1764
        std::string input_line;
N
Niels 已提交
1765
        std::getline(_is, input_line);
N
Niels 已提交
1766
        buffer_ += input_line;
N
Niels 已提交
1767
    }
N
Niels 已提交
1768 1769 1770 1771 1772

    // read first character
    next();
}

N
Niels 已提交
1773
json json::parser::parse()
N
Niels 已提交
1774
{
N
Niels 已提交
1775
    switch (current_)
N
Niels 已提交
1776 1777 1778 1779
    {
        case ('{'):
        {
            // explicitly set result to object to cope with {}
N
Niels 已提交
1780
            json result(value_type::object);
N
Niels 已提交
1781 1782 1783 1784

            next();

            // process nonempty object
N
Niels 已提交
1785
            if (current_ != '}')
N
Niels 已提交
1786 1787 1788 1789
            {
                do
                {
                    // key
N
cleanup  
Niels 已提交
1790
                    auto key = parseString();
N
Niels 已提交
1791 1792 1793 1794 1795

                    // colon
                    expect(':');

                    // value
N
Niels 已提交
1796
                    result[std::move(key)] = parse();
N
cleanup  
Niels 已提交
1797
                    key.clear();
N
Niels 已提交
1798
                }
N
Niels 已提交
1799
                while (current_ == ',' and next());
N
Niels 已提交
1800 1801 1802 1803 1804
            }

            // closing brace
            expect('}');

N
Niels 已提交
1805
            return result;
N
Niels 已提交
1806 1807 1808 1809 1810
        }

        case ('['):
        {
            // explicitly set result to array to cope with []
N
Niels 已提交
1811
            json result(value_type::array);
N
Niels 已提交
1812 1813 1814 1815

            next();

            // process nonempty array
N
Niels 已提交
1816
            if (current_ != ']')
N
Niels 已提交
1817 1818 1819
            {
                do
                {
N
Niels 已提交
1820
                    result.push_back(parse());
N
Niels 已提交
1821
                }
N
Niels 已提交
1822
                while (current_ == ',' and next());
N
Niels 已提交
1823 1824 1825 1826 1827
            }

            // closing bracket
            expect(']');

N
Niels 已提交
1828
            return result;
N
Niels 已提交
1829 1830 1831 1832
        }

        case ('\"'):
        {
N
Niels 已提交
1833
            return json(parseString());
N
Niels 已提交
1834 1835 1836 1837 1838
        }

        case ('t'):
        {
            parseTrue();
N
Niels 已提交
1839
            return json(true);
N
Niels 已提交
1840 1841 1842 1843 1844
        }

        case ('f'):
        {
            parseFalse();
N
Niels 已提交
1845
            return json(false);
N
Niels 已提交
1846 1847 1848 1849 1850
        }

        case ('n'):
        {
            parseNull();
N
Niels 已提交
1851
            return json();
N
Niels 已提交
1852 1853
        }

N
cleanup  
Niels 已提交
1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864
        case ('-'):
        case ('0'):
        case ('1'):
        case ('2'):
        case ('3'):
        case ('4'):
        case ('5'):
        case ('6'):
        case ('7'):
        case ('8'):
        case ('9'):
N
Niels 已提交
1865
        {
N
cleanup  
Niels 已提交
1866
            // remember position of number's first character
N
Niels 已提交
1867
            const auto _firstpos_ = pos_ - 1;
N
cleanup  
Niels 已提交
1868

N
Niels 已提交
1869 1870 1871
            while (next() and (std::isdigit(current_) || current_ == '.'
                               || current_ == 'e' || current_ == 'E'
                               || current_ == '+' || current_ == '-'));
N
cleanup  
Niels 已提交
1872 1873

            try
N
Niels 已提交
1874
            {
N
Niels 已提交
1875
                const auto float_val = std::stod(buffer_.substr(_firstpos_, pos_ - _firstpos_));
N
cleanup  
Niels 已提交
1876
                const auto int_val = static_cast<int>(float_val);
N
Niels 已提交
1877

N
cleanup  
Niels 已提交
1878 1879
                // check if conversion loses precision
                if (float_val == int_val)
N
Niels 已提交
1880
                {
N
cleanup  
Niels 已提交
1881
                    // we would not lose precision -> int
N
Niels 已提交
1882
                    return json(int_val);
N
Niels 已提交
1883
                }
N
cleanup  
Niels 已提交
1884
                else
N
Niels 已提交
1885
                {
N
cleanup  
Niels 已提交
1886
                    // we would lose precision -> float
N
Niels 已提交
1887
                    return json(float_val);
N
Niels 已提交
1888 1889
                }
            }
N
cleanup  
Niels 已提交
1890
            catch (...)
N
Niels 已提交
1891
            {
N
cleanup  
Niels 已提交
1892
                error("error translating " +
N
Niels 已提交
1893
                      buffer_.substr(_firstpos_, pos_ - _firstpos_) + " to number");
N
Niels 已提交
1894 1895
            }
        }
N
cleanup  
Niels 已提交
1896 1897 1898 1899 1900

        default:
        {
            error("unexpected character");
        }
N
Niels 已提交
1901 1902 1903 1904 1905 1906 1907 1908 1909 1910
    }
}

/*!
This function reads the next character from the buffer while ignoring all
trailing whitespace. If another character could be read, the function returns
true. If the end of the buffer is reached, false is returned.

@return whether another non-whitespace character could be read

N
Niels 已提交
1911
@post current_ holds the next character
N
Niels 已提交
1912
*/
N
Niels 已提交
1913
bool json::parser::next()
N
Niels 已提交
1914
{
N
Niels 已提交
1915
    if (pos_ == buffer_.size())
N
Niels 已提交
1916 1917 1918 1919
    {
        return false;
    }

N
Niels 已提交
1920
    current_ = buffer_[pos_++];
N
Niels 已提交
1921 1922

    // skip trailing whitespace
N
Niels 已提交
1923
    while (std::isspace(current_))
N
Niels 已提交
1924
    {
N
Niels 已提交
1925
        if (pos_ == buffer_.size())
N
Niels 已提交
1926 1927 1928 1929
        {
            return false;
        }

N
Niels 已提交
1930
        current_ = buffer_[pos_++];
N
Niels 已提交
1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946
    }

    return true;
}

/*!
This function encapsulates the error reporting functions of the parser class.
It throws a \p std::invalid_argument exception with a description where the
error occurred (given as the number of characters read), what went wrong (using
the error message \p msg), and the last read token.

@param msg  an error message
@return <em>This function does not return.</em>

@exception std::invalid_argument whenever the function is called
*/
N
Niels 已提交
1947
void json::parser::error(const std::string& msg)
N
Niels 已提交
1948 1949
{
    throw std::invalid_argument("parse error at position " +
N
Niels 已提交
1950 1951
                                std::to_string(pos_) + ": " + msg +
                                ", last read: '" + current_ + "'");
N
Niels 已提交
1952 1953 1954 1955 1956 1957 1958 1959
}

/*!
Parses a string after opening quotes (\p ") where read.

@return the parsed string

@pre  An opening quote \p " was read in the main parse function @ref parse.
N
Niels 已提交
1960
      pos_ is the position after the opening quote.
N
Niels 已提交
1961 1962

@post The character after the closing quote \p " is the current character @ref
N
Niels 已提交
1963
      current_. Whitespace is skipped.
N
Niels 已提交
1964
*/
N
Niels 已提交
1965
std::string json::parser::parseString()
N
Niels 已提交
1966 1967
{
    // get position of closing quotes
N
Niels 已提交
1968
    auto quotepos_ = buffer_.find_first_of("\"", pos_);
N
Niels 已提交
1969

N
Niels 已提交
1970 1971
    // if the closing quotes are escaped (character before the quotes is a
    // backslash), we continue looking for the final quotes
N
Niels 已提交
1972
    while (quotepos_ != std::string::npos and buffer_[quotepos_ - 1] == '\\')
N
Niels 已提交
1973
    {
N
Niels 已提交
1974
        quotepos_ = buffer_.find_first_of("\"", quotepos_ + 1);
N
Niels 已提交
1975 1976 1977
    }

    // check if closing quotes were found
N
Niels 已提交
1978
    if (quotepos_ == std::string::npos)
N
Niels 已提交
1979 1980 1981 1982
    {
        error("expected '\"'");
    }

N
Niels 已提交
1983
    // store the coordinates of the string for the later return value
N
Niels 已提交
1984 1985
    const auto stringBegin = pos_;
    const auto stringLength = quotepos_ - pos_;
N
Niels 已提交
1986

N
Niels 已提交
1987
    // set buffer position to the position behind (+1) the closing quote
N
Niels 已提交
1988
    pos_ = quotepos_ + 1;
N
Niels 已提交
1989 1990 1991 1992

    // read next character
    next();

N
Niels 已提交
1993
    // return the string value
N
Niels 已提交
1994
    return buffer_.substr(stringBegin, stringLength);
N
Niels 已提交
1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006
}

/*!
This function is called in case a \p "t" is read in the main parse function
@ref parse. In the standard, the \p "true" token is the only candidate, so the
next three characters are expected to be \p "rue". In case of a mismatch, an
error is raised via @ref error.

@pre  A \p "t" was read in the main parse function @ref parse.
@post The character after the \p "true" is the current character. Whitespace is
      skipped.
*/
N
Niels 已提交
2007
void json::parser::parseTrue()
N
Niels 已提交
2008
{
N
Niels 已提交
2009
    if (buffer_.substr(pos_, 3) != "rue")
N
Niels 已提交
2010 2011 2012 2013
    {
        error("expected true");
    }

N
Niels 已提交
2014
    pos_ += 3;
N
Niels 已提交
2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029

    // read next character
    next();
}

/*!
This function is called in case an \p "f" is read in the main parse function
@ref parse. In the standard, the \p "false" token is the only candidate, so the
next four characters are expected to be \p "alse". In case of a mismatch, an
error is raised via @ref error.

@pre  An \p "f" was read in the main parse function.
@post The character after the \p "false" is the current character. Whitespace
      is skipped.
*/
N
Niels 已提交
2030
void json::parser::parseFalse()
N
Niels 已提交
2031
{
N
Niels 已提交
2032
    if (buffer_.substr(pos_, 4) != "alse")
N
Niels 已提交
2033 2034 2035 2036
    {
        error("expected false");
    }

N
Niels 已提交
2037
    pos_ += 4;
N
Niels 已提交
2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052

    // read next character
    next();
}

/*!
This function is called in case an \p "n" is read in the main parse function
@ref parse. In the standard, the \p "null" token is the only candidate, so the
next three characters are expected to be \p "ull". In case of a mismatch, an
error is raised via @ref error.

@pre  An \p "n" was read in the main parse function.
@post The character after the \p "null" is the current character. Whitespace is
      skipped.
*/
N
Niels 已提交
2053
void json::parser::parseNull()
N
Niels 已提交
2054
{
N
Niels 已提交
2055
    if (buffer_.substr(pos_, 3) != "ull")
N
Niels 已提交
2056 2057 2058 2059
    {
        error("expected null");
    }

N
Niels 已提交
2060
    pos_ += 3;
N
Niels 已提交
2061 2062 2063 2064 2065 2066 2067

    // read next character
    next();
}

/*!
This function wraps functionality to check whether the current character @ref
N
Niels 已提交
2068 2069
current_ matches a given character \p c. In case of a match, the next character
of the buffer @ref buffer_ is read. In case of a mismatch, an error is raised
N
Niels 已提交
2070 2071 2072 2073 2074 2075
via @ref error.

@param c  character that is expected

@post The next chatacter is read. Whitespace is skipped.
*/
N
Niels 已提交
2076
void json::parser::expect(const char c)
N
Niels 已提交
2077
{
N
Niels 已提交
2078
    if (current_ != c)
N
Niels 已提交
2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090
    {
        std::string msg = "expected '";
        msg.append(1, c);
        msg += "'";
        error(msg);
    }
    else
    {
        next();
    }
}

N
Niels 已提交
2091 2092
}

N
Niels 已提交
2093 2094 2095 2096 2097 2098 2099 2100
/*!
This operator implements a user-defined string literal for JSON objects. It can
be used by adding \p "_json" to a string literal and returns a JSON object if
no parse error occurred.

@param s  a string representation of a JSON object
@return a JSON object
*/
N
Niels 已提交
2101
nlohmann::json operator "" _json(const char* s, std::size_t)
N
Niels 已提交
2102
{
N
Niels 已提交
2103
    return nlohmann::json::parse(s);
N
Niels 已提交
2104
}