Skip to content

Commit e6eef69

Browse files
committed
update json11.hpp
1 parent b169801 commit e6eef69

File tree

1 file changed

+89
-72
lines changed

1 file changed

+89
-72
lines changed

tests/autotester/json11.hpp

Lines changed: 89 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,3 @@
1-
/* json11 as a header-only lib */
2-
3-
/* Copyright (c) 2013 Dropbox, Inc.
4-
*
5-
* Permission is hereby granted, free of charge, to any person obtaining a copy
6-
* of this software and associated documentation files (the "Software"), to deal
7-
* in the Software without restriction, including without limitation the rights
8-
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9-
* copies of the Software, and to permit persons to whom the Software is
10-
* furnished to do so, subject to the following conditions:
11-
*
12-
* The above copyright notice and this permission notice shall be included in
13-
* all copies or substantial portions of the Software.
14-
*
15-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16-
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17-
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19-
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20-
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21-
* THE SOFTWARE.
22-
*/
23-
241
/* json11
252
*
263
* json11 is a tiny JSON library for C++11, providing JSON parsing and serialization.
@@ -53,12 +30,47 @@
5330
#ifndef JSON11_HPP
5431
#define JSON11_HPP
5532

33+
/* Copyright (c) 2013 Dropbox, Inc.
34+
*
35+
* Permission is hereby granted, free of charge, to any person obtaining a copy
36+
* of this software and associated documentation files (the "Software"), to deal
37+
* in the Software without restriction, including without limitation the rights
38+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
39+
* copies of the Software, and to permit persons to whom the Software is
40+
* furnished to do so, subject to the following conditions:
41+
*
42+
* The above copyright notice and this permission notice shall be included in
43+
* all copies or substantial portions of the Software.
44+
*
45+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
46+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
47+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
48+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
49+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
50+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
51+
* THE SOFTWARE.
52+
*/
53+
54+
#pragma once
55+
5656
#include <string>
5757
#include <vector>
5858
#include <map>
5959
#include <memory>
6060
#include <initializer_list>
6161

62+
#ifdef _MSC_VER
63+
#if _MSC_VER <= 1800 // VS 2013
64+
#ifndef noexcept
65+
#define noexcept throw()
66+
#endif
67+
68+
#ifndef snprintf
69+
#define snprintf _snprintf_s
70+
#endif
71+
#endif
72+
#endif
73+
6274
namespace json11 {
6375

6476
enum JsonParse {
@@ -98,14 +110,14 @@ class Json final {
98110

99111
// Implicit constructor: map-like objects (std::map, std::unordered_map, etc)
100112
template <class M, typename std::enable_if<
101-
std::is_constructible<std::string, typename M::key_type>::value
102-
&& std::is_constructible<Json, typename M::mapped_type>::value,
113+
std::is_constructible<std::string, decltype(std::declval<M>().begin()->first)>::value
114+
&& std::is_constructible<Json, decltype(std::declval<M>().begin()->second)>::value,
103115
int>::type = 0>
104116
Json(const M & m) : Json(object(m.begin(), m.end())) {}
105117

106118
// Implicit constructor: vector-like objects (std::list, std::vector, std::set, etc)
107119
template <class V, typename std::enable_if<
108-
std::is_constructible<Json, typename V::value_type>::value,
120+
std::is_constructible<Json, decltype(*std::declval<V>().begin())>::value,
109121
int>::type = 0>
110122
Json(const V & v) : Json(array(v.begin(), v.end())) {}
111123

@@ -168,9 +180,18 @@ class Json final {
168180
// Parse multiple objects, concatenated or separated by whitespace
169181
static std::vector<Json> parse_multi(
170182
const std::string & in,
183+
std::string::size_type & parser_stop_pos,
171184
std::string & err,
172185
JsonParse strategy = JsonParse::STANDARD);
173186

187+
static inline std::vector<Json> parse_multi(
188+
const std::string & in,
189+
std::string & err,
190+
JsonParse strategy = JsonParse::STANDARD) {
191+
std::string::size_type parser_stop_pos;
192+
return parse_multi(in, parser_stop_pos, err, strategy);
193+
}
194+
174195
bool operator== (const Json &rhs) const;
175196
bool operator< (const Json &rhs) const;
176197
bool operator!= (const Json &rhs) const { return !(*this == rhs); }
@@ -230,11 +251,20 @@ using std::make_shared;
230251
using std::initializer_list;
231252
using std::move;
232253

254+
/* Helper for representing null - just a do-nothing struct, plus comparison
255+
* operators so the helpers in JsonValue work. We can't use nullptr_t because
256+
* it may not be orderable.
257+
*/
258+
struct NullStruct {
259+
bool operator==(NullStruct) const { return true; }
260+
bool operator<(NullStruct) const { return false; }
261+
};
262+
233263
/* * * * * * * * * * * * * * * * * * * *
234264
* Serialization
235265
*/
236266

237-
static void dump(std::nullptr_t, string &out) {
267+
static void dump(NullStruct, string &out) {
238268
out += "null";
239269
}
240270

@@ -401,34 +431,9 @@ class JsonObject final : public Value<Json::OBJECT, Json::object> {
401431
explicit JsonObject(Json::object &&value) : Value(move(value)) {}
402432
};
403433

404-
template <>
405-
class Value<Json::NUL, std::nullptr_t> : public JsonValue {
406-
protected:
407-
408-
// Constructors
409-
explicit Value(const std::nullptr_t &value) : m_value(value) {}
410-
explicit Value(std::nullptr_t &&value) : m_value(move(value)) {}
411-
412-
// Get type tag
413-
Json::Type type() const override {
414-
return Json::NUL;
415-
}
416-
417-
// Comparisons
418-
bool equals(const JsonValue * other) const override {
419-
return m_value == static_cast<const Value *>(other)->m_value;
420-
}
421-
bool less(const JsonValue *) const override {
422-
return false;
423-
}
424-
425-
const std::nullptr_t m_value;
426-
void dump(string &out) const override { json11::dump(m_value, out); }
427-
};
428-
429-
class JsonNull final : public Value<Json::NUL, std::nullptr_t> {
434+
class JsonNull final : public Value<Json::NUL, NullStruct> {
430435
public:
431-
JsonNull() : Value(nullptr) {}
436+
JsonNull() : Value({}) {}
432437
};
433438

434439
/* * * * * * * * * * * * * * * * * * * *
@@ -509,13 +514,17 @@ const Json & JsonArray::operator[] (size_t i) const {
509514
*/
510515

511516
bool Json::operator== (const Json &other) const {
517+
if (m_ptr == other.m_ptr)
518+
return true;
512519
if (m_ptr->type() != other.m_ptr->type())
513520
return false;
514521

515522
return m_ptr->equals(other.m_ptr.get());
516523
}
517524

518525
bool Json::operator< (const Json &other) const {
526+
if (m_ptr == other.m_ptr)
527+
return false;
519528
if (m_ptr->type() != other.m_ptr->type())
520529
return m_ptr->type() < other.m_ptr->type();
521530

@@ -544,11 +553,12 @@ static inline bool in_range(long x, long lower, long upper) {
544553
return (x >= lower && x <= upper);
545554
}
546555

556+
namespace {
547557
/* JsonParser
548558
*
549559
* Object that tracks all state of an in-progress parse.
550560
*/
551-
struct JsonParser {
561+
struct JsonParser final {
552562

553563
/* State
554564
*/
@@ -592,38 +602,31 @@ struct JsonParser {
592602
if (str[i] == '/') {
593603
i++;
594604
if (i == str.size())
595-
return fail("unexpected end of input inside comment", 0);
605+
return fail("unexpected end of input after start of comment", false);
596606
if (str[i] == '/') { // inline comment
597607
i++;
598-
if (i == str.size())
599-
return fail("unexpected end of input inside inline comment", 0);
600-
// advance until next line
601-
while (str[i] != '\n') {
608+
// advance until next line, or end of input
609+
while (i < str.size() && str[i] != '\n') {
602610
i++;
603-
if (i == str.size())
604-
return fail("unexpected end of input inside inline comment", 0);
605611
}
606612
comment_found = true;
607613
}
608614
else if (str[i] == '*') { // multiline comment
609615
i++;
610616
if (i > str.size()-2)
611-
return fail("unexpected end of input inside multi-line comment", 0);
617+
return fail("unexpected end of input inside multi-line comment", false);
612618
// advance until closing tokens
613619
while (!(str[i] == '*' && str[i+1] == '/')) {
614620
i++;
615621
if (i > str.size()-2)
616622
return fail(
617-
"unexpected end of input inside multi-line comment", 0);
623+
"unexpected end of input inside multi-line comment", false);
618624
}
619625
i += 2;
620-
if (i == str.size())
621-
return fail(
622-
"unexpected end of input inside multi-line comment", 0);
623626
comment_found = true;
624627
}
625628
else
626-
return fail("malformed comment", 0);
629+
return fail("malformed comment", false);
627630
}
628631
return comment_found;
629632
}
@@ -638,6 +641,7 @@ struct JsonParser {
638641
bool comment_found = false;
639642
do {
640643
comment_found = consume_comment();
644+
if (failed) return;
641645
consume_whitespace();
642646
}
643647
while(comment_found);
@@ -651,8 +655,9 @@ struct JsonParser {
651655
*/
652656
char get_next_token() {
653657
consume_garbage();
658+
if (failed) return static_cast<char>(0);
654659
if (i == str.size())
655-
return fail("unexpected end of input", 0);
660+
return fail("unexpected end of input", static_cast<char>(0));
656661

657662
return str[i++];
658663
}
@@ -726,7 +731,7 @@ struct JsonParser {
726731
if (esc.length() < 4) {
727732
return fail("bad \\u escape: " + esc, "");
728733
}
729-
for (int j = 0; j < 4; j++) {
734+
for (size_t j = 0; j < 4; j++) {
730735
if (!in_range(esc[j], 'a', 'f') && !in_range(esc[j], 'A', 'F')
731736
&& !in_range(esc[j], '0', '9'))
732737
return fail("bad \\u escape: " + esc, "");
@@ -936,13 +941,16 @@ struct JsonParser {
936941
return fail("expected value, got " + esc(ch));
937942
}
938943
};
944+
}//namespace {
939945

940946
Json Json::parse(const string &in, string &err, JsonParse strategy) {
941947
JsonParser parser { in, 0, err, false, strategy };
942948
Json result = parser.parse_json(0);
943949

944950
// Check for any trailing garbage
945951
parser.consume_garbage();
952+
if (parser.failed)
953+
return Json();
946954
if (parser.i != in.size())
947955
return parser.fail("unexpected trailing " + esc(in[parser.i]));
948956

@@ -951,15 +959,22 @@ Json Json::parse(const string &in, string &err, JsonParse strategy) {
951959

952960
// Documented in json11.hpp
953961
vector<Json> Json::parse_multi(const string &in,
962+
std::string::size_type &parser_stop_pos,
954963
string &err,
955964
JsonParse strategy) {
956965
JsonParser parser { in, 0, err, false, strategy };
957-
966+
parser_stop_pos = 0;
958967
vector<Json> json_vec;
959968
while (parser.i != in.size() && !parser.failed) {
960969
json_vec.push_back(parser.parse_json(0));
970+
if (parser.failed)
971+
break;
972+
961973
// Check for another object
962974
parser.consume_garbage();
975+
if (parser.failed)
976+
break;
977+
parser_stop_pos = parser.i;
963978
}
964979
return json_vec;
965980
}
@@ -974,8 +989,10 @@ bool Json::has_shape(const shape & types, string & err) const {
974989
return false;
975990
}
976991

992+
const auto& obj_items = object_items();
977993
for (auto & item : types) {
978-
if ((*this)[item.first].type() != item.second) {
994+
const auto it = obj_items.find(item.first);
995+
if (it == obj_items.cend() || it->second.type() != item.second) {
979996
err = "bad type for " + item.first + " in " + dump();
980997
return false;
981998
}

0 commit comments

Comments
 (0)