BDE 4.14.0 Production release
|
Provide a value-semantic type representing a JSON number.
This component provides a single value-semantic class, bdljsn::JsonNumber
, that represents a JSON number. The value of a bdljsn::JsonNumber
object is set at construction using a string representation of the JSON number (see {JSON Textual Specification}) or from one of several C++ arithmetic types (see {Supported Conversions}).
Arithmetic operations are not defined for bdljsn::JsonNumber
objects. For such operations, the value of a bdljsn::JsonNumber
object can be converted to any of those supported types, though the conversion may not be exact.
The bdlsn::JsonNumber
equality operation returns true
if the string representation of the number (returned by the value
accessor method) is the same, even where the two strings represent the same number (e.g., "10" and "1e1"). This definition of equality reflects the fact that the JSON textual representation for the two JsonNumber
objects will be different. The function isEqual
is provided for (a more expensive) numeric equality comparison.
JSON numbers are defined by strings that match the grammar given at https://www.rfc-editor.org/rfc/rfc8259#section-6. The equivalent regular expression is:
Note that "\z" matches end-of-string but not a preceding '
'.
For example:
Notice that:
INF
(infinity) and NaN
(Not A Number) are disallowed.The value of a bdljsn::JsonNumber
object is determined by its given string representation, which is not normalized. Unequal strings lead to unequal bdljsn::JsonNumber
objects even if their numerical values are equal. Numerical equality can be tested with the isEqual
method. Note that the isEqual
method is more computationally expensive than the equality and inequality operators:
The value of a bdljsn::JsonNumber
object can be converted to an assortment of useful types:
int
unsigned int
bsls::Types::Int64
bsls::Types::Uint64
float
double
bdldfp::Decimal64
In addition to named conversion functions (like asInt
and asDouble
) This component provides explicit conversion operations for floating point types (float
, double
, Decimal64
) on platforms where explicit conversions are supported.
Converting a bdlsjn::JsonNumber
to another representation may result in a value that is not the same as the original bdljsn::JsonNumber
. Either the bdljsn::JsonNumber
may represent a numeric value outside of the representable range of the requested type (i.e., it is too large, or too small), or the value may not be representable exactly. bdljsn::JsonNumber
conversions will return the closest approximation of the bdljsn::JsonNumber
, even when a non-zero status is returned indicating an inexact conversion.
All the provided conversions to integral types have signatures that require a return status, whereas conversion functions are provided for floating point types that do not return a status. This is because:
bdljsn::JsonNumber
is outside of the representable range (-INF, +INF)
.bdljsn::JsonNumber
is very often not an error.For users requiring precise conversions to bdldfp::Decimal64
, the function asDecimal64Exact
returns additional status indicating whether the conversion is exact. An exact conversion for a Decimal64
is one that preserves all the significant digits resulting in a decimal representation having the same numerical value as the original JSON text. Note that asDecimal64Exact
has very similar performance to asDecimal64
(i.e., there is not a notable performance penalty to determining this property).
Currently asDecimal64Exact
will return bdljsn::JsonNumber::k_NOT_EXACT
if the input is 0 with an exponent outside of the range ([-398, 369]
). For example, 0e-400
. This reflects the behavior of the underlying 3rd party implementation. Please contact BDE if this is a concern.
This section illustrates intended use of this component.
The specification of values for JSON numbers often starts with user input textual representations of those values. As the specifications for valid representation are complicated and not always intuitive it is prudent to validate that input using the bdljsn::JsonNumber::isValidNumber
function; otherwise, one might try to create a bdljsn::JsonNumber
object from an invalid specification and that leads to undefined behavior.
First, as a expedient for this example, we organize in an array input that might well be entered by some user:
Now, if and only if the input is valid, we use the input to construct a bdljsn::JsonNumber
object and add that object to a vector for later processing.
Finally, we confirm that the vector has the expected number of elements:
We saw in {Example 1} that bdljsn::JsonNumber
objects can validly hold values numeric values that cannot be converted to any of the supported types (e.g., the "astronomic value") for arithmetic operations. Applications that accept arbitrary bdljsn::JsonNumber
objects should be prepared to categorize the contained value and adapt their handling accordingly. In practice, applications may have some assurances of the contents of received bdljsn::JsonNumber
objects. Here, we intentionally avoid such assumptions to explore the wide range of variations that can arise.
Legend, in the output below:
First, we set up a framework (in this case, a for
loop) for examining our input, the same userInput
vector created in {Example 1}:
Then, we categorize the value as integral or not:
If integral, we check if the value is a usable range. Let us assume that bslsl::Type::Int64
is as large a number as we can accept.
Then, we convert the JSON number to that type and check for overflow and underflow:
Next, if the value is not integral, we try to handle it as a floating point value – a bdldfp::Decimal64
in this example – and further categorize it as exact/inexact, too large/small.
Finally, we observe for particular input: