Unverified Commit f47cf152 authored by Niels Lohmann's avatar Niels Lohmann

Merge branch 'develop' into feature/manual_lexer

parents dc6e9b61 d4d51460
......@@ -706,6 +706,7 @@ Though it's 2016 already, the support for C++11 is still a bit sparse. Currently
- GCC 4.9 - 6.0 (and possibly later)
- Clang 3.4 - 3.9 (and possibly later)
- Microsoft Visual C++ 2015 / Build Tools 14.0.25123.0 (and possibly later)
- Microsoft Visual C++ 2017 / Build Tools 15.1.548.43366 (and possibly later)
I would be happy to learn about other compilers/versions.
......@@ -744,7 +745,7 @@ The following compilers are currently used in continuous integration at [Travis]
| Clang Xcode 8.1 | Darwin Kernel Version 16.1.0 (macOS 10.12.1) | Apple LLVM version 8.0.0 (clang-800.0.42.1) |
| Clang Xcode 8.2 | Darwin Kernel Version 16.1.0 (macOS 10.12.1) | Apple LLVM version 8.0.0 (clang-800.0.42.1) |
| Visual Studio 14 2015 | Windows Server 2012 R2 (x64) | Microsoft (R) Build Engine version 14.0.25123.0 |
| Visual Studio 2017 | Windows Server 2016 | Microsoft (R) Build Engine version 15.1.548.43366 |
## License
......@@ -809,7 +810,7 @@ I deeply appreciate the help of the following people.
- [Stefan](https://github.com/5tefan) fixed a minor issue in the documentation.
- [Vasil Dimov](https://github.com/vasild) fixed the documentation regarding conversions from `std::multiset`.
- [ChristophJud](https://github.com/ChristophJud) overworked the CMake files to ease project inclusion.
- [Vladimir Petrigo](https://github.com/vpetrigo) made a SFINAE hack more readable.
- [Vladimir Petrigo](https://github.com/vpetrigo) made a SFINAE hack more readable and added Visual Studio 17 to the build matrix.
- [Denis Andrejew](https://github.com/seeekr) fixed a grammar issue in the README file.
- [Pierre-Antoine Lacaze](https://github.com/palacaze) found a subtle bug in the `dump()` function.
- [TurpentineDistillery](https://github.com/TurpentineDistillery) pointed to [`std::locale::classic()`](http://en.cppreference.com/w/cpp/locale/locale/classic) to avoid too much locale joggling, found some nice performance improvements in the parser, improved the benchmarking code, and realized locale-independent number parsing and printing.
......@@ -893,7 +894,7 @@ $ make json_unit -Ctest
$ ./test/json_unit "*"
===============================================================================
All tests passed (11202597 assertions in 47 test cases)
All tests passed (11203022 assertions in 48 test cases)
```
Alternatively, you can use [CMake](https://cmake.org) and run
......
......@@ -120,29 +120,38 @@ namespace detail
Extension of std::exception objects with a member @a id for exception ids.
@note To have nothrow-copy-constructible exceptions, we internally use
std::runtime_error which can cope with arbitrary-length error messages.
Intermediate strings are built with static functions and then passed to
the actual constructor.
@since version 3.0.0
*/
class exception : public std::exception
{
public:
/// create exception with id an explanatory string
exception(int id_, const std::string& ename, const std::string& what_arg_)
: id(id_),
what_arg("[json.exception." + ename + "." + std::to_string(id_) + "] " + what_arg_)
{}
/// returns the explanatory string
virtual const char* what() const noexcept override
{
return what_arg.c_str();
return m.what();
}
/// the id of the exception
const int id;
protected:
exception(int id_, const char* what_arg)
: id(id_), m(what_arg)
{}
static std::string name(const std::string& ename, int id)
{
return "[json.exception." + ename + "." + std::to_string(id) + "] ";
}
private:
/// the explanatory string
const std::string what_arg;
/// an exception object as storage for error messages
std::runtime_error m;
};
/*!
......@@ -185,17 +194,19 @@ class parse_error : public exception
public:
/*!
@brief create a parse error exception
@param[in] id_ the id of the exception
@param[in] id the id of the exception
@param[in] byte_ the byte index where the error occured (or 0 if
the position cannot be determined)
@param[in] what_arg_ the explanatory string
@param[in] what_arg the explanatory string
@return parse_error object
*/
parse_error(int id_, size_t byte_, const std::string& what_arg_)
: exception(id_, "parse_error", "parse error" +
static parse_error create(int id, size_t byte_, const std::string& what_arg)
{
std::string w = exception::name("parse_error", id) + "parse error" +
(byte_ != 0 ? (" at " + std::to_string(byte_)) : "") +
": " + what_arg_),
byte(byte_)
{}
": " + what_arg;
return parse_error(id, byte_, w.c_str());
}
/*!
@brief byte index of the parse error
......@@ -208,6 +219,11 @@ class parse_error : public exception
MessagePack).
*/
const size_t byte;
private:
parse_error(int id, size_t byte_, const char* what_arg)
: exception(id, what_arg), byte(byte_)
{}
};
/*!
......@@ -237,8 +253,15 @@ json.exception.invalid_iterator.214 | cannot get value | Cannot get value for it
class invalid_iterator : public exception
{
public:
invalid_iterator(int id_, const std::string& what_arg_)
: exception(id_, "invalid_iterator", what_arg_)
static invalid_iterator create(int id, const std::string& what_arg)
{
std::string w = exception::name("invalid_iterator", id) + what_arg;
return invalid_iterator(id, w.c_str());
}
private:
invalid_iterator(int id, const char* what_arg)
: exception(id, what_arg)
{}
};
......@@ -269,8 +292,15 @@ json.exception.type_error.315 | values in object must be primitive | The @ref un
class type_error : public exception
{
public:
type_error(int id_, const std::string& what_arg_)
: exception(id_, "type_error", what_arg_)
static type_error create(int id, const std::string& what_arg)
{
std::string w = exception::name("type_error", id) + what_arg;
return type_error(id, w.c_str());
}
private:
type_error(int id, const char* what_arg)
: exception(id, what_arg)
{}
};
......@@ -293,8 +323,15 @@ json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed n
class out_of_range : public exception
{
public:
out_of_range(int id_, const std::string& what_arg_)
: exception(id_, "out_of_range", what_arg_)
static out_of_range create(int id, const std::string& what_arg)
{
std::string w = exception::name("out_of_range", id) + what_arg;
return out_of_range(id, w.c_str());
}
private:
out_of_range(int id, const char* what_arg)
: exception(id, what_arg)
{}
};
......@@ -312,8 +349,15 @@ json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "valu
class other_error : public exception
{
public:
other_error(int id_, const std::string& what_arg_)
: exception(id_, "other_error", what_arg_)
static other_error create(int id, const std::string& what_arg)
{
std::string w = exception::name("other_error", id) + what_arg;
return other_error(id, w.c_str());
}
private:
other_error(int id, const char* what_arg)
: exception(id, what_arg)
{}
};
......@@ -845,7 +889,7 @@ void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)
}
default:
{
JSON_THROW(type_error(302, "type must be number, but is " + j.type_name()));
JSON_THROW(type_error::create(302, "type must be number, but is " + j.type_name()));
}
}
}
......@@ -855,7 +899,7 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b)
{
if (not j.is_boolean())
{
JSON_THROW(type_error(302, "type must be boolean, but is " + j.type_name()));
JSON_THROW(type_error::create(302, "type must be boolean, but is " + j.type_name()));
}
b = *j.template get_ptr<const typename BasicJsonType::boolean_t*>();
}
......@@ -865,7 +909,7 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)
{
if (not j.is_string())
{
JSON_THROW(type_error(302, "type must be string, but is " + j.type_name()));
JSON_THROW(type_error::create(302, "type must be string, but is " + j.type_name()));
}
s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
}
......@@ -902,7 +946,7 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::array_t& arr)
{
if (not j.is_array())
{
JSON_THROW(type_error(302, "type must be array, but is " + j.type_name()));
JSON_THROW(type_error::create(302, "type must be array, but is " + j.type_name()));
}
arr = *j.template get_ptr<const typename BasicJsonType::array_t*>();
}
......@@ -914,7 +958,7 @@ void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l)
{
if (not j.is_array())
{
JSON_THROW(type_error(302, "type must be array, but is " + j.type_name()));
JSON_THROW(type_error::create(302, "type must be array, but is " + j.type_name()));
}
for (auto it = j.rbegin(), end = j.rend(); it != end; ++it)
......@@ -965,7 +1009,7 @@ void from_json(const BasicJsonType& j, CompatibleArrayType& arr)
{
if (not j.is_array())
{
JSON_THROW(type_error(302, "type must be array, but is " + j.type_name()));
JSON_THROW(type_error::create(302, "type must be array, but is " + j.type_name()));
}
from_json_array_impl(j, arr, priority_tag<1> {});
......@@ -977,7 +1021,7 @@ void from_json(const BasicJsonType& j, CompatibleObjectType& obj)
{
if (not j.is_object())
{
JSON_THROW(type_error(302, "type must be object, but is " + j.type_name()));
JSON_THROW(type_error::create(302, "type must be object, but is " + j.type_name()));
}
auto inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>();
......@@ -1027,7 +1071,7 @@ void from_json(const BasicJsonType& j, ArithmeticType& val)
}
default:
{
JSON_THROW(type_error(302, "type must be number, but is " + j.type_name()));
JSON_THROW(type_error::create(302, "type must be number, but is " + j.type_name()));
}
}
}
......@@ -1974,7 +2018,7 @@ class basic_json
{
if (JSON_UNLIKELY(t == value_t::null))
{
JSON_THROW(other_error(500, "961c151d2e87f2686a955a9be24d316f1362bf21 2.1.1")); // LCOV_EXCL_LINE
JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 2.1.1")); // LCOV_EXCL_LINE
}
break;
}
......@@ -2329,7 +2373,7 @@ class basic_json
// if object is wanted but impossible, throw an exception
if (manual_type == value_t::object and not is_an_object)
{
JSON_THROW(type_error(301, "cannot create object from initializer list"));
JSON_THROW(type_error::create(301, "cannot create object from initializer list"));
}
}
......@@ -2513,7 +2557,7 @@ class basic_json
// make sure iterator fits the current value
if (first.m_object != last.m_object)
{
JSON_THROW(invalid_iterator(201, "iterators are not compatible"));
JSON_THROW(invalid_iterator::create(201, "iterators are not compatible"));
}
// copy type from first iterator
......@@ -2530,7 +2574,7 @@ class basic_json
{
if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end())
{
JSON_THROW(invalid_iterator(204, "iterators out of range"));
JSON_THROW(invalid_iterator::create(204, "iterators out of range"));
}
break;
}
......@@ -2589,7 +2633,7 @@ class basic_json
default:
{
JSON_THROW(invalid_iterator(206, "cannot construct with iterators from " +
JSON_THROW(invalid_iterator::create(206, "cannot construct with iterators from " +
first.m_object->type_name()));
}
}
......@@ -3228,7 +3272,7 @@ class basic_json
return m_value.boolean;
}
JSON_THROW(type_error(302, "type must be boolean, but is " + type_name()));
JSON_THROW(type_error::create(302, "type must be boolean, but is " + type_name()));
}
/// get a pointer to the value (object)
......@@ -3340,7 +3384,7 @@ class basic_json
return *ptr;
}
JSON_THROW(type_error(303, "incompatible ReferenceType for get_ref, actual type is " + obj.type_name()));
JSON_THROW(type_error::create(303, "incompatible ReferenceType for get_ref, actual type is " + obj.type_name()));
}
public:
......@@ -3742,12 +3786,12 @@ class basic_json
JSON_CATCH (std::out_of_range&)
{
// create better exception explanation
JSON_THROW(out_of_range(401, "array index " + std::to_string(idx) + " is out of range"));
JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range"));
}
}
else
{
JSON_THROW(type_error(304, "cannot use at() with " + type_name()));
JSON_THROW(type_error::create(304, "cannot use at() with " + type_name()));
}
}
......@@ -3789,12 +3833,12 @@ class basic_json
JSON_CATCH (std::out_of_range&)
{
// create better exception explanation
JSON_THROW(out_of_range(401, "array index " + std::to_string(idx) + " is out of range"));
JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range"));
}
}
else
{
JSON_THROW(type_error(304, "cannot use at() with " + type_name()));
JSON_THROW(type_error::create(304, "cannot use at() with " + type_name()));
}
}
......@@ -3840,12 +3884,12 @@ class basic_json
JSON_CATCH (std::out_of_range&)
{
// create better exception explanation
JSON_THROW(out_of_range(403, "key '" + key + "' not found"));
JSON_THROW(out_of_range::create(403, "key '" + key + "' not found"));
}
}
else
{
JSON_THROW(type_error(304, "cannot use at() with " + type_name()));
JSON_THROW(type_error::create(304, "cannot use at() with " + type_name()));
}
}
......@@ -3891,12 +3935,12 @@ class basic_json
JSON_CATCH (std::out_of_range&)
{
// create better exception explanation
JSON_THROW(out_of_range(403, "key '" + key + "' not found"));
JSON_THROW(out_of_range::create(403, "key '" + key + "' not found"));
}
}
else
{
JSON_THROW(type_error(304, "cannot use at() with " + type_name()));
JSON_THROW(type_error::create(304, "cannot use at() with " + type_name()));
}
}
......@@ -3949,7 +3993,7 @@ class basic_json
return m_value.array->operator[](idx);
}
JSON_THROW(type_error(305, "cannot use operator[] with " + type_name()));
JSON_THROW(type_error::create(305, "cannot use operator[] with " + type_name()));
}
/*!
......@@ -3979,7 +4023,7 @@ class basic_json
return m_value.array->operator[](idx);
}
JSON_THROW(type_error(305, "cannot use operator[] with " + type_name()));
JSON_THROW(type_error::create(305, "cannot use operator[] with " + type_name()));
}
/*!
......@@ -4025,7 +4069,7 @@ class basic_json
return m_value.object->operator[](key);
}
JSON_THROW(type_error(305, "cannot use operator[] with " + type_name()));
JSON_THROW(type_error::create(305, "cannot use operator[] with " + type_name()));
}
/*!
......@@ -4067,7 +4111,7 @@ class basic_json
return m_value.object->find(key)->second;
}
JSON_THROW(type_error(305, "cannot use operator[] with " + type_name()));
JSON_THROW(type_error::create(305, "cannot use operator[] with " + type_name()));
}
/*!
......@@ -4182,7 +4226,7 @@ class basic_json
return m_value.object->operator[](key);
}
JSON_THROW(type_error(305, "cannot use operator[] with " + type_name()));
JSON_THROW(type_error::create(305, "cannot use operator[] with " + type_name()));
}
/*!
......@@ -4225,7 +4269,7 @@ class basic_json
return m_value.object->find(key)->second;
}
JSON_THROW(type_error(305, "cannot use operator[] with " + type_name()));
JSON_THROW(type_error::create(305, "cannot use operator[] with " + type_name()));
}
/*!
......@@ -4294,7 +4338,7 @@ class basic_json
}
else
{
JSON_THROW(type_error(306, "cannot use value() with " + type_name()));
JSON_THROW(type_error::create(306, "cannot use value() with " + type_name()));
}
}
......@@ -4366,7 +4410,7 @@ class basic_json
}
}
JSON_THROW(type_error(306, "cannot use value() with " + type_name()));
JSON_THROW(type_error::create(306, "cannot use value() with " + type_name()));
}
/*!
......@@ -4519,7 +4563,7 @@ class basic_json
// make sure iterator fits the current value
if (this != pos.m_object)
{
JSON_THROW(invalid_iterator(202, "iterator does not fit current value"));
JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value"));
}
IteratorType result = end();
......@@ -4534,7 +4578,7 @@ class basic_json
{
if (not pos.m_it.primitive_iterator.is_begin())
{
JSON_THROW(invalid_iterator(205, "iterator out of range"));
JSON_THROW(invalid_iterator::create(205, "iterator out of range"));
}
if (is_string())
......@@ -4564,7 +4608,7 @@ class basic_json
default:
{
JSON_THROW(type_error(307, "cannot use erase() with " + type_name()));
JSON_THROW(type_error::create(307, "cannot use erase() with " + type_name()));
}
}
......@@ -4626,7 +4670,7 @@ class basic_json
// make sure iterator fits the current value
if (this != first.m_object or this != last.m_object)
{
JSON_THROW(invalid_iterator(203, "iterators do not fit current value"));
JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value"));
}
IteratorType result = end();
......@@ -4641,7 +4685,7 @@ class basic_json
{
if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end())
{
JSON_THROW(invalid_iterator(204, "iterators out of range"));
JSON_THROW(invalid_iterator::create(204, "iterators out of range"));
}
if (is_string())
......@@ -4673,7 +4717,7 @@ class basic_json
default:
{
JSON_THROW(type_error(307, "cannot use erase() with " + type_name()));
JSON_THROW(type_error::create(307, "cannot use erase() with " + type_name()));
}
}
......@@ -4717,7 +4761,7 @@ class basic_json
return m_value.object->erase(key);
}
JSON_THROW(type_error(307, "cannot use erase() with " + type_name()));
JSON_THROW(type_error::create(307, "cannot use erase() with " + type_name()));
}
/*!
......@@ -4751,14 +4795,14 @@ class basic_json
{
if (idx >= size())
{
JSON_THROW(out_of_range(401, "array index " + std::to_string(idx) + " is out of range"));
JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range"));
}
m_value.array->erase(m_value.array->begin() + static_cast<difference_type>(idx));
}
else
{
JSON_THROW(type_error(307, "cannot use erase() with " + type_name()));
JSON_THROW(type_error::create(307, "cannot use erase() with " + type_name()));
}
}
......@@ -5476,7 +5520,7 @@ class basic_json
// push_back only works for null objects or arrays
if (not(is_null() or is_array()))
{
JSON_THROW(type_error(308, "cannot use push_back() with " + type_name()));
JSON_THROW(type_error::create(308, "cannot use push_back() with " + type_name()));
}
// transform null object into an array
......@@ -5512,7 +5556,7 @@ class basic_json
// push_back only works for null objects or arrays
if (not(is_null() or is_array()))
{
JSON_THROW(type_error(308, "cannot use push_back() with " + type_name()));
JSON_THROW(type_error::create(308, "cannot use push_back() with " + type_name()));
}
// transform null object into an array
......@@ -5562,7 +5606,7 @@ class basic_json
// push_back only works for null objects or objects
if (not(is_null() or is_object()))
{
JSON_THROW(type_error(308, "cannot use push_back() with " + type_name()));
JSON_THROW(type_error::create(308, "cannot use push_back() with " + type_name()));
}
// transform null object into an object
......@@ -5662,7 +5706,7 @@ class basic_json
// emplace_back only works for null objects or arrays
if (not(is_null() or is_array()))
{
JSON_THROW(type_error(311, "cannot use emplace_back() with " + type_name()));
JSON_THROW(type_error::create(311, "cannot use emplace_back() with " + type_name()));
}
// transform null object into an array
......@@ -5710,7 +5754,7 @@ class basic_json
// emplace only works for null objects or arrays
if (not(is_null() or is_object()))
{
JSON_THROW(type_error(311, "cannot use emplace() with " + type_name()));
JSON_THROW(type_error::create(311, "cannot use emplace() with " + type_name()));
}
// transform null object into an object
......@@ -5761,7 +5805,7 @@ class basic_json
// check if iterator pos fits to this JSON value
if (pos.m_object != this)
{
JSON_THROW(invalid_iterator(202, "iterator does not fit current value"));
JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value"));
}
// insert to array and return iterator
......@@ -5770,7 +5814,7 @@ class basic_json
return result;
}
JSON_THROW(type_error(309, "cannot use insert() with " + type_name()));
JSON_THROW(type_error::create(309, "cannot use insert() with " + type_name()));
}
/*!
......@@ -5814,7 +5858,7 @@ class basic_json
// check if iterator pos fits to this JSON value
if (pos.m_object != this)
{
JSON_THROW(invalid_iterator(202, "iterator does not fit current value"));
JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value"));
}
// insert to array and return iterator
......@@ -5823,7 +5867,7 @@ class basic_json
return result;
}
JSON_THROW(type_error(309, "cannot use insert() with " + type_name()));
JSON_THROW(type_error::create(309, "cannot use insert() with " + type_name()));
}
/*!
......@@ -5861,24 +5905,24 @@ class basic_json
// insert only works for arrays
if (not is_array())
{
JSON_THROW(type_error(309, "cannot use insert() with " + type_name()));
JSON_THROW(type_error::create(309, "cannot use insert() with " + type_name()));
}
// check if iterator pos fits to this JSON value
if (pos.m_object != this)
{
JSON_THROW(invalid_iterator(202, "iterator does not fit current value"));
JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value"));
}
// check if range iterators belong to the same JSON object
if (first.m_object != last.m_object)
{
JSON_THROW(invalid_iterator(210, "iterators do not fit"));
JSON_THROW(invalid_iterator::create(210, "iterators do not fit"));
}
if (first.m_object == this or last.m_object == this)
{
JSON_THROW(invalid_iterator(211, "passed iterators may not belong to container"));
JSON_THROW(invalid_iterator::create(211, "passed iterators may not belong to container"));
}
// insert to array and return iterator
......@@ -5919,13 +5963,13 @@ class basic_json
// insert only works for arrays
if (not is_array())
{
JSON_THROW(type_error(309, "cannot use insert() with " + type_name()));
JSON_THROW(type_error::create(309, "cannot use insert() with " + type_name()));
}
// check if iterator pos fits to this JSON value
if (pos.m_object != this)
{
JSON_THROW(invalid_iterator(202, "iterator does not fit current value"));
JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value"));
}
// insert to array and return iterator
......@@ -5992,7 +6036,7 @@ class basic_json
}
else
{
JSON_THROW(type_error(310, "cannot use swap() with " + type_name()));
JSON_THROW(type_error::create(310, "cannot use swap() with " + type_name()));
}
}
......@@ -6025,7 +6069,7 @@ class basic_json
}
else
{
JSON_THROW(type_error(310, "cannot use swap() with " + type_name()));
JSON_THROW(type_error::create(310, "cannot use swap() with " + type_name()));
}
}
......@@ -6058,7 +6102,7 @@ class basic_json
}
else
{
JSON_THROW(type_error(310, "cannot use swap() with " + type_name()));
JSON_THROW(type_error::create(310, "cannot use swap() with " + type_name()));
}
}
......@@ -8003,19 +8047,19 @@ class basic_json
// simple case: requested length is greater than the vector's length
if (len > size or offset > size)
{
JSON_THROW(parse_error(110, offset + 1, "cannot read " + std::to_string(len) + " bytes from vector"));
JSON_THROW(parse_error::create(110, offset + 1, "cannot read " + std::to_string(len) + " bytes from vector"));
}
// second case: adding offset would result in overflow
if ((size > ((std::numeric_limits<size_t>::max)() - offset)))
{
JSON_THROW(parse_error(110, offset + 1, "cannot read " + std::to_string(len) + " bytes from vector"));
JSON_THROW(parse_error::create(110, offset + 1, "cannot read " + std::to_string(len) + " bytes from vector"));
}
// last case: reading past the end of the vector
if (len + offset > size)
{
JSON_THROW(parse_error(110, offset + 1, "cannot read " + std::to_string(len) + " bytes from vector"));
JSON_THROW(parse_error::create(110, offset + 1, "cannot read " + std::to_string(len) + " bytes from vector"));
}
}
......@@ -8047,7 +8091,7 @@ class basic_json
std::stringstream ss;
ss << std::hex << static_cast<int>(v[idx]);
JSON_THROW(parse_error(113, idx + 1, "expected a MessagePack string; last byte: 0x" + ss.str()));
JSON_THROW(parse_error::create(113, idx + 1, "expected a MessagePack string; last byte: 0x" + ss.str()));
}
/*!
......@@ -8077,7 +8121,7 @@ class basic_json
std::stringstream ss;
ss << std::hex << static_cast<int>(v[idx]);
JSON_THROW(parse_error(113, idx + 1, "expected a CBOR string; last byte: 0x" + ss.str()));
JSON_THROW(parse_error::create(113, idx + 1, "expected a CBOR string; last byte: 0x" + ss.str()));
}
/*!
......@@ -8320,7 +8364,7 @@ class basic_json
{
std::stringstream ss;
ss << std::hex << static_cast<int>(v[current_idx]);
JSON_THROW(parse_error(112, current_idx + 1, "error reading MessagePack; last byte: 0x" + ss.str()));
JSON_THROW(parse_error::create(112, current_idx + 1, "error reading MessagePack; last byte: 0x" + ss.str()));
}
}
}
......@@ -8820,7 +8864,7 @@ class basic_json
{
std::stringstream ss;
ss << std::hex << static_cast<int>(v[current_idx]);
JSON_THROW(parse_error(112, current_idx + 1, "error reading CBOR; last byte: 0x" + ss.str()));
JSON_THROW(parse_error::create(112, current_idx + 1, "error reading CBOR; last byte: 0x" + ss.str()));
}
}
}
......@@ -9701,7 +9745,7 @@ class basic_json
case basic_json::value_t::null:
{
JSON_THROW(invalid_iterator(214, "cannot get value"));
JSON_THROW(invalid_iterator::create(214, "cannot get value"));
}
default:
......@@ -9711,7 +9755,7 @@ class basic_json
return *m_object;
}
JSON_THROW(invalid_iterator(214, "cannot get value"));
JSON_THROW(invalid_iterator::create(214, "cannot get value"));
}
}
}
......@@ -9745,7 +9789,7 @@ class basic_json
return m_object;
}
JSON_THROW(invalid_iterator(214, "cannot get value"));
JSON_THROW(invalid_iterator::create(214, "cannot get value"));
}
}
}
......@@ -9845,7 +9889,7 @@ class basic_json
// if objects are not the same, the comparison is undefined
if (m_object != other.m_object)
{
JSON_THROW(invalid_iterator(212, "cannot compare iterators of different containers"));
JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers"));
}
assert(m_object != nullptr);
......@@ -9887,7 +9931,7 @@ class basic_json
// if objects are not the same, the comparison is undefined
if (m_object != other.m_object)
{
JSON_THROW(invalid_iterator(212, "cannot compare iterators of different containers"));
JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers"));
}
assert(m_object != nullptr);
......@@ -9896,7 +9940,7 @@ class basic_json
{
case basic_json::value_t::object:
{
JSON_THROW(invalid_iterator(213, "cannot compare order of object iterators"));
JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators"));
}
case basic_json::value_t::array:
......@@ -9950,7 +9994,7 @@ class basic_json
{
case basic_json::value_t::object:
{
JSON_THROW(invalid_iterator(209, "cannot use offsets with object iterators"));
JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators"));
}
case basic_json::value_t::array:
......@@ -10012,7 +10056,7 @@ class basic_json
{
case basic_json::value_t::object:
{
JSON_THROW(invalid_iterator(209, "cannot use offsets with object iterators"));
JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators"));
}
case basic_json::value_t::array:
......@@ -10039,7 +10083,7 @@ class basic_json
{
case basic_json::value_t::object:
{
JSON_THROW(invalid_iterator(208, "cannot use operator[] for object iterators"));
JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators"));
}
case basic_json::value_t::array:
......@@ -10049,7 +10093,7 @@ class basic_json
case basic_json::value_t::null:
{
JSON_THROW(invalid_iterator(214, "cannot get value"));
JSON_THROW(invalid_iterator::create(214, "cannot get value"));
}
default:
......@@ -10059,7 +10103,7 @@ class basic_json
return *m_object;
}
JSON_THROW(invalid_iterator(214, "cannot get value"));
JSON_THROW(invalid_iterator::create(214, "cannot get value"));
}
}
}
......@@ -10077,7 +10121,7 @@ class basic_json
return m_it.object_iterator->first;
}
JSON_THROW(invalid_iterator(207, "cannot use key() for non-object iterators"));
JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators"));
}
/*!
......@@ -10243,7 +10287,7 @@ class basic_json
// immediately abort if stream is erroneous
if (JSON_UNLIKELY(i.fail()))
{
JSON_THROW(parse_error(111, 0, "bad input stream"));
JSON_THROW(parse_error::create(111, 0, "bad input stream"));
}
// initial fill; unfilled buffer charaters remain EOF
......@@ -10334,7 +10378,7 @@ class basic_json
// immediately abort if stream is erroneous
if (i.fail())
{
JSON_THROW(parse_error(111, 0, "bad input stream"));
JSON_THROW(parse_error::create(111, 0, "bad input stream"));
}
}
......@@ -11334,7 +11378,7 @@ class basic_json
}
error_msg += "; expected " + lexer::token_type_name(t);
JSON_THROW(parse_error(101, m_lexer.get_position(), error_msg));
JSON_THROW(parse_error::create(101, m_lexer.get_position(), error_msg));
}
}
......@@ -11355,7 +11399,7 @@ class basic_json
error_msg += "unexpected " + lexer::token_type_name(last_token);
}
JSON_THROW(parse_error(101, m_lexer.get_position(), error_msg));
JSON_THROW(parse_error::create(101, m_lexer.get_position(), error_msg));
}
}
......@@ -11454,7 +11498,7 @@ class basic_json
{
if (is_root())
{
JSON_THROW(out_of_range(405, "JSON pointer has no parent"));
JSON_THROW(out_of_range::create(405, "JSON pointer has no parent"));
}
auto last = reference_tokens.back();
......@@ -11472,7 +11516,7 @@ class basic_json
{
if (is_root())
{
JSON_THROW(out_of_range(405, "JSON pointer has no parent"));
JSON_THROW(out_of_range::create(405, "JSON pointer has no parent"));
}
json_pointer result = *this;
......@@ -11527,9 +11571,9 @@ class basic_json
{
result = &result->operator[](static_cast<size_type>(std::stoi(reference_token)));
}
JSON_CATCH(std::invalid_argument&)
JSON_CATCH (std::invalid_argument&)
{
JSON_THROW(parse_error(109, 0, "array index '" + reference_token + "' is not a number"));
JSON_THROW(parse_error::create(109, 0, "array index '" + reference_token + "' is not a number"));
}
break;
}
......@@ -11543,7 +11587,7 @@ class basic_json
*/
default:
{
JSON_THROW(type_error(313, "invalid value to unflatten"));
JSON_THROW(type_error::create(313, "invalid value to unflatten"));
}
}
}
......@@ -11611,7 +11655,7 @@ class basic_json
// error condition (cf. RFC 6901, Sect. 4)
if (reference_token.size() > 1 and reference_token[0] == '0')
{
JSON_THROW(parse_error(106, 0, "array index '" + reference_token + "' must not begin with '0'"));
JSON_THROW(parse_error::create(106, 0, "array index '" + reference_token + "' must not begin with '0'"));
}
if (reference_token == "-")
......@@ -11626,9 +11670,9 @@ class basic_json
{
ptr = &ptr->operator[](static_cast<size_type>(std::stoi(reference_token)));
}
JSON_CATCH(std::invalid_argument&)
JSON_CATCH (std::invalid_argument&)
{
JSON_THROW(parse_error(109, 0, "array index '" + reference_token + "' is not a number"));
JSON_THROW(parse_error::create(109, 0, "array index '" + reference_token + "' is not a number"));
}
}
break;
......@@ -11636,7 +11680,7 @@ class basic_json
default:
{
JSON_THROW(out_of_range(404, "unresolved reference token '" + reference_token + "'"));
JSON_THROW(out_of_range::create(404, "unresolved reference token '" + reference_token + "'"));
}
}
}
......@@ -11668,7 +11712,7 @@ class basic_json
if (reference_token == "-")
{
// "-" always fails the range check
JSON_THROW(out_of_range(402, "array index '-' (" +
JSON_THROW(out_of_range::create(402, "array index '-' (" +
std::to_string(ptr->m_value.array->size()) +
") is out of range"));
}
......@@ -11676,7 +11720,7 @@ class basic_json
// error condition (cf. RFC 6901, Sect. 4)
if (reference_token.size() > 1 and reference_token[0] == '0')
{
JSON_THROW(parse_error(106, 0, "array index '" + reference_token + "' must not begin with '0'"));
JSON_THROW(parse_error::create(106, 0, "array index '" + reference_token + "' must not begin with '0'"));
}
// note: at performs range check
......@@ -11684,16 +11728,16 @@ class basic_json
{
ptr = &ptr->at(static_cast<size_type>(std::stoi(reference_token)));
}
JSON_CATCH(std::invalid_argument&)
JSON_CATCH (std::invalid_argument&)
{
JSON_THROW(parse_error(109, 0, "array index '" + reference_token + "' is not a number"));
JSON_THROW(parse_error::create(109, 0, "array index '" + reference_token + "' is not a number"));
}
break;
}
default:
{
JSON_THROW(out_of_range(404, "unresolved reference token '" + reference_token + "'"));
JSON_THROW(out_of_range::create(404, "unresolved reference token '" + reference_token + "'"));
}
}
}
......@@ -11732,7 +11776,7 @@ class basic_json
if (reference_token == "-")
{
// "-" cannot be used for const access
JSON_THROW(out_of_range(402, "array index '-' (" +
JSON_THROW(out_of_range::create(402, "array index '-' (" +
std::to_string(ptr->m_value.array->size()) +
") is out of range"));
}
......@@ -11740,7 +11784,7 @@ class basic_json
// error condition (cf. RFC 6901, Sect. 4)
if (reference_token.size() > 1 and reference_token[0] == '0')
{
JSON_THROW(parse_error(106, 0, "array index '" + reference_token + "' must not begin with '0'"));
JSON_THROW(parse_error::create(106, 0, "array index '" + reference_token + "' must not begin with '0'"));
}
// use unchecked array access
......@@ -11748,16 +11792,16 @@ class basic_json
{
ptr = &ptr->operator[](static_cast<size_type>(std::stoi(reference_token)));
}
JSON_CATCH(std::invalid_argument&)
JSON_CATCH (std::invalid_argument&)
{
JSON_THROW(parse_error(109, 0, "array index '" + reference_token + "' is not a number"));
JSON_THROW(parse_error::create(109, 0, "array index '" + reference_token + "' is not a number"));
}
break;
}
default:
{
JSON_THROW(out_of_range(404, "unresolved reference token '" + reference_token + "'"));
JSON_THROW(out_of_range::create(404, "unresolved reference token '" + reference_token + "'"));
}
}
}
......@@ -11789,7 +11833,7 @@ class basic_json
if (reference_token == "-")
{
// "-" always fails the range check
JSON_THROW(out_of_range(402, "array index '-' (" +
JSON_THROW(out_of_range::create(402, "array index '-' (" +
std::to_string(ptr->m_value.array->size()) +
") is out of range"));
}
......@@ -11797,7 +11841,7 @@ class basic_json
// error condition (cf. RFC 6901, Sect. 4)
if (reference_token.size() > 1 and reference_token[0] == '0')
{
JSON_THROW(parse_error(106, 0, "array index '" + reference_token + "' must not begin with '0'"));
JSON_THROW(parse_error::create(106, 0, "array index '" + reference_token + "' must not begin with '0'"));
}
// note: at performs range check
......@@ -11805,16 +11849,16 @@ class basic_json
{
ptr = &ptr->at(static_cast<size_type>(std::stoi(reference_token)));
}
JSON_CATCH(std::invalid_argument&)
JSON_CATCH (std::invalid_argument&)
{
JSON_THROW(parse_error(109, 0, "array index '" + reference_token + "' is not a number"));
JSON_THROW(parse_error::create(109, 0, "array index '" + reference_token + "' is not a number"));
}
break;
}
default:
{
JSON_THROW(out_of_range(404, "unresolved reference token '" + reference_token + "'"));
JSON_THROW(out_of_range::create(404, "unresolved reference token '" + reference_token + "'"));
}
}
}
......@@ -11844,7 +11888,7 @@ class basic_json
// check if nonempty reference string begins with slash
if (reference_string[0] != '/')
{
JSON_THROW(parse_error(107, 1, "JSON pointer must be empty or begin with '/' - was: '" + reference_string + "'"));
JSON_THROW(parse_error::create(107, 1, "JSON pointer must be empty or begin with '/' - was: '" + reference_string + "'"));
}
// extract the reference tokens:
......@@ -11879,7 +11923,7 @@ class basic_json
(reference_token[pos + 1] != '0' and
reference_token[pos + 1] != '1'))
{
JSON_THROW(parse_error(108, 0, "escape character '~' must be followed with '0' or '1'"));
JSON_THROW(parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'"));
}
}
......@@ -12010,7 +12054,7 @@ class basic_json
{
if (not value.is_object())
{
JSON_THROW(type_error(314, "only objects can be unflattened"));
JSON_THROW(type_error::create(314, "only objects can be unflattened"));
}
basic_json result;
......@@ -12020,7 +12064,7 @@ class basic_json
{
if (not element.second.is_primitive())
{
JSON_THROW(type_error(315, "values in object must be primitive"));
JSON_THROW(type_error::create(315, "values in object must be primitive"));
}
// assign value to reference pointed to by JSON pointer; Note
......@@ -12405,7 +12449,7 @@ class basic_json
if (static_cast<size_type>(idx) > parent.size())
{
// avoid undefined behavior
JSON_THROW(out_of_range(401, "array index " + std::to_string(idx) + " is out of range"));
JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range"));
}
else
{
......@@ -12443,7 +12487,7 @@ class basic_json
}
else
{
JSON_THROW(out_of_range(403, "key '" + last_path + "' not found"));
JSON_THROW(out_of_range::create(403, "key '" + last_path + "' not found"));
}
}
else if (parent.is_array())
......@@ -12456,7 +12500,7 @@ class basic_json
// type check: top level value must be an array
if (not json_patch.is_array())
{
JSON_THROW(parse_error(104, 0, "JSON patch must be an array of objects"));
JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects"));
}
// iterate and apply the operations
......@@ -12476,13 +12520,13 @@ class basic_json
// check if desired value is present
if (it == val.m_value.object->end())
{
JSON_THROW(parse_error(105, 0, error_msg + " must have member '" + member + "'"));
JSON_THROW(parse_error::create(105, 0, error_msg + " must have member '" + member + "'"));
}
// check if result is of type string
if (string_type and not it->second.is_string())
{
JSON_THROW(parse_error(105, 0, error_msg + " must have string member '" + member + "'"));
JSON_THROW(parse_error::create(105, 0, error_msg + " must have string member '" + member + "'"));
}
// no error: return value
......@@ -12492,7 +12536,7 @@ class basic_json
// type check: every element of the array must be an object
if (not val.is_object())
{
JSON_THROW(parse_error(104, 0, "JSON patch must be an array of objects"));
JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects"));
}
// collect mandatory members
......@@ -12565,7 +12609,7 @@ class basic_json
// throw an exception if test fails
if (not success)
{
JSON_THROW(other_error(501, "unsuccessful: " + val.dump()));
JSON_THROW(other_error::create(501, "unsuccessful: " + val.dump()));
}
break;
......@@ -12575,7 +12619,7 @@ class basic_json
{
// op must be "add", "remove", "replace", "move", "copy", or
// "test"
JSON_THROW(parse_error(105, 0, "operation value '" + op + "' is invalid"));
JSON_THROW(parse_error::create(105, 0, "operation value '" + op + "' is invalid"));
}
}
}
......
......@@ -57,3 +57,21 @@ static_assert(noexcept(json(pod{})), "");
static_assert(noexcept(j.get<pod>()), "");
static_assert(not noexcept(j.get<pod_bis>()), "");
static_assert(noexcept(json(pod{})), "");
TEST_CASE("runtime checks")
{
SECTION("nothrow-copy-constructible exceptions")
{
// for ERR60-CPP (https://github.com/nlohmann/json/issues/531):
// Exceptions should be nothrow-copy-constructible. However, compilers
// treat std::runtime_exception differently in this regard. Therefore,
// we can only demand nothrow-copy-constructibility for our exceptions
// if std::runtime_exception is.
CHECK(std::is_nothrow_copy_constructible<json::exception>::value == std::is_nothrow_copy_constructible<std::runtime_error>::value);
CHECK(std::is_nothrow_copy_constructible<json::parse_error>::value == std::is_nothrow_copy_constructible<std::runtime_error>::value);
CHECK(std::is_nothrow_copy_constructible<json::invalid_iterator>::value == std::is_nothrow_copy_constructible<std::runtime_error>::value);
CHECK(std::is_nothrow_copy_constructible<json::type_error>::value == std::is_nothrow_copy_constructible<std::runtime_error>::value);
CHECK(std::is_nothrow_copy_constructible<json::out_of_range>::value == std::is_nothrow_copy_constructible<std::runtime_error>::value);
CHECK(std::is_nothrow_copy_constructible<json::other_error>::value == std::is_nothrow_copy_constructible<std::runtime_error>::value);
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment