Remove unreachable code found by the coverage analysis

Remove code that no input can reach, and mark the lines that cannot be
covered with LCOV_EXCL_LINE:

- BJData writer: the dry_run parameter of the ND-array element writers was
  always true; replace them by range checks.
- BON8 writer: call throw_integer_out_of_range() directly instead of
  write_bon8_value() for values that always throw.
- binary_writer: integer_bits() is only called for integers of up to 64 bits.
- serializer, view serializer, lexer: replace guards that the callers make
  unreachable by assertions or by the simpler code (surrogate pairs under
  ensure_ascii, next_unget, '-' at the end of the buffer).
- json_view: drop unreachable branches in scalar(), set(), check_utf8_scan(),
  append_input_impl() and unescape().
- Mark exception-cleanup braces, 2 GiB limits, big-endian and 32-bit code, and
  fall-through case labels with LCOV_EXCL_LINE.

No behavior changes for any input that reaches these functions.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
Niels Lohmann committed 2026-11-01 22:32:41 +01:00
1 parent 04a5accfb9
commit d7b9472173
21 files changed
+234 -404

No files matched your search

@@ -91,7 +91,7 @@ const typename BasicJsonType::binary_t& binary_value(const BasicJsonType& j)
}
template<typename View, enable_if_t<is_json_view<View>::value, int> = 0>
typename View::basic_json_type::binary_t binary_value(const View& /*unused*/)
typename View::basic_json_type::binary_t binary_value(const View& /*unused*/) // LCOV_EXCL_LINE
{
return {}; // LCOV_EXCL_LINE
}
@@ -572,7 +572,7 @@ class input_stream_adapter
}
else
{
current_in_get_area = true;
current_in_get_area = true; // LCOV_EXCL_LINE (called only when the get area is exhausted)
}
#endif
return res;
+1 -1
View File
@@ -999,7 +999,7 @@ class json_sax_dom_parser : public json_sax_dom_error_state
ordered_data.members[f.ordered.dest_member].second = std::move(value);
}
static void place_member(const frame& /*f*/, BasicJsonType&& /*value*/, std::false_type /*indexed*/) noexcept {}
static void place_member(const frame& /*f*/, BasicJsonType&& /*value*/, std::false_type /*indexed*/) noexcept {} // LCOV_EXCL_LINE
/// store the members of a new object directly in it
bool start_stored_object(std::size_t len)
+8 -15
View File
@@ -437,11 +437,10 @@ class lexer : public lexer_base<BasicJsonType>
template<bool Keep>
char_int_type get_after_string_run(std::true_type /*bulk*/, std::integral_constant<bool, Keep> keep)
{
// a pending unget must be consumed through the normal path first
if (next_unget)
{
return get();
}
// scan_string() is entered from scan_after_whitespace(), whose current
// was read by skip_whitespace() (its first get() clears a pending
// unget), and nothing in scan_string() calls unget()
JSON_ASSERT(!next_unget);
const std::size_t remaining = ia.bulk_remaining();
if (remaining == 0)
{
@@ -1516,11 +1515,9 @@ scan_number_done:
*/
token_type scan_number_bulk_contiguous()
{
// a pending unget offsets the buffer position from current; fall back
if (next_unget)
{
return token_type::uninitialized;
}
// called right after scan_after_whitespace() read current (see
// get_after_string_run()), so no unget is pending
JSON_ASSERT(!next_unget);
const std::size_t rem = ia.bulk_remaining();
if (rem == 0)
{
@@ -1541,11 +1538,7 @@ scan_number_done:
if (data[0] == '-')
{
number_type = token_type::value_integer;
i = 1;
if (i >= avail)
{
return token_type::uninitialized;
}
i = 1; // avail >= 2: rem == 0 returned above
}
const std::size_t integer_begin = i;
if (data[i] == '0')
+1 -1
View File
@@ -598,7 +598,7 @@ class parser
}
return error_msg;
}
} // LCOV_EXCL_LINE (exception cleanup only)
private:
/// callback function
+4 -4
View File
@@ -304,7 +304,7 @@ class json_pointer
result.reference_tokens.insert(result.reference_tokens.end(), lhs.reference_tokens.begin(), lhs.reference_tokens.end());
result.reference_tokens.insert(result.reference_tokens.end(), rhs.reference_tokens.begin(), rhs.reference_tokens.end());
return result;
}
} // LCOV_EXCL_LINE (exception cleanup only)
/// @brief create a new JSON pointer by appending the unescaped token at the end of the JSON pointer
/// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/
@@ -315,7 +315,7 @@ class json_pointer
result.reference_tokens.insert(result.reference_tokens.end(), lhs.reference_tokens.begin(), lhs.reference_tokens.end());
result.reference_tokens.push_back(std::move(token));
return result;
}
} // LCOV_EXCL_LINE (exception cleanup only)
/// @brief create a new JSON pointer by appending the array-index-token at the end of the JSON pointer
/// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/
@@ -2180,7 +2180,7 @@ class json_pointer
{
// create an entry in the array
current = &current->operator[](array_index<BasicJsonType>(token));
break;
break; // LCOV_EXCL_LINE (needs an array index with 10 or more digits: more than 1e9 elements)
}
/*
@@ -2217,7 +2217,7 @@ class json_pointer
json_pointer<string_t> result;
result.reference_tokens = reference_tokens;
return result;
}
} // LCOV_EXCL_LINE (exception cleanup only)
json_pointer<string_t> convert()&&
{
@@ -833,7 +833,7 @@ class binary_writer
while (n != 0);
std::reverse(result.begin(), result.end());
return result;
}
} // LCOV_EXCL_LINE (exception cleanup only)
/*!
@brief the decimal digits of the integer @a n, with a leading '-' if it
@@ -860,7 +860,7 @@ class binary_writer
}
std::reverse(result.begin(), result.end());
return result;
}
} // LCOV_EXCL_LINE (exception cleanup only)
/*!
@brief throws because the integer @a j is too large for @a format
@@ -1792,7 +1792,7 @@ class binary_writer
std::memcpy(out, &n, sizeof(NumberType));
if (!is_little_endian)
{
std::reverse(out, out + sizeof(NumberType));
std::reverse(out, out + sizeof(NumberType)); // LCOV_EXCL_LINE (big-endian hosts only)
}
}
@@ -1921,7 +1921,7 @@ class binary_writer
const string_t& value = *j.m_data.m_value.string;
if (JSON_HEDLEY_UNLIKELY(!value_in_range_of<std::int32_t>(value.size() + 1ul)))
{
return false;
return false; // LCOV_EXCL_LINE (a string of 2 GiB or more)
}
out[0] = to_char_type(0x02);
store_little_endian<std::int32_t>(p, static_cast<std::int32_t>(value.size() + 1ul));
@@ -2378,7 +2378,7 @@ class binary_writer
const std::size_t size = oa.written() - pos;
if (JSON_HEDLEY_UNLIKELY(!value_in_range_of<std::int32_t>(size)))
{
return false;
return false; // LCOV_EXCL_LINE (a document of 2 GiB or more)
}
const auto le_size = static_cast<std::uint32_t>(size);
oa.overwrite(pos, is_little_endian ? le_size : byteswap(le_size));
@@ -2507,7 +2507,7 @@ class binary_writer
{
if (JSON_HEDLEY_UNLIKELY(!close_bson_container(nested_size_pos)))
{
return false;
return false; // LCOV_EXCL_LINE (a document of 2 GiB or more)
}
continue;
}
@@ -2522,7 +2522,7 @@ class binary_writer
if (JSON_HEDLEY_UNLIKELY(!close_bson_container(current.size_slot)))
{
return false;
return false; // LCOV_EXCL_LINE (a document of 2 GiB or more)
}
if (parents.empty())
{
@@ -2779,10 +2779,10 @@ class binary_writer
Selected through masks rather than branches, as the type and the sign of
the values in an array of mixed signs alternate unpredictably (non-negative
integers are number_unsigned after parsing). Up to 64 bits, the sign is bit
63 of the result (a narrower integer is sign-extended); computing it with
masks keeps GCC from branching on the type. A wider integer has to be
compared.
integers are number_unsigned after parsing). The sign is bit 63 of the
result (a narrower integer is sign-extended); computing it with masks keeps
GCC from branching on the type. Only called if @ref integers_fit_64_bits();
a wider number type is written with range checks on the whole value.
*/
static std::uint64_t integer_bits(const BasicJsonType& j, std::uint64_t& sign_mask) noexcept
{
@@ -2790,9 +2790,7 @@ class binary_writer
const std::uint64_t raw = is_signed
? static_cast<std::uint64_t>(j.m_data.m_value.number_integer)
: static_cast<std::uint64_t>(j.m_data.m_value.number_unsigned);
sign_mask = sizeof(typename BasicJsonType::number_integer_t) <= sizeof(std::uint64_t)
? (std::uint64_t{0} - static_cast<std::uint64_t>(is_signed)) & (std::uint64_t{0} - (raw >> 63u))
: std::uint64_t{0} - static_cast<std::uint64_t>(is_signed && j.m_data.m_value.number_integer < 0);
sign_mask = (std::uint64_t{0} - static_cast<std::uint64_t>(is_signed)) & (std::uint64_t{0} - (raw >> 63u));
return raw;
}
@@ -4159,57 +4157,34 @@ class binary_writer
}
/*!
@brief validate (dry_run) or write one BJData ND-array element of integer dtype @a T
@return whether @a el's value is in range of @a T; always true when @a dry_run is false
*/
template<typename T>
bool write_bjdata_ndarray_element(const BasicJsonType& el, const bool dry_run)
{
if (dry_run)
{
return bjdata_ndarray_value_in_range<T>(el);
}
using storage_type = typename std::conditional<std::is_unsigned<T>::value, std::uint64_t, std::int64_t>::type;
write_number(static_cast<T>(el.template get<storage_type>()), true);
return true;
}
/*!
@brief validate (dry_run) or write one BJData ND-array element of dtype 'd' (single precision)
@brief whether the BJData ND-array element @a el can be written with dtype 'd' (single precision)
@return whether @a el's value survives narrowing to float and back without any change
(so the ND-array round-trips exactly), or is infinite or NaN; always true when
@a dry_run is false
(so the ND-array round-trips exactly), or is infinite or NaN
*/
bool write_bjdata_ndarray_float_element(const BasicJsonType& el, const bool dry_run)
static bool bjdata_ndarray_float_in_range(const BasicJsonType& el) noexcept
{
const auto dval = static_cast<double>(el.m_data.m_value.number_float);
if (dry_run)
{
#ifdef __GNUC__
JSON_HEDLEY_DIAGNOSTIC_PUSH
JSON_HEDLEY_PRAGMA(GCC diagnostic ignored "-Wfloat-equal")
JSON_HEDLEY_DIAGNOSTIC_PUSH
JSON_HEDLEY_PRAGMA(GCC diagnostic ignored "-Wfloat-equal")
#endif
// a value that would be rounded (rather than exactly represented) by the
// narrowing to float is treated like an out-of-range integer element; this
// is the same criterion write_compact_float() uses for CBOR/MessagePack
const bool in_range = std::isnan(dval) ||
(dval >= static_cast<double>(std::numeric_limits<float>::lowest()) &&
dval <= static_cast<double>((std::numeric_limits<float>::max)()) &&
static_cast<double>(static_cast<float>(dval)) == dval) ||
std::isinf(dval);
// a value that would be rounded (rather than exactly represented) by the
// narrowing to float is treated like an out-of-range integer element; this
// is the same criterion write_compact_float() uses for CBOR/MessagePack
return std::isnan(dval) ||
(dval >= static_cast<double>(std::numeric_limits<float>::lowest()) &&
dval <= static_cast<double>((std::numeric_limits<float>::max)()) &&
static_cast<double>(static_cast<float>(dval)) == dval) ||
std::isinf(dval);
#ifdef __GNUC__
JSON_HEDLEY_DIAGNOSTIC_POP
JSON_HEDLEY_DIAGNOSTIC_POP
#endif
return in_range;
}
write_number(static_cast<float>(dval), true);
return true;
}
/*!
@brief write the elements of an ND-array as the number kind @a dtype names
(see @ref write_bjdata_ndarray), after they have been found to be
in range by a dry run of @ref write_bjdata_ndarray_elements
in range by @ref bjdata_ndarray_elements_in_range
The elements are encoded in blocks into space reserved from the sink.
*/
@@ -4291,20 +4266,13 @@ class binary_writer
}
/*!
@brief validate or write every element of a BJData ND-array's `_ArrayData_`
@brief whether every element of a BJData ND-array's `_ArrayData_` is in range for its dtype
@param[in] array_data the `_ArrayData_` array
@param[in] dtype the ND-array dtype marker, as returned by bjdata_ndarray_type_marker()
@param[in] dry_run true to only range-check each element, false to write it
@return whether every element is in range for @a dtype (always true when @a dry_run is false)
@return whether every element is in range for @a dtype
*/
bool write_bjdata_ndarray_elements(const BasicJsonType& array_data, const CharType dtype, const bool dry_run)
static bool bjdata_ndarray_elements_in_range(const BasicJsonType& array_data, const CharType dtype)
{
if (!dry_run)
{
write_bjdata_ndarray_values(array_data, dtype);
return true;
}
for (const auto& el : array_data)
{
bool ok = true;
@@ -4312,43 +4280,39 @@ class binary_writer
{
case 'U':
case 'B':
ok = write_bjdata_ndarray_element<std::uint8_t>(el, dry_run);
ok = bjdata_ndarray_value_in_range<std::uint8_t>(el);
break;
case 'C':
// BJData limits a char to 0..127 (the intersection of the int8 and uint8 ranges)
ok = bjdata_ndarray_value_in_range<std::int8_t>(el) && bjdata_ndarray_value_in_range<std::uint8_t>(el);
break;
case 'i':
ok = write_bjdata_ndarray_element<std::int8_t>(el, dry_run);
ok = bjdata_ndarray_value_in_range<std::int8_t>(el);
break;
case 'u':
ok = write_bjdata_ndarray_element<std::uint16_t>(el, dry_run);
ok = bjdata_ndarray_value_in_range<std::uint16_t>(el);
break;
case 'I':
ok = write_bjdata_ndarray_element<std::int16_t>(el, dry_run);
ok = bjdata_ndarray_value_in_range<std::int16_t>(el);
break;
case 'm':
ok = write_bjdata_ndarray_element<std::uint32_t>(el, dry_run);
ok = bjdata_ndarray_value_in_range<std::uint32_t>(el);
break;
case 'l':
ok = write_bjdata_ndarray_element<std::int32_t>(el, dry_run);
ok = bjdata_ndarray_value_in_range<std::int32_t>(el);
break;
case 'M':
ok = write_bjdata_ndarray_element<std::uint64_t>(el, dry_run);
ok = bjdata_ndarray_value_in_range<std::uint64_t>(el);
break;
case 'L':
ok = write_bjdata_ndarray_element<std::int64_t>(el, dry_run);
ok = bjdata_ndarray_value_in_range<std::int64_t>(el);
break;
case 'd':
ok = write_bjdata_ndarray_float_element(el, dry_run);
ok = bjdata_ndarray_float_in_range(el);
break;
case 'D':
default:
// 'D' (double) already spans the full range of number_float_t
if (!dry_run)
{
write_number(el.template get<double>(), true);
}
break;
}
if (!ok)
@@ -4435,7 +4399,7 @@ class binary_writer
const auto dim = el.template get<std::uint64_t>();
if (!value_in_range_of<std::size_t>(dim))
{
return true;
return true; // LCOV_EXCL_LINE (size_t is narrower than 64 bits)
}
const auto dim_size = static_cast<std::size_t>(dim);
@@ -4485,7 +4449,7 @@ class binary_writer
// wrap (integers) or overflow to infinity (the "single" precision
// float) instead of being reported, so such an object falls back to
// a plain object encoding as well
if (!write_bjdata_ndarray_elements(array_data, dtype, true))
if (!bjdata_ndarray_elements_in_range(array_data, dtype))
{
return true;
}
@@ -4497,7 +4461,7 @@ class binary_writer
write_ubjson(array_size, use_count, use_type, true, true, bjdata_version);
write_bjdata_ndarray_elements(array_data, dtype, false);
write_bjdata_ndarray_values(array_data, dtype);
return false;
}
@@ -4823,8 +4787,8 @@ class binary_writer
run are encoded into space reserved from the sink, as in
@ref write_array_elements; an integer that BON8 cannot write (an unsigned
one above the int64 range, or one of a number type wider than 64 bits) throws
from write_bon8_value, like any other value that is not a number. Kept out
of line, like @ref write_cbor_array.
out_of_range.407, as write_bon8_value does. Kept out of line, like
@ref write_cbor_array.
*/
template<typename ArrayType>
JSON_HEDLEY_NEVER_INLINE
@@ -4874,10 +4838,10 @@ class binary_writer
string_open = false;
}
if (unencodable)
if (JSON_HEDLEY_UNLIKELY(unencodable))
{
write_bon8_value(*it, string_open, depth + 1);
++it;
// an integer beyond the int64 range, as write_bon8_value would report it
throw_integer_out_of_range(*it, input_format_t::bon8, "int64");
}
}
}
@@ -4912,14 +4876,13 @@ class binary_writer
break;
case value_t::number_integer:
if (JSON_HEDLEY_LIKELY(integer_fits<std::int64_t>(value.m_data.m_value.number_integer)))
if (JSON_HEDLEY_UNLIKELY(!integer_fits<std::int64_t>(value.m_data.m_value.number_integer)))
{
write_bon8_integer(static_cast<std::int64_t>(value.m_data.m_value.number_integer));
string_open = false;
break;
// beyond 64 bits (number types wider than that)
throw_integer_out_of_range(value, input_format_t::bon8, "int64");
}
// beyond 64 bits (number types wider than that): throws
write_bon8_value(value, string_open, depth + 1);
write_bon8_integer(static_cast<std::int64_t>(value.m_data.m_value.number_integer));
string_open = false;
break;
case value_t::number_float:
@@ -4928,14 +4891,13 @@ class binary_writer
break;
case value_t::number_unsigned:
if (JSON_HEDLEY_LIKELY(integer_fits_max<std::int64_t>(value.m_data.m_value.number_unsigned)))
if (JSON_HEDLEY_UNLIKELY(!integer_fits_max<std::int64_t>(value.m_data.m_value.number_unsigned)))
{
write_bon8_integer(static_cast<std::int64_t>(value.m_data.m_value.number_unsigned));
string_open = false;
break;
// too large for BON8
throw_integer_out_of_range(value, input_format_t::bon8, "int64");
}
// too large for BON8: throws
write_bon8_value(value, string_open, depth + 1);
write_bon8_integer(static_cast<std::int64_t>(value.m_data.m_value.number_unsigned));
string_open = false;
break;
case value_t::object:
+3 -11
View File
@@ -1117,7 +1117,7 @@ class serializer
// character
if (EnsureAscii)
{
JSON_ASSERT(codepoint >= 0x7F);
JSON_ASSERT(codepoint == 0x7F);
if (error_handler == error_handler_t::keep)
{
// this character was buffered as raw bytes below
@@ -1128,21 +1128,13 @@ class serializer
// character instead
bytes = bytes_after_last_accept;
}
if (codepoint <= 0xFFFF)
{
write_u_escape(bytes, static_cast<std::uint16_t>(codepoint));
}
else
{
write_u_escape(bytes, static_cast<std::uint16_t>(0xD7C0u + (codepoint >> 10u)));
write_u_escape(bytes, static_cast<std::uint16_t>(0xDC00u + (codepoint & 0x3FFu)));
}
write_u_escape(bytes, static_cast<std::uint16_t>(codepoint));
}
else
{
// copy byte to buffer (all previous bytes of the
// sequence have been copied in the default case below)
string_buffer[bytes++] = s[i];
string_buffer[bytes++] = s[i]; // LCOV_EXCL_LINE (well-formed sequences are copied in runs)
}
reserve_string_buffer(bytes);
+1 -1
View File
@@ -139,7 +139,7 @@ inline OutStringType concat(Args && ... args)
str.reserve(concat_length(args...));
concat_into(str, std::forward<Args>(args)...);
return str;
}
} // LCOV_EXCL_LINE (exception cleanup only)
} // namespace detail
NLOHMANN_JSON_NAMESPACE_END
@@ -83,10 +83,6 @@ template<typename StringType>
inline void unescape(StringType& s)
{
auto pos = s.find_first_of('~', 0);
if (pos == StringType::npos)
{
return;
}
StringType result;
result.reserve(s.size());
+3 -3
View File
@@ -36,7 +36,7 @@ StringType to_string(std::size_t value)
StringType result;
int_to_string(result, value);
return result;
}
} // LCOV_EXCL_LINE (exception cleanup only)
/// @return a byte as two uppercase hexadecimal digits
inline std::string hex_byte(const std::uint8_t byte)
@@ -46,7 +46,7 @@ inline std::string hex_byte(const std::uint8_t byte)
result[0] = nibble_to_hex[byte / 16];
result[1] = nibble_to_hex[byte % 16];
return result;
}
} // LCOV_EXCL_LINE (exception cleanup only)
/*!
@brief write a UTF-16 code unit as four lowercase hexadecimal digits
@@ -390,7 +390,7 @@ inline StringType sanitize_utf8(const StringType& s, const error_handler_t error
}
return result;
}
} // LCOV_EXCL_LINE (exception cleanup only)
} // namespace detail
NLOHMANN_JSON_NAMESPACE_END
+9 -18
View File
@@ -428,28 +428,19 @@ class view_side
return string_view_t(m_view.m_doc->str(*m_view.m_node), m_view.m_node->len);
}
/// a number, boolean, or null as a basic_json value (no allocation)
/// a number as a basic_json value (no allocation); only called for numbers
BasicJsonType scalar() const
{
switch (m_view.type())
const value_t t = m_view.type();
if (t == value_t::number_integer)
{
case value_t::number_integer:
return BasicJsonType(m_view.template get<typename BasicJsonType::number_integer_t>());
case value_t::number_unsigned:
return BasicJsonType(m_view.template get<typename BasicJsonType::number_unsigned_t>());
case value_t::number_float:
return BasicJsonType(m_view.template get<typename BasicJsonType::number_float_t>());
case value_t::boolean:
return BasicJsonType(m_view.template get<bool>());
case value_t::null:
case value_t::object:
case value_t::array:
case value_t::string:
case value_t::binary:
case value_t::discarded:
default:
return BasicJsonType(nullptr);
return BasicJsonType(m_view.template get<typename BasicJsonType::number_integer_t>());
}
if (t == value_t::number_unsigned)
{
return BasicJsonType(m_view.template get<typename BasicJsonType::number_unsigned_t>());
}
return BasicJsonType(m_view.template get<typename BasicJsonType::number_float_t>());
}
/// start at the first element of this array
+2 -2
View File
@@ -96,11 +96,11 @@ NLOHMANN_VIEW_NOINLINE inline void check_utf8_scan(const unsigned char* p, std::
}
if (*q >= 0x80)
{
check_utf8_bytewise(p, n, static_cast<std::size_t>(q - p));
return; // not reached: the scan stopped at ill-formed UTF-8
break; // ill-formed UTF-8: reported below
}
++q; // a quote, backslash, or control character
}
check_utf8_bytewise(p, n, static_cast<std::size_t>(q - p));
}
inline void check_utf8(const char* s, std::size_t n)
@@ -243,7 +243,7 @@ inline node* find_parent(const document_data& d, const node* target)
}
if (target == lo)
{
return nullptr;
return nullptr; // LCOV_EXCL_LINE (the root, or a new value's root, which is linked)
}
for (;;)
{
+2
View File
@@ -420,10 +420,12 @@ struct throwing_sax
return true;
}
// LCOV_EXCL_START (throw_parse_failure parses JSON only)
bool binary(binary_t& /*unused*/)
{
return true;
}
// LCOV_EXCL_STOP
bool start_object(std::size_t /*unused*/)
{
+3 -8
View File
@@ -65,14 +65,9 @@ struct position_source
return token{end - start};
}
/// the range [first, last), or none if either is npos
/// the range [first, last)
void set(std::size_t first, std::size_t last) noexcept
{
if (first == std::string::npos || last == std::string::npos)
{
clear();
return;
}
start = first;
end = last;
}
@@ -191,11 +186,11 @@ struct position_source
first = n.off;
last = n.off + 4u;
break;
case node_kind::object:
case node_kind::object: // LCOV_EXCL_LINE
case node_kind::array:
case node_kind::link:
default:
break;
break; // LCOV_EXCL_LINE
}
// (a crafted image can point past the text)
if (last == std::string::npos || last > d.size)
+3 -21
View File
@@ -1389,20 +1389,10 @@ class view_serializer
/// a float node as dump() writes it
void write_float_node(const node& n)
{
write_float_node(n, fast_double {});
}
void write_float_node(const node& n, std::false_type /*other*/)
{
// (only for types other than double: doubles go through write_double_ahead())
write_float(float_value<number_float_t>(m_doc, n));
}
void write_float_node(const node& n, std::true_type /*double*/)
{
m_out.reserve(64);
m_out.set_cursor(write_double_at(m_out.cursor(), n));
}
/*!
@brief (doubles) the float at n as dump() writes it, at w (64 bytes of room)
@@ -1497,7 +1487,7 @@ class view_serializer
{
const string_t dumped = BasicJsonType(string_t(reinterpret_cast<const char*>(s), n)).dump(); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
static_cast<void>(dumped);
}
} // LCOV_EXCL_LINE (dump() throws: the callers pass only ill-formed UTF-8)
template<bool EnsureAscii>
void write_codepoint(std::uint32_t codepoint, const unsigned char* bytes, std::size_t len)
@@ -1530,15 +1520,7 @@ class view_serializer
}
if (codepoint <= 0x1F || (EnsureAscii && codepoint >= 0x7F))
{
if (codepoint <= 0xFFFF)
{
write_u_escape(codepoint);
}
else
{
write_u_escape(0xD7C0u + (codepoint >> 10u));
write_u_escape(0xDC00u + (codepoint & 0x3FFu));
}
write_u_escape(codepoint); // (a single byte: the only caller passes s[i])
return;
}
m_out.put(reinterpret_cast<const char*>(bytes), len); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) LCOV_EXCL_LINE (printable characters are copied in runs)
+13 -13
View File
@@ -400,7 +400,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
result["compiler"] = {{"family", "clang"}, {"version", __clang_version__}};
#elif defined(__GNUC__) || defined(__GNUG__)
result["compiler"] = {{"family", "gcc"}, {"version", detail::concat<string_t>(
detail::to_string<string_t>(static_cast<std::size_t>(__GNUC__)), '.',
detail::to_string<string_t>(static_cast<std::size_t>(__GNUC__)), '.', // LCOV_EXCL_LINE
detail::to_string<string_t>(static_cast<std::size_t>(__GNUC_MINOR__)), '.',
detail::to_string<string_t>(static_cast<std::size_t>(__GNUC_PATCHLEVEL__)))
}
@@ -672,14 +672,14 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
case value_t::binary:
binary = create<binary_t>();
break;
case value_t::null:
case value_t::null: // LCOV_EXCL_LINE
case value_t::boolean:
case value_t::number_integer:
case value_t::number_unsigned:
case value_t::number_float:
case value_t::discarded:
default:
break;
break; // LCOV_EXCL_LINE
}
}
@@ -1034,14 +1034,14 @@ public:
destroy_container(t);
break;
case value_t::null:
case value_t::null: // LCOV_EXCL_LINE
case value_t::boolean:
case value_t::number_integer:
case value_t::number_unsigned:
case value_t::number_float:
case value_t::discarded:
default:
break;
break; // LCOV_EXCL_LINE
}
}
};
@@ -1214,9 +1214,9 @@ public:
return is_array() ? array_capacity() : object_capacity();
}
#else
static constexpr std::size_t container_capacity() noexcept
static constexpr std::size_t container_capacity() noexcept // LCOV_EXCL_LINE
{
return detail::unknown_size();
return detail::unknown_size(); // LCOV_EXCL_LINE
}
#endif
@@ -1402,7 +1402,7 @@ public:
/// into this switch is worth a few percent when copying a value made
/// mostly of numbers
JSON_HEDLEY_ALWAYS_INLINE
static void copy_leaf_value(const basic_json& src, basic_json& dst)
static void copy_leaf_value(const basic_json& src, basic_json& dst) // LCOV_EXCL_LINE
{
switch (src.m_data.m_type)
{
@@ -5554,7 +5554,7 @@ public:
/// their inlined code at each call site small. Binary values are
/// rare and left to equal_general().
JSON_HEDLEY_ALWAYS_INLINE
static int equal_leaf(const_reference lhs, const_reference rhs) noexcept
static int equal_leaf(const_reference lhs, const_reference rhs) noexcept // LCOV_EXCL_LINE
{
#ifdef __GNUC__
JSON_HEDLEY_DIAGNOSTIC_PUSH
@@ -6863,7 +6863,7 @@ public:
basic_json result(value_t::object);
json_pointer::flatten("", *this, result);
return result;
}
} // LCOV_EXCL_LINE (exception cleanup only)
/// @brief unflatten a previously flattened JSON value
/// @sa https://json.nlohmann.me/api/basic_json/unflatten/
@@ -7576,7 +7576,7 @@ public:
result.append(path.data(), path.size());
diff_append_key(result, key);
return result;
}
} // LCOV_EXCL_LINE (exception cleanup only)
/// @brief the path of the element @a index of the value at @a path
static string_t diff_index_path(const string_t& path, const std::size_t index)
@@ -7586,7 +7586,7 @@ public:
result.append(path.data(), path.size());
diff_append_index(result, index);
return result;
}
} // LCOV_EXCL_LINE (exception cleanup only)
/// @brief append the "remove" operations for the elements of array
/// @a source from @a index on, and the "add" operations for the
@@ -7746,7 +7746,7 @@ public:
// operations
if (source == target)
{
return false;
return false; // LCOV_EXCL_LINE (equal objects with the same members in the same order return early)
}
// slow path: the common keys are in a different relative
+4 -2
View File
@@ -1705,9 +1705,11 @@ class basic_json_document
{
// (as before: the library's adapter decides what a null stream yields)
detail::view::append_adapter(buf, detail::input_adapter(file));
return;
}
detail::view::append_file(buf, file);
else
{
detail::view::append_file(buf, file);
}
}
#endif
+93 -150
View File
@@ -3637,10 +3637,6 @@ template<typename StringType>
inline void unescape(StringType& s)
{
auto pos = s.find_first_of('~', 0);
if (pos == StringType::npos)
{
return;
}
StringType result;
result.reserve(s.size());
@@ -5516,7 +5512,7 @@ inline OutStringType concat(Args && ... args)
str.reserve(concat_length(args...));
concat_into(str, std::forward<Args>(args)...);
return str;
}
} // LCOV_EXCL_LINE (exception cleanup only)
} // namespace detail
NLOHMANN_JSON_NAMESPACE_END
@@ -6236,7 +6232,7 @@ const typename BasicJsonType::binary_t& binary_value(const BasicJsonType& j)
}
template<typename View, enable_if_t<is_json_view<View>::value, int> = 0>
typename View::basic_json_type::binary_t binary_value(const View& /*unused*/)
typename View::basic_json_type::binary_t binary_value(const View& /*unused*/) // LCOV_EXCL_LINE
{
return {}; // LCOV_EXCL_LINE
}
@@ -7162,7 +7158,7 @@ StringType to_string(std::size_t value)
StringType result;
int_to_string(result, value);
return result;
}
} // LCOV_EXCL_LINE (exception cleanup only)
/// @return a byte as two uppercase hexadecimal digits
inline std::string hex_byte(const std::uint8_t byte)
@@ -7172,7 +7168,7 @@ inline std::string hex_byte(const std::uint8_t byte)
result[0] = nibble_to_hex[byte / 16];
result[1] = nibble_to_hex[byte % 16];
return result;
}
} // LCOV_EXCL_LINE (exception cleanup only)
/*!
@brief write a UTF-16 code unit as four lowercase hexadecimal digits
@@ -7516,7 +7512,7 @@ inline StringType sanitize_utf8(const StringType& s, const error_handler_t error
}
return result;
}
} // LCOV_EXCL_LINE (exception cleanup only)
} // namespace detail
NLOHMANN_JSON_NAMESPACE_END
@@ -9683,7 +9679,7 @@ class input_stream_adapter
}
else
{
current_in_get_area = true;
current_in_get_area = true; // LCOV_EXCL_LINE (called only when the get area is exhausted)
}
#endif
return res;
@@ -13475,11 +13471,10 @@ class lexer : public lexer_base<BasicJsonType>
template<bool Keep>
char_int_type get_after_string_run(std::true_type /*bulk*/, std::integral_constant<bool, Keep> keep)
{
// a pending unget must be consumed through the normal path first
if (next_unget)
{
return get();
}
// scan_string() is entered from scan_after_whitespace(), whose current
// was read by skip_whitespace() (its first get() clears a pending
// unget), and nothing in scan_string() calls unget()
JSON_ASSERT(!next_unget);
const std::size_t remaining = ia.bulk_remaining();
if (remaining == 0)
{
@@ -14554,11 +14549,9 @@ scan_number_done:
*/
token_type scan_number_bulk_contiguous()
{
// a pending unget offsets the buffer position from current; fall back
if (next_unget)
{
return token_type::uninitialized;
}
// called right after scan_after_whitespace() read current (see
// get_after_string_run()), so no unget is pending
JSON_ASSERT(!next_unget);
const std::size_t rem = ia.bulk_remaining();
if (rem == 0)
{
@@ -14579,11 +14572,7 @@ scan_number_done:
if (data[0] == '-')
{
number_type = token_type::value_integer;
i = 1;
if (i >= avail)
{
return token_type::uninitialized;
}
i = 1; // avail >= 2: rem == 0 returned above
}
const std::size_t integer_begin = i;
if (data[i] == '0')
@@ -16644,7 +16633,7 @@ class json_sax_dom_parser : public json_sax_dom_error_state
ordered_data.members[f.ordered.dest_member].second = std::move(value);
}
static void place_member(const frame& /*f*/, BasicJsonType&& /*value*/, std::false_type /*indexed*/) noexcept {}
static void place_member(const frame& /*f*/, BasicJsonType&& /*value*/, std::false_type /*indexed*/) noexcept {} // LCOV_EXCL_LINE
/// store the members of a new object directly in it
bool start_stored_object(std::size_t len)
@@ -23773,7 +23762,7 @@ class parser
}
return error_msg;
}
} // LCOV_EXCL_LINE (exception cleanup only)
private:
/// callback function
@@ -25084,7 +25073,7 @@ class json_pointer
result.reference_tokens.insert(result.reference_tokens.end(), lhs.reference_tokens.begin(), lhs.reference_tokens.end());
result.reference_tokens.insert(result.reference_tokens.end(), rhs.reference_tokens.begin(), rhs.reference_tokens.end());
return result;
}
} // LCOV_EXCL_LINE (exception cleanup only)
/// @brief create a new JSON pointer by appending the unescaped token at the end of the JSON pointer
/// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/
@@ -25095,7 +25084,7 @@ class json_pointer
result.reference_tokens.insert(result.reference_tokens.end(), lhs.reference_tokens.begin(), lhs.reference_tokens.end());
result.reference_tokens.push_back(std::move(token));
return result;
}
} // LCOV_EXCL_LINE (exception cleanup only)
/// @brief create a new JSON pointer by appending the array-index-token at the end of the JSON pointer
/// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/
@@ -26960,7 +26949,7 @@ class json_pointer
{
// create an entry in the array
current = &current->operator[](array_index<BasicJsonType>(token));
break;
break; // LCOV_EXCL_LINE (needs an array index with 10 or more digits: more than 1e9 elements)
}
/*
@@ -26997,7 +26986,7 @@ class json_pointer
json_pointer<string_t> result;
result.reference_tokens = reference_tokens;
return result;
}
} // LCOV_EXCL_LINE (exception cleanup only)
json_pointer<string_t> convert()&&
{
@@ -28767,7 +28756,7 @@ class binary_writer
while (n != 0);
std::reverse(result.begin(), result.end());
return result;
}
} // LCOV_EXCL_LINE (exception cleanup only)
/*!
@brief the decimal digits of the integer @a n, with a leading '-' if it
@@ -28794,7 +28783,7 @@ class binary_writer
}
std::reverse(result.begin(), result.end());
return result;
}
} // LCOV_EXCL_LINE (exception cleanup only)
/*!
@brief throws because the integer @a j is too large for @a format
@@ -29726,7 +29715,7 @@ class binary_writer
std::memcpy(out, &n, sizeof(NumberType));
if (!is_little_endian)
{
std::reverse(out, out + sizeof(NumberType));
std::reverse(out, out + sizeof(NumberType)); // LCOV_EXCL_LINE (big-endian hosts only)
}
}
@@ -29855,7 +29844,7 @@ class binary_writer
const string_t& value = *j.m_data.m_value.string;
if (JSON_HEDLEY_UNLIKELY(!value_in_range_of<std::int32_t>(value.size() + 1ul)))
{
return false;
return false; // LCOV_EXCL_LINE (a string of 2 GiB or more)
}
out[0] = to_char_type(0x02);
store_little_endian<std::int32_t>(p, static_cast<std::int32_t>(value.size() + 1ul));
@@ -30312,7 +30301,7 @@ class binary_writer
const std::size_t size = oa.written() - pos;
if (JSON_HEDLEY_UNLIKELY(!value_in_range_of<std::int32_t>(size)))
{
return false;
return false; // LCOV_EXCL_LINE (a document of 2 GiB or more)
}
const auto le_size = static_cast<std::uint32_t>(size);
oa.overwrite(pos, is_little_endian ? le_size : byteswap(le_size));
@@ -30441,7 +30430,7 @@ class binary_writer
{
if (JSON_HEDLEY_UNLIKELY(!close_bson_container(nested_size_pos)))
{
return false;
return false; // LCOV_EXCL_LINE (a document of 2 GiB or more)
}
continue;
}
@@ -30456,7 +30445,7 @@ class binary_writer
if (JSON_HEDLEY_UNLIKELY(!close_bson_container(current.size_slot)))
{
return false;
return false; // LCOV_EXCL_LINE (a document of 2 GiB or more)
}
if (parents.empty())
{
@@ -30713,10 +30702,10 @@ class binary_writer
Selected through masks rather than branches, as the type and the sign of
the values in an array of mixed signs alternate unpredictably (non-negative
integers are number_unsigned after parsing). Up to 64 bits, the sign is bit
63 of the result (a narrower integer is sign-extended); computing it with
masks keeps GCC from branching on the type. A wider integer has to be
compared.
integers are number_unsigned after parsing). The sign is bit 63 of the
result (a narrower integer is sign-extended); computing it with masks keeps
GCC from branching on the type. Only called if @ref integers_fit_64_bits();
a wider number type is written with range checks on the whole value.
*/
static std::uint64_t integer_bits(const BasicJsonType& j, std::uint64_t& sign_mask) noexcept
{
@@ -30724,9 +30713,7 @@ class binary_writer
const std::uint64_t raw = is_signed
? static_cast<std::uint64_t>(j.m_data.m_value.number_integer)
: static_cast<std::uint64_t>(j.m_data.m_value.number_unsigned);
sign_mask = sizeof(typename BasicJsonType::number_integer_t) <= sizeof(std::uint64_t)
? (std::uint64_t{0} - static_cast<std::uint64_t>(is_signed)) & (std::uint64_t{0} - (raw >> 63u))
: std::uint64_t{0} - static_cast<std::uint64_t>(is_signed && j.m_data.m_value.number_integer < 0);
sign_mask = (std::uint64_t{0} - static_cast<std::uint64_t>(is_signed)) & (std::uint64_t{0} - (raw >> 63u));
return raw;
}
@@ -32093,57 +32080,34 @@ class binary_writer
}
/*!
@brief validate (dry_run) or write one BJData ND-array element of integer dtype @a T
@return whether @a el's value is in range of @a T; always true when @a dry_run is false
*/
template<typename T>
bool write_bjdata_ndarray_element(const BasicJsonType& el, const bool dry_run)
{
if (dry_run)
{
return bjdata_ndarray_value_in_range<T>(el);
}
using storage_type = typename std::conditional<std::is_unsigned<T>::value, std::uint64_t, std::int64_t>::type;
write_number(static_cast<T>(el.template get<storage_type>()), true);
return true;
}
/*!
@brief validate (dry_run) or write one BJData ND-array element of dtype 'd' (single precision)
@brief whether the BJData ND-array element @a el can be written with dtype 'd' (single precision)
@return whether @a el's value survives narrowing to float and back without any change
(so the ND-array round-trips exactly), or is infinite or NaN; always true when
@a dry_run is false
(so the ND-array round-trips exactly), or is infinite or NaN
*/
bool write_bjdata_ndarray_float_element(const BasicJsonType& el, const bool dry_run)
static bool bjdata_ndarray_float_in_range(const BasicJsonType& el) noexcept
{
const auto dval = static_cast<double>(el.m_data.m_value.number_float);
if (dry_run)
{
#ifdef __GNUC__
JSON_HEDLEY_DIAGNOSTIC_PUSH
JSON_HEDLEY_PRAGMA(GCC diagnostic ignored "-Wfloat-equal")
JSON_HEDLEY_DIAGNOSTIC_PUSH
JSON_HEDLEY_PRAGMA(GCC diagnostic ignored "-Wfloat-equal")
#endif
// a value that would be rounded (rather than exactly represented) by the
// narrowing to float is treated like an out-of-range integer element; this
// is the same criterion write_compact_float() uses for CBOR/MessagePack
const bool in_range = std::isnan(dval) ||
(dval >= static_cast<double>(std::numeric_limits<float>::lowest()) &&
dval <= static_cast<double>((std::numeric_limits<float>::max)()) &&
static_cast<double>(static_cast<float>(dval)) == dval) ||
std::isinf(dval);
// a value that would be rounded (rather than exactly represented) by the
// narrowing to float is treated like an out-of-range integer element; this
// is the same criterion write_compact_float() uses for CBOR/MessagePack
return std::isnan(dval) ||
(dval >= static_cast<double>(std::numeric_limits<float>::lowest()) &&
dval <= static_cast<double>((std::numeric_limits<float>::max)()) &&
static_cast<double>(static_cast<float>(dval)) == dval) ||
std::isinf(dval);
#ifdef __GNUC__
JSON_HEDLEY_DIAGNOSTIC_POP
JSON_HEDLEY_DIAGNOSTIC_POP
#endif
return in_range;
}
write_number(static_cast<float>(dval), true);
return true;
}
/*!
@brief write the elements of an ND-array as the number kind @a dtype names
(see @ref write_bjdata_ndarray), after they have been found to be
in range by a dry run of @ref write_bjdata_ndarray_elements
in range by @ref bjdata_ndarray_elements_in_range
The elements are encoded in blocks into space reserved from the sink.
*/
@@ -32225,20 +32189,13 @@ class binary_writer
}
/*!
@brief validate or write every element of a BJData ND-array's `_ArrayData_`
@brief whether every element of a BJData ND-array's `_ArrayData_` is in range for its dtype
@param[in] array_data the `_ArrayData_` array
@param[in] dtype the ND-array dtype marker, as returned by bjdata_ndarray_type_marker()
@param[in] dry_run true to only range-check each element, false to write it
@return whether every element is in range for @a dtype (always true when @a dry_run is false)
@return whether every element is in range for @a dtype
*/
bool write_bjdata_ndarray_elements(const BasicJsonType& array_data, const CharType dtype, const bool dry_run)
static bool bjdata_ndarray_elements_in_range(const BasicJsonType& array_data, const CharType dtype)
{
if (!dry_run)
{
write_bjdata_ndarray_values(array_data, dtype);
return true;
}
for (const auto& el : array_data)
{
bool ok = true;
@@ -32246,43 +32203,39 @@ class binary_writer
{
case 'U':
case 'B':
ok = write_bjdata_ndarray_element<std::uint8_t>(el, dry_run);
ok = bjdata_ndarray_value_in_range<std::uint8_t>(el);
break;
case 'C':
// BJData limits a char to 0..127 (the intersection of the int8 and uint8 ranges)
ok = bjdata_ndarray_value_in_range<std::int8_t>(el) && bjdata_ndarray_value_in_range<std::uint8_t>(el);
break;
case 'i':
ok = write_bjdata_ndarray_element<std::int8_t>(el, dry_run);
ok = bjdata_ndarray_value_in_range<std::int8_t>(el);
break;
case 'u':
ok = write_bjdata_ndarray_element<std::uint16_t>(el, dry_run);
ok = bjdata_ndarray_value_in_range<std::uint16_t>(el);
break;
case 'I':
ok = write_bjdata_ndarray_element<std::int16_t>(el, dry_run);
ok = bjdata_ndarray_value_in_range<std::int16_t>(el);
break;
case 'm':
ok = write_bjdata_ndarray_element<std::uint32_t>(el, dry_run);
ok = bjdata_ndarray_value_in_range<std::uint32_t>(el);
break;
case 'l':
ok = write_bjdata_ndarray_element<std::int32_t>(el, dry_run);
ok = bjdata_ndarray_value_in_range<std::int32_t>(el);
break;
case 'M':
ok = write_bjdata_ndarray_element<std::uint64_t>(el, dry_run);
ok = bjdata_ndarray_value_in_range<std::uint64_t>(el);
break;
case 'L':
ok = write_bjdata_ndarray_element<std::int64_t>(el, dry_run);
ok = bjdata_ndarray_value_in_range<std::int64_t>(el);
break;
case 'd':
ok = write_bjdata_ndarray_float_element(el, dry_run);
ok = bjdata_ndarray_float_in_range(el);
break;
case 'D':
default:
// 'D' (double) already spans the full range of number_float_t
if (!dry_run)
{
write_number(el.template get<double>(), true);
}
break;
}
if (!ok)
@@ -32369,7 +32322,7 @@ class binary_writer
const auto dim = el.template get<std::uint64_t>();
if (!value_in_range_of<std::size_t>(dim))
{
return true;
return true; // LCOV_EXCL_LINE (size_t is narrower than 64 bits)
}
const auto dim_size = static_cast<std::size_t>(dim);
@@ -32419,7 +32372,7 @@ class binary_writer
// wrap (integers) or overflow to infinity (the "single" precision
// float) instead of being reported, so such an object falls back to
// a plain object encoding as well
if (!write_bjdata_ndarray_elements(array_data, dtype, true))
if (!bjdata_ndarray_elements_in_range(array_data, dtype))
{
return true;
}
@@ -32431,7 +32384,7 @@ class binary_writer
write_ubjson(array_size, use_count, use_type, true, true, bjdata_version);
write_bjdata_ndarray_elements(array_data, dtype, false);
write_bjdata_ndarray_values(array_data, dtype);
return false;
}
@@ -32757,8 +32710,8 @@ class binary_writer
run are encoded into space reserved from the sink, as in
@ref write_array_elements; an integer that BON8 cannot write (an unsigned
one above the int64 range, or one of a number type wider than 64 bits) throws
from write_bon8_value, like any other value that is not a number. Kept out
of line, like @ref write_cbor_array.
out_of_range.407, as write_bon8_value does. Kept out of line, like
@ref write_cbor_array.
*/
template<typename ArrayType>
JSON_HEDLEY_NEVER_INLINE
@@ -32808,10 +32761,10 @@ class binary_writer
string_open = false;
}
if (unencodable)
if (JSON_HEDLEY_UNLIKELY(unencodable))
{
write_bon8_value(*it, string_open, depth + 1);
++it;
// an integer beyond the int64 range, as write_bon8_value would report it
throw_integer_out_of_range(*it, input_format_t::bon8, "int64");
}
}
}
@@ -32846,14 +32799,13 @@ class binary_writer
break;
case value_t::number_integer:
if (JSON_HEDLEY_LIKELY(integer_fits<std::int64_t>(value.m_data.m_value.number_integer)))
if (JSON_HEDLEY_UNLIKELY(!integer_fits<std::int64_t>(value.m_data.m_value.number_integer)))
{
write_bon8_integer(static_cast<std::int64_t>(value.m_data.m_value.number_integer));
string_open = false;
break;
// beyond 64 bits (number types wider than that)
throw_integer_out_of_range(value, input_format_t::bon8, "int64");
}
// beyond 64 bits (number types wider than that): throws
write_bon8_value(value, string_open, depth + 1);
write_bon8_integer(static_cast<std::int64_t>(value.m_data.m_value.number_integer));
string_open = false;
break;
case value_t::number_float:
@@ -32862,14 +32814,13 @@ class binary_writer
break;
case value_t::number_unsigned:
if (JSON_HEDLEY_LIKELY(integer_fits_max<std::int64_t>(value.m_data.m_value.number_unsigned)))
if (JSON_HEDLEY_UNLIKELY(!integer_fits_max<std::int64_t>(value.m_data.m_value.number_unsigned)))
{
write_bon8_integer(static_cast<std::int64_t>(value.m_data.m_value.number_unsigned));
string_open = false;
break;
// too large for BON8
throw_integer_out_of_range(value, input_format_t::bon8, "int64");
}
// too large for BON8: throws
write_bon8_value(value, string_open, depth + 1);
write_bon8_integer(static_cast<std::int64_t>(value.m_data.m_value.number_unsigned));
string_open = false;
break;
case value_t::object:
@@ -36326,7 +36277,7 @@ class serializer
// character
if (EnsureAscii)
{
JSON_ASSERT(codepoint >= 0x7F);
JSON_ASSERT(codepoint == 0x7F);
if (error_handler == error_handler_t::keep)
{
// this character was buffered as raw bytes below
@@ -36337,21 +36288,13 @@ class serializer
// character instead
bytes = bytes_after_last_accept;
}
if (codepoint <= 0xFFFF)
{
write_u_escape(bytes, static_cast<std::uint16_t>(codepoint));
}
else
{
write_u_escape(bytes, static_cast<std::uint16_t>(0xD7C0u + (codepoint >> 10u)));
write_u_escape(bytes, static_cast<std::uint16_t>(0xDC00u + (codepoint & 0x3FFu)));
}
write_u_escape(bytes, static_cast<std::uint16_t>(codepoint));
}
else
{
// copy byte to buffer (all previous bytes of the
// sequence have been copied in the default case below)
string_buffer[bytes++] = s[i];
string_buffer[bytes++] = s[i]; // LCOV_EXCL_LINE (well-formed sequences are copied in runs)
}
reserve_string_buffer(bytes);
@@ -38192,7 +38135,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
result["compiler"] = {{"family", "clang"}, {"version", __clang_version__}};
#elif defined(__GNUC__) || defined(__GNUG__)
result["compiler"] = {{"family", "gcc"}, {"version", detail::concat<string_t>(
detail::to_string<string_t>(static_cast<std::size_t>(__GNUC__)), '.',
detail::to_string<string_t>(static_cast<std::size_t>(__GNUC__)), '.', // LCOV_EXCL_LINE
detail::to_string<string_t>(static_cast<std::size_t>(__GNUC_MINOR__)), '.',
detail::to_string<string_t>(static_cast<std::size_t>(__GNUC_PATCHLEVEL__)))
}
@@ -38464,14 +38407,14 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
case value_t::binary:
binary = create<binary_t>();
break;
case value_t::null:
case value_t::null: // LCOV_EXCL_LINE
case value_t::boolean:
case value_t::number_integer:
case value_t::number_unsigned:
case value_t::number_float:
case value_t::discarded:
default:
break;
break; // LCOV_EXCL_LINE
}
}
@@ -38826,14 +38769,14 @@ public:
destroy_container(t);
break;
case value_t::null:
case value_t::null: // LCOV_EXCL_LINE
case value_t::boolean:
case value_t::number_integer:
case value_t::number_unsigned:
case value_t::number_float:
case value_t::discarded:
default:
break;
break; // LCOV_EXCL_LINE
}
}
};
@@ -39006,9 +38949,9 @@ public:
return is_array() ? array_capacity() : object_capacity();
}
#else
static constexpr std::size_t container_capacity() noexcept
static constexpr std::size_t container_capacity() noexcept // LCOV_EXCL_LINE
{
return detail::unknown_size();
return detail::unknown_size(); // LCOV_EXCL_LINE
}
#endif
@@ -39194,7 +39137,7 @@ public:
/// into this switch is worth a few percent when copying a value made
/// mostly of numbers
JSON_HEDLEY_ALWAYS_INLINE
static void copy_leaf_value(const basic_json& src, basic_json& dst)
static void copy_leaf_value(const basic_json& src, basic_json& dst) // LCOV_EXCL_LINE
{
switch (src.m_data.m_type)
{
@@ -43346,7 +43289,7 @@ public:
/// their inlined code at each call site small. Binary values are
/// rare and left to equal_general().
JSON_HEDLEY_ALWAYS_INLINE
static int equal_leaf(const_reference lhs, const_reference rhs) noexcept
static int equal_leaf(const_reference lhs, const_reference rhs) noexcept // LCOV_EXCL_LINE
{
#ifdef __GNUC__
JSON_HEDLEY_DIAGNOSTIC_PUSH
@@ -44655,7 +44598,7 @@ public:
basic_json result(value_t::object);
json_pointer::flatten("", *this, result);
return result;
}
} // LCOV_EXCL_LINE (exception cleanup only)
/// @brief unflatten a previously flattened JSON value
/// @sa https://json.nlohmann.me/api/basic_json/unflatten/
@@ -45368,7 +45311,7 @@ public:
result.append(path.data(), path.size());
diff_append_key(result, key);
return result;
}
} // LCOV_EXCL_LINE (exception cleanup only)
/// @brief the path of the element @a index of the value at @a path
static string_t diff_index_path(const string_t& path, const std::size_t index)
@@ -45378,7 +45321,7 @@ public:
result.append(path.data(), path.size());
diff_append_index(result, index);
return result;
}
} // LCOV_EXCL_LINE (exception cleanup only)
/// @brief append the "remove" operations for the elements of array
/// @a source from @a index on, and the "add" operations for the
@@ -45538,7 +45481,7 @@ public:
// operations
if (source == target)
{
return false;
return false; // LCOV_EXCL_LINE (equal objects with the same members in the same order return early)
}
// slow path: the common keys are in a different relative
+24 -52
View File
@@ -3580,28 +3580,19 @@ class view_side
return string_view_t(m_view.m_doc->str(*m_view.m_node), m_view.m_node->len);
}
/// a number, boolean, or null as a basic_json value (no allocation)
/// a number as a basic_json value (no allocation); only called for numbers
BasicJsonType scalar() const
{
switch (m_view.type())
const value_t t = m_view.type();
if (t == value_t::number_integer)
{
case value_t::number_integer:
return BasicJsonType(m_view.template get<typename BasicJsonType::number_integer_t>());
case value_t::number_unsigned:
return BasicJsonType(m_view.template get<typename BasicJsonType::number_unsigned_t>());
case value_t::number_float:
return BasicJsonType(m_view.template get<typename BasicJsonType::number_float_t>());
case value_t::boolean:
return BasicJsonType(m_view.template get<bool>());
case value_t::null:
case value_t::object:
case value_t::array:
case value_t::string:
case value_t::binary:
case value_t::discarded:
default:
return BasicJsonType(nullptr);
return BasicJsonType(m_view.template get<typename BasicJsonType::number_integer_t>());
}
if (t == value_t::number_unsigned)
{
return BasicJsonType(m_view.template get<typename BasicJsonType::number_unsigned_t>());
}
return BasicJsonType(m_view.template get<typename BasicJsonType::number_float_t>());
}
/// start at the first element of this array
@@ -4478,14 +4469,9 @@ struct position_source
return token{end - start};
}
/// the range [first, last), or none if either is npos
/// the range [first, last)
void set(std::size_t first, std::size_t last) noexcept
{
if (first == std::string::npos || last == std::string::npos)
{
clear();
return;
}
start = first;
end = last;
}
@@ -4604,11 +4590,11 @@ struct position_source
first = n.off;
last = n.off + 4u;
break;
case node_kind::object:
case node_kind::object: // LCOV_EXCL_LINE
case node_kind::array:
case node_kind::link:
default:
break;
break; // LCOV_EXCL_LINE
}
// (a crafted image can point past the text)
if (last == std::string::npos || last > d.size)
@@ -5262,10 +5248,12 @@ struct throwing_sax
return true;
}
// LCOV_EXCL_START (throw_parse_failure parses JSON only)
bool binary(binary_t& /*unused*/)
{
return true;
}
// LCOV_EXCL_STOP
bool start_object(std::size_t /*unused*/)
{
@@ -5573,7 +5561,7 @@ inline node* find_parent(const document_data& d, const node* target)
}
if (target == lo)
{
return nullptr;
return nullptr; // LCOV_EXCL_LINE (the root, or a new value's root, which is linked)
}
for (;;)
{
@@ -6194,11 +6182,11 @@ NLOHMANN_VIEW_NOINLINE inline void check_utf8_scan(const unsigned char* p, std::
}
if (*q >= 0x80)
{
check_utf8_bytewise(p, n, static_cast<std::size_t>(q - p));
return; // not reached: the scan stopped at ill-formed UTF-8
break; // ill-formed UTF-8: reported below
}
++q; // a quote, backslash, or control character
}
check_utf8_bytewise(p, n, static_cast<std::size_t>(q - p));
}
inline void check_utf8(const char* s, std::size_t n)
@@ -9853,20 +9841,10 @@ class view_serializer
/// a float node as dump() writes it
void write_float_node(const node& n)
{
write_float_node(n, fast_double {});
}
void write_float_node(const node& n, std::false_type /*other*/)
{
// (only for types other than double: doubles go through write_double_ahead())
write_float(float_value<number_float_t>(m_doc, n));
}
void write_float_node(const node& n, std::true_type /*double*/)
{
m_out.reserve(64);
m_out.set_cursor(write_double_at(m_out.cursor(), n));
}
/*!
@brief (doubles) the float at n as dump() writes it, at w (64 bytes of room)
@@ -9961,7 +9939,7 @@ class view_serializer
{
const string_t dumped = BasicJsonType(string_t(reinterpret_cast<const char*>(s), n)).dump(); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
static_cast<void>(dumped);
}
} // LCOV_EXCL_LINE (dump() throws: the callers pass only ill-formed UTF-8)
template<bool EnsureAscii>
void write_codepoint(std::uint32_t codepoint, const unsigned char* bytes, std::size_t len)
@@ -9994,15 +9972,7 @@ class view_serializer
}
if (codepoint <= 0x1F || (EnsureAscii && codepoint >= 0x7F))
{
if (codepoint <= 0xFFFF)
{
write_u_escape(codepoint);
}
else
{
write_u_escape(0xD7C0u + (codepoint >> 10u));
write_u_escape(0xDC00u + (codepoint & 0x3FFu));
}
write_u_escape(codepoint); // (a single byte: the only caller passes s[i])
return;
}
m_out.put(reinterpret_cast<const char*>(bytes), len); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) LCOV_EXCL_LINE (printable characters are copied in runs)
@@ -11799,9 +11769,11 @@ class basic_json_document
{
// (as before: the library's adapter decides what a null stream yields)
detail::view::append_adapter(buf, detail::input_adapter(file));
return;
}
detail::view::append_file(buf, file);
else
{
detail::view::append_file(buf, file);
}
}
#endif