🔨 further cleanup

This commit is contained in:
Niels Lohmann 2017-07-22 13:35:04 +02:00
parent 024fec8a9b
commit f513c46749
No known key found for this signature in database
GPG key ID: 7F3CEA63AE251B69
3 changed files with 178 additions and 226 deletions

View file

@ -134,17 +134,17 @@ class basic_json;
// Ugly macros to avoid uglier copy-paste when specializing basic_json // Ugly macros to avoid uglier copy-paste when specializing basic_json
// This is only temporary and will be removed in 3.0 // This is only temporary and will be removed in 3.0
#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ #define NLOHMANN_BASIC_JSON_TPL_DECLARATION \
template <template <typename, typename, typename...> class ObjectType, \ template <template <typename, typename, typename...> class ObjectType, \
template <typename, typename...> class ArrayType, \ template <typename, typename...> class ArrayType, \
class StringType, class BooleanType, class NumberIntegerType, \ class StringType, class BooleanType, class NumberIntegerType, \
class NumberUnsignedType, class NumberFloatType, \ class NumberUnsignedType, class NumberFloatType, \
template <typename> class AllocatorType, \ template <typename> class AllocatorType, \
template <typename, typename = void> class JSONSerializer> template <typename, typename = void> class JSONSerializer>
#define NLOHMANN_BASIC_JSON_TPL \ #define NLOHMANN_BASIC_JSON_TPL \
basic_json<ObjectType, ArrayType, StringType, BooleanType, \ basic_json<ObjectType, ArrayType, StringType, BooleanType, \
NumberIntegerType, NumberUnsignedType, NumberFloatType, \ NumberIntegerType, NumberUnsignedType, NumberFloatType, \
AllocatorType, JSONSerializer> AllocatorType, JSONSerializer>
@ -189,8 +189,7 @@ class exception : public std::exception
protected: protected:
exception(int id_, const char* what_arg) exception(int id_, const char* what_arg)
: id(id_), m(what_arg) : id(id_), m(what_arg) {}
{}
static std::string name(const std::string& ename, int id) static std::string name(const std::string& ename, int id)
{ {
@ -205,17 +204,16 @@ class exception : public std::exception
/*! /*!
@brief exception indicating a parse error @brief exception indicating a parse error
This excpetion is thrown by the library when a parse error occurs. Parse This excpetion is thrown by the library when a parse error occurs. Parse errors
errors can occur during the deserialization of JSON text as well as when can occur during the deserialization of JSON text as well as when using JSON
using JSON Patch. Patch.
Member @a byte holds the byte index of the last read character in the input Member @a byte holds the byte index of the last read character in the input
file. file.
@note For an input with n bytes, 1 is the index of the first character @note For an input with n bytes, 1 is the index of the first character and n+1
and n+1 is the index of the terminating null byte or the end of is the index of the terminating null byte or the end of file. This also
file. This also holds true when reading a byte vector (CBOR or holds true when reading a byte vector (CBOR or MessagePack).
MessagePack).
Exceptions have ids 1xx. Exceptions have ids 1xx.
@ -241,10 +239,10 @@ class parse_error : public exception
public: public:
/*! /*!
@brief create a parse error exception @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 occurred (or 0 if @param[in] byte_ the byte index where the error occurred (or 0 if the
the position cannot be determined) position cannot be determined)
@param[in] what_arg the explanatory string @param[in] what_arg the explanatory string
@return parse_error object @return parse_error object
*/ */
static parse_error create(int id, std::size_t byte_, const std::string& what_arg) static parse_error create(int id, std::size_t byte_, const std::string& what_arg)
@ -260,17 +258,15 @@ class parse_error : public exception
The byte index of the last read character in the input file. The byte index of the last read character in the input file.
@note For an input with n bytes, 1 is the index of the first character @note For an input with n bytes, 1 is the index of the first character and
and n+1 is the index of the terminating null byte or the end of n+1 is the index of the terminating null byte or the end of file.
file. This also holds true when reading a byte vector (CBOR or This also holds true when reading a byte vector (CBOR or MessagePack).
MessagePack).
*/ */
const std::size_t byte; const std::size_t byte;
private: private:
parse_error(int id_, std::size_t byte_, const char* what_arg) parse_error(int id_, std::size_t byte_, const char* what_arg)
: exception(id_, what_arg), byte(byte_) : exception(id_, what_arg), byte(byte_) {}
{}
}; };
/*! /*!
@ -308,8 +304,7 @@ class invalid_iterator : public exception
private: private:
invalid_iterator(int id_, const char* what_arg) invalid_iterator(int id_, const char* what_arg)
: exception(id_, what_arg) : exception(id_, what_arg) {}
{}
}; };
/*! /*!
@ -347,8 +342,7 @@ class type_error : public exception
private: private:
type_error(int id_, const char* what_arg) type_error(int id_, const char* what_arg)
: exception(id_, what_arg) : exception(id_, what_arg) {}
{}
}; };
/*! /*!
@ -378,8 +372,7 @@ class out_of_range : public exception
private: private:
out_of_range(int id_, const char* what_arg) out_of_range(int id_, const char* what_arg)
: exception(id_, what_arg) : exception(id_, what_arg) {}
{}
}; };
/*! /*!
@ -405,8 +398,7 @@ class other_error : public exception
private: private:
other_error(int id_, const char* what_arg) other_error(int id_, const char* what_arg)
: exception(id_, what_arg) : exception(id_, what_arg) {}
{}
}; };
@ -1307,9 +1299,9 @@ class cached_input_stream_adapter : public input_adapter
{ {
// clear stream flags // clear stream flags
is.clear(); is.clear();
// We initially read a lot of characters into the buffer, and we // We initially read a lot of characters into the buffer, and we may not
// may not have processed all of them. Therefore, we need to // have processed all of them. Therefore, we need to "rewind" the stream
// "rewind" the stream after the last processed char. // after the last processed char.
is.seekg(start_position); is.seekg(start_position);
is.ignore(static_cast<std::streamsize>(processed_chars)); is.ignore(static_cast<std::streamsize>(processed_chars));
// clear stream flags // clear stream flags
@ -1491,16 +1483,14 @@ struct input_adapter_factory
first, last, std::pair<bool, int>(true, 0), first, last, std::pair<bool, int>(true, 0),
[&first](std::pair<bool, int> res, decltype(*first) val) [&first](std::pair<bool, int> res, decltype(*first) val)
{ {
res.first &= res.first &= (val == *(std::next(std::addressof(*first), res.second++)));
(val ==
*(std::next(std::addressof(*first), res.second++)));
return res; return res;
}) }).first);
.first);
// assertion to check that each element is 1 byte long // assertion to check that each element is 1 byte long
static_assert( static_assert(
sizeof(typename std::iterator_traits<IteratorType>::value_type) == 1, "each element in the iterator range must have the size of 1 byte"); sizeof(typename std::iterator_traits<IteratorType>::value_type) == 1,
"each element in the iterator range must have the size of 1 byte");
const auto len = static_cast<size_t>(std::distance(first, last)); const auto len = static_cast<size_t>(std::distance(first, last));
if (JSON_LIKELY(len > 0)) if (JSON_LIKELY(len > 0))
@ -1911,12 +1901,12 @@ class lexer
@brief scan a string literal @brief scan a string literal
This function scans a string according to Sect. 7 of RFC 7159. While This function scans a string according to Sect. 7 of RFC 7159. While
scanning, bytes are escaped and copied into buffer yytext. Then the scanning, bytes are escaped and copied into buffer yytext. Then the function
function returns successfully, yytext is null-terminated and yylen returns successfully, yytext is null-terminated and yylen contains the
contains the number of bytes in the string. number of bytes in the string.
@return token_type::value_string if string could be successfully @return token_type::value_string if string could be successfully scanned,
scanned, token_type::parse_error otherwise token_type::parse_error otherwise
@note In case of errors, variable error_message contains a textual @note In case of errors, variable error_message contains a textual
description. description.
@ -2011,8 +2001,7 @@ class lexer
if (JSON_UNLIKELY(codepoint2 == -1)) if (JSON_UNLIKELY(codepoint2 == -1))
{ {
error_message = error_message = "invalid string: '\\u' must be followed by 4 hex digits";
"invalid string: '\\u' must be followed by 4 hex digits";
return token_type::parse_error; return token_type::parse_error;
} }
@ -2031,15 +2020,13 @@ class lexer
} }
else else
{ {
error_message = "invalid string: surrogate U+DC00..U+DFFF must " error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF";
"be followed by U+DC00..U+DFFF";
return token_type::parse_error; return token_type::parse_error;
} }
} }
else else
{ {
error_message = "invalid string: surrogate U+DC00..U+DFFF must " error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF";
"be followed by U+DC00..U+DFFF";
return token_type::parse_error; return token_type::parse_error;
} }
} }
@ -2047,8 +2034,7 @@ class lexer
{ {
if (JSON_UNLIKELY(0xDC00 <= codepoint1 and codepoint1 <= 0xDFFF)) if (JSON_UNLIKELY(0xDC00 <= codepoint1 and codepoint1 <= 0xDFFF))
{ {
error_message = "invalid string: surrogate U+DC00..U+DFFF must " error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF";
"follow U+D800..U+DBFF";
return token_type::parse_error; return token_type::parse_error;
} }
@ -3543,14 +3529,12 @@ class parser
} }
else else
{ {
error_msg += error_msg += "unexpected " + std::string(lexer_t::token_type_name(last_token));
"unexpected " + std::string(lexer_t::token_type_name(last_token));
} }
if (expected != token_type::uninitialized) if (expected != token_type::uninitialized)
{ {
error_msg += error_msg += "; expected " + std::string(lexer_t::token_type_name(expected));
"; expected " + std::string(lexer_t::token_type_name(expected));
} }
JSON_THROW(parse_error::create(101, m_lexer.get_position(), error_msg)); JSON_THROW(parse_error::create(101, m_lexer.get_position(), error_msg));
@ -3732,9 +3716,6 @@ template <typename BasicJsonType> struct internal_iterator
typename BasicJsonType::array_t::iterator array_iterator {}; typename BasicJsonType::array_t::iterator array_iterator {};
/// generic iterator for all other types /// generic iterator for all other types
primitive_iterator_t primitive_iterator {}; primitive_iterator_t primitive_iterator {};
/// create an uninitialized internal_iterator
internal_iterator() = default;
}; };
template <typename IteratorType> class iteration_proxy; template <typename IteratorType> class iteration_proxy;
@ -3745,11 +3726,10 @@ template <typename IteratorType> class iteration_proxy;
This class implements a both iterators (iterator and const_iterator) for the This class implements a both iterators (iterator and const_iterator) for the
@ref basic_json class. @ref basic_json class.
@note An iterator is called *initialized* when a pointer to a JSON value @note An iterator is called *initialized* when a pointer to a JSON value has
has been set (e.g., by a constructor or a copy assignment). If the been set (e.g., by a constructor or a copy assignment). If the iterator is
iterator is default-constructed, it is *uninitialized* and most default-constructed, it is *uninitialized* and most methods are undefined.
methods are undefined. **The library uses assertions to detect calls **The library uses assertions to detect calls on uninitialized iterators.**
on uninitialized iterators.**
@requirement The class satisfies the following concept requirements: @requirement The class satisfies the following concept requirements:
- -
@ -4703,8 +4683,7 @@ class binary_reader
// EOF // EOF
case std::char_traits<char>::eof(): case std::char_traits<char>::eof():
{ {
JSON_THROW( JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input"));
parse_error::create(110, chars_read, "unexpected end of input"));
} }
// Integer 0x00..0x17 (0..23) // Integer 0x00..0x17 (0..23)
@ -5094,8 +5073,7 @@ class binary_reader
{ {
std::stringstream ss; std::stringstream ss;
ss << std::setw(2) << std::setfill('0') << std::hex << current; ss << std::setw(2) << std::setfill('0') << std::hex << current;
JSON_THROW(parse_error::create( JSON_THROW(parse_error::create(112, chars_read, "error reading CBOR; last byte: 0x" + ss.str()));
112, chars_read, "error reading CBOR; last byte: 0x" + ss.str()));
} }
} }
} }
@ -5115,8 +5093,7 @@ class binary_reader
// EOF // EOF
case std::char_traits<char>::eof(): case std::char_traits<char>::eof():
{ {
JSON_THROW( JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input"));
parse_error::create(110, chars_read, "unexpected end of input"));
} }
// positive fixint // positive fixint
@ -5520,9 +5497,8 @@ class binary_reader
@note from http://stackoverflow.com/a/1001328/266378 @note from http://stackoverflow.com/a/1001328/266378
*/ */
static bool little_endianess() noexcept static constexpr bool little_endianess(int num = 1) noexcept
{ {
int num = 1;
return (*reinterpret_cast<char*>(&num) == 1); return (*reinterpret_cast<char*>(&num) == 1);
} }
@ -5792,8 +5768,7 @@ class binary_reader
{ {
if (JSON_UNLIKELY(current == std::char_traits<char>::eof())) if (JSON_UNLIKELY(current == std::char_traits<char>::eof()))
{ {
JSON_THROW( JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input"));
parse_error::create(110, chars_read, "unexpected end of input"));
} }
} }
@ -5859,20 +5834,17 @@ class binary_writer
{ {
write_number(static_cast<uint8_t>(j.m_value.number_integer)); write_number(static_cast<uint8_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_integer <= else if (j.m_value.number_integer <= (std::numeric_limits<uint8_t>::max)())
(std::numeric_limits<uint8_t>::max)())
{ {
oa->write_character(0x18); oa->write_character(0x18);
write_number(static_cast<uint8_t>(j.m_value.number_integer)); write_number(static_cast<uint8_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_integer <= else if (j.m_value.number_integer <= (std::numeric_limits<uint16_t>::max)())
(std::numeric_limits<uint16_t>::max)())
{ {
oa->write_character(0x19); oa->write_character(0x19);
write_number(static_cast<uint16_t>(j.m_value.number_integer)); write_number(static_cast<uint16_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_integer <= else if (j.m_value.number_integer <= (std::numeric_limits<uint32_t>::max)())
(std::numeric_limits<uint32_t>::max)())
{ {
oa->write_character(0x1a); oa->write_character(0x1a);
write_number(static_cast<uint32_t>(j.m_value.number_integer)); write_number(static_cast<uint32_t>(j.m_value.number_integer));
@ -5922,20 +5894,17 @@ class binary_writer
{ {
write_number(static_cast<uint8_t>(j.m_value.number_unsigned)); write_number(static_cast<uint8_t>(j.m_value.number_unsigned));
} }
else if (j.m_value.number_unsigned <= else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)())
(std::numeric_limits<uint8_t>::max)())
{ {
oa->write_character(0x18); oa->write_character(0x18);
write_number(static_cast<uint8_t>(j.m_value.number_unsigned)); write_number(static_cast<uint8_t>(j.m_value.number_unsigned));
} }
else if (j.m_value.number_unsigned <= else if (j.m_value.number_unsigned <= (std::numeric_limits<uint16_t>::max)())
(std::numeric_limits<uint16_t>::max)())
{ {
oa->write_character(0x19); oa->write_character(0x19);
write_number(static_cast<uint16_t>(j.m_value.number_unsigned)); write_number(static_cast<uint16_t>(j.m_value.number_unsigned));
} }
else if (j.m_value.number_unsigned <= else if (j.m_value.number_unsigned <= (std::numeric_limits<uint32_t>::max)())
(std::numeric_limits<uint32_t>::max)())
{ {
oa->write_character(0x1a); oa->write_character(0x1a);
write_number(static_cast<uint32_t>(j.m_value.number_unsigned)); write_number(static_cast<uint32_t>(j.m_value.number_unsigned));
@ -6114,29 +6083,25 @@ class binary_writer
// positive fixnum // positive fixnum
write_number(static_cast<uint8_t>(j.m_value.number_integer)); write_number(static_cast<uint8_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_unsigned <= else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)())
(std::numeric_limits<uint8_t>::max)())
{ {
// uint 8 // uint 8
oa->write_character(0xcc); oa->write_character(0xcc);
write_number(static_cast<uint8_t>(j.m_value.number_integer)); write_number(static_cast<uint8_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_unsigned <= else if (j.m_value.number_unsigned <= (std::numeric_limits<uint16_t>::max)())
(std::numeric_limits<uint16_t>::max)())
{ {
// uint 16 // uint 16
oa->write_character(0xcd); oa->write_character(0xcd);
write_number(static_cast<uint16_t>(j.m_value.number_integer)); write_number(static_cast<uint16_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_unsigned <= else if (j.m_value.number_unsigned <= (std::numeric_limits<uint32_t>::max)())
(std::numeric_limits<uint32_t>::max)())
{ {
// uint 32 // uint 32
oa->write_character(0xce); oa->write_character(0xce);
write_number(static_cast<uint32_t>(j.m_value.number_integer)); write_number(static_cast<uint32_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_unsigned <= else if (j.m_value.number_unsigned <= (std::numeric_limits<uint64_t>::max)())
(std::numeric_limits<uint64_t>::max)())
{ {
// uint 64 // uint 64
oa->write_character(0xcf); oa->write_character(0xcf);
@ -6150,37 +6115,29 @@ class binary_writer
// negative fixnum // negative fixnum
write_number(static_cast<int8_t>(j.m_value.number_integer)); write_number(static_cast<int8_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_integer >= else if (j.m_value.number_integer >= (std::numeric_limits<int8_t>::min)() and
(std::numeric_limits<int8_t>::min)() and j.m_value.number_integer <= (std::numeric_limits<int8_t>::max)())
j.m_value.number_integer <=
(std::numeric_limits<int8_t>::max)())
{ {
// int 8 // int 8
oa->write_character(0xd0); oa->write_character(0xd0);
write_number(static_cast<int8_t>(j.m_value.number_integer)); write_number(static_cast<int8_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_integer >= else if (j.m_value.number_integer >= (std::numeric_limits<int16_t>::min)() and
(std::numeric_limits<int16_t>::min)() and j.m_value.number_integer <= (std::numeric_limits<int16_t>::max)())
j.m_value.number_integer <=
(std::numeric_limits<int16_t>::max)())
{ {
// int 16 // int 16
oa->write_character(0xd1); oa->write_character(0xd1);
write_number(static_cast<int16_t>(j.m_value.number_integer)); write_number(static_cast<int16_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_integer >= else if (j.m_value.number_integer >= (std::numeric_limits<int32_t>::min)() and
(std::numeric_limits<int32_t>::min)() and j.m_value.number_integer <= (std::numeric_limits<int32_t>::max)())
j.m_value.number_integer <=
(std::numeric_limits<int32_t>::max)())
{ {
// int 32 // int 32
oa->write_character(0xd2); oa->write_character(0xd2);
write_number(static_cast<int32_t>(j.m_value.number_integer)); write_number(static_cast<int32_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_integer >= else if (j.m_value.number_integer >= (std::numeric_limits<int64_t>::min)() and
(std::numeric_limits<int64_t>::min)() and j.m_value.number_integer <= (std::numeric_limits<int64_t>::max)())
j.m_value.number_integer <=
(std::numeric_limits<int64_t>::max)())
{ {
// int 64 // int 64
oa->write_character(0xd3); oa->write_character(0xd3);
@ -6197,29 +6154,25 @@ class binary_writer
// positive fixnum // positive fixnum
write_number(static_cast<uint8_t>(j.m_value.number_integer)); write_number(static_cast<uint8_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_unsigned <= else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)())
(std::numeric_limits<uint8_t>::max)())
{ {
// uint 8 // uint 8
oa->write_character(0xcc); oa->write_character(0xcc);
write_number(static_cast<uint8_t>(j.m_value.number_integer)); write_number(static_cast<uint8_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_unsigned <= else if (j.m_value.number_unsigned <= (std::numeric_limits<uint16_t>::max)())
(std::numeric_limits<uint16_t>::max)())
{ {
// uint 16 // uint 16
oa->write_character(0xcd); oa->write_character(0xcd);
write_number(static_cast<uint16_t>(j.m_value.number_integer)); write_number(static_cast<uint16_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_unsigned <= else if (j.m_value.number_unsigned <= (std::numeric_limits<uint32_t>::max)())
(std::numeric_limits<uint32_t>::max)())
{ {
// uint 32 // uint 32
oa->write_character(0xce); oa->write_character(0xce);
write_number(static_cast<uint32_t>(j.m_value.number_integer)); write_number(static_cast<uint32_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_unsigned <= else if (j.m_value.number_unsigned <= (std::numeric_limits<uint64_t>::max)())
(std::numeric_limits<uint64_t>::max)())
{ {
// uint 64 // uint 64
oa->write_character(0xcf); oa->write_character(0xcf);
@ -6726,8 +6679,7 @@ class serializer
return res; return res;
} }
static void escape_codepoint(const int codepoint, static void escape_codepoint(int codepoint, string_t& result, size_t& pos)
string_t& result, size_t& pos)
{ {
// expecting a proper codepoint // expecting a proper codepoint
assert(0x00 <= codepoint and codepoint <= 0x10FFFF); assert(0x00 <= codepoint and codepoint <= 0x10FFFF);
@ -6760,8 +6712,9 @@ class serializer
// codepoints U+10000..U+10FFFF need a surrogate pair to be // codepoints U+10000..U+10FFFF need a surrogate pair to be
// represented as \uxxxx\uxxxx. // represented as \uxxxx\uxxxx.
// http://www.unicode.org/faq/utf_bom.html#utf16-4 // http://www.unicode.org/faq/utf_bom.html#utf16-4
const int high_surrogate = 0xD800 - (0x10000 >> 10) + (codepoint >> 10); codepoint -= 0x10000;
const int low_surrogate = 0xDC00 + (codepoint & 0x3FF); const int high_surrogate = 0xD800 | ((codepoint >> 10) & 0x3FF);
const int low_surrogate = 0xDC00 | (codepoint & 0x3FF);
result[++pos] = hexify[(high_surrogate >> 12) & 0x0F]; result[++pos] = hexify[(high_surrogate >> 12) & 0x0F];
result[++pos] = hexify[(high_surrogate >> 8) & 0x0F]; result[++pos] = hexify[(high_surrogate >> 8) & 0x0F];
result[++pos] = hexify[(high_surrogate >> 4) & 0x0F]; result[++pos] = hexify[(high_surrogate >> 4) & 0x0F];
@ -7019,8 +6972,7 @@ class serializer
static constexpr auto d = std::numeric_limits<number_float_t>::digits10; static constexpr auto d = std::numeric_limits<number_float_t>::digits10;
// the actual conversion // the actual conversion
std::ptrdiff_t len = std::ptrdiff_t len = snprintf(number_buffer.data(), number_buffer.size(), "%.*g", d, x);
snprintf(number_buffer.data(), number_buffer.size(), "%.*g", d, x);
// negative value indicates an error // negative value indicates an error
assert(len > 0); assert(len > 0);
@ -7158,44 +7110,43 @@ class json_pointer
public: public:
/*! /*!
@brief create JSON pointer @brief create JSON pointer
Create a JSON pointer according to the syntax described in Create a JSON pointer according to the syntax described in
[Section 3 of RFC6901](https://tools.ietf.org/html/rfc6901#section-3). [Section 3 of RFC6901](https://tools.ietf.org/html/rfc6901#section-3).
@param[in] s string representing the JSON pointer; if omitted, the @param[in] s string representing the JSON pointer; if omitted, the empty
empty string is assumed which references the whole JSON string is assumed which references the whole JSON value
value
@throw parse_error.107 if the given JSON pointer @a s is nonempty and @throw parse_error.107 if the given JSON pointer @a s is nonempty and
does not begin with a slash (`/`); see example below does not begin with a slash (`/`); see example below
@throw parse_error.108 if a tilde (`~`) in the given JSON pointer @a s @throw parse_error.108 if a tilde (`~`) in the given JSON pointer @a s
is not followed by `0` (representing `~`) or `1` (representing `/`); is not followed by `0` (representing `~`) or `1` (representing `/`);
see example below see example below
@liveexample{The example shows the construction several valid JSON @liveexample{The example shows the construction several valid JSON
pointers as well as the exceptional behavior.,json_pointer} pointers as well as the exceptional behavior.,json_pointer}
@since version 2.0.0 @since version 2.0.0
*/ */
explicit json_pointer(const std::string& s = "") : reference_tokens(split(s)) {} explicit json_pointer(const std::string& s = "") : reference_tokens(split(s)) {}
/*! /*!
@brief return a string representation of the JSON pointer @brief return a string representation of the JSON pointer
@invariant For each JSON pointer `ptr`, it holds: @invariant For each JSON pointer `ptr`, it holds:
@code {.cpp} @code {.cpp}
ptr == json_pointer(ptr.to_string()); ptr == json_pointer(ptr.to_string());
@endcode @endcode
@return a string representation of the JSON pointer @return a string representation of the JSON pointer
@liveexample{The example shows the result of `to_string`., @liveexample{The example shows the result of `to_string`.,
json_pointer__to_string} json_pointer__to_string}
@since version 2.0.0 @since version 2.0.0
*/ */
std::string to_string() const noexcept std::string to_string() const noexcept
{ {
return std::accumulate(reference_tokens.begin(), reference_tokens.end(), return std::accumulate(reference_tokens.begin(), reference_tokens.end(),
@ -7214,15 +7165,14 @@ class json_pointer
private: private:
/*! /*!
@brief remove and return last reference pointer @brief remove and return last reference pointer
@throw out_of_range.405 if JSON pointer has no parent @throw out_of_range.405 if JSON pointer has no parent
*/ */
std::string pop_back() std::string pop_back()
{ {
if (is_root()) if (is_root())
{ {
JSON_THROW( JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent"));
detail::out_of_range::create(405, "JSON pointer has no parent"));
} }
auto last = reference_tokens.back(); auto last = reference_tokens.back();
@ -7250,81 +7200,81 @@ class json_pointer
/*! /*!
@brief create and return a reference to the pointed to value @brief create and return a reference to the pointed to value
@complexity Linear in the number of reference tokens. @complexity Linear in the number of reference tokens.
@throw parse_error.109 if array index is not a number @throw parse_error.109 if array index is not a number
@throw type_error.313 if value cannot be unflattened @throw type_error.313 if value cannot be unflattened
*/ */
NLOHMANN_BASIC_JSON_TPL_DECLARATION NLOHMANN_BASIC_JSON_TPL_DECLARATION
NLOHMANN_BASIC_JSON_TPL& get_and_create(NLOHMANN_BASIC_JSON_TPL& j) const; NLOHMANN_BASIC_JSON_TPL& get_and_create(NLOHMANN_BASIC_JSON_TPL& j) const;
/*! /*!
@brief return a reference to the pointed to value @brief return a reference to the pointed to value
@note This version does not throw if a value is not present, but tries @note This version does not throw if a value is not present, but tries to
to create nested values instead. For instance, calling this function create nested values instead. For instance, calling this function
with pointer `"/this/that"` on a null value is equivalent to calling with pointer `"/this/that"` on a null value is equivalent to calling
`operator[]("this").operator[]("that")` on that value, effectively `operator[]("this").operator[]("that")` on that value, effectively
changing the null value to an object. changing the null value to an object.
@param[in] ptr a JSON value @param[in] ptr a JSON value
@return reference to the JSON value pointed to by the JSON pointer @return reference to the JSON value pointed to by the JSON pointer
@complexity Linear in the length of the JSON pointer. @complexity Linear in the length of the JSON pointer.
@throw parse_error.106 if an array index begins with '0' @throw parse_error.106 if an array index begins with '0'
@throw parse_error.109 if an array index was not a number @throw parse_error.109 if an array index was not a number
@throw out_of_range.404 if the JSON pointer can not be resolved @throw out_of_range.404 if the JSON pointer can not be resolved
*/ */
NLOHMANN_BASIC_JSON_TPL_DECLARATION NLOHMANN_BASIC_JSON_TPL_DECLARATION
NLOHMANN_BASIC_JSON_TPL& get_unchecked(NLOHMANN_BASIC_JSON_TPL* ptr) const; NLOHMANN_BASIC_JSON_TPL& get_unchecked(NLOHMANN_BASIC_JSON_TPL* ptr) const;
/*! /*!
@throw parse_error.106 if an array index begins with '0' @throw parse_error.106 if an array index begins with '0'
@throw parse_error.109 if an array index was not a number @throw parse_error.109 if an array index was not a number
@throw out_of_range.402 if the array index '-' is used @throw out_of_range.402 if the array index '-' is used
@throw out_of_range.404 if the JSON pointer can not be resolved @throw out_of_range.404 if the JSON pointer can not be resolved
*/ */
NLOHMANN_BASIC_JSON_TPL_DECLARATION NLOHMANN_BASIC_JSON_TPL_DECLARATION
NLOHMANN_BASIC_JSON_TPL& get_checked(NLOHMANN_BASIC_JSON_TPL* ptr) const; NLOHMANN_BASIC_JSON_TPL& get_checked(NLOHMANN_BASIC_JSON_TPL* ptr) const;
/*! /*!
@brief return a const reference to the pointed to value @brief return a const reference to the pointed to value
@param[in] ptr a JSON value @param[in] ptr a JSON value
@return const reference to the JSON value pointed to by the JSON @return const reference to the JSON value pointed to by the JSON
pointer pointer
@throw parse_error.106 if an array index begins with '0' @throw parse_error.106 if an array index begins with '0'
@throw parse_error.109 if an array index was not a number @throw parse_error.109 if an array index was not a number
@throw out_of_range.402 if the array index '-' is used @throw out_of_range.402 if the array index '-' is used
@throw out_of_range.404 if the JSON pointer can not be resolved @throw out_of_range.404 if the JSON pointer can not be resolved
*/ */
NLOHMANN_BASIC_JSON_TPL_DECLARATION NLOHMANN_BASIC_JSON_TPL_DECLARATION
const NLOHMANN_BASIC_JSON_TPL& get_unchecked(const NLOHMANN_BASIC_JSON_TPL* ptr) const; const NLOHMANN_BASIC_JSON_TPL& get_unchecked(const NLOHMANN_BASIC_JSON_TPL* ptr) const;
/*! /*!
@throw parse_error.106 if an array index begins with '0' @throw parse_error.106 if an array index begins with '0'
@throw parse_error.109 if an array index was not a number @throw parse_error.109 if an array index was not a number
@throw out_of_range.402 if the array index '-' is used @throw out_of_range.402 if the array index '-' is used
@throw out_of_range.404 if the JSON pointer can not be resolved @throw out_of_range.404 if the JSON pointer can not be resolved
*/ */
NLOHMANN_BASIC_JSON_TPL_DECLARATION NLOHMANN_BASIC_JSON_TPL_DECLARATION
const NLOHMANN_BASIC_JSON_TPL& get_checked(const NLOHMANN_BASIC_JSON_TPL* ptr) const; const NLOHMANN_BASIC_JSON_TPL& get_checked(const NLOHMANN_BASIC_JSON_TPL* ptr) const;
/*! /*!
@brief split the string input to reference tokens @brief split the string input to reference tokens
@note This function is only called by the json_pointer constructor. @note This function is only called by the json_pointer constructor.
All exceptions below are documented there. All exceptions below are documented there.
@throw parse_error.107 if the pointer is not empty or begins with '/' @throw parse_error.107 if the pointer is not empty or begins with '/'
@throw parse_error.108 if character '~' is not followed by '0' or '1' @throw parse_error.108 if character '~' is not followed by '0' or '1'
*/ */
static std::vector<std::string> split(const std::string& reference_string) static std::vector<std::string> split(const std::string& reference_string)
{ {
std::vector<std::string> result; std::vector<std::string> result;
@ -7390,18 +7340,18 @@ class json_pointer
} }
/*! /*!
@brief replace all occurrences of a substring by another string @brief replace all occurrences of a substring by another string
@param[in,out] s the string to manipulate; changed so that all @param[in,out] s the string to manipulate; changed so that all
occurrences of @a f are replaced with @a t occurrences of @a f are replaced with @a t
@param[in] f the substring to replace with @a t @param[in] f the substring to replace with @a t
@param[in] t the string to replace @a f @param[in] t the string to replace @a f
@pre The search string @a f must not be empty. **This precondition is @pre The search string @a f must not be empty. **This precondition is
enforced with an assertion.** enforced with an assertion.**
@since version 2.0.0 @since version 2.0.0
*/ */
static void replace_substring(std::string& s, const std::string& f, static void replace_substring(std::string& s, const std::string& f,
const std::string& t) const std::string& t)
{ {
@ -7432,27 +7382,27 @@ class json_pointer
} }
/*! /*!
@param[in] reference_string the reference string to the current value @param[in] reference_string the reference string to the current value
@param[in] value the value to consider @param[in] value the value to consider
@param[in,out] result the result object to insert values to @param[in,out] result the result object to insert values to
@note Empty objects or arrays are flattened to `null`. @note Empty objects or arrays are flattened to `null`.
*/ */
NLOHMANN_BASIC_JSON_TPL_DECLARATION NLOHMANN_BASIC_JSON_TPL_DECLARATION
static void flatten(const std::string& reference_string, static void flatten(const std::string& reference_string,
const NLOHMANN_BASIC_JSON_TPL& value, const NLOHMANN_BASIC_JSON_TPL& value,
NLOHMANN_BASIC_JSON_TPL& result); NLOHMANN_BASIC_JSON_TPL& result);
/*! /*!
@param[in] value flattened JSON @param[in] value flattened JSON
@return unflattened JSON @return unflattened JSON
@throw parse_error.109 if array index is not a number @throw parse_error.109 if array index is not a number
@throw type_error.314 if value is not an object @throw type_error.314 if value is not an object
@throw type_error.315 if object values are not primitive @throw type_error.315 if object values are not primitive
@throw type_error.313 if value cannot be unflattened @throw type_error.313 if value cannot be unflattened
*/ */
NLOHMANN_BASIC_JSON_TPL_DECLARATION NLOHMANN_BASIC_JSON_TPL_DECLARATION
static NLOHMANN_BASIC_JSON_TPL static NLOHMANN_BASIC_JSON_TPL
unflatten(const NLOHMANN_BASIC_JSON_TPL& value); unflatten(const NLOHMANN_BASIC_JSON_TPL& value);
@ -9151,7 +9101,8 @@ class basic_json
@since version 1.0.0; indentation character added in version 3.0.0 @since version 1.0.0; indentation character added in version 3.0.0
*/ */
string_t dump(const int indent = -1, const char indent_char = ' ', const bool ensure_ascii = false) const string_t dump(const int indent = -1, const char indent_char = ' ',
const bool ensure_ascii = false) const
{ {
string_t result; string_t result;
serializer s(detail::output_adapter_factory<char>::create(result), indent_char); serializer s(detail::output_adapter_factory<char>::create(result), indent_char);

View file

@ -11,6 +11,7 @@ target_include_directories(catch_main PRIVATE "thirdparty/catch")
set(JSON_UNITTEST_TARGET_NAME "json_unit") set(JSON_UNITTEST_TARGET_NAME "json_unit")
add_executable(${JSON_UNITTEST_TARGET_NAME} add_executable(${JSON_UNITTEST_TARGET_NAME}
$<TARGET_OBJECTS:catch_main> $<TARGET_OBJECTS:catch_main>
"../src/json.hpp"
"src/unit-algorithms.cpp" "src/unit-algorithms.cpp"
"src/unit-allocator.cpp" "src/unit-allocator.cpp"
"src/unit-capacity.cpp" "src/unit-capacity.cpp"

View file

@ -45,7 +45,7 @@ void check_utf8string(bool success_expected, int byte1, int byte2 = -1, int byte
{ {
if (++calls % 100000 == 0) if (++calls % 100000 == 0)
{ {
std::cout << calls << " UTF-8 strings checked" << std::endl; std::cout << calls << " of 8860608 UTF-8 strings checked" << std::endl;
} }
std::string json_string = "\""; std::string json_string = "\"";