* Handle numbers that do not fit narrow number types in the binary readers With custom number types narrower than the values in a binary document, for example basic_json<..., std::int32_t, std::uint32_t, float>, every binary reader (CBOR, MessagePack, UBJSON, BJData, BSON, BON8) passed the decoded number to the SAX interface with an implicit conversion: the integer 5000000000 silently became 705032704, and a finite double such as 1e300 became infinity. The lexer handles the same values in JSON text: an integer that fits neither integer type is stored as number_float_t, and a finite number that overflows number_float_t is rejected with out_of_range.406. Pass every number read from binary input through three helpers that apply the lexer's rules: - emit_signed(): number_integer_t, else number_unsigned_t for a non-negative value, else number_float_t - emit_unsigned(): number_unsigned_t, else number_float_t - emit_float(): out_of_range.406 if a finite value overflows number_float_t; infinity and NaN are passed on For consistency, a CBOR negative integer below the range of number_integer_t is now stored as number_float_t, like a too small integer in JSON text, instead of being rejected with parse_error.112. With the default number types, this is the only change in behavior. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Fix MSVC and clang 3.5 in the narrow number type test MSVC types 3000000000 and 5000000000 as unsigned long, so json(-3000000000) triggered C4146 (unary minus on an unsigned type), which /WX turns into an error. Use LL literals, as elsewhere in the tests. clang 3.5 cannot convert the lambdas in the braced initializer of the format table to function pointers. Use named functions instead. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Check integer-to-float fallbacks for overflow in the binary readers emit_signed, emit_unsigned, and the CBOR negative integer fallback now pass their number_float_t fallback through emit_float, so a value that overflows number_float_t is rejected with out_of_range.406 like a floating-point value, instead of silently becoming infinity. This only matters for a number_float_t that cannot represent 2^64, such as a half-precision type. The CBOR value -1 - n is computed as long double so that emit_float sees a finite value. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Use the input_format member instead of passing the format to binary_reader helpers The helpers (get_number, get_to, get_string, get_binary, get_bytes, emit_signed, emit_unsigned, emit_float, unexpect_eof, exception_message) are members of binary_reader, which already stores the format it was constructed with, so the parameter was redundant. Signed-off-by: Niels Lohmann <mail@nlohmann.me> --------- Signed-off-by: Niels Lohmann <mail@nlohmann.me>
4.0 KiB
nlohmann::basic_json::number_unsigned_t
using number_unsigned_t = NumberUnsignedType;
The type used to store JSON numbers (unsigned).
RFC 8259 describes numbers as follows:
The representation of numbers is similar to that used in most programming languages. A number is represented in base 10 using decimal digits. It contains an integer component that may be prefixed with an optional minus sign, which may be followed by a fraction part and/or an exponent part. Leading zeros are not allowed. (...) Numeric values that cannot be represented in the grammar below (such as Infinity and NaN) are not permitted.
This description includes both integer and floating-point numbers. However, C++ allows more precise storage if it is
known whether the number is a signed integer, an unsigned integer, or a floating-point number. Therefore, three different
types, number_integer_t, number_unsigned_t and number_float_t are
used.
To store unsigned integer numbers in C++, a type is defined by the template parameter NumberUnsignedType which chooses
the type to use.
Template parameters
NumberUnsignedType- the type to store unsigned integers. It must be an unsigned integral type (
#!cpp std::is_integral) with a#!cpp std::numeric_limitsspecialization, and it must be able to represent the absolute value of everynumber_integer_tvalue. See Template Parameter Requirements.
Notes
Default type
With the default values for NumberUnsignedType (std::uint64_t), the default value for number_unsigned_t is
#!cpp std::uint64_t.
Default behavior
- The restrictions about leading zeros are not enforced in C++. Instead, leading zeros in integer literals lead to an
interpretation as an octal number. Internally, the value will be stored as a decimal number. For instance, the C++
integer literal
010will be serialized to8. During deserialization, leading zeros yield an error.
Limits
RFC 8259 specifies:
An implementation may set limits on the range and precision of numbers.
When the default type is used, the maximal integer number that can be stored is 18446744073709551615 (UINT64_MAX) and
the minimal integer number that can be stored is 0. Integer numbers that are out of range will yield over/underflow
when used in a constructor. During deserialization (from JSON text or any of the binary formats), too large or small
integer numbers will automatically be stored as number_integer_t or
number_float_t.
RFC 8259 further states:
Note that when such software is used, numbers that are integers and are in the range [-253+1, 253-1] are interoperable in the sense that implementations will agree exactly on their numeric values.
As this range is a subrange (when considered in conjunction with the number_integer_t type) of the exactly supported
range [0, UINT64_MAX], this class's integer type is interoperable.
Storage
Integer number values are stored directly inside a basic_json type.
Examples
??? example
The following code shows that `number_unsigned_t` is by default, a typedef to `#!cpp std::uint64_t`.
```cpp
--8<-- "examples/number_unsigned_t.cpp"
```
Output:
```json
--8<-- "examples/number_unsigned_t.output"
```
See also
- number_integer_t the type used to store JSON integer numbers
- number_float_t the type used to store JSON floating-point numbers
- is_number_unsigned checks whether the JSON value is an unsigned integer number
- Number Handling - the article on number handling
Version history
- Added in version 2.0.0.