69 Data(
double d) : float_(d) {}
70 Data(
long l) : integer_(l) {}
71 Data(
bool b) : boolean_(b) {}
72 Data(
const std::string& s) : string_(
new std::string(s)) {}
73 Data() : integer_(0) {}
75 std::deque<JSON>* list_;
76 std::map<std::string, JSON>* map_;
94 template <
typename Container>
class JSONWrapper {
100 JSONWrapper(Container* val) : object(val) {}
101 JSONWrapper(std::nullptr_t) : object(
nullptr) {}
103 typename Container::iterator begin() {
104 return object ?
object->begin() :
typename Container::iterator();
106 typename Container::iterator end() {
107 return object ?
object->end() :
typename Container::iterator();
109 typename Container::const_iterator begin()
const {
110 return object ?
object->begin() :
typename Container::iterator();
112 typename Container::const_iterator end()
const {
113 return object ?
object->end() :
typename Container::iterator();
117 template <
typename Container>
118 class JSONConstWrapper {
121 const Container* object;
124 JSONConstWrapper(
const Container* val) : object(val) {}
125 JSONConstWrapper(std::nullptr_t) : object(
nullptr) {}
127 typename Container::const_iterator begin()
const
128 {
return object ?
object->begin()
129 :
typename Container::const_iterator(); }
130 typename Container::const_iterator end()
const
131 {
return object ?
object->end()
132 :
typename Container::const_iterator(); }
135 JSON() : data_(), type_(DataType::Null) {}
137 JSON(std::initializer_list<JSON> list) :
JSON()
139 set_type(DataType::Object);
140 for(
auto i = list.begin(), e = list.end(); i != e; ++i, ++i)
141 operator[](i->to_string()) = *std::next(i);
144 JSON(JSON&& other) : data_(other.data_), type_(other.type_)
145 { other.type_ = DataType::Null; other.data_.map_ =
nullptr; }
147 JSON& operator=(JSON&& other) {
150 other.data_.map_ =
nullptr;
151 other.type_ = DataType::Null;
155 JSON(
const JSON& other) {
156 switch(other.type_) {
157 case DataType::Object:
158 data_.map_ =
new std::map<std::string,JSON>(
159 other.data_.map_->begin(), other.data_.map_->end());
161 case DataType::Array:
162 data_.list_ =
new std::deque<JSON>(other.data_.list_->begin(),
163 other.data_.list_->end());
165 case DataType::String:
166 data_.string_ =
new std::string(*other.data_.string_);
174 JSON& operator=(
const JSON& other) {
175 switch(other.type_) {
176 case DataType::Object:
177 data_.map_ =
new std::map<std::string,JSON>(
178 other.data_.map_->begin(), other.data_.map_->end());
180 case DataType::Array:
181 data_.list_ =
new std::deque<JSON>( other.data_.list_->begin(),
182 other.data_.list_->end());
184 case DataType::String:
185 data_.string_ =
new std::string(*other.data_.string_);
196 case DataType::Array:
199 case DataType::Object:
202 case DataType::String:
203 delete data_.string_;
209 template <
typename T> JSON(T b,
210 typename std::enable_if<std::is_same<T,bool>::value>::type* = 0)
211 : data_(b), type_(DataType::Boolean) {}
213 template <
typename T> JSON(T i,
214 typename std::enable_if<std::is_integral<T>::value
215 && !std::is_same<T,bool>::value>::type* = 0)
216 : data_(static_cast<long>(i)), type_(DataType::Integral) {}
218 template <
typename T> JSON(T f,
219 typename std::enable_if<std::is_floating_point<T>::value>::type* = 0)
220 : data_(static_cast<double>(f)), type_(DataType::Floating) {}
222 explicit JSON(
const std::string& s)
223 : data_(s), type_(DataType::String) {}
230 JSON(std::nullptr_t) : data_(), type_(DataType::Null) {}
232 static inline JSON make(DataType type) {
238 static inline JSON array() {
239 return JSON::make(JSON::DataType::Array);
242 template <
typename... T>
243 static JSON array( T... args )
245 JSON arr = JSON::make(JSON::DataType::Array);
250 static inline JSON object() {
251 return JSON::make(JSON::DataType::Object);
254 static inline JSON load(
const std::string& s);
255 static inline JSON load(std::istream& is);
256 static inline JSON load(StreamReader& reader);
257 static inline JSON load_file(
const std::string& s);
259 template <
typename T>
void append(T arg) {
260 set_type(DataType::Array);
261 data_.list_->emplace_back(arg);
264 template <
typename T,
typename... U>
void append(T arg, U... args) {
265 append(arg); append(args...);
268 template <
typename T>
269 typename std::enable_if<std::is_same<T,bool>::value, JSON&>::type
272 set_type(DataType::Boolean);
277 template <
typename T>
typename std::enable_if<std::is_integral<T>::value
278 && !std::is_same<T,bool>::value, JSON&>::type operator=(T i)
280 set_type( DataType::Integral );
285 template <
typename T>
286 typename std::enable_if<std::is_floating_point<T>::value, JSON&>::type
289 set_type(DataType::Floating);
294 template <
typename T>
typename std::enable_if<std::is_convertible<T,
295 std::string>::value, JSON&>::type operator=(T s)
297 set_type(DataType::String);
298 *data_.string_ = std::string(s);
302 JSON& operator[](
const std::string& key) {
303 set_type(DataType::Object);
304 return data_.map_->operator[](key);
307 JSON& operator[](
unsigned index) {
308 set_type(DataType::Array);
309 if (index >= data_.list_->size()) data_.list_->resize(index + 1);
310 return data_.list_->operator[](index);
313 JSON& at(
const std::string& key) {
314 return operator[](key);
317 const JSON& at(
const std::string &key)
const {
318 return data_.map_->at(key);
321 JSON& at(
unsigned index) {
322 return operator[](index);
325 const JSON& at(
unsigned index)
const {
326 return data_.list_->at(index);
330 if (type_ == DataType::Array)
return data_.list_->size();
334 bool has_key(
const std::string& key)
const {
335 if (type_ == DataType::Object)
336 return data_.map_->find( key ) != data_.map_->end();
341 if (type_ == DataType::Object)
342 return data_.map_->size();
343 else if (type_ == DataType::Array)
344 return data_.list_->size();
349 inline DataType type()
const {
return type_; }
352 inline bool is_null()
const {
return type_ == DataType::Null; }
353 inline bool is_object()
const {
return type_ == DataType::Object; }
354 inline bool is_array()
const {
return type_ == DataType::Array; }
355 inline bool is_string()
const {
return type_ == DataType::String; }
356 inline bool is_float()
const {
return type_ == DataType::Floating; }
357 inline bool is_integer()
const {
return type_ == DataType::Integral; }
358 inline bool is_bool()
const {
return type_ == DataType::Boolean; }
360 std::string to_string()
const {
365 std::string to_string(
bool& ok)
const {
366 ok = (type_ == DataType::String);
367 return ok ? json_escape(*data_.string_) : std::string(
"");
370 std::string to_string_or_throw()
const {
372 std::string result = to_string(ok);
373 if (!ok)
throw marley::Error(
"Failed to convert JSON value to string");
377 double to_double()
const {
382 double to_double(
bool& ok)
const {
383 ok = (type_ == DataType::Floating);
384 if (ok)
return data_.float_;
385 ok = (type_ == DataType::Integral);
386 if (ok)
return data_.integer_;
390 double to_double_or_throw()
const {
392 double result = to_double(ok);
393 if (!ok)
throw marley::Error(
"Failed to convert JSON value '"
394 + to_string() +
"' to double");
398 long to_long()
const {
403 long to_long(
bool& ok)
const {
404 ok = (type_ == DataType::Integral);
405 return ok ? data_.integer_ : 0;
408 long to_long_or_throw()
const {
410 double result = to_long(ok);
411 if (!ok)
throw marley::Error(
"Failed to convert JSON value '"
412 + to_string() +
"' to long");
416 bool to_bool()
const {
421 bool to_bool(
bool& ok)
const {
422 ok = (type_ == DataType::Boolean);
423 return ok ? data_.boolean_ :
false;
426 bool to_bool_or_throw()
const {
428 double result = to_bool(ok);
429 if (!ok)
throw marley::Error(
"Failed to convert JSON value '"
430 + to_string() +
"' to bool");
435 if (type_ == DataType::Object)
441 if (type_ == DataType::Array)
447 if (type_ == DataType::Object)
454 if ( type_ == DataType::Array )
462 std::string dump_string(
const int indent_step = -1)
const {
463 std::stringstream out;
466 if (indent_step >= 0)
467 print(out,
static_cast<unsigned int>(indent_step),
true);
469 else print(out, 0,
false);
477 void print(std::ostream& out,
const unsigned int indent_step,
478 bool pretty,
const unsigned int current_indent = 0)
const
484 static std::ostringstream out_float;
485 static bool set_precision =
false;
486 if (!set_precision) {
487 out_float.precision(std::numeric_limits<double>::max_digits10);
488 set_precision =
true;
491 unsigned int indent = current_indent;
497 case DataType::Object: {
500 indent += indent_step;
504 for(
auto &p : *data_.map_ ) {
507 if (pretty) out <<
'\n';
510 out << std::string(indent,
' ') <<
'\"'
511 << json_escape( p.first ) <<
'\"';
513 if (pretty) out <<
" : ";
516 p.second.print( out, indent_step, pretty, indent );
520 indent -= indent_step;
523 out << std::string(indent,
' ') +
'}';
526 case DataType::Array: {
529 indent += indent_step;
533 for(
auto &p : *data_.list_ ) {
536 if (pretty) out <<
'\n';
538 out << std::string(indent,
' ');
539 p.print( out, indent_step, pretty, indent );
543 indent -= indent_step;
546 out << std::string(indent,
' ') <<
']';
549 case DataType::String:
550 out <<
'\"' + json_escape( *data_.string_ ) +
'\"';
552 case DataType::Floating:
557 out_float << data_.float_;
559 out << out_float.str();
561 case DataType::Integral:
562 out << data_.integer_;
564 case DataType::Boolean:
565 out << (data_.boolean_ ?
"true" :
"false");
574 void check_if_object(
const std::string& key )
const {
575 if ( type_ != DataType::Object )
throw marley::Error(
"Attempted"
576 " to retrieve a value for the key '" + key +
"' from a JSON"
577 " primitive that is not an object" );
582 void set_type( DataType type ) {
583 if ( type == type_ )
return;
586 case DataType::Object:
589 case DataType::Array:
592 case DataType::String:
593 delete data_.string_;
600 data_.map_ =
nullptr;
602 case DataType::Object:
603 data_.map_ =
new std::map< std::string, JSON >();
605 case DataType::Array:
606 data_.list_ =
new std::deque< JSON >();
608 case DataType::String:
609 data_.string_ =
new std::string();
611 case DataType::Floating:
614 case DataType::Integral:
617 case DataType::Boolean:
618 data_.boolean_ =
false;
629 double get_double(
const std::string& key )
const {
630 check_if_object( key );
631 if ( has_key(key) )
return this->at( key ).to_double_or_throw();
632 else throw marley::Error(
"Missing JSON key '" + key +
'\'' );
639 double get_double(
const std::string& key,
double default_value )
const {
640 check_if_object( key );
641 if ( !has_key(key) )
return default_value;
642 else return this->at( key ).to_double_or_throw();
647 long get_long(
const std::string& key )
const {
648 check_if_object( key );
649 if ( has_key(key) )
return this->at( key ).to_long_or_throw();
650 else throw marley::Error(
"Missing JSON key '" + key +
'\'' );
657 long get_long(
const std::string& key,
long default_value )
const {
658 check_if_object( key );
659 if ( !has_key(key) )
return default_value;
660 else return this->at( key ).to_long_or_throw();
665 bool get_bool(
const std::string& key )
const {
666 check_if_object( key );
667 if ( has_key(key) )
return this->at( key ).to_bool_or_throw();
668 else throw marley::Error(
"Missing JSON key '" + key +
'\'' );
675 bool get_bool(
const std::string& key,
bool default_value )
const {
676 check_if_object( key );
677 if ( !has_key(key) )
return default_value;
678 else return this->at( key ).to_bool_or_throw();
683 std::string get_string(
const std::string& key )
const {
684 check_if_object( key );
685 if ( has_key(key) )
return this->at( key ).to_string_or_throw();
686 else throw marley::Error(
"Missing JSON key '" + key +
'\'' );
687 return std::string(
"" );
693 std::string get_string(
const std::string& key,
694 const std::string& default_value )
const
696 check_if_object( key );
697 if ( !has_key(key) )
return default_value;
698 else return this->at( key ).to_string_or_throw();
703 marley::JSON get_object(
const std::string& key,
704 bool throw_error =
true )
const
706 check_if_object( key );
707 if ( has_key(key) )
return this->at( key );
708 else if ( throw_error )
throw marley::Error(
709 "Missing JSON key '" + key +
'\'' );
710 return JSON::make( JSON::DataType::Object );
715 DataType type_ = DataType::Null;
720 StreamReader(std::istream& stream, std::string filename = {},
721 StreamReader* parent =
nullptr)
722 : stream_(&stream), filename_(std::move(filename)),
725 StreamReader(std::unique_ptr<std::istream> stream,
726 std::string filename = {}, StreamReader* parent =
nullptr)
727 : stream_(stream.get()), owner_(std::move(stream)),
728 filename_(std::move(filename)), parent_(parent) {}
732 has_putback_ =
false;
733 char c = putback_char_;
734 if (c ==
'\n') { ++line_; col_ = 1; }
739 if (stream_->get(c)) {
740 prev_line_ = line_; prev_col_ = col_; prev_known_ =
true;
741 if (c ==
'\n') { ++line_; col_ = 1; }
750 if (has_putback_)
return putback_char_;
751 int ch = stream_->peek();
752 if (ch == std::char_traits<char>::eof()) {
753 fail_ =
true;
return '\0';
755 return static_cast<char>(ch);
760 line_ = prev_line_; col_ = prev_col_;
767 if (has_putback_)
return true;
768 return !fail_ && stream_->good();
771 size_t line()
const {
return line_; }
772 size_t col()
const {
return col_; }
773 const std::string& filename()
const {
return filename_; }
775 std::string format_error(
const std::string& message)
const {
777 auto report_col = [&](
const StreamReader& r) -> std::string {
778 return std::to_string(r.prev_known_ ? r.prev_line_ : r.line_)
779 +
", column " + std::to_string(r.prev_known_ ? r.prev_col_ : r.col_);
781 if (!filename_.empty()) {
782 result +=
"In \"" + filename_ +
"\", line " + report_col(*
this)
785 std::string indent =
" ";
786 for (
const StreamReader* p = parent_; p; p = p->parent_) {
787 result += indent +
"(included from \"" + p->filename_
788 +
"\", line " + report_col(*p) +
")\n";
796 std::istream* stream_ =
nullptr;
797 std::unique_ptr<std::istream> owner_;
798 std::string filename_;
799 StreamReader* parent_ =
nullptr;
801 size_t line_ = 1, col_ = 1;
802 size_t prev_line_ = 1, prev_col_ = 1;
803 bool prev_known_ =
false;
805 char putback_char_ = 0;
806 bool has_putback_ =
false;