*/
bool Json::operator== (const Json &other) const {
+ if (m_ptr == other.m_ptr)
+ return true;
if (m_ptr->type() != other.m_ptr->type())
return false;
}
bool Json::operator< (const Json &other) const {
+ if (m_ptr == other.m_ptr)
+ return false;
if (m_ptr->type() != other.m_ptr->type())
return m_ptr->type() < other.m_ptr->type();
if (str[i] == '/') {
i++;
if (i == str.size())
- return fail("unexpected end of input inside comment", false);
+ return fail("unexpected end of input after start of comment", false);
if (str[i] == '/') { // inline comment
i++;
- if (i == str.size())
- return fail("unexpected end of input inside inline comment", false);
- // advance until next line
- while (str[i] != '\n') {
+ // advance until next line, or end of input
+ while (i < str.size() && str[i] != '\n') {
i++;
- if (i == str.size())
- return fail("unexpected end of input inside inline comment", false);
}
comment_found = true;
}
"unexpected end of input inside multi-line comment", false);
}
i += 2;
- if (i == str.size())
- return fail(
- "unexpected end of input inside multi-line comment", false);
comment_found = true;
}
else
bool comment_found = false;
do {
comment_found = consume_comment();
+ if (failed) return;
consume_whitespace();
}
while(comment_found);
*/
char get_next_token() {
consume_garbage();
+ if (failed) return (char)0;
if (i == str.size())
return fail("unexpected end of input", (char)0);
// Check for any trailing garbage
parser.consume_garbage();
+ if (parser.failed)
+ return Json();
if (parser.i != in.size())
return parser.fail("unexpected trailing " + esc(in[parser.i]));
vector<Json> json_vec;
while (parser.i != in.size() && !parser.failed) {
json_vec.push_back(parser.parse_json(0));
+ if (parser.failed)
+ break;
+
// Check for another object
parser.consume_garbage();
- if (!parser.failed)
- parser_stop_pos = parser.i;
+ if (parser.failed)
+ break;
+ parser_stop_pos = parser.i;
}
return json_vec;
}
return false;
}
+ const auto& obj_items = object_items();
for (auto & item : types) {
- if ((*this)[item.first].type() != item.second) {
+ const auto it = obj_items.find(item.first);
+ if (it == obj_items.cend() || it->second.type() != item.second) {
err = "bad type for " + item.first + " in " + dump();
return false;
}
// Implicit constructor: map-like objects (std::map, std::unordered_map, etc)
template <class M, typename std::enable_if<
- std::is_constructible<std::string, typename M::key_type>::value
- && std::is_constructible<Json, typename M::mapped_type>::value,
+ std::is_constructible<std::string, decltype(std::declval<M>().begin()->first)>::value
+ && std::is_constructible<Json, decltype(std::declval<M>().begin()->second)>::value,
int>::type = 0>
Json(const M & m) : Json(object(m.begin(), m.end())) {}
// Implicit constructor: vector-like objects (std::list, std::vector, std::set, etc)
template <class V, typename std::enable_if<
- std::is_constructible<Json, typename V::value_type>::value,
+ std::is_constructible<Json, decltype(*std::declval<V>().begin())>::value,
int>::type = 0>
Json(const V & v) : Json(array(v.begin(), v.end())) {}