GameApi 28
Library used by GameApi Builder tool
Loading...
Searching...
No Matches
json.hpp
Go to the documentation of this file.
1// From github.com/nbsdx/SimpleJSON.
2// Released under the DWTFYW PL
3//
4
5
6#pragma once
7
8#ifndef SIMPLEJSON_HPP
9#define SIMPLEJSON_HPP
10
11
12#include <cstdint>
13#include <cmath>
14#include <cctype>
15#include <string>
16#include <vector>
17#include <map>
18#include <type_traits>
19#include <initializer_list>
20#include <ostream>
21#include <iostream>
23
24namespace json {
25
26using std::enable_if;
27using std::initializer_list;
28using std::is_same;
29using std::is_convertible;
30using std::is_integral;
31using std::is_floating_point;
32
33
34
35
36class JSON
37{
38 public:
48
49 private:
50
51 struct QuickFlatMap
52 {
53 auto find(const std::string &s) {
54 return std::find_if(std::begin(data), std::end(data), [&s](const auto &d) { return d.first == s; });
55 }
56
57 auto find(const std::string &s) const {
58 return std::find_if(std::begin(data), std::end(data), [&s](const auto &d) { return d.first == s; });
59 }
60
61 auto size() const {
62 return data.size();
63 }
64
65 auto begin() const {
66 return data.begin();
67 }
68
69 auto end() const {
70 return data.end();
71 }
72
73
74 auto begin() {
75 return data.begin();
76 }
77
78 auto end() {
79 return data.end();
80 }
81
82
83 JSON &operator[](const std::string &s) {
84 const auto itr = find(s);
85 if (itr != data.end()) {
86 return itr->second;
87 } else {
88 data.emplace_back(s, JSON());
89 return data.back().second;
90 }
91 }
92
93 JSON &at(const std::string &s) {
94 const auto itr = find(s);
95 if (itr != data.end()) {
96 return itr->second;
97 } else {
98 throw std::out_of_range("Unknown key: " + s);
99 }
100 }
101
102 const JSON &at(const std::string &s) const {
103 const auto itr = find(s);
104 if (itr != data.end()) {
105 return itr->second;
106 } else {
107 throw std::out_of_range("Unknown key: " + s);
108 }
109 }
110
111 size_t count(const std::string &s) const {
112 return (find(s) != data.end())?1:0;
113 }
114
115 std::vector<std::pair<std::string, JSON>> data;
116
117 using iterator = decltype(data)::iterator;
118 using const_iterator = decltype(data)::const_iterator;
119
120
121 };
122
123 struct Internal {
124 template<typename T>
125 auto clone(const std::unique_ptr<T> &ptr) {
126 if (ptr != nullptr) {
127 return std::make_unique<T>(*ptr);
128 } else {
129 return std::unique_ptr<T>(nullptr);
130 }
131 }
132
133 Internal( double d ) : Float( d ), Type(Class::Floating) {}
134 Internal( int64_t l ) : Int( l ), Type(Class::Integral) {}
135 Internal( bool b ) : Bool( b ), Type(Class::Boolean) {}
136 Internal( std::string s ) : String(std::make_unique<std::string>(std::move(s))), Type(Class::String) {}
137 Internal() : Type(Class::Null) {}
138
139 Internal(Class t_type) {
140 set_type(t_type);
141 }
142
143 Internal(const Internal &other)
144 : List(clone(other.List)),
145 Map(clone(other.Map)),
146 String(clone(other.String)),
147 Float(other.Float),
148 Int(other.Int),
149 Bool(other.Bool),
150 Type(other.Type)
151 {
152 }
153
154 Internal &operator=(const Internal &other)
155 {
156 List = clone(other.List);
157 Map = clone(other.Map);
158 String = clone(other.String);
159 Float = other.Float;
160 Int = other.Int;
161 Bool = other.Bool;
162 Type = other.Type;
163 return *this;
164 }
165
166 void set_type( Class type ) {
167 if( type == Type ) {
168 return;
169 }
170
171 Map.reset();
172 List.reset();
173 String.reset();
174
175 switch( type ) {
176 case Class::Object: Map = std::make_unique<QuickFlatMap>(); break;
177 case Class::Array: List = std::make_unique<std::vector<JSON>>(); break;
178 case Class::String: String = std::make_unique<std::string>(); break;
179 case Class::Floating: Float = 0.0; break;
180 case Class::Integral: Int = 0; break;
181 case Class::Boolean: Bool = false; break;
182 case Class::Null: break;
183 }
184
185 Type = type;
186 }
187
188 Internal(Internal &&) = default;
189 Internal &operator=(Internal &&) = default;
190
191 std::unique_ptr<std::vector<JSON>> List;
192 std::unique_ptr<QuickFlatMap> Map;
193 std::unique_ptr<std::string> String;
194 double Float = 0;
195 int64_t Int = 0;
196 bool Bool = false;
197
198 Class Type = Class::Null;
199 };
200
201 Internal internal;
202
203 public:
204
205 template <typename Container>
207 Container *object = nullptr;
208
209 public:
210 JSONWrapper( Container *val ) : object( val ) {}
211 JSONWrapper( std::nullptr_t ) {}
212
213 typename Container::iterator begin() { return object ? object->begin() : typename Container::iterator(); }
214 typename Container::iterator end() { return object ? object->end() : typename Container::iterator(); }
215 typename Container::const_iterator begin() const { return object ? object->begin() : typename Container::iterator(); }
216 typename Container::const_iterator end() const { return object ? object->end() : typename Container::iterator(); }
217 };
218
219 template <typename Container>
221 const Container *object = nullptr;
222
223 public:
224 JSONConstWrapper( const Container *val ) : object( val ) {}
225 JSONConstWrapper( std::nullptr_t ) {}
226
227 typename Container::const_iterator begin() const { return object ? object->begin() : typename Container::const_iterator(); }
228 typename Container::const_iterator end() const { return object ? object->end() : typename Container::const_iterator(); }
229 };
230
231 JSON() = default;
232 JSON( std::nullptr_t ) {}
233
234 explicit JSON(Class type)
235 : internal(type)
236 {
237 }
238
239 JSON( initializer_list<JSON> list )
240 : internal(Class::Object)
241 {
242 for( auto i = list.begin(), e = list.end(); i != e; ++i, ++i ) {
243 operator[]( i->to_string() ) = *std::next( i );
244 }
245 }
246
247 template <typename T>
248 explicit JSON( T b, typename enable_if<is_same<T,bool>::value>::type* = nullptr ) : internal( static_cast<bool>(b) ) {}
249
250 template <typename T>
251 explicit JSON( T i, typename enable_if<is_integral<T>::value && !is_same<T,bool>::value>::type* = nullptr ) : internal( static_cast<int64_t>(i) ) {}
252
253 template <typename T>
254 explicit JSON( T f, typename enable_if<is_floating_point<T>::value>::type* = nullptr ) : internal( static_cast<double>(f) ) {}
255
256 template <typename T>
257 explicit JSON( T s, typename enable_if<is_convertible<T,std::string>::value>::type* = nullptr ) : internal( static_cast<std::string>(s) ) {}
258
259
260
261 static JSON Load( const std::string & );
262
263 JSON& operator[]( const std::string &key ) {
264 internal.set_type( Class::Object );
265 return internal.Map->operator[]( key );
266 }
267
268 JSON& operator[]( const size_t index ) {
269 internal.set_type( Class::Array );
270 if( index >= internal.List->size() ) {
271 internal.List->resize( index + 1 );
272 }
273
274 return internal.List->operator[]( index );
275 }
276
277
278 JSON &at( const std::string &key ) {
279 return operator[]( key );
280 }
281
282 const JSON &at( const std::string &key ) const {
283 return internal.Map->at( key );
284 }
285
286 JSON &at( size_t index ) {
287 return operator[]( index );
288 }
289
290 const JSON &at( size_t index ) const {
291 return internal.List->at( index );
292 }
293
294
295 long length() const {
296 if( internal.Type == Class::Array ) {
297 return static_cast<long>(internal.List->size());
298 } else {
299 return -1;
300 }
301 }
302
303 bool has_key( const std::string &key ) const {
304 if( internal.Type == Class::Object ) {
305 return internal.Map->count(key) != 0;
306 }
307
308 return false;
309 }
310
311 int size() const {
312 if( internal.Type == Class::Object ) {
313 return static_cast<int>(internal.Map->size());
314 } else if( internal.Type == Class::Array ) {
315 return static_cast<int>(internal.List->size());
316 } else {
317 return -1;
318 }
319 }
320
321 Class JSONType() const { return internal.Type; }
322
324 bool is_null() const { return internal.Type == Class::Null; }
325
326 std::string to_string() const { bool b; return to_string( b ); }
327 std::string to_string( bool &ok ) const {
328 ok = (internal.Type == Class::String);
329 return ok ? *internal.String : std::string("");
330 }
331
332 double to_float() const { bool b; return to_float( b ); }
333 double to_float( bool &ok ) const {
334 ok = (internal.Type == Class::Floating);
335 return ok ? internal.Float : 0.0;
336 }
337
338 int64_t to_int() const { bool b; return to_int( b ); }
339 int64_t to_int( bool &ok ) const {
340 ok = (internal.Type == Class::Integral);
341 return ok ? internal.Int : 0;
342 }
343
344 bool to_bool() const { bool b; return to_bool( b ); }
345 bool to_bool( bool &ok ) const {
346 ok = (internal.Type == Class::Boolean);
347 return ok ? internal.Bool : false;
348 }
349
351 if( internal.Type == Class::Object ) {
352 return JSONWrapper<QuickFlatMap>( internal.Map.get() );
353 } else {
354 return JSONWrapper<QuickFlatMap>( nullptr );
355 }
356 }
357
359 if( internal.Type == Class::Array ) {
360 return JSONWrapper<std::vector<JSON>>( internal.List.get() );
361 } else {
362 return JSONWrapper<std::vector<JSON>>( nullptr );
363 }
364 }
365
367 if( internal.Type == Class::Object ) {
368 return JSONConstWrapper<QuickFlatMap>( internal.Map.get() );
369 } else {
370 return JSONConstWrapper<QuickFlatMap>( nullptr );
371 }
372 }
373
374
376 if( internal.Type == Class::Array ) {
377 return JSONConstWrapper<std::vector<JSON>>( internal.List.get() );
378 } else {
379 return JSONConstWrapper<std::vector<JSON>>( nullptr );
380 }
381 }
382
383 std::string dump( long depth = 1, std::string tab = " ") const {
384 switch( internal.Type ) {
385 case Class::Null:
386 return "null";
387 case Class::Object: {
388 std::string pad = "";
389 for( long i = 0; i < depth; ++i, pad += tab ) { }
390
391 std::string s = "{\n";
392 bool skip = true;
393 for( auto &p : *internal.Map ) {
394 if( !skip ) { s += ",\n"; }
395 s += ( pad + "\"" + json_escape(p.first) + "\" : " + p.second.dump( depth + 1, tab ) );
396 skip = false;
397 }
398 s += ( "\n" + pad.erase( 0, 2 ) + "}" ) ;
399 return s;
400 }
401 case Class::Array: {
402 std::string s = "[";
403 bool skip = true;
404 for( auto &p : *internal.List ) {
405 if( !skip ) { s += ", "; }
406 s += p.dump( depth + 1, tab );
407 skip = false;
408 }
409 s += "]";
410 return s;
411 }
412 case Class::String:
413 return "\"" + json_escape( *internal.String ) + "\"";
414 case Class::Floating:
415 return std::to_string( internal.Float );
416 case Class::Integral:
417 return std::to_string( internal.Int );
418 case Class::Boolean:
419 return internal.Bool ? "true" : "false";
420 }
421
422 throw std::runtime_error("Unhandled JSON type");
423 }
424
425
426 private:
427 static std::string json_escape( const std::string &str ) {
428 std::string output;
429 for(char i : str) {
430 switch( i ) {
431 case '\"': output += "\\\""; break;
432 case '\\': output += "\\\\"; break;
433 case '\b': output += "\\b"; break;
434 case '\f': output += "\\f"; break;
435 case '\n': output += "\\n"; break;
436 case '\r': output += "\\r"; break;
437 case '\t': output += "\\t"; break;
438 default : output += i; break;
439 }
440}
441 return output;
442 }
443
444
445 private:
446};
447
448
450 static bool isspace(const char c)
451 {
452#ifdef CHAISCRIPT_MSVC
453 // MSVC warns on these line in some circumstances
454#pragma warning(push)
455#pragma warning(disable : 6330)
456#endif
457 return ::isspace(c) != 0;
458#ifdef CHAISCRIPT_MSVC
459#pragma warning(pop)
460#endif
461
462
463 }
464
465 static void consume_ws( const std::string &str, size_t &offset ) {
466 while( isspace( str.at(offset) ) && offset <= str.size() ) { ++offset; }
467 }
468
469 static JSON parse_object( const std::string &str, size_t &offset ) {
470 JSON Object( JSON::Class::Object );
471
472 ++offset;
473 consume_ws( str, offset );
474 if( str.at(offset) == '}' ) {
475 ++offset; return Object;
476 }
477
478 for (;offset<str.size();) {
479 JSON Key = parse_next( str, offset );
480 consume_ws( str, offset );
481 if( str.at(offset) != ':' ) {
482 throw std::runtime_error(std::string("JSON ERROR: Object: Expected colon, found '") + str.at(offset) + "'\n");
483 }
484 consume_ws( str, ++offset );
485 JSON Value = parse_next( str, offset );
486 Object[Key.to_string()] = Value;
487
488 consume_ws( str, offset );
489 if( str.at(offset) == ',' ) {
490 ++offset; continue;
491 }
492 else if( str.at(offset) == '}' ) {
493 ++offset; break;
494 }
495 else {
496 throw std::runtime_error(std::string("JSON ERROR: Object: Expected comma, found '") + str.at(offset) + "'\n");
497 }
498 }
499
500 return Object;
501 }
502
503 static JSON parse_array( const std::string &str, size_t &offset ) {
505 size_t index = 0;
506
507 ++offset;
508 consume_ws( str, offset );
509 if( str.at(offset) == ']' ) {
510 ++offset; return Array;
511 }
512
513 for (;offset < str.size();) {
514 Array[index++] = parse_next( str, offset );
515 consume_ws( str, offset );
516
517 if( str.at(offset) == ',' ) {
518 ++offset; continue;
519 }
520 else if( str.at(offset) == ']' ) {
521 ++offset; break;
522 }
523 else {
524 throw std::runtime_error(std::string("JSON ERROR: Array: Expected ',' or ']', found '") + str.at(offset) + "'\n");
525 }
526 }
527
528 return Array;
529 }
530
531 static JSON parse_string( const std::string &str, size_t &offset ) {
532 std::string val;
533 for( char c = str.at(++offset); c != '\"' ; c = str.at(++offset) ) {
534 if( c == '\\' ) {
535 switch( str.at(++offset) ) {
536 case '\"': val += '\"'; break;
537 case '\\': val += '\\'; break;
538 case '/' : val += '/' ; break;
539 case 'b' : val += '\b'; break;
540 case 'f' : val += '\f'; break;
541 case 'n' : val += '\n'; break;
542 case 'r' : val += '\r'; break;
543 case 't' : val += '\t'; break;
544 case 'u' : {
545 val += "\\u" ;
546 for( size_t i = 1; i <= 4; ++i ) {
547 c = str.at(offset+i);
548 if( (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') ) {
549 val += c;
550 } else {
551 throw std::runtime_error(std::string("JSON ERROR: String: Expected hex character in unicode escape, found '") + c + "'");
552 }
553 }
554 offset += 4;
555 } break;
556 default : val += '\\'; break;
557 }
558 } else {
559 val += c;
560 }
561 }
562 ++offset;
563 return JSON(val);
564 }
565
566 static JSON parse_number( const std::string &str, size_t &offset ) {
567 std::string val, exp_str;
568 char c = '\0';
569 bool isDouble = false;
570 bool isNegative = false;
571 int64_t exp = 0;
572 bool isExpNegative = false;
573 if( offset < str.size() && str.at(offset) == '-' ) {
574 isNegative = true;
575 ++offset;
576 }
577 for (; offset < str.size() ;) {
578 c = str.at(offset++);
579 if( c >= '0' && c <= '9' ) {
580 val += c;
581 } else if( c == '.' && !isDouble ) {
582 val += c;
583 isDouble = true;
584 } else {
585 break;
586 }
587 }
588 if( offset < str.size() && (c == 'E' || c == 'e' )) {
589 c = str.at(offset++);
590 if( c == '-' ) {
591 isExpNegative = true;
592 } else if( c == '+' ) {
593 // do nothing
594 } else {
595 --offset;
596 }
597
598 for (; offset < str.size() ;) {
599 c = str.at(offset++);
600 if( c >= '0' && c <= '9' ) {
601 exp_str += c;
602 } else if( !isspace( c ) && c != ',' && c != ']' && c != '}' ) {
603 throw std::runtime_error(std::string("JSON ERROR: Number: Expected a number for exponent, found '") + c + "'");
604 }
605 else {
606 break;
607 }
608 }
609 exp = chaiscript::parse_num<int64_t>( exp_str ) * (isExpNegative?-1:1);
610 }
611 else if( offset < str.size() && (!isspace( c ) && c != ',' && c != ']' && c != '}' )) {
612 throw std::runtime_error(std::string("JSON ERROR: Number: unexpected character '") + c + "'");
613 }
614 --offset;
615
616 if( isDouble ) {
617 return JSON((isNegative?-1:1) * chaiscript::parse_num<double>( val ) * std::pow( 10, exp ));
618 } else {
619 if( !exp_str.empty() ) {
620 return JSON((isNegative?-1:1) * static_cast<double>(chaiscript::parse_num<int64_t>( val )) * std::pow( 10, exp ));
621 } else {
622 return JSON((isNegative?-1:1) * chaiscript::parse_num<int64_t>( val ));
623 }
624 }
625 }
626
627 static JSON parse_bool( const std::string &str, size_t &offset ) {
628 if( str.substr( offset, 4 ) == "true" ) {
629 offset += 4;
630 return JSON(true);
631 } else if( str.substr( offset, 5 ) == "false" ) {
632 offset += 5;
633 return JSON(false);
634 } else {
635 throw std::runtime_error(std::string("JSON ERROR: Bool: Expected 'true' or 'false', found '") + str.substr( offset, 5 ) + "'");
636 }
637 }
638
639 static JSON parse_null( const std::string &str, size_t &offset ) {
640 if( str.substr( offset, 4 ) != "null" ) {
641 throw std::runtime_error(std::string("JSON ERROR: Null: Expected 'null', found '") + str.substr( offset, 4 ) + "'");
642 }
643 offset += 4;
644 return JSON();
645 }
646
647 static JSON parse_next( const std::string &str, size_t &offset ) {
648 char value;
649 consume_ws( str, offset );
650 value = str.at(offset);
651 switch( value ) {
652 case '[' : return parse_array( str, offset );
653 case '{' : return parse_object( str, offset );
654 case '\"': return parse_string( str, offset );
655 case 't' :
656 case 'f' : return parse_bool( str, offset );
657 case 'n' : return parse_null( str, offset );
658 default : if( ( value <= '9' && value >= '0' ) || value == '-' ) {
659 return parse_number( str, offset );
660 }
661 }
662 throw std::runtime_error(std::string("JSON ERROR: Parse: Unexpected starting character '") + value + "'");
663 }
664
665};
666
667inline JSON JSON::Load( const std::string &str ) {
668 size_t offset = 0;
669 return JSONParser::parse_next( str, offset );
670}
671
672} // End Namespace json
673
674
675#endif
Env e
Definition Common.cc:2
Complex exp(Complex z, int n)
Definition GameApi_pl.cc:31416
SM String(std::string s)
Definition Language.hh:977
void * find(int i)
Definition ui.cc:347
Definition EffectI.hh:22
Definition Containment.hh:34
Definition Expression.hh:105
Definition json.hpp:220
JSONConstWrapper(std::nullptr_t)
Definition json.hpp:225
Container::const_iterator begin() const
Definition json.hpp:227
Container::const_iterator end() const
Definition json.hpp:228
JSONConstWrapper(const Container *val)
Definition json.hpp:224
Definition json.hpp:206
JSONWrapper(std::nullptr_t)
Definition json.hpp:211
Container::const_iterator begin() const
Definition json.hpp:215
Container::const_iterator end() const
Definition json.hpp:216
Container::iterator begin()
Definition json.hpp:213
JSONWrapper(Container *val)
Definition json.hpp:210
Container::iterator end()
Definition json.hpp:214
Definition json.hpp:37
bool has_key(const std::string &key) const
Definition json.hpp:303
std::string to_string(bool &ok) const
Definition json.hpp:327
std::string to_string() const
Definition json.hpp:326
double to_float() const
Definition json.hpp:332
bool is_null() const
Functions for getting primitives from the JSON object.
Definition json.hpp:324
JSON & at(size_t index)
Definition json.hpp:286
Class JSONType() const
Definition json.hpp:321
JSONWrapper< QuickFlatMap > object_range()
Definition json.hpp:350
JSON(Class type)
Definition json.hpp:234
JSONConstWrapper< QuickFlatMap > object_range() const
Definition json.hpp:366
JSONConstWrapper< std::vector< JSON > > array_range() const
Definition json.hpp:375
JSON(T i, typename enable_if< is_integral< T >::value &&!is_same< T, bool >::value >::type *=nullptr)
Definition json.hpp:251
std::string dump(long depth=1, std::string tab=" ") const
Definition json.hpp:383
JSON & operator[](const std::string &key)
Definition json.hpp:263
bool to_bool(bool &ok) const
Definition json.hpp:345
JSON(T s, typename enable_if< is_convertible< T, std::string >::value >::type *=nullptr)
Definition json.hpp:257
static JSON Load(const std::string &)
Definition json.hpp:667
long length() const
Definition json.hpp:295
Class
Definition json.hpp:39
@ String
Definition json.hpp:43
@ Boolean
Definition json.hpp:46
@ Array
Definition json.hpp:42
@ Object
Definition json.hpp:41
@ Integral
Definition json.hpp:45
@ Null
Definition json.hpp:40
@ Floating
Definition json.hpp:44
JSON(T b, typename enable_if< is_same< T, bool >::value >::type *=nullptr)
Definition json.hpp:248
JSON()=default
const JSON & at(const std::string &key) const
Definition json.hpp:282
JSON & operator[](const size_t index)
Definition json.hpp:268
double to_float(bool &ok) const
Definition json.hpp:333
JSON(T f, typename enable_if< is_floating_point< T >::value >::type *=nullptr)
Definition json.hpp:254
JSON(std::nullptr_t)
Definition json.hpp:232
int64_t to_int(bool &ok) const
Definition json.hpp:339
const JSON & at(size_t index) const
Definition json.hpp:290
JSON & at(const std::string &key)
Definition json.hpp:278
bool to_bool() const
Definition json.hpp:344
JSON(initializer_list< JSON > list)
Definition json.hpp:239
JSONWrapper< std::vector< JSON > > array_range()
Definition json.hpp:358
int64_t to_int() const
Definition json.hpp:338
int size() const
Definition json.hpp:311
d
Definition meshpage.php:3895
lazy data
Definition meshpage.php:1583
str
Definition meshpage.php:1778
std::unique_ptr< B > make_unique(Arg &&... arg)
Definition chaiscript_defines.hpp:97
auto parse_num(const char *t_str) -> typename std::enable_if< std::is_integral< T >::value, T >::type
Definition chaiscript_defines.hpp:155
Definition json.hpp:24
@ string
string value
Definition json.hpp:1223
STL namespace.
double f(const std::string &, double, bool) noexcept
Definition profile_cpp_calls_2.cpp:4
Definition GameApi.h:42
Definition json.hpp:449
static JSON parse_null(const std::string &str, size_t &offset)
Definition json.hpp:639
static JSON parse_next(const std::string &str, size_t &offset)
Definition json.hpp:647
static JSON parse_array(const std::string &str, size_t &offset)
Definition json.hpp:503
static JSON parse_number(const std::string &str, size_t &offset)
Definition json.hpp:566
static JSON parse_bool(const std::string &str, size_t &offset)
Definition json.hpp:627
static JSON parse_string(const std::string &str, size_t &offset)
Definition json.hpp:531
static bool isspace(const char c)
Definition json.hpp:450
static void consume_ws(const std::string &str, size_t &offset)
Definition json.hpp:465
static JSON parse_object(const std::string &str, size_t &offset)
Definition json.hpp:469