Giri's C++ Support Library
C++ library providing everything you need to quickly create awesome applications.
JSON.h
Go to the documentation of this file.
1 
23 #ifndef SUPPORTLIB_JSON_H
24 #define SUPPORTLIB_JSON_H
25 #include <cstdint>
26 #include <cmath>
27 #include <cctype>
28 #include <string>
29 #include <deque>
30 #include <map>
31 #include <type_traits>
32 #include <initializer_list>
33 #include <ostream>
34 #include <charconv>
35 
36 #if __has_include("Object.h")
37 # include "Object.h"
38 #endif
39 
40 namespace giri {
41 
45  namespace json {
46 
50  enum class error
51  {
52  float_conversion_failed_invalid_arg = 42,
53  float_conversion_failed_out_of_range,
54  float_conversion_failed,
55  object_missing_colon,
56  object_missing_comma,
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,
64  bool_wrong_text,
65  bool_conversion_failed,
66  null_wrong_text,
67  unknown_starting_char
68  };
69 
74  struct error_category : std::error_category
75  {
76  const char* name() const noexcept override{
77  return "JSON";
78  }
79  std::string message(int ev) const override{
80  switch (static_cast<json::error>(ev))
81  {
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!";
114  default:
115  return "Unrecognized error occured...";
116  }
117  }
118  };
119  }
120 }
121 
123 namespace std {
124  template <> struct is_error_code_enum<giri::json::error> : true_type {};
125 }
126 
127 namespace giri {
128  namespace json {
129 
133  namespace utility {
134 
139  inline std::string json_escape( const std::string &str ) {
140  std::string output;
141  for( unsigned i = 0; i < str.length(); ++i )
142  switch( str[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;
151  }
152  return output;
153  }
154 
157  }
158 
164  inline std::error_code make_error_code(json::error e) noexcept {
165  return {static_cast<int>(e), utility::json_error_category};
166  };
167 
440 #if __has_include("Object.h")
441  class JSON final : public Object<JSON>
442 #else
443  class JSON final
444 #endif
445  {
446  union BackingData {
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 ){}
452 
453  std::deque<JSON> *List;
454  std::map<std::string,JSON> *Map;
455  std::string *String;
456  double Float;
457  long long Int;
458  bool Bool;
459  } Internal;
460 
461  public:
462  enum class Class {
463  Null,
464  Object,
465  Array,
466  String,
467  Floating,
468  Integral,
469  Boolean
470  };
474  template <typename Container>
475  class JSONWrapper {
476  Container *object;
477 
478  public:
479  JSONWrapper( Container *val ) : object( val ) {}
480  JSONWrapper( std::nullptr_t ) : object( nullptr ) {}
481 
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(); }
486  };
490  template <typename Container>
492  const Container *object;
493 
494  public:
495  JSONConstWrapper( const Container *val ) : object( val ) {}
496  JSONConstWrapper( std::nullptr_t ) : object( nullptr ) {}
497 
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(); }
500  };
501 
502  JSON() : Internal(), Type( Class::Null ){}
503 
504  explicit JSON(Class type): JSON() { SetType( type ); }
505 
506  JSON( std::initializer_list<JSON> list )
507  : JSON()
508  {
509  SetType( Class::Object );
510  for( auto i = list.begin(), e = list.end(); i != e; ++i, ++i )
511  operator[]( i->ToString() ) = *std::next( i );
512  }
513 
514  JSON( JSON&& other )
515  : Internal( other.Internal )
516  , Type( other.Type )
517  { other.Type = Class::Null; other.Internal.Map = nullptr; }
518 
519  JSON& operator=( JSON&& other ) {
520  ClearInternal();
521  Internal = other.Internal;
522  Type = other.Type;
523  other.Internal.Map = nullptr;
524  other.Type = Class::Null;
525  return *this;
526  }
527 
528  JSON( const JSON &other ) {
529  switch( other.Type ) {
530  case Class::Object:
531  Internal.Map =
532  new std::map<std::string,JSON>( other.Internal.Map->begin(),
533  other.Internal.Map->end() );
534  break;
535  case Class::Array:
536  Internal.List =
537  new std::deque<JSON>( other.Internal.List->begin(),
538  other.Internal.List->end() );
539  break;
540  case Class::String:
541  Internal.String =
542  new std::string( *other.Internal.String );
543  break;
544  default:
545  Internal = other.Internal;
546  }
547  Type = other.Type;
548  }
549 
550  JSON& operator=( const JSON &other ) {
551  if (&other == this) return *this;
552  ClearInternal();
553  switch( other.Type ) {
554  case Class::Object:
555  Internal.Map =
556  new std::map<std::string,JSON>( other.Internal.Map->begin(),
557  other.Internal.Map->end() );
558  break;
559  case Class::Array:
560  Internal.List =
561  new std::deque<JSON>( other.Internal.List->begin(),
562  other.Internal.List->end() );
563  break;
564  case Class::String:
565  Internal.String =
566  new std::string( *other.Internal.String );
567  break;
568  default:
569  Internal = other.Internal;
570  }
571  Type = other.Type;
572  return *this;
573  }
574 
575  ~JSON() {
576  switch( Type ) {
577  case Class::Array:
578  delete Internal.List;
579  break;
580  case Class::Object:
581  delete Internal.Map;
582  break;
583  case Class::String:
584  delete Internal.String;
585  break;
586  default:;
587  }
588  }
589 
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 ){}
592 
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 ){}
595 
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 ){}
598 
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 ){}
601 
602  JSON( std::nullptr_t ) : Internal(), Type( Class::Null ){}
603 
609  static JSON Make( Class type ) {
610  return JSON(type);
611  }
612 
618  static JSON Load( const std::string &str);
619 
626  static JSON Load( const std::string &str, std::error_code &ec) noexcept;
627 
633  template <typename T>
634  void append( T arg ) {
635  SetType( Class::Array ); Internal.List->emplace_back( arg );
636  }
637 
644  template <typename T, typename... U>
645  void append( T arg, U... args ) {
646  append( arg ); append( args... );
647  }
648 
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;
652  }
653 
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;
657  }
658 
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;
662  }
663 
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;
667  }
668 
674  JSON& operator[]( const std::string &key ) {
675  SetType( Class::Object ); return Internal.Map->operator[]( key );
676  }
677 
683  JSON& operator[]( unsigned index ) {
684  SetType( Class::Array );
685  if( index >= Internal.List->size() ) Internal.List->resize( index + 1 );
686  return Internal.List->operator[]( index );
687  }
688 
694  JSON &at( const std::string &key ) {
695  return operator[]( key );
696  }
697 
703  const JSON &at( const std::string &key ) const {
704  return Internal.Map->at( key );
705  }
706 
712  JSON &at( unsigned index ) {
713  return operator[]( index );
714  }
715 
721  const JSON &at( unsigned index ) const {
722  return Internal.List->at( index );
723  }
724 
729  std::size_t length() const {
730  if( Type == Class::Array )
731  return Internal.List->size();
732  else
733  return -1;
734  }
735 
740  bool hasKey( const std::string &key ) const {
741  if( Type == Class::Object )
742  return Internal.Map->find( key ) != Internal.Map->end();
743  return false;
744  }
745 
750  std::size_t size() const {
751  if( Type == Class::Object )
752  return Internal.Map->size();
753  else if( Type == Class::Array )
754  return Internal.List->size();
755  else
756  return -1;
757  }
758 
762  Class JSONType() const { return Type; }
763 
764 
768  bool IsNull() const { return Type == Class::Null; }
769 
773  bool IsArray() const { return Type == Class::Array; }
774 
778  bool IsBoolean() const { return Type == Class::Boolean; }
779 
783  bool IsFloating() const { return Type == Class::Floating; }
784 
788  bool IsIntegral() const { return Type == Class::Integral; }
789 
793  bool IsString() const { return Type == Class::String; }
794 
798  bool IsObject() const { return Type == Class::Object; }
799 
807  std::string ToString( std::error_code &ec ) const noexcept {
808  if(Type == Class::String)
809  return utility::json_escape( *Internal.String );
810 
811  if(Type == Class::Object)
812  return dumpMinified();
813 
814  if(Type == Class::Array)
815  return dumpMinified();
816 
817  if(Type == Class::Boolean)
818  return Internal.Bool ? std::string("true") : std::string("false");
819 
820  if(Type == Class::Floating)
821  return std::to_string(Internal.Float);
822 
823  if(Type == Class::Integral)
824  return std::to_string(Internal.Int);
825 
826  if(Type == Class::Null)
827  return std::string("null");
828 
829  ec = error::string_conversion_failed;
830  return std::string("");
831  }
832 
839  std::string ToString() const {
840  std::error_code ec;
841  std::string ret = ToString( ec );
842  if(ec)
843  throw ec;
844  return ret;
845  }
846 
854  std::string ToUnescapedString( std::error_code &ec ) const noexcept {
855  if(Type == Class::String)
856  return std::string( *Internal.String );
857 
858  if(Type == Class::Object)
859  return dumpMinified();
860 
861  if(Type == Class::Array)
862  return dumpMinified();
863 
864  if(Type == Class::Boolean)
865  return Internal.Bool ? std::string("true") : std::string("false");
866 
867  if(Type == Class::Floating)
868  return std::to_string(Internal.Float);
869 
870  if(Type == Class::Integral)
871  return std::to_string(Internal.Int);
872 
873  if(Type == Class::Null)
874  return std::string("null");
875 
876  ec = error::string_unescaped_conversion_failed;
877  return std::string("");
878  }
879 
886  std::string ToUnescapedString() const {
887  std::error_code ec;
888  std::string ret = ToUnescapedString( ec );
889  if(ec)
890  throw ec;
891  return ret;
892  }
893 
899  double ToFloat( std::error_code &ec ) const noexcept {
900  if (Type == Class::Floating)
901  return Internal.Float;
902 
903  if(Type == Class::Boolean)
904  return Internal.Bool;
905 
906  if (Type == Class::Integral)
907  return Internal.Int;
908 
909  if (Type == Class::String)
910  {
911  double parsed;
912  try {
913  parsed = std::stod(*Internal.String);
914  }
915  catch(const std::invalid_argument &e) {
916  ec = error::float_conversion_failed_invalid_arg;
917  }
918  catch(const std::out_of_range &e) {
919  ec = error::float_conversion_failed_out_of_range;
920  }
921  if(!ec)
922  return parsed;
923  }
924 
925  ec = error::float_conversion_failed;
926  return 0.0;
927  }
928 
933  double ToFloat() const {
934  std::error_code ec;
935  double ret = ToFloat( ec );
936  if(ec)
937  throw ec;
938  return ret;
939  }
940 
946  long long ToInt( std::error_code &ec ) const noexcept {
947  if (Type == Class::Integral)
948  return Internal.Int;
949 
950  if(Type == Class::Boolean)
951  return Internal.Bool;
952 
953  if (Type == Class::Floating)
954  return Internal.Float;
955 
956  if (Type == Class::String)
957  {
958  long long parsed;
959  std::from_chars_result result = std::from_chars(Internal.String->data(), Internal.String->data() + Internal.String->size(), parsed);
960  if(!(bool)result.ec)
961  return parsed;
962  }
963 
964  ec = error::number_conversion_failed;
965  return 0;
966  }
967 
972  long long ToInt() const {
973  std::error_code ec;
974  long long ret = ToInt( ec );
975  if(ec)
976  throw ec;
977  return ret;
978  }
979 
985  bool ToBool( std::error_code &ec ) const noexcept {
986  if(Type == Class::Boolean)
987  return Internal.Bool;
988 
989  if (Type == Class::Integral)
990  return Internal.Int;
991 
992  if (Type == Class::Floating)
993  return Internal.Float;
994 
995  if (Type == Class::String)
996  {
997  if(Internal.String->find("true")!=std::string::npos)
998  return true;
999  if(Internal.String->find("false")!=std::string::npos)
1000  return false;
1001  int parsed;
1002  std::from_chars_result result = std::from_chars(Internal.String->data(), Internal.String->data() + Internal.String->size(), parsed);
1003  if(!(bool)result.ec)
1004  return parsed;
1005  }
1006 
1007  ec = error::bool_conversion_failed;
1008  return false;
1009  }
1010 
1015  bool ToBool() const {
1016  std::error_code ec;
1017  bool ret = ToBool( ec );
1018  if(ec)
1019  throw ec;
1020  return ret;
1021  }
1022 
1028  if( Type == Class::Object )
1029  return JSONWrapper<std::map<std::string,JSON>>( Internal.Map );
1030  return JSONWrapper<std::map<std::string,JSON>>( nullptr );
1031  }
1032 
1038  if( Type == Class::Array )
1039  return JSONWrapper<std::deque<JSON>>( Internal.List );
1040  return JSONWrapper<std::deque<JSON>>( nullptr );
1041  }
1042 
1048  if( Type == Class::Object )
1049  return JSONConstWrapper<std::map<std::string,JSON>>( Internal.Map );
1051  }
1052 
1058  if( Type == Class::Array )
1059  return JSONConstWrapper<std::deque<JSON>>( Internal.List );
1060  return JSONConstWrapper<std::deque<JSON>>( nullptr );
1061  }
1062 
1069  std::string dump( int depth = 1, std::string tab = " ") const {
1070  switch( Type ) {
1071  case Class::Null:
1072  return "null";
1073  case Class::Object: {
1074  std::string pad = "";
1075  for( int i = 0; i < depth; ++i, pad += tab );
1076  std::string s = "{\n";
1077  bool skip = true;
1078  for( auto &p : *Internal.Map ) {
1079  if( !skip ) s += ",\n";
1080  s += ( pad + "\"" + p.first + "\" : " + p.second.dump( depth + 1, tab ) );
1081  skip = false;
1082  }
1083  s += ( "\n" + pad.erase( 0, tab.size() ) + "}" ) ;
1084  return s;
1085  }
1086  case Class::Array: {
1087  std::string s = "[";
1088  bool skip = true;
1089  for( auto &p : *Internal.List ) {
1090  if( !skip ) s += ", ";
1091  s += p.dump( depth + 1, tab );
1092  skip = false;
1093  }
1094  s += "]";
1095  return s;
1096  }
1097  case Class::String:
1098  return "\"" + utility::json_escape( *Internal.String ) + "\"";
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";
1105  default:
1106  return "";
1107  }
1108  return "";
1109  }
1110 
1115  std::string dumpMinified() const {
1116  switch( Type ) {
1117  case Class::Null:
1118  return "null";
1119  case Class::Object: {
1120  std::string s = "{";
1121  bool skip = true;
1122  for( auto &p : *Internal.Map ) {
1123  if( !skip ) s += ",";
1124  s += ("\"" + p.first + "\":" + p.second.dumpMinified() );
1125  skip = false;
1126  }
1127  s += "}";
1128  return s;
1129  }
1130  case Class::Array: {
1131  std::string s = "[";
1132  bool skip = true;
1133  for( auto &p : *Internal.List ) {
1134  if( !skip ) s += ",";
1135  s += p.dumpMinified();
1136  skip = false;
1137  }
1138  s += "]";
1139  return s;
1140  }
1141  case Class::String:
1142  return "\"" + utility::json_escape( *Internal.String ) + "\"";
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";
1149  default:
1150  return "";
1151  }
1152  return "";
1153  }
1154 
1155  friend std::ostream& operator<<( std::ostream&, const JSON & );
1156 
1157  private:
1158  void SetType( Class type ) {
1159  if( type == Type )
1160  return;
1161 
1162  ClearInternal();
1163 
1164  switch( 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;
1172  }
1173  Type = type;
1174  }
1175 
1176  private:
1177  /* beware: only call if YOU know that Internal is allocated. No checks performed here.
1178  This function should be called in a constructed JSON just before you are going to
1179  overwrite Internal...
1180  */
1181  void ClearInternal() {
1182  switch( Type ) {
1183  case Class::Object: delete Internal.Map; break;
1184  case Class::Array: delete Internal.List; break;
1185  case Class::String: delete Internal.String; break;
1186  default:;
1187  }
1188  }
1189 
1190  private:
1191  Class Type = Class::Null;
1192  };
1193 
1194  inline JSON Array() {
1195  return JSON::Make( JSON::Class::Array );
1196  }
1197 
1198  template <typename... T>
1199  JSON Array( T... args ) {
1200  JSON arr = JSON::Make( JSON::Class::Array );
1201  arr.append( args... );
1202  return arr;
1203  }
1204 
1205  inline JSON Object() {
1206  return JSON::Make( JSON::Class::Object );
1207  }
1208 
1209  inline std::ostream& operator<<( std::ostream &os, const JSON &json ) {
1210  os << json.dump();
1211  return os;
1212  }
1213 
1217  namespace parsers {
1218  inline JSON parse_next( const std::string &, size_t &, std::error_code& ) noexcept;
1219 
1220  inline void consume_ws( const std::string &str, size_t &offset ) {
1221  while( isspace( str[offset] ) ) ++offset;
1222  }
1223 
1224  inline JSON parse_object( const std::string &str, size_t &offset, std::error_code &ec ) noexcept {
1225  JSON Object = JSON::Make( JSON::Class::Object );
1226 
1227  ++offset;
1228  consume_ws( str, offset );
1229  if( str[offset] == '}' ) {
1230  ++offset; return Object;
1231  }
1232 
1233  while( true ) {
1234  JSON Key = parse_next( str, offset, ec );
1235  consume_ws( str, offset );
1236  if( str[offset] != ':' ) {
1237  ec = error::object_missing_colon;
1238  break;
1239  }
1240  consume_ws( str, ++offset );
1241  JSON Value = parse_next( str, offset, ec );
1242  Object[Key.ToString()] = Value;
1243 
1244  consume_ws( str, offset );
1245  if( str[offset] == ',' ) {
1246  ++offset; continue;
1247  }
1248  else if( str[offset] == '}' ) {
1249  ++offset; break;
1250  }
1251  else {
1252  ec = error::object_missing_comma;
1253  break;
1254  }
1255  }
1256  return Object;
1257  }
1258 
1259  inline JSON parse_array( const std::string &str, size_t &offset, std::error_code &ec ) noexcept {
1260  JSON Array = JSON::Make( JSON::Class::Array );
1261  unsigned index = 0;
1262 
1263  ++offset;
1264  consume_ws( str, offset );
1265  if( str[offset] == ']' ) {
1266  ++offset; return Array;
1267  }
1268 
1269  while( true ) {
1270  Array[index++] = parse_next( str, offset, ec );
1271  consume_ws( str, offset );
1272 
1273  if( str[offset] == ',' ) {
1274  ++offset; continue;
1275  }
1276  else if( str[offset] == ']' ) {
1277  ++offset; break;
1278  }
1279  else {
1280  ec = error::array_missing_comma_or_bracket;
1281  return JSON::Make( JSON::Class::Array );
1282  }
1283  }
1284  return Array;
1285  }
1286 
1287  inline JSON parse_string( const std::string &str, size_t &offset, std::error_code &ec ) noexcept {
1288  std::string val;
1289  for( char c = str[++offset]; c != '\"' ; c = str[++offset] ) {
1290  if( c == '\\' ) {
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;
1300  case 'u' : {
1301  val += "\\u" ;
1302  for( unsigned i = 1; i <= 4; ++i ) {
1303  c = str[offset+i];
1304  if( (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') )
1305  val += c;
1306  else {
1307  ec = error::string_missing_hex_char;
1308  return JSON::Make( JSON::Class::String );
1309  }
1310  }
1311  offset += 4;
1312  } break;
1313  default : val += '\\'; break;
1314  }
1315  }
1316  else
1317  val += c;
1318  }
1319  ++offset;
1320  return JSON(val);
1321  }
1322 
1323  inline JSON parse_number( const std::string &str, size_t &offset, std::error_code &ec ) noexcept {
1324  JSON Number;
1325  std::string val, exp_str;
1326  char c;
1327  bool isDouble = false;
1328  long long exp = 0;
1329  while( true ) {
1330  c = str[offset++];
1331  if( (c == '-') || (c >= '0' && c <= '9') )
1332  val += c;
1333  else if( c == '.' ) {
1334  val += c;
1335  isDouble = true;
1336  }
1337  else
1338  break;
1339  }
1340  if( c == 'E' || c == 'e' ) {
1341  c = str[ offset ];
1342  if( c == '-' ){ ++offset; exp_str += '-';}
1343  if( c == '+' ){ ++offset;}
1344  while( true ) {
1345  c = str[ offset++ ];
1346  if( c >= '0' && c <= '9' )
1347  exp_str += c;
1348  else if( !isspace( c ) && c != ',' && c != ']' && c != '}' ) {
1349  ec = error::number_missing_exponent;
1350  return JSON::Make( JSON::Class::Null );
1351  }
1352  else
1353  break;
1354  }
1355  exp = std::stol( exp_str );
1356  }
1357  else if( !isspace( c ) && c != ',' && c != ']' && c != '}' ) {
1358  ec = error::number_unexpected_char;
1359  return JSON::Make( JSON::Class::Null );
1360  }
1361  --offset;
1362 
1363  if( isDouble )
1364  Number = std::stod( val ) * std::pow( 10, exp );
1365  else {
1366  if( !exp_str.empty() )
1367  Number = std::stol( val ) * std::pow( 10, exp );
1368  else
1369  Number = std::stol( val );
1370  }
1371  return Number;
1372  }
1373 
1374  inline JSON parse_bool( const std::string &str, size_t &offset, std::error_code &ec ) noexcept {
1375  JSON Bool;
1376  if( str.substr( offset, 4 ) == "true" )
1377  Bool = true;
1378  else if( str.substr( offset, 5 ) == "false" )
1379  Bool = false;
1380  else {
1381  ec = error::bool_wrong_text;
1382  return JSON::Make( JSON::Class::Null );
1383  }
1384  offset += (Bool.ToBool() ? 4 : 5);
1385  return Bool;
1386  }
1387 
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;
1391  return JSON::Make( JSON::Class::Null );
1392  }
1393  offset += 4;
1394  return JSON();
1395  }
1396 
1397  inline JSON parse_next( const std::string &str, size_t &offset, std::error_code &ec ) noexcept {
1398  char value;
1399  consume_ws( str, offset );
1400  value = str[offset];
1401  switch( value ) {
1402  case '[' : return parse_array( str, offset, ec );
1403  case '{' : return parse_object( str, offset, ec );
1404  case '\"': return parse_string( str, offset, ec );
1405  case 't' :
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 );
1410  }
1411  ec = error::unknown_starting_char;
1412  return JSON();
1413  }
1414  }
1415 
1416  inline JSON JSON::Load( const std::string &str, std::error_code &ec ) noexcept {
1417  size_t offset = 0;
1418  return parsers::parse_next( str, offset, ec );
1419  }
1420 
1421  inline JSON JSON::Load( const std::string &str ) {
1422  size_t offset = 0;
1423  std::error_code ec;
1424  JSON obj = parsers::parse_next( str, offset, ec );
1425  if(ec)
1426  throw ec;
1427  return obj;
1428  }
1429  } // End Namespace json
1430 }
1431 #endif //SUPPORTLIB_JSON_H
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
Definition: JSON.h:123
Error category object used to convert the error code to a understandable message via std::error_code.
Definition: JSON.h:75