23 #ifndef SUPPORTLIB_JSON_H
24 #define SUPPORTLIB_JSON_H
31 #include <type_traits>
32 #include <initializer_list>
36 #if __has_include("Object.h")
52 float_conversion_failed_invalid_arg = 42,
53 float_conversion_failed_out_of_range,
54 float_conversion_failed,
57 array_missing_comma_or_bracket,
58 string_missing_hex_char,
59 string_conversion_failed,
60 string_unescaped_conversion_failed,
61 number_missing_exponent,
62 number_unexpected_char,
63 number_conversion_failed,
65 bool_conversion_failed,
76 const char* name()
const noexcept
override{
79 std::string message(
int ev)
const override{
82 case json::error::float_conversion_failed_invalid_arg:
83 return "Failed to convert the value to float: Invalid argument!";
84 case json::error::float_conversion_failed_out_of_range:
85 return "Failed to convert the value to float: Out of range!";
86 case json::error::float_conversion_failed:
87 return "Failed to convert the value to float!";
88 case json::error::object_missing_colon:
89 return "Parsing Object failed: Expected colon not found!";
90 case json::error::object_missing_comma:
91 return "Parsing Object failed: Expected comma not found!";
92 case json::error::array_missing_comma_or_bracket:
93 return "Parsing Array failed: Expected ',' or ']' not found!";
94 case json::error::string_missing_hex_char:
95 return "Parsing String failed: Expected hex character in unicode escape not found!";
96 case json::error::string_conversion_failed:
97 return "Failed to convert the value to string!";
98 case json::error::string_unescaped_conversion_failed:
99 return "Failed to convert the value to a unescaped string!";
100 case json::error::number_missing_exponent:
101 return "Parsing Number failed: Expected number for exponent not found!";
102 case json::error::number_unexpected_char:
103 return "Parsing Number failed: Unexpected character!";
104 case json::error::number_conversion_failed:
105 return "Failed to convert the value to int!";
106 case json::error::bool_wrong_text:
107 return "Parsing Bool failed: Expected 'true' or 'false' not found!";
108 case json::error::bool_conversion_failed:
109 return "Failed to convert the value to boolean!";
110 case json::error::null_wrong_text:
111 return "Parsing Null failed: Expected 'null' not found!";
112 case json::error::unknown_starting_char:
113 return "Parsing failed: Unknown starting character!";
115 return "Unrecognized error occured...";
141 for(
unsigned i = 0; i < str.length(); ++i )
143 case '\"': output +=
"\\\"";
break;
144 case '\\': output +=
"\\\\";
break;
145 case '\b': output +=
"\\b";
break;
146 case '\f': output +=
"\\f";
break;
147 case '\n': output +=
"\\n";
break;
148 case '\r': output +=
"\\r";
break;
149 case '\t': output +=
"\\t";
break;
150 default : output += str[i];
break;
440 #if __has_include("Object.h")
441 class JSON final :
public Object<JSON>
447 BackingData(
double d ) : Float( d ){}
448 BackingData(
long long l ) : Int( l ){}
449 BackingData(
bool b ) : Bool( b ){}
450 BackingData( std::string s ) : String(
new std::string( s ) ){}
451 BackingData() : Int( 0 ){}
453 std::deque<JSON> *List;
454 std::map<std::string,JSON> *Map;
474 template <
typename Container>
480 JSONWrapper( std::nullptr_t ) : object(
nullptr ) {}
482 typename Container::iterator begin() {
return object ?
object->begin() :
typename Container::iterator(); }
483 typename Container::iterator end() {
return object ?
object->end() :
typename Container::iterator(); }
484 typename Container::const_iterator begin()
const {
return object ?
object->begin() :
typename Container::iterator(); }
485 typename Container::const_iterator end()
const {
return object ?
object->end() :
typename Container::iterator(); }
490 template <
typename Container>
492 const Container *object;
498 typename Container::const_iterator begin()
const {
return object ?
object->begin() :
typename Container::const_iterator(); }
499 typename Container::const_iterator end()
const {
return object ?
object->end() :
typename Container::const_iterator(); }
502 JSON() : Internal(), Type( Class::Null ){}
504 explicit JSON(Class type):
JSON() { SetType( type ); }
506 JSON( std::initializer_list<JSON> list )
509 SetType( Class::Object );
510 for(
auto i = list.begin(), e = list.end(); i != e; ++i, ++i )
511 operator[]( i->ToString() ) = *std::next( i );
515 : Internal( other.Internal )
517 { other.Type = Class::Null; other.Internal.Map =
nullptr; }
519 JSON& operator=( JSON&& other ) {
521 Internal = other.Internal;
523 other.Internal.Map =
nullptr;
524 other.Type = Class::Null;
528 JSON(
const JSON &other ) {
529 switch( other.Type ) {
532 new std::map<std::string,JSON>( other.Internal.Map->begin(),
533 other.Internal.Map->end() );
537 new std::deque<JSON>( other.Internal.List->begin(),
538 other.Internal.List->end() );
542 new std::string( *other.Internal.String );
545 Internal = other.Internal;
550 JSON& operator=(
const JSON &other ) {
551 if (&other ==
this)
return *
this;
553 switch( other.Type ) {
556 new std::map<std::string,JSON>( other.Internal.Map->begin(),
557 other.Internal.Map->end() );
561 new std::deque<JSON>( other.Internal.List->begin(),
562 other.Internal.List->end() );
566 new std::string( *other.Internal.String );
569 Internal = other.Internal;
578 delete Internal.List;
584 delete Internal.String;
590 template <
typename T>
591 JSON( T b,
typename std::enable_if<std::is_same<T,bool>::value>::type* = 0 ) : Internal( b ), Type( Class::Boolean ){}
593 template <
typename T>
594 JSON( T i,
typename std::enable_if<std::is_integral<T>::value && !std::is_same<T,bool>::value>::type* = 0 ) : Internal( (long long)i ), Type( Class::Integral ){}
596 template <
typename T>
597 JSON( T f,
typename std::enable_if<std::is_floating_point<T>::value>::type* = 0 ) : Internal( (double)f ), Type( Class::Floating ){}
599 template <
typename T>
600 JSON( T s,
typename std::enable_if<std::is_convertible<T,std::string>::value>::type* = 0 ) : Internal(
std::string( s ) ), Type( Class::String ){}
602 JSON( std::nullptr_t ) : Internal(), Type( Class::Null ){}
618 static JSON Load(
const std::string &str);
626 static JSON Load(
const std::string &str, std::error_code &ec) noexcept;
633 template <
typename T>
635 SetType( Class::Array ); Internal.List->emplace_back( arg );
644 template <
typename T,
typename... U>
649 template <
typename T>
650 typename std::enable_if<std::is_same<T,bool>::value,
JSON&>::type operator=( T b ) {
651 SetType( Class::Boolean ); Internal.Bool = b;
return *
this;
654 template <
typename T>
655 typename std::enable_if<std::is_integral<T>::value && !std::is_same<T,bool>::value, JSON&>::type operator=( T i ) {
656 SetType( Class::Integral ); Internal.Int = i;
return *
this;
659 template <
typename T>
660 typename std::enable_if<std::is_floating_point<T>::value, JSON&>::type operator=( T f ) {
661 SetType( Class::Floating ); Internal.Float = f;
return *
this;
664 template <
typename T>
665 typename std::enable_if<std::is_convertible<T,std::string>::value, JSON&>::type operator=( T s ) {
666 SetType( Class::String ); *Internal.String = std::string( s );
return *
this;
675 SetType( Class::Object );
return Internal.Map->operator[]( key );
684 SetType( Class::Array );
685 if( index >= Internal.List->size() ) Internal.List->resize( index + 1 );
686 return Internal.List->operator[]( index );
703 const JSON &
at(
const std::string &key )
const {
704 return Internal.Map->at( key );
722 return Internal.List->at( index );
730 if( Type == Class::Array )
731 return Internal.List->size();
740 bool hasKey(
const std::string &key )
const {
741 if( Type == Class::Object )
742 return Internal.Map->find( key ) != Internal.Map->end();
751 if( Type == Class::Object )
752 return Internal.Map->size();
753 else if( Type == Class::Array )
754 return Internal.List->size();
768 bool IsNull()
const {
return Type == Class::Null; }
773 bool IsArray()
const {
return Type == Class::Array; }
778 bool IsBoolean()
const {
return Type == Class::Boolean; }
793 bool IsString()
const {
return Type == Class::String; }
798 bool IsObject()
const {
return Type == Class::Object; }
807 std::string
ToString( std::error_code &ec )
const noexcept {
808 if(Type == Class::String)
811 if(Type == Class::Object)
814 if(Type == Class::Array)
817 if(Type == Class::Boolean)
818 return Internal.Bool ? std::string(
"true") : std::string(
"false");
820 if(Type == Class::Floating)
821 return std::to_string(Internal.Float);
823 if(Type == Class::Integral)
824 return std::to_string(Internal.Int);
826 if(Type == Class::Null)
827 return std::string(
"null");
829 ec = error::string_conversion_failed;
830 return std::string(
"");
855 if(Type == Class::String)
856 return std::string( *Internal.String );
858 if(Type == Class::Object)
861 if(Type == Class::Array)
864 if(Type == Class::Boolean)
865 return Internal.Bool ? std::string(
"true") : std::string(
"false");
867 if(Type == Class::Floating)
868 return std::to_string(Internal.Float);
870 if(Type == Class::Integral)
871 return std::to_string(Internal.Int);
873 if(Type == Class::Null)
874 return std::string(
"null");
876 ec = error::string_unescaped_conversion_failed;
877 return std::string(
"");
899 double ToFloat( std::error_code &ec )
const noexcept {
900 if (Type == Class::Floating)
901 return Internal.Float;
903 if(Type == Class::Boolean)
904 return Internal.Bool;
906 if (Type == Class::Integral)
909 if (Type == Class::String)
913 parsed = std::stod(*Internal.String);
915 catch(
const std::invalid_argument &e) {
916 ec = error::float_conversion_failed_invalid_arg;
918 catch(
const std::out_of_range &e) {
919 ec = error::float_conversion_failed_out_of_range;
925 ec = error::float_conversion_failed;
946 long long ToInt( std::error_code &ec )
const noexcept {
947 if (Type == Class::Integral)
950 if(Type == Class::Boolean)
951 return Internal.Bool;
953 if (Type == Class::Floating)
954 return Internal.Float;
956 if (Type == Class::String)
959 std::from_chars_result result = std::from_chars(Internal.String->data(), Internal.String->data() + Internal.String->size(), parsed);
964 ec = error::number_conversion_failed;
974 long long ret =
ToInt( ec );
985 bool ToBool( std::error_code &ec )
const noexcept {
986 if(Type == Class::Boolean)
987 return Internal.Bool;
989 if (Type == Class::Integral)
992 if (Type == Class::Floating)
993 return Internal.Float;
995 if (Type == Class::String)
997 if(Internal.String->find(
"true")!=std::string::npos)
999 if(Internal.String->find(
"false")!=std::string::npos)
1002 std::from_chars_result result = std::from_chars(Internal.String->data(), Internal.String->data() + Internal.String->size(), parsed);
1003 if(!(
bool)result.ec)
1007 ec = error::bool_conversion_failed;
1028 if( Type == Class::Object )
1038 if( Type == Class::Array )
1048 if( Type == Class::Object )
1058 if( Type == Class::Array )
1069 std::string
dump(
int depth = 1, std::string tab =
" ")
const {
1073 case Class::Object: {
1074 std::string pad =
"";
1075 for(
int i = 0; i < depth; ++i, pad += tab );
1076 std::string s =
"{\n";
1078 for(
auto &p : *Internal.Map ) {
1079 if( !skip ) s +=
",\n";
1080 s += ( pad +
"\"" + p.first +
"\" : " + p.second.dump( depth + 1, tab ) );
1083 s += (
"\n" + pad.erase( 0, tab.size() ) +
"}" ) ;
1086 case Class::Array: {
1087 std::string s =
"[";
1089 for(
auto &p : *Internal.List ) {
1090 if( !skip ) s +=
", ";
1091 s += p.dump( depth + 1, tab );
1099 case Class::Floating:
1100 return std::to_string( Internal.Float );
1101 case Class::Integral:
1102 return std::to_string( Internal.Int );
1103 case Class::Boolean:
1104 return Internal.Bool ?
"true" :
"false";
1119 case Class::Object: {
1120 std::string s =
"{";
1122 for(
auto &p : *Internal.Map ) {
1123 if( !skip ) s +=
",";
1124 s += (
"\"" + p.first +
"\":" + p.second.dumpMinified() );
1130 case Class::Array: {
1131 std::string s =
"[";
1133 for(
auto &p : *Internal.List ) {
1134 if( !skip ) s +=
",";
1135 s += p.dumpMinified();
1143 case Class::Floating:
1144 return std::to_string( Internal.Float );
1145 case Class::Integral:
1146 return std::to_string( Internal.Int );
1147 case Class::Boolean:
1148 return Internal.Bool ?
"true" :
"false";
1155 friend std::ostream& operator<<( std::ostream&,
const JSON & );
1158 void SetType( Class type ) {
1165 case Class::Null: Internal.Map =
nullptr;
break;
1166 case Class::Object: Internal.Map =
new std::map<std::string,JSON>();
break;
1167 case Class::Array: Internal.List =
new std::deque<JSON>();
break;
1168 case Class::String: Internal.String =
new std::string();
break;
1169 case Class::Floating: Internal.Float = 0.0;
break;
1170 case Class::Integral: Internal.Int = 0;
break;
1171 case Class::Boolean: Internal.Bool =
false;
break;
1181 void ClearInternal() {
1183 case Class::Object:
delete Internal.Map;
break;
1184 case Class::Array:
delete Internal.List;
break;
1185 case Class::String:
delete Internal.String;
break;
1191 Class Type = Class::Null;
1194 inline JSON Array() {
1198 template <
typename... T>
1199 JSON Array( T... args ) {
1201 arr.append( args... );
1205 inline JSON Object() {
1209 inline std::ostream& operator<<( std::ostream &os,
const JSON &json ) {
1218 inline JSON parse_next(
const std::string &,
size_t &, std::error_code& ) noexcept;
1220 inline void consume_ws(
const std::string &str,
size_t &offset ) {
1221 while( isspace( str[offset] ) ) ++offset;
1224 inline JSON parse_object(
const std::string &str,
size_t &offset, std::error_code &ec ) noexcept {
1228 consume_ws( str, offset );
1229 if( str[offset] ==
'}' ) {
1234 JSON Key = parse_next( str, offset, ec );
1235 consume_ws( str, offset );
1236 if( str[offset] !=
':' ) {
1237 ec = error::object_missing_colon;
1240 consume_ws( str, ++offset );
1241 JSON Value = parse_next( str, offset, ec );
1244 consume_ws( str, offset );
1245 if( str[offset] ==
',' ) {
1248 else if( str[offset] ==
'}' ) {
1252 ec = error::object_missing_comma;
1259 inline JSON parse_array(
const std::string &str,
size_t &offset, std::error_code &ec ) noexcept {
1264 consume_ws( str, offset );
1265 if( str[offset] ==
']' ) {
1266 ++offset;
return Array;
1270 Array[index++] = parse_next( str, offset, ec );
1271 consume_ws( str, offset );
1273 if( str[offset] ==
',' ) {
1276 else if( str[offset] ==
']' ) {
1280 ec = error::array_missing_comma_or_bracket;
1287 inline JSON parse_string(
const std::string &str,
size_t &offset, std::error_code &ec ) noexcept {
1289 for(
char c = str[++offset]; c !=
'\"' ; c = str[++offset] ) {
1291 switch( str[ ++offset ] ) {
1292 case '\"': val +=
'\"';
break;
1293 case '\\': val +=
'\\';
break;
1294 case '/' : val +=
'/' ;
break;
1295 case 'b' : val +=
'\b';
break;
1296 case 'f' : val +=
'\f';
break;
1297 case 'n' : val +=
'\n';
break;
1298 case 'r' : val +=
'\r';
break;
1299 case 't' : val +=
'\t';
break;
1302 for(
unsigned i = 1; i <= 4; ++i ) {
1304 if( (c >=
'0' && c <=
'9') || (c >=
'a' && c <=
'f') || (c >=
'A' && c <=
'F') )
1307 ec = error::string_missing_hex_char;
1313 default : val +=
'\\';
break;
1323 inline JSON parse_number(
const std::string &str,
size_t &offset, std::error_code &ec ) noexcept {
1325 std::string val, exp_str;
1327 bool isDouble =
false;
1331 if( (c ==
'-') || (c >=
'0' && c <=
'9') )
1333 else if( c ==
'.' ) {
1340 if( c ==
'E' || c ==
'e' ) {
1342 if( c ==
'-' ){ ++offset; exp_str +=
'-';}
1343 if( c ==
'+' ){ ++offset;}
1345 c = str[ offset++ ];
1346 if( c >=
'0' && c <=
'9' )
1348 else if( !isspace( c ) && c !=
',' && c !=
']' && c !=
'}' ) {
1349 ec = error::number_missing_exponent;
1355 exp = std::stol( exp_str );
1357 else if( !isspace( c ) && c !=
',' && c !=
']' && c !=
'}' ) {
1358 ec = error::number_unexpected_char;
1364 Number = std::stod( val ) * std::pow( 10, exp );
1366 if( !exp_str.empty() )
1367 Number = std::stol( val ) * std::pow( 10, exp );
1369 Number = std::stol( val );
1374 inline JSON parse_bool(
const std::string &str,
size_t &offset, std::error_code &ec ) noexcept {
1376 if( str.substr( offset, 4 ) ==
"true" )
1378 else if( str.substr( offset, 5 ) ==
"false" )
1381 ec = error::bool_wrong_text;
1384 offset += (Bool.
ToBool() ? 4 : 5);
1388 inline JSON parse_null(
const std::string &str,
size_t &offset, std::error_code &ec ) noexcept {
1389 if( str.substr( offset, 4 ) !=
"null" ) {
1390 ec = error::null_wrong_text;
1397 inline JSON parse_next(
const std::string &str,
size_t &offset, std::error_code &ec ) noexcept {
1399 consume_ws( str, offset );
1400 value = str[offset];
1402 case '[' :
return parse_array( str, offset, ec );
1403 case '{' :
return parse_object( str, offset, ec );
1404 case '\"':
return parse_string( str, offset, ec );
1406 case 'f' :
return parse_bool( str, offset, ec );
1407 case 'n' :
return parse_null( str, offset, ec );
1408 default :
if( ( value <= '9' && value >=
'0' ) || value ==
'-' )
1409 return parse_number( str, offset, ec );
1411 ec = error::unknown_starting_char;
1418 return parsers::parse_next( str, offset, ec );
1424 JSON obj = parsers::parse_next( str, offset, ec );
Base class of all classes.
Key class implementing passkey idiom.
Definition: PassKey.h:76
Base Class of all classes.
Definition: Object.h:33
Provides const iterators to iterate over objects/arrays.
Definition: JSON.h:491
Provides iterators to iterate over objects/arrays.
Definition: JSON.h:475
Class to represent and use JSON objects. Class may throw exceptions of type std::error_code on error.
Definition: JSON.h:445
JSON & at(unsigned index)
Definition: JSON.h:712
bool IsObject() const
Definition: JSON.h:798
std::string ToUnescapedString(std::error_code &ec) const noexcept
Definition: JSON.h:854
bool IsString() const
Definition: JSON.h:793
void append(T arg, U... args)
Definition: JSON.h:645
std::string ToString() const
Definition: JSON.h:839
std::string dumpMinified() const
Definition: JSON.h:1115
const JSON & at(const std::string &key) const
Definition: JSON.h:703
bool ToBool(std::error_code &ec) const noexcept
Definition: JSON.h:985
long long ToInt(std::error_code &ec) const noexcept
Definition: JSON.h:946
JSONConstWrapper< std::deque< JSON > > ArrayRange() const
Definition: JSON.h:1057
bool ToBool() const
Definition: JSON.h:1015
JSON & at(const std::string &key)
Definition: JSON.h:694
bool IsArray() const
Definition: JSON.h:773
static JSON Load(const std::string &str)
Definition: JSON.h:1421
bool IsNull() const
Definition: JSON.h:768
bool IsBoolean() const
Definition: JSON.h:778
void append(T arg)
Definition: JSON.h:634
JSONWrapper< std::map< std::string, JSON > > ObjectRange()
Definition: JSON.h:1027
bool hasKey(const std::string &key) const
Definition: JSON.h:740
const JSON & at(unsigned index) const
Definition: JSON.h:721
bool IsFloating() const
Definition: JSON.h:783
std::size_t length() const
Definition: JSON.h:729
JSONWrapper< std::deque< JSON > > ArrayRange()
Definition: JSON.h:1037
JSON & operator[](unsigned index)
Definition: JSON.h:683
static JSON Make(Class type)
Definition: JSON.h:609
Class JSONType() const
Definition: JSON.h:762
long long ToInt() const
Definition: JSON.h:972
double ToFloat() const
Definition: JSON.h:933
double ToFloat(std::error_code &ec) const noexcept
Definition: JSON.h:899
std::string ToUnescapedString() const
Definition: JSON.h:886
JSONConstWrapper< std::map< std::string, JSON > > ObjectRange() const
Definition: JSON.h:1047
std::string dump(int depth=1, std::string tab=" ") const
Definition: JSON.h:1069
JSON & operator[](const std::string &key)
Definition: JSON.h:674
std::size_t size() const
Definition: JSON.h:750
bool IsIntegral() const
Definition: JSON.h:788
std::string ToString(std::error_code &ec) const noexcept
Definition: JSON.h:807
std::string json_escape(const std::string &str)
Definition: JSON.h:139
const json::error_category json_error_category
Definition: JSON.h:156
std::error_code make_error_code(json::error e) noexcept
Definition: JSON.h:164
error
Enum class to identify parsing and conversion errors.
Definition: JSON.h:51
Namespace for giri's C++ support library.
Definition: Base64.h:47
Error category object used to convert the error code to a understandable message via std::error_code.
Definition: JSON.h:75