|
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:
intunsigned intbsls::Types::Int64bsls::Types::Uint64floatdoublebdldfp::Decimal64In 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: