diff --git a/README.md b/README.md index ffc33805d..8cbc1d790 100644 --- a/README.md +++ b/README.md @@ -184,7 +184,7 @@ bool foo = j.at(2); // other stuff j.size(); // 3 entries j.empty(); // false -j.type(); // json::value_type::array +j.type(); // json::value_t::array j.clear(); // the array is empty again // comparison diff --git a/header_only/json.h b/header_only/json.h index 37b6f64be..ba992d64f 100644 --- a/header_only/json.h +++ b/header_only/json.h @@ -2,7 +2,7 @@ @file @copyright The code is licensed under the MIT License , - Copyright (c) 2013-2014 Niels Lohmann. + Copyright (c) 2013-2015 Niels Lohmann. @author Niels Lohmann @@ -18,6 +18,7 @@ #include // std::vector #include // std::iterator #include // std::numeric_limits +#include // std::hash namespace nlohmann { @@ -41,30 +42,21 @@ due to alignment. */ class json { - // forward declaration to friend this class public: + // forward declaration to friend this class class iterator; class const_iterator; - public: - /// possible types of a JSON object - enum class value_type : uint8_t - { - /// ordered collection of values - array = 0, - /// unordered set of name/value pairs - object, - /// null value - null, - /// string value - string, - /// Boolean value - boolean, - /// number value (integer) - number, - /// number value (float) - number_float - }; + // container types + using value_type = json; + using reference = json&; + using const_reference = const json&; + using pointer = json*; + using const_pointer = const json*; + using iterator = json::iterator; + using const_iterator = json::const_iterator; + using difference_type = std::ptrdiff_t; + using size_type = std::size_t; /// a type for an object using object_t = std::map; @@ -113,9 +105,28 @@ class json value(number_float_t); }; + /// possible types of a JSON object + enum class value_t : uint8_t + { + /// ordered collection of values + array = 0, + /// unordered set of name/value pairs + object, + /// null value + null, + /// string value + string, + /// Boolean value + boolean, + /// number value (integer) + number, + /// number value (float) + number_float + }; + public: /// create an object according to given type - json(const value_type); + json(const value_t); /// create a null object json() = default; /// create a null object @@ -140,15 +151,23 @@ class json json(list_init_t); /// create a number object (integer) - template::is_integer, T>::type = 0> + template::is_integer, T>::type + = 0> json(const T n) noexcept - : type_(value_type::number), value_(static_cast(n)) + : type_(value_t::number), + value_(static_cast(n)) {} /// create a number object (float) - template::value>::type> + template::value>::type + > json(const T n) noexcept - : type_(value_type::number_float), value_(static_cast(n)) + : type_(value_t::number_float), + value_(static_cast(n)) {} /// create an array object @@ -284,27 +303,29 @@ class json /// operator to get an element in an array const json& operator[](const int) const; /// operator to get an element in an array - json& at(const int); + reference at(const int); /// operator to get an element in an array - const json& at(const int) const; + const_reference at(const int) const; /// operator to set an element in an object - json& operator[](const std::string&); + reference operator[](const std::string&); /// operator to set an element in an object - json& operator[](const char*); + reference operator[](const char*); /// operator to get an element in an object - const json& operator[](const std::string&) const; + const_reference operator[](const std::string&) const; /// operator to set an element in an object - json& at(const std::string&); + reference at(const std::string&); /// operator to set an element in an object - json& at(const char*); + reference at(const char*); /// operator to get an element in an object - const json& at(const std::string&) const; + const_reference at(const std::string&) const; /// operator to get an element in an object - const json& at(const char*) const; + const_reference at(const char*) const; /// return the number of stored values - std::size_t size() const noexcept; + size_type size() const noexcept; + /// return the maximal number of values that can be stored + size_type max_size() const noexcept; /// checks whether object is empty bool empty() const noexcept; /// removes all elements from compounds and resets values to default @@ -314,7 +335,7 @@ class json void swap(json&) noexcept; /// return the type of the object - value_type type() const noexcept; + value_t type() const noexcept; /// find an element in an object (returns end() iterator otherwise) iterator find(const std::string&); @@ -345,7 +366,7 @@ class json private: /// the type of this object - value_type type_ = value_type::null; + value_t type_ = value_t::null; /// the payload value value_ {}; @@ -475,23 +496,37 @@ class json /// user-defined literal operator to create JSON objects from strings nlohmann::json operator "" _json(const char*, std::size_t); -// specialization of std::swap +// specialization of std::swap, and std::hash namespace std { template <> /// swaps the values of two JSON objects inline void swap(nlohmann::json& j1, - nlohmann::json& j2) noexcept(is_nothrow_move_constructible::value and - is_nothrow_move_assignable::value) + nlohmann::json& j2) noexcept( + is_nothrow_move_constructible::value and + is_nothrow_move_assignable::value + ) { j1.swap(j2); } + +template <> +/// hash value for JSON objects +struct hash +{ + size_t operator()(const nlohmann::json& j) const + { + // a naive hashing via the string representation + return hash()(j.dump()); + } +}; + } /*! @file @copyright The code is licensed under the MIT License , - Copyright (c) 2013-2014 Niels Lohmann. + Copyright (c) 2013-2015 Niels Lohmann. @author Niels Lohmann @@ -531,37 +566,37 @@ Construct an empty JSON given the type. @post Memory for array, object, and string are allocated. */ -json::json(const value_type t) +json::json(const value_t t) : type_(t) { switch (type_) { - case (value_type::array): + case (value_t::array): { value_.array = new array_t(); break; } - case (value_type::object): + case (value_t::object): { value_.object = new object_t(); break; } - case (value_type::string): + case (value_t::string): { value_.string = new string_t(); break; } - case (value_type::boolean): + case (value_t::boolean): { value_.boolean = boolean_t(); break; } - case (value_type::number): + case (value_t::number): { value_.number = number_t(); break; } - case (value_type::number_float): + case (value_t::number_float): { value_.number_float = number_float_t(); break; @@ -585,35 +620,35 @@ Construct a string JSON object. @param s a string to initialize the JSON object with */ json::json(const std::string& s) - : type_(value_type::string), value_(new string_t(s)) + : type_(value_t::string), value_(new string_t(s)) {} json::json(std::string&& s) - : type_(value_type::string), value_(new string_t(std::move(s))) + : type_(value_t::string), value_(new string_t(std::move(s))) {} json::json(const char* s) - : type_(value_type::string), value_(new string_t(s)) + : type_(value_t::string), value_(new string_t(s)) {} json::json(const bool b) noexcept - : type_(value_type::boolean), value_(b) + : type_(value_t::boolean), value_(b) {} json::json(const array_t& a) - : type_(value_type::array), value_(new array_t(a)) + : type_(value_t::array), value_(new array_t(a)) {} json::json(array_t&& a) - : type_(value_type::array), value_(new array_t(std::move(a))) + : type_(value_t::array), value_(new array_t(std::move(a))) {} json::json(const object_t& o) - : type_(value_type::object), value_(new object_t(o)) + : type_(value_t::object), value_(new object_t(o)) {} json::json(object_t&& o) - : type_(value_type::object), value_(new object_t(std::move(o))) + : type_(value_t::object), value_(new object_t(std::move(o))) {} /*! @@ -637,20 +672,20 @@ json::json(list_init_t a) // is a string for (const auto& element : a) { - if (element.type_ != value_type::array or + if (element.type_ != value_t::array or element.size() != 2 or - element[0].type_ != value_type::string) + element[0].type_ != value_t::string) { // the initializer list describes an array - type_ = value_type::array; + type_ = value_t::array; value_ = new array_t(a); return; } } // the initializer list is a list of pairs - type_ = value_type::object; + type_ = value_t::object; value_ = new object_t(); for (const json& element : a) { @@ -670,32 +705,32 @@ json::json(const json& o) { switch (type_) { - case (value_type::array): + case (value_t::array): { value_.array = new array_t(*o.value_.array); break; } - case (value_type::object): + case (value_t::object): { value_.object = new object_t(*o.value_.object); break; } - case (value_type::string): + case (value_t::string): { value_.string = new string_t(*o.value_.string); break; } - case (value_type::boolean): + case (value_t::boolean): { value_.boolean = o.value_.boolean; break; } - case (value_type::number): + case (value_t::number): { value_.number = o.value_.number; break; } - case (value_type::number_float): + case (value_t::number_float): { value_.number_float = o.value_.number_float; break; @@ -718,7 +753,7 @@ json::json(json&& o) noexcept : type_(std::move(o.type_)), value_(std::move(o.value_)) { // invalidate payload - o.type_ = value_type::null; + o.type_ = value_t::null; o.value_ = {}; } @@ -739,17 +774,17 @@ json::~json() noexcept { switch (type_) { - case (value_type::array): + case (value_t::array): { delete value_.array; break; } - case (value_type::object): + case (value_t::object): { delete value_.object; break; } - case (value_type::string): + case (value_t::string): { delete value_.string; break; @@ -785,23 +820,23 @@ std::string json::type_name() const noexcept { switch (type_) { - case (value_type::array): + case (value_t::array): { return "array"; } - case (value_type::object): + case (value_t::object): { return "object"; } - case (value_type::null): + case (value_t::null): { return "null"; } - case (value_type::string): + case (value_t::string): { return "string"; } - case (value_type::boolean): + case (value_t::boolean): { return "boolean"; } @@ -826,7 +861,7 @@ std::string json::get() const { switch (type_) { - case (value_type::string): + case (value_t::string): return *value_.string; default: throw std::logic_error("cannot cast " + type_name() + " to JSON string"); @@ -842,9 +877,9 @@ int json::get() const { switch (type_) { - case (value_type::number): + case (value_t::number): return value_.number; - case (value_type::number_float): + case (value_t::number_float): return static_cast(value_.number_float); default: throw std::logic_error("cannot cast " + type_name() + " to JSON number"); @@ -860,9 +895,9 @@ int64_t json::get() const { switch (type_) { - case (value_type::number): + case (value_t::number): return value_.number; - case (value_type::number_float): + case (value_t::number_float): return static_cast(value_.number_float); default: throw std::logic_error("cannot cast " + type_name() + " to JSON number"); @@ -878,9 +913,9 @@ double json::get() const { switch (type_) { - case (value_type::number): + case (value_t::number): return static_cast(value_.number); - case (value_type::number_float): + case (value_t::number_float): return value_.number_float; default: throw std::logic_error("cannot cast " + type_name() + " to JSON number"); @@ -896,7 +931,7 @@ bool json::get() const { switch (type_) { - case (value_type::boolean): + case (value_t::boolean): return value_.boolean; default: throw std::logic_error("cannot cast " + type_name() + " to JSON Boolean"); @@ -910,11 +945,11 @@ bool json::get() const template<> json::array_t json::get() const { - if (type_ == value_type::array) + if (type_ == value_t::array) { return *value_.array; } - if (type_ == value_type::object) + if (type_ == value_t::object) { throw std::logic_error("cannot cast " + type_name() + " to JSON array"); } @@ -931,7 +966,7 @@ json::array_t json::get() const template<> json::object_t json::get() const { - if (type_ == value_type::object) + if (type_ == value_t::object) { return *value_.object; } @@ -994,27 +1029,27 @@ std::string json::dump(const bool prettyPrint, const unsigned int indentStep, switch (type_) { - case (value_type::string): + case (value_t::string): { return std::string("\"") + escapeString(*value_.string) + "\""; } - case (value_type::boolean): + case (value_t::boolean): { return value_.boolean ? "true" : "false"; } - case (value_type::number): + case (value_t::number): { return std::to_string(value_.number); } - case (value_type::number_float): + case (value_t::number_float): { return std::to_string(value_.number_float); } - case (value_type::array): + case (value_t::array): { if (value_.array->empty()) { @@ -1049,7 +1084,7 @@ std::string json::dump(const bool prettyPrint, const unsigned int indentStep, return result + indent() + "]"; } - case (value_type::object): + case (value_t::object): { if (value_.object->empty()) { @@ -1086,7 +1121,7 @@ std::string json::dump(const bool prettyPrint, const unsigned int indentStep, return result + indent() + "}"; } - // actually only value_type::null - but making the compiler happy + // actually only value_t::null - but making the compiler happy default: { return "null"; @@ -1206,15 +1241,15 @@ an array, the passed element is added to the array. void json::push_back(const json& o) { // push_back only works for null objects or arrays - if (not(type_ == value_type::null or type_ == value_type::array)) + if (not(type_ == value_t::null or type_ == value_t::array)) { throw std::runtime_error("cannot add element to " + type_name()); } // transform null object into an array - if (type_ == value_type::null) + if (type_ == value_t::null) { - type_ = value_type::array; + type_ = value_t::array; value_.array = new array_t; } @@ -1241,22 +1276,22 @@ an array, the passed element is added to the array using move semantics. void json::push_back(json&& o) { // push_back only works for null objects or arrays - if (not(type_ == value_type::null or type_ == value_type::array)) + if (not(type_ == value_t::null or type_ == value_t::array)) { throw std::runtime_error("cannot add element to " + type_name()); } // transform null object into an array - if (type_ == value_type::null) + if (type_ == value_t::null) { - type_ = value_type::array; + type_ = value_t::array; value_.array = new array_t; } // add element to array (move semantics) value_.array->emplace_back(std::move(o)); // invalidate object - o.type_ = value_type::null; + o.type_ = value_t::null; } /*! @@ -1278,9 +1313,9 @@ void json::push_back(list_init_t a) // is a string for (const auto& element : a) { - if (element.type_ != value_type::array or + if (element.type_ != value_t::array or element.size() != 2 or - element[0].type_ != value_type::string) + element[0].type_ != value_t::string) { // the initializer list describes an array is_array = true; @@ -1321,10 +1356,10 @@ index. Bounds will not be checked. @pre Object is an array. @exception std::domain_error if object is not an array */ -json& json::operator[](const int index) +json::reference json::operator[](const int index) { // this [] operator only works for arrays - if (type_ != value_type::array) + if (type_ != value_t::array) { throw std::domain_error("cannot add entry with index " + std::to_string(index) + " to " + type_name()); @@ -1350,10 +1385,10 @@ index. Bounds will not be checked. @pre Object is an array. @exception std::domain_error if object is not an array */ -const json& json::operator[](const int index) const +json::const_reference json::operator[](const int index) const { // this [] operator only works for arrays - if (type_ != value_type::array) + if (type_ != value_t::array) { throw std::domain_error("cannot get entry with index " + std::to_string(index) + " from " + type_name()); @@ -1380,10 +1415,10 @@ index. Bounds will be checked. @exception std::domain_error if object is not an array @exception std::out_of_range if index is out of range (via std::vector::at) */ -json& json::at(const int index) +json::reference json::at(const int index) { // this function only works for arrays - if (type_ != value_type::array) + if (type_ != value_t::array) { throw std::domain_error("cannot add entry with index " + std::to_string(index) + " to " + type_name()); @@ -1410,10 +1445,10 @@ index. Bounds will be checked. @exception std::domain_error if object is not an array @exception std::out_of_range if index is out of range (via std::vector::at) */ -const json& json::at(const int index) const +json::const_reference json::at(const int index) const { // this function only works for arrays - if (type_ != value_type::array) + if (type_ != value_t::array) { throw std::domain_error("cannot get entry with index " + std::to_string(index) + " from " + type_name()); @@ -1426,7 +1461,7 @@ const json& json::at(const int index) const /*! @copydoc json::operator[](const char* key) */ -json& json::operator[](const std::string& key) +json::reference json::operator[](const std::string& key) { return operator[](key.c_str()); } @@ -1444,17 +1479,17 @@ key. @exception std::domain_error if object is not an object (or null) */ -json& json::operator[](const char* key) +json::reference json::operator[](const char* key) { // implicitly convert null to object - if (type_ == value_type::null) + if (type_ == value_t::null) { - type_ = value_type::object; + type_ = value_t::object; value_.object = new object_t; } // this [] operator only works for objects - if (type_ != value_type::object) + if (type_ != value_t::object) { throw std::domain_error("cannot add entry with key " + std::string(key) + " to " + type_name()); @@ -1481,10 +1516,10 @@ key. @exception std::domain_error if object is not an object @exception std::out_of_range if key is not found in object */ -const json& json::operator[](const std::string& key) const +json::const_reference json::operator[](const std::string& key) const { // this [] operator only works for objects - if (type_ != value_type::object) + if (type_ != value_t::object) { throw std::domain_error("cannot get entry with key " + std::string(key) + " from " + type_name()); @@ -1506,7 +1541,7 @@ const json& json::operator[](const std::string& key) const /*! @copydoc json::at(const char* key) */ -json& json::at(const std::string& key) +json::reference json::at(const std::string& key) { return at(key.c_str()); } @@ -1524,10 +1559,10 @@ key. @exception std::domain_error if object is not an object @exception std::out_of_range if key was not found (via std::map::at) */ -json& json::at(const char* key) +json::reference json::at(const char* key) { // this function operator only works for objects - if (type_ != value_type::object) + if (type_ != value_t::object) { throw std::domain_error("cannot add entry with key " + std::string(key) + " to " + type_name()); @@ -1540,7 +1575,7 @@ json& json::at(const char* key) /*! @copydoc json::at(const char *key) const */ -const json& json::at(const std::string& key) const +json::const_reference json::at(const std::string& key) const { return at(key.c_str()); } @@ -1556,10 +1591,10 @@ key. @exception std::domain_error if object is not an object @exception std::out_of_range if key is not found (via std::map::at) */ -const json& json::at(const char* key) const +json::const_reference json::at(const char* key) const { // this [] operator only works for objects - if (type_ != value_type::object) + if (type_ != value_t::object) { throw std::domain_error("cannot get entry with key " + std::string(key) + " from " + type_name()); @@ -1569,7 +1604,6 @@ const json& json::at(const char* key) const return value_.object->at(key); } - /*! Returns the size of the JSON object. @@ -1579,19 +1613,49 @@ Returns the size of the JSON object. @invariant The size is reported as 0 if and only if empty() would return true. */ -std::size_t json::size() const noexcept +json::size_type json::size() const noexcept { switch (type_) { - case (value_type::array): + case (value_t::array): { return value_.array->size(); } - case (value_type::object): + case (value_t::object): { return value_.object->size(); } - case (value_type::null): + case (value_t::null): + { + return 0; + } + default: + { + return 1; + } + } +} + +/*! +Returns the maximal size of the JSON object. + +@return the maximal size of the JSON object; the maximal size is the maximal + number of elements in compounds (array and object), 1 for value types + (true, false, number, string), and 0 for null. +*/ +json::size_type json::max_size() const noexcept +{ + switch (type_) + { + case (value_t::array): + { + return value_.array->max_size(); + } + case (value_t::object): + { + return value_.object->max_size(); + } + case (value_t::null): { return 0; } @@ -1615,15 +1679,15 @@ bool json::empty() const noexcept { switch (type_) { - case (value_type::array): + case (value_t::array): { return value_.array->empty(); } - case (value_type::object): + case (value_t::object): { return value_.object->empty(); } - case (value_type::null): + case (value_t::null): { return true; } @@ -1645,32 +1709,32 @@ void json::clear() noexcept { switch (type_) { - case (value_type::array): + case (value_t::array): { value_.array->clear(); break; } - case (value_type::object): + case (value_t::object): { value_.object->clear(); break; } - case (value_type::string): + case (value_t::string): { value_.string->clear(); break; } - case (value_type::boolean): + case (value_t::boolean): { value_.boolean = {}; break; } - case (value_type::number): + case (value_t::number): { value_.number = {}; break; } - case (value_type::number_float): + case (value_t::number_float): { value_.number_float = {}; break; @@ -1688,7 +1752,7 @@ void json::swap(json& o) noexcept std::swap(value_, o.value_); } -json::value_type json::type() const noexcept +json::value_t json::type() const noexcept { return type_; } @@ -1705,7 +1769,7 @@ json::const_iterator json::find(const std::string& key) const json::iterator json::find(const char* key) { - if (type_ != value_type::object) + if (type_ != value_t::object) { return end(); } @@ -1729,7 +1793,7 @@ json::iterator json::find(const char* key) json::const_iterator json::find(const char* key) const { - if (type_ != value_type::object) + if (type_ != value_t::object) { return end(); } @@ -1755,65 +1819,65 @@ bool json::operator==(const json& o) const noexcept { switch (type_) { - case (value_type::array): + case (value_t::array): { - if (o.type_ == value_type::array) + if (o.type_ == value_t::array) { return *value_.array == *o.value_.array; } break; } - case (value_type::object): + case (value_t::object): { - if (o.type_ == value_type::object) + if (o.type_ == value_t::object) { return *value_.object == *o.value_.object; } break; } - case (value_type::null): + case (value_t::null): { - if (o.type_ == value_type::null) + if (o.type_ == value_t::null) { return true; } break; } - case (value_type::string): + case (value_t::string): { - if (o.type_ == value_type::string) + if (o.type_ == value_t::string) { return *value_.string == *o.value_.string; } break; } - case (value_type::boolean): + case (value_t::boolean): { - if (o.type_ == value_type::boolean) + if (o.type_ == value_t::boolean) { return value_.boolean == o.value_.boolean; } break; } - case (value_type::number): + case (value_t::number): { - if (o.type_ == value_type::number) + if (o.type_ == value_t::number) { return value_.number == o.value_.number; } - if (o.type_ == value_type::number_float) + if (o.type_ == value_t::number_float) { return value_.number == static_cast(o.value_.number_float); } break; } - case (value_type::number_float): + case (value_t::number_float): { - if (o.type_ == value_type::number) + if (o.type_ == value_t::number) { return value_.number_float == static_cast(o.value_.number); } - if (o.type_ == value_type::number_float) + if (o.type_ == value_t::number_float) { return value_.number_float == o.value_.number_float; } @@ -1865,7 +1929,7 @@ json::iterator::iterator(json* j) : object_(j) { if (object_ != nullptr) { - if (object_->type_ == json::value_type::array) + if (object_->type_ == json::value_t::array) { if (object_->empty()) { @@ -1876,7 +1940,7 @@ json::iterator::iterator(json* j) : object_(j) vi_ = new array_t::iterator(object_->value_.array->begin()); } } - else if (object_->type_ == json::value_type::object) + else if (object_->type_ == json::value_t::object) { if (object_->empty()) { @@ -1894,7 +1958,7 @@ json::iterator::iterator(const json::iterator& o) : object_(o.object_) { if (object_ != nullptr) { - if (object_->type_ == json::value_type::array) + if (object_->type_ == json::value_t::array) { if (object_->empty()) { @@ -1905,7 +1969,7 @@ json::iterator::iterator(const json::iterator& o) : object_(o.object_) vi_ = new array_t::iterator(object_->value_.array->begin()); } } - else if (object_->type_ == json::value_type::object) + else if (object_->type_ == json::value_t::object) { if (object_->empty()) { @@ -1942,11 +2006,11 @@ bool json::iterator::operator==(const json::iterator& o) const if (object_ != nullptr) { - if (object_->type_ == json::value_type::array) + if (object_->type_ == json::value_t::array) { return (vi_ == o.vi_); } - if (object_->type_ == json::value_type::object) + if (object_->type_ == json::value_t::object) { return (oi_ == o.oi_); } @@ -1970,7 +2034,7 @@ json::iterator& json::iterator::operator++() switch (object_->type_) { - case (json::value_type::array): + case (json::value_t::array): { if (++(*vi_) == object_->value_.array->end()) { @@ -1978,7 +2042,7 @@ json::iterator& json::iterator::operator++() } break; } - case (json::value_type::object): + case (json::value_t::object): { if (++(*oi_) == object_->value_.object->end()) { @@ -2004,11 +2068,11 @@ json& json::iterator::operator*() const switch (object_->type_) { - case (json::value_type::array): + case (json::value_t::array): { return **vi_; } - case (json::value_type::object): + case (json::value_t::object): { return (*oi_)->second; } @@ -2029,11 +2093,11 @@ json* json::iterator::operator->() const switch (object_->type_) { - case (json::value_type::array): + case (json::value_t::array): { return &(**vi_); } - case (json::value_type::object): + case (json::value_t::object): { return &((*oi_)->second); } @@ -2046,7 +2110,7 @@ json* json::iterator::operator->() const std::string json::iterator::key() const { - if (object_ != nullptr and object_->type_ == json::value_type::object) + if (object_ != nullptr and object_->type_ == json::value_t::object) { return (*oi_)->first; } @@ -2066,11 +2130,11 @@ json& json::iterator::value() const switch (object_->type_) { - case (json::value_type::array): + case (json::value_t::array): { return **vi_; } - case (json::value_type::object): + case (json::value_t::object): { return (*oi_)->second; } @@ -2086,7 +2150,7 @@ json::const_iterator::const_iterator(const json* j) : object_(j) { if (object_ != nullptr) { - if (object_->type_ == json::value_type::array) + if (object_->type_ == json::value_t::array) { if (object_->empty()) { @@ -2097,7 +2161,7 @@ json::const_iterator::const_iterator(const json* j) : object_(j) vi_ = new array_t::const_iterator(object_->value_.array->begin()); } } - else if (object_->type_ == json::value_type::object) + else if (object_->type_ == json::value_t::object) { if (object_->empty()) { @@ -2115,7 +2179,7 @@ json::const_iterator::const_iterator(const json::const_iterator& o) : object_(o. { if (object_ != nullptr) { - if (object_->type_ == json::value_type::array) + if (object_->type_ == json::value_t::array) { if (object_->empty()) { @@ -2126,7 +2190,7 @@ json::const_iterator::const_iterator(const json::const_iterator& o) : object_(o. vi_ = new array_t::const_iterator(object_->value_.array->begin()); } } - else if (object_->type_ == json::value_type::object) + else if (object_->type_ == json::value_t::object) { if (object_->empty()) { @@ -2144,7 +2208,7 @@ json::const_iterator::const_iterator(const json::iterator& o) : object_(o.object { if (object_ != nullptr) { - if (object_->type_ == json::value_type::array) + if (object_->type_ == json::value_t::array) { if (object_->empty()) { @@ -2155,7 +2219,7 @@ json::const_iterator::const_iterator(const json::iterator& o) : object_(o.object vi_ = new array_t::const_iterator(object_->value_.array->begin()); } } - else if (object_->type_ == json::value_type::object) + else if (object_->type_ == json::value_t::object) { if (object_->empty()) { @@ -2192,11 +2256,11 @@ bool json::const_iterator::operator==(const json::const_iterator& o) const if (object_ != nullptr) { - if (object_->type_ == json::value_type::array) + if (object_->type_ == json::value_t::array) { return (vi_ == o.vi_); } - if (object_->type_ == json::value_type::object) + if (object_->type_ == json::value_t::object) { return (oi_ == o.oi_); } @@ -2220,7 +2284,7 @@ json::const_iterator& json::const_iterator::operator++() switch (object_->type_) { - case (json::value_type::array): + case (json::value_t::array): { if (++(*vi_) == object_->value_.array->end()) { @@ -2228,7 +2292,7 @@ json::const_iterator& json::const_iterator::operator++() } break; } - case (json::value_type::object): + case (json::value_t::object): { if (++(*oi_) == object_->value_.object->end()) { @@ -2254,11 +2318,11 @@ const json& json::const_iterator::operator*() const switch (object_->type_) { - case (json::value_type::array): + case (json::value_t::array): { return **vi_; } - case (json::value_type::object): + case (json::value_t::object): { return (*oi_)->second; } @@ -2279,11 +2343,11 @@ const json* json::const_iterator::operator->() const switch (object_->type_) { - case (json::value_type::array): + case (json::value_t::array): { return &(**vi_); } - case (json::value_type::object): + case (json::value_t::object): { return &((*oi_)->second); } @@ -2296,7 +2360,7 @@ const json* json::const_iterator::operator->() const std::string json::const_iterator::key() const { - if (object_ != nullptr and object_->type_ == json::value_type::object) + if (object_ != nullptr and object_->type_ == json::value_t::object) { return (*oi_)->first; } @@ -2316,11 +2380,11 @@ const json& json::const_iterator::value() const switch (object_->type_) { - case (json::value_type::array): + case (json::value_t::array): { return **vi_; } - case (json::value_type::object): + case (json::value_t::object): { return (*oi_)->second; } @@ -2390,7 +2454,7 @@ json json::parser::parse() case ('{'): { // explicitly set result to object to cope with {} - json result(value_type::object); + json result(value_t::object); next(); @@ -2421,7 +2485,7 @@ json json::parser::parse() case ('['): { // explicitly set result to array to cope with [] - json result(value_type::array); + json result(value_t::array); next(); diff --git a/src/json.cc b/src/json.cc index b849c68fe..69c0e0cf1 100644 --- a/src/json.cc +++ b/src/json.cc @@ -2,7 +2,7 @@ @file @copyright The code is licensed under the MIT License , - Copyright (c) 2013-2014 Niels Lohmann. + Copyright (c) 2013-2015 Niels Lohmann. @author Niels Lohmann @@ -42,37 +42,37 @@ Construct an empty JSON given the type. @post Memory for array, object, and string are allocated. */ -json::json(const value_type t) +json::json(const value_t t) : type_(t) { switch (type_) { - case (value_type::array): + case (value_t::array): { value_.array = new array_t(); break; } - case (value_type::object): + case (value_t::object): { value_.object = new object_t(); break; } - case (value_type::string): + case (value_t::string): { value_.string = new string_t(); break; } - case (value_type::boolean): + case (value_t::boolean): { value_.boolean = boolean_t(); break; } - case (value_type::number): + case (value_t::number): { value_.number = number_t(); break; } - case (value_type::number_float): + case (value_t::number_float): { value_.number_float = number_float_t(); break; @@ -96,35 +96,35 @@ Construct a string JSON object. @param s a string to initialize the JSON object with */ json::json(const std::string& s) - : type_(value_type::string), value_(new string_t(s)) + : type_(value_t::string), value_(new string_t(s)) {} json::json(std::string&& s) - : type_(value_type::string), value_(new string_t(std::move(s))) + : type_(value_t::string), value_(new string_t(std::move(s))) {} json::json(const char* s) - : type_(value_type::string), value_(new string_t(s)) + : type_(value_t::string), value_(new string_t(s)) {} json::json(const bool b) noexcept - : type_(value_type::boolean), value_(b) + : type_(value_t::boolean), value_(b) {} json::json(const array_t& a) - : type_(value_type::array), value_(new array_t(a)) + : type_(value_t::array), value_(new array_t(a)) {} json::json(array_t&& a) - : type_(value_type::array), value_(new array_t(std::move(a))) + : type_(value_t::array), value_(new array_t(std::move(a))) {} json::json(const object_t& o) - : type_(value_type::object), value_(new object_t(o)) + : type_(value_t::object), value_(new object_t(o)) {} json::json(object_t&& o) - : type_(value_type::object), value_(new object_t(std::move(o))) + : type_(value_t::object), value_(new object_t(std::move(o))) {} /*! @@ -148,20 +148,20 @@ json::json(list_init_t a) // is a string for (const auto& element : a) { - if (element.type_ != value_type::array or + if (element.type_ != value_t::array or element.size() != 2 or - element[0].type_ != value_type::string) + element[0].type_ != value_t::string) { // the initializer list describes an array - type_ = value_type::array; + type_ = value_t::array; value_ = new array_t(a); return; } } // the initializer list is a list of pairs - type_ = value_type::object; + type_ = value_t::object; value_ = new object_t(); for (const json& element : a) { @@ -181,32 +181,32 @@ json::json(const json& o) { switch (type_) { - case (value_type::array): + case (value_t::array): { value_.array = new array_t(*o.value_.array); break; } - case (value_type::object): + case (value_t::object): { value_.object = new object_t(*o.value_.object); break; } - case (value_type::string): + case (value_t::string): { value_.string = new string_t(*o.value_.string); break; } - case (value_type::boolean): + case (value_t::boolean): { value_.boolean = o.value_.boolean; break; } - case (value_type::number): + case (value_t::number): { value_.number = o.value_.number; break; } - case (value_type::number_float): + case (value_t::number_float): { value_.number_float = o.value_.number_float; break; @@ -229,7 +229,7 @@ json::json(json&& o) noexcept : type_(std::move(o.type_)), value_(std::move(o.value_)) { // invalidate payload - o.type_ = value_type::null; + o.type_ = value_t::null; o.value_ = {}; } @@ -250,17 +250,17 @@ json::~json() noexcept { switch (type_) { - case (value_type::array): + case (value_t::array): { delete value_.array; break; } - case (value_type::object): + case (value_t::object): { delete value_.object; break; } - case (value_type::string): + case (value_t::string): { delete value_.string; break; @@ -296,23 +296,23 @@ std::string json::type_name() const noexcept { switch (type_) { - case (value_type::array): + case (value_t::array): { return "array"; } - case (value_type::object): + case (value_t::object): { return "object"; } - case (value_type::null): + case (value_t::null): { return "null"; } - case (value_type::string): + case (value_t::string): { return "string"; } - case (value_type::boolean): + case (value_t::boolean): { return "boolean"; } @@ -337,7 +337,7 @@ std::string json::get() const { switch (type_) { - case (value_type::string): + case (value_t::string): return *value_.string; default: throw std::logic_error("cannot cast " + type_name() + " to JSON string"); @@ -353,9 +353,9 @@ int json::get() const { switch (type_) { - case (value_type::number): + case (value_t::number): return value_.number; - case (value_type::number_float): + case (value_t::number_float): return static_cast(value_.number_float); default: throw std::logic_error("cannot cast " + type_name() + " to JSON number"); @@ -371,9 +371,9 @@ int64_t json::get() const { switch (type_) { - case (value_type::number): + case (value_t::number): return value_.number; - case (value_type::number_float): + case (value_t::number_float): return static_cast(value_.number_float); default: throw std::logic_error("cannot cast " + type_name() + " to JSON number"); @@ -389,9 +389,9 @@ double json::get() const { switch (type_) { - case (value_type::number): + case (value_t::number): return static_cast(value_.number); - case (value_type::number_float): + case (value_t::number_float): return value_.number_float; default: throw std::logic_error("cannot cast " + type_name() + " to JSON number"); @@ -407,7 +407,7 @@ bool json::get() const { switch (type_) { - case (value_type::boolean): + case (value_t::boolean): return value_.boolean; default: throw std::logic_error("cannot cast " + type_name() + " to JSON Boolean"); @@ -421,11 +421,11 @@ bool json::get() const template<> json::array_t json::get() const { - if (type_ == value_type::array) + if (type_ == value_t::array) { return *value_.array; } - if (type_ == value_type::object) + if (type_ == value_t::object) { throw std::logic_error("cannot cast " + type_name() + " to JSON array"); } @@ -442,7 +442,7 @@ json::array_t json::get() const template<> json::object_t json::get() const { - if (type_ == value_type::object) + if (type_ == value_t::object) { return *value_.object; } @@ -505,27 +505,27 @@ std::string json::dump(const bool prettyPrint, const unsigned int indentStep, switch (type_) { - case (value_type::string): + case (value_t::string): { return std::string("\"") + escapeString(*value_.string) + "\""; } - case (value_type::boolean): + case (value_t::boolean): { return value_.boolean ? "true" : "false"; } - case (value_type::number): + case (value_t::number): { return std::to_string(value_.number); } - case (value_type::number_float): + case (value_t::number_float): { return std::to_string(value_.number_float); } - case (value_type::array): + case (value_t::array): { if (value_.array->empty()) { @@ -560,7 +560,7 @@ std::string json::dump(const bool prettyPrint, const unsigned int indentStep, return result + indent() + "]"; } - case (value_type::object): + case (value_t::object): { if (value_.object->empty()) { @@ -597,7 +597,7 @@ std::string json::dump(const bool prettyPrint, const unsigned int indentStep, return result + indent() + "}"; } - // actually only value_type::null - but making the compiler happy + // actually only value_t::null - but making the compiler happy default: { return "null"; @@ -717,15 +717,15 @@ an array, the passed element is added to the array. void json::push_back(const json& o) { // push_back only works for null objects or arrays - if (not(type_ == value_type::null or type_ == value_type::array)) + if (not(type_ == value_t::null or type_ == value_t::array)) { throw std::runtime_error("cannot add element to " + type_name()); } // transform null object into an array - if (type_ == value_type::null) + if (type_ == value_t::null) { - type_ = value_type::array; + type_ = value_t::array; value_.array = new array_t; } @@ -752,22 +752,22 @@ an array, the passed element is added to the array using move semantics. void json::push_back(json&& o) { // push_back only works for null objects or arrays - if (not(type_ == value_type::null or type_ == value_type::array)) + if (not(type_ == value_t::null or type_ == value_t::array)) { throw std::runtime_error("cannot add element to " + type_name()); } // transform null object into an array - if (type_ == value_type::null) + if (type_ == value_t::null) { - type_ = value_type::array; + type_ = value_t::array; value_.array = new array_t; } // add element to array (move semantics) value_.array->emplace_back(std::move(o)); // invalidate object - o.type_ = value_type::null; + o.type_ = value_t::null; } /*! @@ -789,9 +789,9 @@ void json::push_back(list_init_t a) // is a string for (const auto& element : a) { - if (element.type_ != value_type::array or + if (element.type_ != value_t::array or element.size() != 2 or - element[0].type_ != value_type::string) + element[0].type_ != value_t::string) { // the initializer list describes an array is_array = true; @@ -832,10 +832,10 @@ index. Bounds will not be checked. @pre Object is an array. @exception std::domain_error if object is not an array */ -json& json::operator[](const int index) +json::reference json::operator[](const int index) { // this [] operator only works for arrays - if (type_ != value_type::array) + if (type_ != value_t::array) { throw std::domain_error("cannot add entry with index " + std::to_string(index) + " to " + type_name()); @@ -861,10 +861,10 @@ index. Bounds will not be checked. @pre Object is an array. @exception std::domain_error if object is not an array */ -const json& json::operator[](const int index) const +json::const_reference json::operator[](const int index) const { // this [] operator only works for arrays - if (type_ != value_type::array) + if (type_ != value_t::array) { throw std::domain_error("cannot get entry with index " + std::to_string(index) + " from " + type_name()); @@ -891,10 +891,10 @@ index. Bounds will be checked. @exception std::domain_error if object is not an array @exception std::out_of_range if index is out of range (via std::vector::at) */ -json& json::at(const int index) +json::reference json::at(const int index) { // this function only works for arrays - if (type_ != value_type::array) + if (type_ != value_t::array) { throw std::domain_error("cannot add entry with index " + std::to_string(index) + " to " + type_name()); @@ -921,10 +921,10 @@ index. Bounds will be checked. @exception std::domain_error if object is not an array @exception std::out_of_range if index is out of range (via std::vector::at) */ -const json& json::at(const int index) const +json::const_reference json::at(const int index) const { // this function only works for arrays - if (type_ != value_type::array) + if (type_ != value_t::array) { throw std::domain_error("cannot get entry with index " + std::to_string(index) + " from " + type_name()); @@ -937,7 +937,7 @@ const json& json::at(const int index) const /*! @copydoc json::operator[](const char* key) */ -json& json::operator[](const std::string& key) +json::reference json::operator[](const std::string& key) { return operator[](key.c_str()); } @@ -955,17 +955,17 @@ key. @exception std::domain_error if object is not an object (or null) */ -json& json::operator[](const char* key) +json::reference json::operator[](const char* key) { // implicitly convert null to object - if (type_ == value_type::null) + if (type_ == value_t::null) { - type_ = value_type::object; + type_ = value_t::object; value_.object = new object_t; } // this [] operator only works for objects - if (type_ != value_type::object) + if (type_ != value_t::object) { throw std::domain_error("cannot add entry with key " + std::string(key) + " to " + type_name()); @@ -992,10 +992,10 @@ key. @exception std::domain_error if object is not an object @exception std::out_of_range if key is not found in object */ -const json& json::operator[](const std::string& key) const +json::const_reference json::operator[](const std::string& key) const { // this [] operator only works for objects - if (type_ != value_type::object) + if (type_ != value_t::object) { throw std::domain_error("cannot get entry with key " + std::string(key) + " from " + type_name()); @@ -1017,7 +1017,7 @@ const json& json::operator[](const std::string& key) const /*! @copydoc json::at(const char* key) */ -json& json::at(const std::string& key) +json::reference json::at(const std::string& key) { return at(key.c_str()); } @@ -1035,10 +1035,10 @@ key. @exception std::domain_error if object is not an object @exception std::out_of_range if key was not found (via std::map::at) */ -json& json::at(const char* key) +json::reference json::at(const char* key) { // this function operator only works for objects - if (type_ != value_type::object) + if (type_ != value_t::object) { throw std::domain_error("cannot add entry with key " + std::string(key) + " to " + type_name()); @@ -1051,7 +1051,7 @@ json& json::at(const char* key) /*! @copydoc json::at(const char *key) const */ -const json& json::at(const std::string& key) const +json::const_reference json::at(const std::string& key) const { return at(key.c_str()); } @@ -1067,10 +1067,10 @@ key. @exception std::domain_error if object is not an object @exception std::out_of_range if key is not found (via std::map::at) */ -const json& json::at(const char* key) const +json::const_reference json::at(const char* key) const { // this [] operator only works for objects - if (type_ != value_type::object) + if (type_ != value_t::object) { throw std::domain_error("cannot get entry with key " + std::string(key) + " from " + type_name()); @@ -1080,7 +1080,6 @@ const json& json::at(const char* key) const return value_.object->at(key); } - /*! Returns the size of the JSON object. @@ -1090,19 +1089,49 @@ Returns the size of the JSON object. @invariant The size is reported as 0 if and only if empty() would return true. */ -std::size_t json::size() const noexcept +json::size_type json::size() const noexcept { switch (type_) { - case (value_type::array): + case (value_t::array): { return value_.array->size(); } - case (value_type::object): + case (value_t::object): { return value_.object->size(); } - case (value_type::null): + case (value_t::null): + { + return 0; + } + default: + { + return 1; + } + } +} + +/*! +Returns the maximal size of the JSON object. + +@return the maximal size of the JSON object; the maximal size is the maximal + number of elements in compounds (array and object), 1 for value types + (true, false, number, string), and 0 for null. +*/ +json::size_type json::max_size() const noexcept +{ + switch (type_) + { + case (value_t::array): + { + return value_.array->max_size(); + } + case (value_t::object): + { + return value_.object->max_size(); + } + case (value_t::null): { return 0; } @@ -1126,15 +1155,15 @@ bool json::empty() const noexcept { switch (type_) { - case (value_type::array): + case (value_t::array): { return value_.array->empty(); } - case (value_type::object): + case (value_t::object): { return value_.object->empty(); } - case (value_type::null): + case (value_t::null): { return true; } @@ -1156,32 +1185,32 @@ void json::clear() noexcept { switch (type_) { - case (value_type::array): + case (value_t::array): { value_.array->clear(); break; } - case (value_type::object): + case (value_t::object): { value_.object->clear(); break; } - case (value_type::string): + case (value_t::string): { value_.string->clear(); break; } - case (value_type::boolean): + case (value_t::boolean): { value_.boolean = {}; break; } - case (value_type::number): + case (value_t::number): { value_.number = {}; break; } - case (value_type::number_float): + case (value_t::number_float): { value_.number_float = {}; break; @@ -1199,7 +1228,7 @@ void json::swap(json& o) noexcept std::swap(value_, o.value_); } -json::value_type json::type() const noexcept +json::value_t json::type() const noexcept { return type_; } @@ -1216,7 +1245,7 @@ json::const_iterator json::find(const std::string& key) const json::iterator json::find(const char* key) { - if (type_ != value_type::object) + if (type_ != value_t::object) { return end(); } @@ -1240,7 +1269,7 @@ json::iterator json::find(const char* key) json::const_iterator json::find(const char* key) const { - if (type_ != value_type::object) + if (type_ != value_t::object) { return end(); } @@ -1266,65 +1295,65 @@ bool json::operator==(const json& o) const noexcept { switch (type_) { - case (value_type::array): + case (value_t::array): { - if (o.type_ == value_type::array) + if (o.type_ == value_t::array) { return *value_.array == *o.value_.array; } break; } - case (value_type::object): + case (value_t::object): { - if (o.type_ == value_type::object) + if (o.type_ == value_t::object) { return *value_.object == *o.value_.object; } break; } - case (value_type::null): + case (value_t::null): { - if (o.type_ == value_type::null) + if (o.type_ == value_t::null) { return true; } break; } - case (value_type::string): + case (value_t::string): { - if (o.type_ == value_type::string) + if (o.type_ == value_t::string) { return *value_.string == *o.value_.string; } break; } - case (value_type::boolean): + case (value_t::boolean): { - if (o.type_ == value_type::boolean) + if (o.type_ == value_t::boolean) { return value_.boolean == o.value_.boolean; } break; } - case (value_type::number): + case (value_t::number): { - if (o.type_ == value_type::number) + if (o.type_ == value_t::number) { return value_.number == o.value_.number; } - if (o.type_ == value_type::number_float) + if (o.type_ == value_t::number_float) { return value_.number == static_cast(o.value_.number_float); } break; } - case (value_type::number_float): + case (value_t::number_float): { - if (o.type_ == value_type::number) + if (o.type_ == value_t::number) { return value_.number_float == static_cast(o.value_.number); } - if (o.type_ == value_type::number_float) + if (o.type_ == value_t::number_float) { return value_.number_float == o.value_.number_float; } @@ -1376,7 +1405,7 @@ json::iterator::iterator(json* j) : object_(j) { if (object_ != nullptr) { - if (object_->type_ == json::value_type::array) + if (object_->type_ == json::value_t::array) { if (object_->empty()) { @@ -1387,7 +1416,7 @@ json::iterator::iterator(json* j) : object_(j) vi_ = new array_t::iterator(object_->value_.array->begin()); } } - else if (object_->type_ == json::value_type::object) + else if (object_->type_ == json::value_t::object) { if (object_->empty()) { @@ -1405,7 +1434,7 @@ json::iterator::iterator(const json::iterator& o) : object_(o.object_) { if (object_ != nullptr) { - if (object_->type_ == json::value_type::array) + if (object_->type_ == json::value_t::array) { if (object_->empty()) { @@ -1416,7 +1445,7 @@ json::iterator::iterator(const json::iterator& o) : object_(o.object_) vi_ = new array_t::iterator(object_->value_.array->begin()); } } - else if (object_->type_ == json::value_type::object) + else if (object_->type_ == json::value_t::object) { if (object_->empty()) { @@ -1453,11 +1482,11 @@ bool json::iterator::operator==(const json::iterator& o) const if (object_ != nullptr) { - if (object_->type_ == json::value_type::array) + if (object_->type_ == json::value_t::array) { return (vi_ == o.vi_); } - if (object_->type_ == json::value_type::object) + if (object_->type_ == json::value_t::object) { return (oi_ == o.oi_); } @@ -1481,7 +1510,7 @@ json::iterator& json::iterator::operator++() switch (object_->type_) { - case (json::value_type::array): + case (json::value_t::array): { if (++(*vi_) == object_->value_.array->end()) { @@ -1489,7 +1518,7 @@ json::iterator& json::iterator::operator++() } break; } - case (json::value_type::object): + case (json::value_t::object): { if (++(*oi_) == object_->value_.object->end()) { @@ -1515,11 +1544,11 @@ json& json::iterator::operator*() const switch (object_->type_) { - case (json::value_type::array): + case (json::value_t::array): { return **vi_; } - case (json::value_type::object): + case (json::value_t::object): { return (*oi_)->second; } @@ -1540,11 +1569,11 @@ json* json::iterator::operator->() const switch (object_->type_) { - case (json::value_type::array): + case (json::value_t::array): { return &(**vi_); } - case (json::value_type::object): + case (json::value_t::object): { return &((*oi_)->second); } @@ -1557,7 +1586,7 @@ json* json::iterator::operator->() const std::string json::iterator::key() const { - if (object_ != nullptr and object_->type_ == json::value_type::object) + if (object_ != nullptr and object_->type_ == json::value_t::object) { return (*oi_)->first; } @@ -1577,11 +1606,11 @@ json& json::iterator::value() const switch (object_->type_) { - case (json::value_type::array): + case (json::value_t::array): { return **vi_; } - case (json::value_type::object): + case (json::value_t::object): { return (*oi_)->second; } @@ -1597,7 +1626,7 @@ json::const_iterator::const_iterator(const json* j) : object_(j) { if (object_ != nullptr) { - if (object_->type_ == json::value_type::array) + if (object_->type_ == json::value_t::array) { if (object_->empty()) { @@ -1608,7 +1637,7 @@ json::const_iterator::const_iterator(const json* j) : object_(j) vi_ = new array_t::const_iterator(object_->value_.array->begin()); } } - else if (object_->type_ == json::value_type::object) + else if (object_->type_ == json::value_t::object) { if (object_->empty()) { @@ -1626,7 +1655,7 @@ json::const_iterator::const_iterator(const json::const_iterator& o) : object_(o. { if (object_ != nullptr) { - if (object_->type_ == json::value_type::array) + if (object_->type_ == json::value_t::array) { if (object_->empty()) { @@ -1637,7 +1666,7 @@ json::const_iterator::const_iterator(const json::const_iterator& o) : object_(o. vi_ = new array_t::const_iterator(object_->value_.array->begin()); } } - else if (object_->type_ == json::value_type::object) + else if (object_->type_ == json::value_t::object) { if (object_->empty()) { @@ -1655,7 +1684,7 @@ json::const_iterator::const_iterator(const json::iterator& o) : object_(o.object { if (object_ != nullptr) { - if (object_->type_ == json::value_type::array) + if (object_->type_ == json::value_t::array) { if (object_->empty()) { @@ -1666,7 +1695,7 @@ json::const_iterator::const_iterator(const json::iterator& o) : object_(o.object vi_ = new array_t::const_iterator(object_->value_.array->begin()); } } - else if (object_->type_ == json::value_type::object) + else if (object_->type_ == json::value_t::object) { if (object_->empty()) { @@ -1703,11 +1732,11 @@ bool json::const_iterator::operator==(const json::const_iterator& o) const if (object_ != nullptr) { - if (object_->type_ == json::value_type::array) + if (object_->type_ == json::value_t::array) { return (vi_ == o.vi_); } - if (object_->type_ == json::value_type::object) + if (object_->type_ == json::value_t::object) { return (oi_ == o.oi_); } @@ -1731,7 +1760,7 @@ json::const_iterator& json::const_iterator::operator++() switch (object_->type_) { - case (json::value_type::array): + case (json::value_t::array): { if (++(*vi_) == object_->value_.array->end()) { @@ -1739,7 +1768,7 @@ json::const_iterator& json::const_iterator::operator++() } break; } - case (json::value_type::object): + case (json::value_t::object): { if (++(*oi_) == object_->value_.object->end()) { @@ -1765,11 +1794,11 @@ const json& json::const_iterator::operator*() const switch (object_->type_) { - case (json::value_type::array): + case (json::value_t::array): { return **vi_; } - case (json::value_type::object): + case (json::value_t::object): { return (*oi_)->second; } @@ -1790,11 +1819,11 @@ const json* json::const_iterator::operator->() const switch (object_->type_) { - case (json::value_type::array): + case (json::value_t::array): { return &(**vi_); } - case (json::value_type::object): + case (json::value_t::object): { return &((*oi_)->second); } @@ -1807,7 +1836,7 @@ const json* json::const_iterator::operator->() const std::string json::const_iterator::key() const { - if (object_ != nullptr and object_->type_ == json::value_type::object) + if (object_ != nullptr and object_->type_ == json::value_t::object) { return (*oi_)->first; } @@ -1827,11 +1856,11 @@ const json& json::const_iterator::value() const switch (object_->type_) { - case (json::value_type::array): + case (json::value_t::array): { return **vi_; } - case (json::value_type::object): + case (json::value_t::object): { return (*oi_)->second; } @@ -1901,7 +1930,7 @@ json json::parser::parse() case ('{'): { // explicitly set result to object to cope with {} - json result(value_type::object); + json result(value_t::object); next(); @@ -1932,7 +1961,7 @@ json json::parser::parse() case ('['): { // explicitly set result to array to cope with [] - json result(value_type::array); + json result(value_t::array); next(); diff --git a/src/json.h b/src/json.h index ec7343de0..fb9a1f7db 100644 --- a/src/json.h +++ b/src/json.h @@ -2,7 +2,7 @@ @file @copyright The code is licensed under the MIT License , - Copyright (c) 2013-2014 Niels Lohmann. + Copyright (c) 2013-2015 Niels Lohmann. @author Niels Lohmann @@ -18,6 +18,7 @@ #include // std::vector #include // std::iterator #include // std::numeric_limits +#include // std::hash namespace nlohmann { @@ -41,30 +42,21 @@ due to alignment. */ class json { - // forward declaration to friend this class public: + // forward declaration to friend this class class iterator; class const_iterator; - public: - /// possible types of a JSON object - enum class value_type : uint8_t - { - /// ordered collection of values - array = 0, - /// unordered set of name/value pairs - object, - /// null value - null, - /// string value - string, - /// Boolean value - boolean, - /// number value (integer) - number, - /// number value (float) - number_float - }; + // container types + using value_type = json; + using reference = json&; + using const_reference = const json&; + using pointer = json*; + using const_pointer = const json*; + using iterator = json::iterator; + using const_iterator = json::const_iterator; + using difference_type = std::ptrdiff_t; + using size_type = std::size_t; /// a type for an object using object_t = std::map; @@ -113,9 +105,28 @@ class json value(number_float_t); }; + /// possible types of a JSON object + enum class value_t : uint8_t + { + /// ordered collection of values + array = 0, + /// unordered set of name/value pairs + object, + /// null value + null, + /// string value + string, + /// Boolean value + boolean, + /// number value (integer) + number, + /// number value (float) + number_float + }; + public: /// create an object according to given type - json(const value_type); + json(const value_t); /// create a null object json() = default; /// create a null object @@ -140,15 +151,23 @@ class json json(list_init_t); /// create a number object (integer) - template::is_integer, T>::type = 0> + template::is_integer, T>::type + = 0> json(const T n) noexcept - : type_(value_type::number), value_(static_cast(n)) + : type_(value_t::number), + value_(static_cast(n)) {} /// create a number object (float) - template::value>::type> + template::value>::type + > json(const T n) noexcept - : type_(value_type::number_float), value_(static_cast(n)) + : type_(value_t::number_float), + value_(static_cast(n)) {} /// create an array object @@ -284,27 +303,29 @@ class json /// operator to get an element in an array const json& operator[](const int) const; /// operator to get an element in an array - json& at(const int); + reference at(const int); /// operator to get an element in an array - const json& at(const int) const; + const_reference at(const int) const; /// operator to set an element in an object - json& operator[](const std::string&); + reference operator[](const std::string&); /// operator to set an element in an object - json& operator[](const char*); + reference operator[](const char*); /// operator to get an element in an object - const json& operator[](const std::string&) const; + const_reference operator[](const std::string&) const; /// operator to set an element in an object - json& at(const std::string&); + reference at(const std::string&); /// operator to set an element in an object - json& at(const char*); + reference at(const char*); /// operator to get an element in an object - const json& at(const std::string&) const; + const_reference at(const std::string&) const; /// operator to get an element in an object - const json& at(const char*) const; + const_reference at(const char*) const; /// return the number of stored values - std::size_t size() const noexcept; + size_type size() const noexcept; + /// return the maximal number of values that can be stored + size_type max_size() const noexcept; /// checks whether object is empty bool empty() const noexcept; /// removes all elements from compounds and resets values to default @@ -314,7 +335,7 @@ class json void swap(json&) noexcept; /// return the type of the object - value_type type() const noexcept; + value_t type() const noexcept; /// find an element in an object (returns end() iterator otherwise) iterator find(const std::string&); @@ -345,7 +366,7 @@ class json private: /// the type of this object - value_type type_ = value_type::null; + value_t type_ = value_t::null; /// the payload value value_ {}; @@ -475,15 +496,29 @@ class json /// user-defined literal operator to create JSON objects from strings nlohmann::json operator "" _json(const char*, std::size_t); -// specialization of std::swap +// specialization of std::swap, and std::hash namespace std { template <> /// swaps the values of two JSON objects inline void swap(nlohmann::json& j1, - nlohmann::json& j2) noexcept(is_nothrow_move_constructible::value and - is_nothrow_move_assignable::value) + nlohmann::json& j2) noexcept( + is_nothrow_move_constructible::value and + is_nothrow_move_assignable::value + ) { j1.swap(j2); } + +template <> +/// hash value for JSON objects +struct hash +{ + size_t operator()(const nlohmann::json& j) const + { + // a naive hashing via the string representation + return hash()(j.dump()); + } +}; + } diff --git a/test/json_unit.cc b/test/json_unit.cc index 01d796096..a5f346ba0 100644 --- a/test/json_unit.cc +++ b/test/json_unit.cc @@ -19,8 +19,8 @@ TEST_CASE("array") SECTION("Basics") { // construction with given type - json j(json::value_type::array); - CHECK(j.type() == json::value_type::array); + json j(json::value_t::array); + CHECK(j.type() == json::value_t::array); // const object const json j_const (j); @@ -34,7 +34,9 @@ TEST_CASE("array") // container members CHECK(j.size() == 0); + CHECK(j.max_size() > 0); CHECK(j.empty() == true); + CHECK_NOTHROW(size_t h = std::hash()(j)); // implicit conversions CHECK_NOTHROW(json::array_t v = j); @@ -88,21 +90,21 @@ TEST_CASE("array") // case 1: there is an element that is not an array json j3 = { {"foo", "bar"}, 3 }; - CHECK(j3.type() == json::value_type::array); + CHECK(j3.type() == json::value_t::array); // case 2: there is an element with more than two elements json j4 = { {"foo", "bar"}, {"one", "two", "three"} }; - CHECK(j4.type() == json::value_type::array); + CHECK(j4.type() == json::value_t::array); // case 3: there is an element whose first element is not a string json j5 = { {"foo", "bar"}, {true, "baz"} }; - CHECK(j5.type() == json::value_type::array); + CHECK(j5.type() == json::value_t::array); // check if nested arrays work and are recognized as arrays json j6 = { {{"foo", "bar"}} }; - CHECK(j6.type() == json::value_type::array); + CHECK(j6.type() == json::value_t::array); CHECK(j6.size() == 1); - CHECK(j6[0].type() == json::value_type::object); + CHECK(j6[0].type() == json::value_t::object); // move constructor json j7(std::move(v1)); @@ -152,8 +154,8 @@ TEST_CASE("array") json empty1, empty2; empty1 += "foo"; empty2.push_back("foo"); - CHECK(empty1.type() == json::value_type::array); - CHECK(empty2.type() == json::value_type::array); + CHECK(empty1.type() == json::value_t::array); + CHECK(empty2.type() == json::value_t::array); CHECK(empty1 == empty2); // exceptions @@ -182,7 +184,7 @@ TEST_CASE("array") CHECK_THROWS_AS(nonarray2.push_back(nonarray3), std::runtime_error); CHECK_THROWS_AS(nonarray2.push_back(3), std::runtime_error); CHECK_NOTHROW(empty3.push_back(nonarray3)); - CHECK(empty3.type() == json::value_type::array); + CHECK(empty3.type() == json::value_t::array); } const json k = j; @@ -300,12 +302,12 @@ TEST_CASE("array") // turn arrays with two strings. However, this is treated like the // initializer list of an object. json j_should_be_an_array = { {"foo", "bar"}, {"baz", "bat"} }; - CHECK(j_should_be_an_array.type() == json::value_type::object); + CHECK(j_should_be_an_array.type() == json::value_t::object); } SECTION("Iterators and empty arrays") { - json empty_array(json::value_type::array); + json empty_array(json::value_t::array); for (json::iterator it = empty_array.begin(); it != empty_array.end(); ++it) {} for (json::const_iterator it = empty_array.begin(); it != empty_array.end(); ++it) {} for (json::const_iterator it = empty_array.cbegin(); it != empty_array.cend(); ++it) {} @@ -338,47 +340,47 @@ TEST_CASE("array") { std::vector c_vector {1, 2, 3, 4}; json j_vec(c_vector); - CHECK(j_vec.type() == json::value_type::array); + CHECK(j_vec.type() == json::value_t::array); CHECK(j_vec.size() == 4); std::set c_set {"one", "two", "three", "four", "one"}; json j_set(c_set); - CHECK(j_set.type() == json::value_type::array); + CHECK(j_set.type() == json::value_t::array); CHECK(j_set.size() == 4); std::unordered_set c_uset {"one", "two", "three", "four", "one"}; json j_uset(c_uset); - CHECK(j_uset.type() == json::value_type::array); + CHECK(j_uset.type() == json::value_t::array); CHECK(j_uset.size() == 4); std::multiset c_mset {"one", "two", "one", "four"}; json j_mset(c_mset); - CHECK(j_mset.type() == json::value_type::array); + CHECK(j_mset.type() == json::value_t::array); CHECK(j_mset.size() == 4); std::unordered_multiset c_umset {"one", "two", "one", "four"}; json j_umset(c_umset); - CHECK(j_umset.type() == json::value_type::array); + CHECK(j_umset.type() == json::value_t::array); CHECK(j_umset.size() == 4); std::deque c_deque {1.2, 2.3, 3.4, 5.6}; json j_deque(c_deque); - CHECK(j_deque.type() == json::value_type::array); + CHECK(j_deque.type() == json::value_t::array); CHECK(j_deque.size() == 4); std::list c_list {true, true, false, true}; json j_list(c_list); - CHECK(j_list.type() == json::value_type::array); + CHECK(j_list.type() == json::value_t::array); CHECK(j_list.size() == 4); std::forward_list c_flist {12345678909876, 23456789098765, 34567890987654, 45678909876543}; json j_flist(c_flist); - CHECK(j_flist.type() == json::value_type::array); + CHECK(j_flist.type() == json::value_t::array); CHECK(j_flist.size() == 4); std::array c_array {{1, 2, 3, 4}}; json j_array(c_array); - CHECK(j_array.type() == json::value_type::array); + CHECK(j_array.type() == json::value_t::array); CHECK(j_array.size() == 4); } } @@ -388,8 +390,8 @@ TEST_CASE("object") SECTION("Basics") { // construction with given type - json j(json::value_type::object); - CHECK(j.type() == json::value_type::object); + json j(json::value_t::object); + CHECK(j.type() == json::value_t::object); // const object const json j_const = j; @@ -403,7 +405,9 @@ TEST_CASE("object") // container members CHECK(j.size() == 0); + CHECK(j.max_size() > 0); CHECK(j.empty() == true); + CHECK_NOTHROW(size_t h = std::hash()(j)); // implicit conversions CHECK_THROWS_AS(json::array_t v = j, std::logic_error); @@ -604,7 +608,7 @@ TEST_CASE("object") // implicit transformation into an object json empty; empty["foo"] = "bar"; - CHECK(empty.type() == json::value_type::object); + CHECK(empty.type() == json::value_t::object); CHECK(empty["foo"] == "bar"); // exceptions @@ -649,8 +653,8 @@ TEST_CASE("object") CHECK(false); } - CHECK((*it).type() == json::value_type::number); - CHECK(it->type() == json::value_type::number); + CHECK((*it).type() == json::value_t::number); + CHECK(it->type() == json::value_t::number); } // range-based for @@ -680,8 +684,8 @@ TEST_CASE("object") CHECK(false); } - CHECK((*it).type() == json::value_type::number); - CHECK(it->type() == json::value_type::number); + CHECK((*it).type() == json::value_t::number); + CHECK(it->type() == json::value_t::number); } // const_iterator using cbegin/cend @@ -705,8 +709,8 @@ TEST_CASE("object") CHECK(false); } - CHECK((*it).type() == json::value_type::number); - CHECK(it->type() == json::value_type::number); + CHECK((*it).type() == json::value_t::number); + CHECK(it->type() == json::value_t::number); } // const_iterator (on const object) @@ -730,8 +734,8 @@ TEST_CASE("object") CHECK(false); } - CHECK((*it).type() == json::value_type::number); - CHECK(it->type() == json::value_type::number); + CHECK((*it).type() == json::value_t::number); + CHECK(it->type() == json::value_t::number); } // const_iterator using cbegin/cend (on const object) @@ -755,8 +759,8 @@ TEST_CASE("object") CHECK(false); } - CHECK((*it).type() == json::value_type::number); - CHECK(it->type() == json::value_type::number); + CHECK((*it).type() == json::value_t::number); + CHECK(it->type() == json::value_t::number); } // range-based for (on const object) @@ -768,7 +772,7 @@ TEST_CASE("object") SECTION("Iterators and empty objects") { - json empty_object(json::value_type::object); + json empty_object(json::value_t::object); for (json::iterator it = empty_object.begin(); it != empty_object.end(); ++it) {} for (json::const_iterator it = empty_object.begin(); it != empty_object.end(); ++it) {} for (json::const_iterator it = empty_object.cbegin(); it != empty_object.cend(); ++it) {} @@ -806,22 +810,22 @@ TEST_CASE("object") { std::map c_map { {"one", 1}, {"two", 2}, {"three", 3} }; json j_map(c_map); - CHECK(j_map.type() == json::value_type::object); + CHECK(j_map.type() == json::value_t::object); CHECK(j_map.size() == 3); std::unordered_map c_umap { {"one", 1.2}, {"two", 2.3}, {"three", 3.4} }; json j_umap(c_umap); - CHECK(j_umap.type() == json::value_type::object); + CHECK(j_umap.type() == json::value_t::object); CHECK(j_umap.size() == 3); std::multimap c_mmap { {"one", true}, {"two", true}, {"three", false}, {"three", true} }; json j_mmap(c_mmap); - CHECK(j_mmap.type() == json::value_type::object); + CHECK(j_mmap.type() == json::value_t::object); CHECK(j_mmap.size() == 3); std::unordered_multimap c_ummap { {"one", true}, {"two", true}, {"three", false}, {"three", true} }; json j_ummap(c_ummap); - CHECK(j_ummap.type() == json::value_type::object); + CHECK(j_ummap.type() == json::value_t::object); CHECK(j_ummap.size() == 3); } } @@ -832,7 +836,7 @@ TEST_CASE("null") { // construction with given type json j; - CHECK(j.type() == json::value_type::null); + CHECK(j.type() == json::value_t::null); // string representation of default value CHECK(j.dump() == "null"); @@ -843,7 +847,9 @@ TEST_CASE("null") // container members CHECK(j.size() == 0); + CHECK(j.max_size() == 0); CHECK(j.empty() == true); + CHECK_NOTHROW(size_t h = std::hash()(j)); // implicit conversions CHECK_NOTHROW(json::array_t v = j); @@ -878,7 +884,7 @@ TEST_CASE("null") SECTION("Create from value") { json j1 = nullptr; - CHECK(j1.type() == json::value_type::null); + CHECK(j1.type() == json::value_t::null); } SECTION("Operators") @@ -911,8 +917,8 @@ TEST_CASE("string") SECTION("Basics") { // construction with given type - json j(json::value_type::string); - CHECK(j.type() == json::value_type::string); + json j(json::value_t::string); + CHECK(j.type() == json::value_t::string); // const object const json j_const = j; @@ -926,7 +932,9 @@ TEST_CASE("string") // container members CHECK(j.size() == 1); + CHECK(j.max_size() == 1); CHECK(j.empty() == false); + CHECK_NOTHROW(size_t h = std::hash()(j)); // implicit conversions CHECK_NOTHROW(json::array_t v = j); @@ -1022,8 +1030,8 @@ TEST_CASE("boolean") SECTION("Basics") { // construction with given type - json j(json::value_type::boolean); - CHECK(j.type() == json::value_type::boolean); + json j(json::value_t::boolean); + CHECK(j.type() == json::value_t::boolean); // const object const json j_const = j; @@ -1037,7 +1045,9 @@ TEST_CASE("boolean") // container members CHECK(j.size() == 1); + CHECK(j.max_size() == 1); CHECK(j.empty() == false); + CHECK_NOTHROW(size_t h = std::hash()(j)); // implicit conversions CHECK_NOTHROW(json::array_t v = j); @@ -1118,8 +1128,8 @@ TEST_CASE("number (int)") SECTION("Basics") { // construction with given type - json j(json::value_type::number); - CHECK(j.type() == json::value_type::number); + json j(json::value_t::number); + CHECK(j.type() == json::value_t::number); // const object const json j_const = j; @@ -1133,7 +1143,9 @@ TEST_CASE("number (int)") // container members CHECK(j.size() == 1); + CHECK(j.max_size() == 1); CHECK(j.empty() == false); + CHECK_NOTHROW(size_t h = std::hash()(j)); // implicit conversions CHECK_NOTHROW(json::array_t v = j); @@ -1229,8 +1241,8 @@ TEST_CASE("number (float)") SECTION("Basics") { // construction with given type - json j(json::value_type::number_float); - CHECK(j.type() == json::value_type::number_float); + json j(json::value_t::number_float); + CHECK(j.type() == json::value_t::number_float); // const object const json j_const = j; @@ -1244,7 +1256,9 @@ TEST_CASE("number (float)") // container members CHECK(j.size() == 1); + CHECK(j.max_size() == 1); CHECK(j.empty() == false); + CHECK_NOTHROW(size_t h = std::hash()(j)); // implicit conversions CHECK_NOTHROW(json::array_t v = j); @@ -1388,35 +1402,35 @@ TEST_CASE("Iterators") CHECK_THROWS_AS(* j7_const.cend(), std::runtime_error); // operator -> - CHECK(j1.begin()->type() == json::value_type::number); - CHECK(j1.cbegin()->type() == json::value_type::number); - CHECK(j2.begin()->type() == json::value_type::string); - CHECK(j2.cbegin()->type() == json::value_type::string); - CHECK(j3.begin()->type() == json::value_type::boolean); - CHECK(j3.cbegin()->type() == json::value_type::boolean); - CHECK(j4.begin()->type() == json::value_type::null); - CHECK(j4.cbegin()->type() == json::value_type::null); - CHECK(j5.begin()->type() == json::value_type::number); - CHECK(j5.cbegin()->type() == json::value_type::number); - CHECK(j6.begin()->type() == json::value_type::number_float); - CHECK(j6.cbegin()->type() == json::value_type::number_float); - CHECK(j7.begin()->type() == json::value_type::string); - CHECK(j7.cbegin()->type() == json::value_type::string); + CHECK(j1.begin()->type() == json::value_t::number); + CHECK(j1.cbegin()->type() == json::value_t::number); + CHECK(j2.begin()->type() == json::value_t::string); + CHECK(j2.cbegin()->type() == json::value_t::string); + CHECK(j3.begin()->type() == json::value_t::boolean); + CHECK(j3.cbegin()->type() == json::value_t::boolean); + CHECK(j4.begin()->type() == json::value_t::null); + CHECK(j4.cbegin()->type() == json::value_t::null); + CHECK(j5.begin()->type() == json::value_t::number); + CHECK(j5.cbegin()->type() == json::value_t::number); + CHECK(j6.begin()->type() == json::value_t::number_float); + CHECK(j6.cbegin()->type() == json::value_t::number_float); + CHECK(j7.begin()->type() == json::value_t::string); + CHECK(j7.cbegin()->type() == json::value_t::string); - CHECK(j1_const.begin()->type() == json::value_type::number); - CHECK(j1_const.cbegin()->type() == json::value_type::number); - CHECK(j2_const.begin()->type() == json::value_type::string); - CHECK(j2_const.cbegin()->type() == json::value_type::string); - CHECK(j3_const.begin()->type() == json::value_type::boolean); - CHECK(j3_const.cbegin()->type() == json::value_type::boolean); - CHECK(j4_const.begin()->type() == json::value_type::null); - CHECK(j4_const.cbegin()->type() == json::value_type::null); - CHECK(j5_const.begin()->type() == json::value_type::number); - CHECK(j5_const.cbegin()->type() == json::value_type::number); - CHECK(j6_const.begin()->type() == json::value_type::number_float); - CHECK(j6_const.cbegin()->type() == json::value_type::number_float); - CHECK(j7_const.begin()->type() == json::value_type::string); - CHECK(j7_const.cbegin()->type() == json::value_type::string); + CHECK(j1_const.begin()->type() == json::value_t::number); + CHECK(j1_const.cbegin()->type() == json::value_t::number); + CHECK(j2_const.begin()->type() == json::value_t::string); + CHECK(j2_const.cbegin()->type() == json::value_t::string); + CHECK(j3_const.begin()->type() == json::value_t::boolean); + CHECK(j3_const.cbegin()->type() == json::value_t::boolean); + CHECK(j4_const.begin()->type() == json::value_t::null); + CHECK(j4_const.cbegin()->type() == json::value_t::null); + CHECK(j5_const.begin()->type() == json::value_t::number); + CHECK(j5_const.cbegin()->type() == json::value_t::number); + CHECK(j6_const.begin()->type() == json::value_t::number_float); + CHECK(j6_const.cbegin()->type() == json::value_t::number_float); + CHECK(j7_const.begin()->type() == json::value_t::string); + CHECK(j7_const.cbegin()->type() == json::value_t::string); CHECK_THROWS_AS(j1.end()->type(), std::runtime_error); CHECK_THROWS_AS(j1.cend()->type(), std::runtime_error); @@ -1449,35 +1463,35 @@ TEST_CASE("Iterators") CHECK_THROWS_AS(j7_const.cend()->type(), std::runtime_error); // value - CHECK(j1.begin().value().type() == json::value_type::number); - CHECK(j1.cbegin().value().type() == json::value_type::number); - CHECK(j2.begin().value().type() == json::value_type::string); - CHECK(j2.cbegin().value().type() == json::value_type::string); - CHECK(j3.begin().value().type() == json::value_type::boolean); - CHECK(j3.cbegin().value().type() == json::value_type::boolean); - CHECK(j4.begin().value().type() == json::value_type::null); - CHECK(j4.cbegin().value().type() == json::value_type::null); - CHECK(j5.begin().value().type() == json::value_type::number); - CHECK(j5.cbegin().value().type() == json::value_type::number); - CHECK(j6.begin().value().type() == json::value_type::number_float); - CHECK(j6.cbegin().value().type() == json::value_type::number_float); - CHECK(j7.begin().value().type() == json::value_type::string); - CHECK(j7.cbegin().value().type() == json::value_type::string); + CHECK(j1.begin().value().type() == json::value_t::number); + CHECK(j1.cbegin().value().type() == json::value_t::number); + CHECK(j2.begin().value().type() == json::value_t::string); + CHECK(j2.cbegin().value().type() == json::value_t::string); + CHECK(j3.begin().value().type() == json::value_t::boolean); + CHECK(j3.cbegin().value().type() == json::value_t::boolean); + CHECK(j4.begin().value().type() == json::value_t::null); + CHECK(j4.cbegin().value().type() == json::value_t::null); + CHECK(j5.begin().value().type() == json::value_t::number); + CHECK(j5.cbegin().value().type() == json::value_t::number); + CHECK(j6.begin().value().type() == json::value_t::number_float); + CHECK(j6.cbegin().value().type() == json::value_t::number_float); + CHECK(j7.begin().value().type() == json::value_t::string); + CHECK(j7.cbegin().value().type() == json::value_t::string); - CHECK(j1_const.begin().value().type() == json::value_type::number); - CHECK(j1_const.cbegin().value().type() == json::value_type::number); - CHECK(j2_const.begin().value().type() == json::value_type::string); - CHECK(j2_const.cbegin().value().type() == json::value_type::string); - CHECK(j3_const.begin().value().type() == json::value_type::boolean); - CHECK(j3_const.cbegin().value().type() == json::value_type::boolean); - CHECK(j4_const.begin().value().type() == json::value_type::null); - CHECK(j4_const.cbegin().value().type() == json::value_type::null); - CHECK(j5_const.begin().value().type() == json::value_type::number); - CHECK(j5_const.cbegin().value().type() == json::value_type::number); - CHECK(j6_const.begin().value().type() == json::value_type::number_float); - CHECK(j6_const.cbegin().value().type() == json::value_type::number_float); - CHECK(j7_const.begin().value().type() == json::value_type::string); - CHECK(j7_const.cbegin().value().type() == json::value_type::string); + CHECK(j1_const.begin().value().type() == json::value_t::number); + CHECK(j1_const.cbegin().value().type() == json::value_t::number); + CHECK(j2_const.begin().value().type() == json::value_t::string); + CHECK(j2_const.cbegin().value().type() == json::value_t::string); + CHECK(j3_const.begin().value().type() == json::value_t::boolean); + CHECK(j3_const.cbegin().value().type() == json::value_t::boolean); + CHECK(j4_const.begin().value().type() == json::value_t::null); + CHECK(j4_const.cbegin().value().type() == json::value_t::null); + CHECK(j5_const.begin().value().type() == json::value_t::number); + CHECK(j5_const.cbegin().value().type() == json::value_t::number); + CHECK(j6_const.begin().value().type() == json::value_t::number_float); + CHECK(j6_const.cbegin().value().type() == json::value_t::number_float); + CHECK(j7_const.begin().value().type() == json::value_t::string); + CHECK(j7_const.cbegin().value().type() == json::value_t::string); CHECK_THROWS_AS(j1.end().value(), std::out_of_range); CHECK_THROWS_AS(j1.cend().value(), std::out_of_range);