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.
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+
6274namespace json11 {
6375
6476enum 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;
230251using std::initializer_list;
231252using 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> {
430435public:
431- JsonNull () : Value(nullptr ) {}
436+ JsonNull () : Value({} ) {}
432437};
433438
434439/* * * * * * * * * * * * * * * * * * * *
@@ -509,13 +514,17 @@ const Json & JsonArray::operator[] (size_t i) const {
509514 */
510515
511516bool 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
518525bool 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
940946Json 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
953961vector<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