BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bdljsn_jsonnumber.h
Go to the documentation of this file.
1/// @file bdljsn_jsonnumber.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdljsn_jsonnumber.h -*-C++-*-
8#ifndef INCLUDED_BDLJSN_JSONNUMBER
9#define INCLUDED_BDLJSN_JSONNUMBER
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bdljsn_jsonnumber bdljsn_jsonnumber
15/// @brief Provide a value-semantic type representing a JSON number.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdljsn
19/// @{
20/// @addtogroup bdljsn_jsonnumber
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdljsn_jsonnumber-purpose"> Purpose</a>
25/// * <a href="#bdljsn_jsonnumber-classes"> Classes </a>
26/// * <a href="#bdljsn_jsonnumber-description"> Description </a>
27/// * <a href="#bdljsn_jsonnumber-json-textual-specification"> JSON Textual Specification </a>
28/// * <a href="#bdljsn_jsonnumber-supported-conversions"> Supported Conversions </a>
29/// * <a href="#bdljsn_jsonnumber-handling-inexact-conversions-floating-point-vs-integral-types"> Handling Inexact Conversions: Floating Point Vs Integral Types </a>
30/// * <a href="#bdljsn_jsonnumber-exact-decima64-representations"> Exact Decima64 Representations </a>
31/// * <a href="#bdljsn_jsonnumber-known-issues-with-asdecima64exact"> Known Issues With asDecima64Exact </a>
32/// * <a href="#bdljsn_jsonnumber-usage"> Usage </a>
33/// * <a href="#bdljsn_jsonnumber-example-1-creating-json-number-object-from-user-input"> Example 1: Creating JSON Number Object from User Input </a>
34/// * <a href="#bdljsn_jsonnumber-example-2-using-bdljsn-jsonnumber-objects"> Example 2: Using bdljsn::JsonNumber Objects </a>
35///
36/// # Purpose {#bdljsn_jsonnumber-purpose}
37/// Provide a value-semantic type representing a JSON number.
38///
39/// # Classes {#bdljsn_jsonnumber-classes}
40///
41/// - bdljsn::JsonNumber: value-semantic type representing a JSON number
42///
43/// # Description {#bdljsn_jsonnumber-description}
44/// This component provides a single value-semantic class,
45/// `bdljsn::JsonNumber`, that represents a JSON number. The value of a
46/// `bdljsn::JsonNumber` object is set at construction using a string
47/// representation of the JSON number (see {JSON Textual Specification}) or from
48/// one of several C++ arithmetic types (see {Supported Conversions}).
49///
50/// Arithmetic operations are *not* defined for `bdljsn::JsonNumber` objects.
51/// For such operations, the value of a `bdljsn::JsonNumber` object can be
52/// converted to any of those supported types, though the conversion may not be
53/// exact.
54///
55/// The `bdlsn::JsonNumber` equality operation returns `true` if the string
56/// representation of the number (returned by the `value` accessor method) is
57/// the same, even where the two strings represent the same number (e.g., "10"
58/// and "1e1"). This definition of equality reflects the fact that the JSON
59/// textual representation for the two `JsonNumber` objects will be different.
60/// The function `isEqual` is provided for (a more expensive) numeric equality
61/// comparison.
62///
63/// ## JSON Textual Specification {#bdljsn_jsonnumber-json-textual-specification}
64///
65///
66/// JSON numbers are defined by strings that match the grammar given at
67/// https://www.rfc-editor.org/rfc/rfc8259#section-6. The equivalent regular
68/// expression is:
69/// @code
70/// /^-?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][-+]?[0-9]+)?\z/
71/// @endcode
72/// Note that "\z" matches end-of-string but not a preceding '\n'.
73///
74/// For example:
75/// @code
76/// 1
77/// 2.1
78/// -3
79/// 4e1
80/// 5.1e+2
81/// 6.12e-3
82/// 7e+04
83/// -8.1e+005
84/// @endcode
85/// Notice that:
86///
87/// * Leading zeros are not allowed for the mantissa but are allowed for the
88/// exponent.
89/// * A decimal point must be followed by at least one digit.
90/// * The grammar does *not* specify any limit on the number of digits in the
91/// mantissa or the exponent.
92///
93/// - One can validly represent JSON numbers that are too large or too small
94/// for conversion to any of the supported arithmetic types.
95/// * The special values, `INF` (infinity) and `NaN` (Not A Number) are
96/// disallowed.
97///
98/// The value of a `bdljsn::JsonNumber` object is determined by its given string
99/// representation, which is *not* normalized. Unequal strings lead to unequal
100/// `bdljsn::JsonNumber` objects even if their numerical values are equal.
101/// Numerical equality can be tested with the `isEqual` method. Note that the
102/// `isEqual` method is more computationally expensive than the equality and
103/// inequality operators:
104/// @code
105/// // The following 'JsonNumber' objects do not compare equal because their
106/// // string representations are different:
107/// assert(bdljsn::JsonNumber("1") != bdljsn::JsonNumber("1.0"));
108///
109/// // But, they are numerically equal, so 'isEqual' returns 'true':
110/// assert(bdljsn::JsonNumber("1").isEqual(bdljsn::JsonNumber("1.0")));
111/// @endcode
112///
113/// ## Supported Conversions {#bdljsn_jsonnumber-supported-conversions}
114///
115///
116/// The value of a `bdljsn::JsonNumber` object can be converted to an assortment
117/// of useful types:
118///
119/// * `int`
120/// * `unsigned int`
121/// * `bsls::Types::Int64`
122/// * `bsls::Types::Uint64`
123/// * `float`
124/// * `double`
125/// * `bdldfp::Decimal64`
126///
127/// In addition to named conversion functions (like `asInt` and `asDouble`) This
128/// component provides explicit conversion operations for floating point types
129/// (`float`, `double`, `Decimal64`) on platforms where explicit conversions are
130/// supported.
131///
132/// ### Handling Inexact Conversions: Floating Point Vs Integral Types {#bdljsn_jsonnumber-handling-inexact-conversions-floating-point-vs-integral-types}
133///
134///
135/// Converting a `bdlsjn::JsonNumber` to another representation may result in a
136/// value that is not the same as the original `bdljsn::JsonNumber`. Either the
137/// `bdljsn::JsonNumber` may represent a numeric value outside of the
138/// representable range of the requested type (i.e., it is too large, or too
139/// small), or the value may not be representable exactly. `bdljsn::JsonNumber`
140/// conversions will return the closest approximation of the
141/// `bdljsn::JsonNumber`, even when a non-zero status is returned indicating an
142/// inexact conversion.
143///
144/// All the provided conversions to integral types have signatures that require
145/// a return status, whereas conversion functions are provided for floating
146/// point types that do not return a status. This is because:
147///
148/// 1. Floating point representations have specific values to indicate a
149/// `bdljsn::JsonNumber` is outside of the representable range
150/// `(-INF, +INF)`.
151/// 2. Truncating the fractional part of a number to coerce a value to an
152/// integer is typically an error (the data being processed did not meet the
153/// programmer's expectation), whereas returning the closest floating point
154/// approximation to a `bdljsn::JsonNumber` is very often not an error.
155///
156/// ### Exact Decima64 Representations {#bdljsn_jsonnumber-exact-decima64-representations}
157///
158///
159/// For users requiring precise conversions to `bdldfp::Decimal64`, the function
160/// `asDecimal64Exact` returns additional status indicating whether the
161/// conversion is exact. An exact conversion for a `Decimal64` is one that
162/// preserves all the significant digits resulting in a decimal representation
163/// having the same numerical value as the original JSON text. Note that
164/// `asDecimal64Exact` has very similar performance to `asDecimal64` (i.e.,
165/// there is not a notable performance penalty to determining this property).
166///
167/// ### Known Issues With asDecima64Exact {#bdljsn_jsonnumber-known-issues-with-asdecima64exact}
168///
169///
170/// Currently `asDecimal64Exact` will return `bdljsn::JsonNumber::k_NOT_EXACT`
171/// if the input is 0 with an exponent outside of the range (`[-398, 369]`).
172/// For example, `0e-400`. This reflects the behavior of the underlying 3rd
173/// party implementation. Please contact BDE if this is a concern.
174///
175/// ## Usage {#bdljsn_jsonnumber-usage}
176///
177///
178/// This section illustrates intended use of this component.
179///
180/// ### Example 1: Creating JSON Number Object from User Input {#bdljsn_jsonnumber-example-1-creating-json-number-object-from-user-input}
181///
182///
183/// The specification of values for JSON numbers often starts with user input
184/// textual representations of those values. As the specifications for valid
185/// representation are complicated and not always intuitive it is prudent to
186/// validate that input using the `bdljsn::JsonNumber::isValidNumber` function;
187/// otherwise, one might try to create a `bdljsn::JsonNumber` object from an
188/// invalid specification and that leads to undefined behavior.
189///
190/// First, as a expedient for this example, we organize in an array input that
191/// might well be entered by some user:
192/// @code
193/// struct {
194/// const char *d_text_p;
195/// const char *d_description_p;
196/// bool d_expected;
197/// } USER_INPUT[] = {
198///
199/// // VALUE DESCRIPTION EXP
200/// // ---------------------- -------------------------------------- ---
201///
202/// // Invalid Input (that is valid in other contexts).
203///
204/// { "1.", "Not uncommon way to write '1'." , 0 }
205/// , { "1,000", "No commas allowed" , 0 }
206/// , { "01", "Leading '0', disallowed by JSON." , 0 }
207/// , { "", "0 per 'atoi', disallowed by JSON." , 0 }
208/// , { "Hello, world!", "0 per 'atoi', disallowed by JSON." , 0 }
209/// , { "NaN", "invalid number" , 0 }
210/// , { "INF", "invalid number" , 0 }
211/// , { "-INF", "invalid number" , 0 }
212/// , { "+INF", "invalid number" , 0 }
213///
214/// // Valid input (some surprising)
215///
216/// , { "1234567890", "Integral value" , 1 }
217/// , { "1234567890.123456", "Non-integral value" , 1 }
218/// , { "1234567890.1234567", "Beyond Decimal64 precision" , 1 }
219/// , { "-9223372036854775809", "INT64_MIN, underflow, but valid JSON", 1 }
220/// , { "1.5e27", "INT64_MAX, overflow, but valid JSON", 1 }
221/// , { "999999999999999999999999999999999999999999999999999999999999"
222/// "e"
223/// "999999999999999999999999999999999999999999999999999999999999",
224/// "astronomic value" , 1 }
225/// };
226///
227/// const bsl::size_t NUM_USER_INPUT = sizeof USER_INPUT / sizeof *USER_INPUT;
228/// @endcode
229/// Now, if and only if the input is valid, we use the input to construct a
230/// `bdljsn::JsonNumber` object and add that object to a vector for later
231/// processing.
232/// @code
233/// bsl::vector<bdljsn::JsonNumber> userInput; // when valid input
234///
235/// for (bsl::size_t ti = 0; ti < NUM_USER_INPUT; ++ti) {
236/// const char *TEXT = USER_INPUT[ti].d_text_p;
237/// const char *DESC = USER_INPUT[ti].d_description_p; (void) DESC;
238/// const bool EXP = USER_INPUT[ti].d_expected;
239///
240/// const bool isValid = bdljsn::JsonNumber::isValidNumber(TEXT);
241/// assert(EXP == isValid);
242///
243/// if (isValid) {
244/// userInput.push_back(bdljsn::JsonNumber(TEXT));
245/// }
246/// }
247/// @endcode
248/// Finally, we confirm that the vector has the expected number of elements:
249/// @code
250/// assert(6 == userInput.size());
251/// @endcode
252///
253/// ### Example 2: Using bdljsn::JsonNumber Objects {#bdljsn_jsonnumber-example-2-using-bdljsn-jsonnumber-objects}
254///
255///
256/// We saw in {Example 1} that `bdljsn::JsonNumber` objects can validly hold
257/// values numeric values that cannot be converted to any of the supported types
258/// (e.g., the "astronomic value") for arithmetic operations. Applications that
259/// accept arbitrary `bdljsn::JsonNumber` objects should be prepared to
260/// categorize the contained value and adapt their handling accordingly. In
261/// practice, applications may have some assurances of the contents of received
262/// `bdljsn::JsonNumber` objects. Here, we intentionally avoid such assumptions
263/// to explore the wide range of variations that can arise.
264///
265/// Legend, in the output below:
266///
267/// * "OK":
268/// - Means "OKay to use". In some cases, the numeric value of the
269/// arithmetic type is an approximation of JSON number and the application
270/// may have to allow for that difference.
271/// * "NG":
272/// - Means "No Good" (do not use). The JSON number is outside of the valid
273/// range of the arithmetic type.
274///
275/// First, we set up a framework (in this case, a `for` loop) for examining our
276/// input, the same `userInput` vector created in {Example 1}:
277/// @code
278/// for (bsl::size_t i = 0; i < userInput.size(); ++i) {
279/// const bdljsn::JsonNumber obj = userInput[i];
280/// @endcode
281/// Then, we categorize the value as integral or not:
282/// @code
283/// if (obj.isIntegral()) {
284/// bsl::cout << "Integral: ";
285/// @endcode
286/// If integral, we check if the value is a usable range. Let us assume that
287/// `bslsl::Type::Int64` is as large a number as we can accept.
288///
289/// Then, we convert the JSON number to that type and check for overflow and
290/// underflow:
291/// @code
292/// bsls::Types::Int64 value;
293/// int rc = obj.asInt64(&value);
294/// switch (rc) {
295/// case 0: {
296/// bsl::cout << value << " : OK to USE" << bsl::endl;
297/// } break;
298/// case bdljsn::JsonNumber::k_OVERFLOW: {
299/// bsl::cout << obj.value() << ": NG too large" << bsl::endl;
300/// } break;
301/// case bdljsn::JsonNumber::k_UNDERFLOW: {
302/// bsl::cout << obj.value() << ": NG too small" << bsl::endl;
303/// } break;
304/// case bdljsn::JsonNumber::k_NOT_INTEGRAL: {
305/// assert(0 == "reached");
306/// } break;
307/// }
308/// @endcode
309/// Next, if the value is not integral, we try to handle it as a floating point
310/// value -- a `bdldfp::Decimal64` in this example -- and further categorize it
311/// as exact/inexact, too large/small.
312/// @code
313/// } else {
314/// bsl::cout << "Not-Integral: ";
315///
316/// bdldfp::Decimal64 value;
317/// int rc = obj.asDecimal64Exact(&value);
318/// switch (rc) {
319/// case 0: {
320/// bsl::cout << value << " : exact: OK to USE";
321/// } break;
322/// case bdljsn::JsonNumber::k_INEXACT: {
323/// bsl::cout << value << ": inexact: USE approximation";
324/// } break;
325/// case bdljsn::JsonNumber::k_NOT_INTEGRAL: {
326/// assert(0 == "reached");
327/// } break;
328/// }
329///
330/// const bdldfp::Decimal64 INF =
331/// bsl::numeric_limits<bdldfp::Decimal64>::infinity();
332///
333/// if ( INF == value) {
334/// bsl::cout << ": NG too large" << bsl::endl;
335/// } else if (-INF == value) {
336/// bsl::cout << ": NG too small" << bsl::endl;
337/// } else {
338/// bsl::cout << bsl::endl;
339/// }
340/// }
341/// }
342/// @endcode
343/// Finally, we observe for particular input:
344/// @code
345/// Integral: 1234567890 : OK to USE
346/// Not-Integral: 1234567890.123456 : exact: OK to USE
347/// Not-Integral: 1234567890.123457: inexact: USE approximation
348/// Integral: -9223372036854775809: NG too small
349/// Integral: 1.5e27: NG too large
350/// Integral: 999999999999999999999999999999999999999999999999999999999999e9999
351/// 99999999999999999999999999999999999999999999999999999999: NG too large
352/// @endcode
353/// @}
354/** @} */
355/** @} */
356
357/** @addtogroup bdl
358 * @{
359 */
360/** @addtogroup bdljsn
361 * @{
362 */
363/** @addtogroup bdljsn_jsonnumber
364 * @{
365 */
366
367#include <bdlscm_version.h>
368
369#include <bdljsn_numberutil.h>
370
371#include <bdlb_float.h>
372#include <bdldfp_decimal.h>
373#include <bdldfp_decimalutil.h>
374
375#include <bslalg_swaputil.h>
376
377#include <bslma_bslallocator.h>
378
379#include <bslmf_assert.h>
381#include <bslmf_isintegral.h>
383
384#include <bsls_annotation.h>
385#include <bsls_assert.h>
386#include <bsls_keyword.h> // 'BSLS_KEYWORD_NOEXCEPT'
387#include <bsls_types.h> // 'bsls::Types::Int64', 'bsls::Types::Uint64'
388
389#include <bsl_iosfwd.h>
390#include <bsl_string.h>
391
392
393namespace bdljsn {
394
395 // ================
396 // class JsonNumber
397 // ================
398
399/// This class defines a value-semantic class that represents a JSON number.
400/// Objects of this class have a value determined at construction and does
401/// not change except by assignment from or swap with another `JsonNumber`
402/// object. The value can be specified by supplying a string that conforms
403/// to the {JSON Textual Specification} or from one of the {Supported
404/// Types}. The value of a JSON object can be converted to any of those
405/// types; however, some of those conversions can be inexact.
406///
407/// See @ref bdljsn_jsonnumber
409
410 // PRIVATE TYPES
411 typedef NumberUtil Nu;
412
413 // DATA
414 bsl::string d_value;
415
416 // FRIENDS
417 friend void swap(JsonNumber& , JsonNumber& );
418
419 public:
420 // CONSTANTS
421 enum {
422 // special integer conversion status values
423 k_OVERFLOW = Nu::k_OVERFLOW, // above the representable range
424 k_UNDERFLOW = Nu::k_UNDERFLOW, // below the representable range
425 k_NOT_INTEGRAL = Nu::k_NOT_INTEGRAL, // the number is not an integer
426
427 // special exact Decimal64 conversion status values
429 };
430
431 // TRAITS
433
434 // TYPES
436
437 // CLASS METHODS
438
439 /// Return `true` if the specified `text` complies with the grammar of a
440 /// JSON number, and `false` otherwise. See the {JSON Textual
441 /// Specification}.
442 static bool isValidNumber(const bsl::string_view& text);
443
444 // CREATORS
445
446 JsonNumber();
447 /// Create a `JsonNumber` having the value "0". Optionally specify an
448 /// `allocator` (e.g., the address of a `bslma::Allocator` object) used
449 /// to supply memory.
450 explicit JsonNumber(const allocator_type& allocator);
451
452 explicit JsonNumber(const char *text,
454 /// Create a `JsonNumber` having the value of the specified `text`.
455 /// Optionally specify an `allocator` (e.g., the address of a
456 /// `bslma::Allocator` object) used to supply memory. The behavior is
457 /// undefined unless `isValidJsonNumber(text)` is `true`. See {JSON
458 /// Textual Specification}.
459 explicit JsonNumber(const bsl::string_view& text,
461
462 /// Create a `JsonNumber` object having the same value and the same
463 /// allocator as the specified `text`. The contents of the `value`
464 /// string becomes unspecified but valid, and its allocator remains
465 /// unchanged. The behavior is undefined unless `isValidNumber(text)`
466 /// is `true`. See {JSON Textual Specification}.
468
469 /// Create a `JsonNumber` object having the same value as the specified
470 /// `text`, using the specified `allocator` (e.g., the address of a
471 /// `bslma::Allocator` object) to supply memory. The allocator of the
472 /// `text` string remains unchanged. If the `text` and the newly
473 /// created object have the same allocator then the contents of `text`
474 /// string becomes unspecified but valid, and no exceptions will be
475 /// thrown; otherwise the `text` string is unchanged and an exception
476 /// may be thrown. The behavior is undefined unless
477 /// `isValidNumber(text)` is `true`. See {JSON Textual Specification}.
480
481 explicit JsonNumber(int value,
483 explicit JsonNumber(unsigned int value,
487 /// Create a `JsonNumber` having the specified `value`. Optionally
488 /// specify an `allocator` (e.g., the address of a `bslma::Allocator`
489 /// object) used to supply memory.
492
493 explicit JsonNumber(float value,
495 explicit JsonNumber(double value,
497 /// Create a `JsonNumber` having the specified `value`. Optionally
498 /// specify an `allocator` (e.g., the address of a `bslma::Allocator`
499 /// object) used to supply memory. The behavior is undefined if the
500 /// `value` is infinite (`INF`) or not-a-number (`NaN`).
503
504 /// Create a `JsonNumber` object having the same value as the specified
505 /// `original` object. Optionally specify an `allocator` (e.g., the
506 /// address of a `bslma::Allocator` object) used to supply memory.
507 JsonNumber(const JsonNumber& original,
509
510 /// Create a `JsonNumber` object having the same value and the same
511 /// allocator as the specified `original` object. The value of
512 /// `original` becomes unspecified but valid, and its allocator remains
513 /// unchanged.
515
516 /// Create a `JsonNumber` object having the same value as the specified
517 /// `original` object, using the specified `allocator` (e.g., the
518 /// address of a `bslma::Allocator` object) to supply memory. The
519 /// allocator of `original` remains unchanged. If `original` and the
520 /// newly created object have the same allocator then the value of
521 /// `original` becomes unspecified but valid, and no exceptions will be
522 /// thrown; otherwise `original` is unchanged (and an exception may be
523 /// thrown).
526
527 ~JsonNumber() = default;
528 // Destroy this object.
529
530 // MANIPULATORS
531
532 /// Assign to this object the value of the specified `rhs` object, and
533 /// return a non-`const` reference to this object.
534 JsonNumber& operator=(const JsonNumber& rhs);
535
536 /// Assign to this object the value of the specified `rhs` object, and
537 /// return a non-`const` reference to this object. The allocators of
538 /// this object and `rhs` both remain unchanged. If `rhs` and this
539 /// object have the same allocator then the value of `rhs` becomes
540 /// unspecified but valid, and no exceptions will be thrown; otherwise
541 /// `rhs` is unchanged (and an exception may be thrown).
543
544 /// Assign to this object the value of the specified `rhs`, and return a
545 /// non-`const` reference to this object.
546 JsonNumber& operator=(int rhs);
547 JsonNumber& operator=(unsigned int rhs);
550
551 /// Assign to this object the value of the specified `rhs`, and return a
552 /// non-`const` reference to this object. The behavior is undefined if
553 /// `rhs` is infinite (`INF`) or not-a-number (`NaN`).
554 JsonNumber& operator=(float rhs);
555 JsonNumber& operator=(double rhs);
557
558 /// Efficiently exchange the value of this object with the value of the
559 /// specified `other` object. This method provides the no-throw
560 /// exception-safety guarantee. The behavior is undefined unless this
561 /// object was created with the same allocator as `other`.
562 void swap(JsonNumber& other);
563
564 // ACCESSORS
565
566 /// Return `true` if this number and the specified `other` number
567 /// represent the same numeric value, and `false` otherwise. This
568 /// method will return `true` for differing representations of the same
569 /// number (e.g., `1.0`, "1", "0.1e+1" are all equivalent) *except* in
570 /// cases where the exponent cannot be represented by a 64-bit integer.
571 /// If the exponent is outside the range of a 64-bit integer, `true`
572 /// will be returned if `*this == other`. For example, comparing
573 /// "1e18446744073709551615" with itself will return `true`, but
574 /// comparing it to "10e18446744073709551614" will return `false`. Note
575 /// that this method is more computationally expensive than the equality
576 /// and inequality operators.
577 bool isEqual(const JsonNumber& other) const;
578
579 /// Return `true` if the value of this `JsonNumber` is an (exact)
580 /// integral value, or `false` otherwise. Note that this function may
581 /// return `true` even this number cannot be represented in a
582 /// fundamental integral type.
583 bool isIntegral() const;
584
585 /// Return the textual representation of this `JsonNumber`.
586 const bsl::string& value() const;
587
588// BDE_VERIFY pragma: push
589// BDE_VERIFY pragma: -FABC01 // not in alphabetic order
590
591 // Integer Accessors
592
593 /// Load into the specified `result` the integer value of this number.
594 /// Return 0 on success, `k_OVERFLOW` if `value` is larger than can be
595 /// represented by `result`, `k_UNDERFLOW` if `value` is smaller than can
596 /// be represented by `result`, and `k_NOT_INTEGRAL` if `value` is not an
597 /// integral number (i.e., there is a fractional part). For underflow,
598 /// `result` will be loaded with the minimum representable value, for
599 /// overflow, `result` will be loaded with the maximum representable value,
600 /// for non-integral values `result` will be loaded with the integer part
601 /// of `value` (truncating the fractional part). If the result is not an
602 /// integer and also either overflows or underflows, it is treated as an
603 /// overflow or underflow (respectively). Note that this operation returns
604 /// an error status value (unlike similar floating point conversions)
605 /// because typically it is an error if a conversion to an integer results
606 /// in an in-exact value.
607 int asInt(int *result) const;
608 int asInt64 (bsls::Types::Int64 *result) const;
609 int asUint (unsigned int *result) const;
610 int asUint64(bsls::Types::Uint64 *result) const;
611
612 /// Return the closest floating point representation to this number. If
613 /// this number is outside the representable range, return `+INF` or `-INF`
614 /// (as appropriate). Note that values smaller than the smallest
615 /// representable non-zero value (a.k.a, `MIN`) are rounded to `MIN`
616 /// (positive or negative, as appropriate) or 0, whichever is the better
617 /// approximation.
618 float asFloat() const;
619 double asDouble() const;
621
622 // 'Exact' Accessors
623
624 /// Load to the specified `result` the closest floating point
625 /// representation to this number, even if a non-zero status is
626 /// returned. Return 0 if this number can be represented exactly, and
627 /// return `k_INEXACT` and load `result` with the closest approximation
628 /// if `value` cannot be represented exactly. If this number is outside
629 /// the representable range, load `result` with `+INF` or `-INF` (as
630 /// appropriate). A number can be represented exactly as a `Decimal64`
631 /// if, for the significand and exponent,
632 /// `abs(significand) <= 9,999,999,999,999,999` and
633 /// `-398 <= exponent <= 369`.
634 int asDecimal64Exact(bdldfp::Decimal64 *result) const;
635
636// BDE_VERIFY pragma: pop
637
638 // 'explicit' (conversion) operators
639
640#if defined(BSLS_COMPILERFEATURES_SUPPORT_OPERATOR_EXPLICIT)
641 /// Return the closest floating point representation to this number. If
642 /// this number is outside the representable range, return `+INF` or
643 /// `-INF` (as appropriate). Note that the values returned by these
644 /// operators match those returned by `asFloat`, `asDouble`, and
645 /// `asDecimal64`, respectively.
646 explicit operator float() const;
647 explicit operator double() const;
648 explicit operator bdldfp::Decimal64() const;
649#endif
650
651 // Aspects
652
653 /// @deprecated Use @ref get_allocator() instead.
654 ///
655 /// Return `get_allocator().mechanism()`, i.e., the memory resource used
656 /// by this object to supply memory.
658
659 /// Return the allocator used by this object to supply memory.
661
662 /// Write the value of this object to the specified output `stream` in a
663 /// human-readable format, and return a non-`const` reference to
664 /// `stream`. Optionally specify an initial indentation `level`, whose
665 /// absolute value is incremented recursively for nested objects. If
666 /// `level` is specified, optionally specify `spacesPerLevel`, whose
667 /// absolute value indicates the number of spaces per indentation level
668 /// for this and all of its nested objects. If `level` is negative,
669 /// suppress indentation of the first line. If `spacesPerLevel` is
670 /// negative, format the entire output on one line, suppressing all but
671 /// the initial indentation (as governed by `level`). If `stream` is
672 /// not valid on entry, this operation has no effect. Note that the
673 /// format is not fully specified, and can change without notice.
674 bsl::ostream& print(bsl::ostream& stream,
675 int level = 0,
676 int spacesPerLevel = 4) const;
677};
678
679// FREE OPERATORS
680
681/// Write the value of the specified `object` to the specified output
682/// `stream` in a single-line format, and return a non-`const` reference to
683/// `stream`. If `stream` is not valid on entry, this operation has no
684/// effect. Note that this human-readable format is not fully specified and
685/// can change without notice. Also note that this method has the same
686/// behavior as `object.print(stream, 0, -1)`.
687bsl::ostream& operator<<(bsl::ostream& stream, const JsonNumber& object);
688
689/// Return `true` if the specified `lhs` and `rhs` objects have the same
690/// value, and `false` otherwise. Two `JsonNumber` objects have the same
691/// value if their `value` attributes are the same.
692bool operator==(const JsonNumber& lhs, const JsonNumber& rhs);
693
694/// Return `true` if the specified `lhs` and `rhs` objects do not have the
695/// same value, and `false` otherwise. Two `JsonNumber` objects do not have
696/// the same value if their `value` attributes are not the same.
697bool operator!=(const JsonNumber& lhs, const JsonNumber& rhs);
698
699// FREE FUNCTIONS
700
701/// Pass the specified `object` to the specified `hashAlgorithm`. This
702/// function integrates with the `bslh` modular hashing system and
703/// effectively provides a `bsl::hash` specialization for `JsonNumber`.
704template <class HASHALG>
705void hashAppend(HASHALG& hashAlgorithm, const JsonNumber& object);
706
707/// Exchange the values of the specified `a` and `b` objects. This function
708/// provides the no-throw exception-safety guarantee if the two objects were
709/// created with the same allocator and the basic guarantee otherwise.
710void swap(JsonNumber& a, JsonNumber& b);
711
712// ============================================================================
713// INLINE DEFINITIONS
714// ============================================================================
715
716 // -----------------
717 // struct JsonNumber
718 // -----------------
719
720// CLASS METHODS
721inline
723{
724 return NumberUtil::isValidNumber(text);
725}
726
727// CREATORS
728inline
730: d_value(1, '0')
731{
732}
733
734inline
736: d_value(1, '0', allocator)
737{
738}
739
740inline
741JsonNumber::JsonNumber(const char *text,
742 const allocator_type& allocator)
743: d_value(text, allocator)
744{
746}
747
748inline
750 const allocator_type& allocator)
751: d_value(text, allocator)
752{
754}
755
756inline
757JsonNumber::JsonNumber(int value, const allocator_type& allocator)
758: d_value(allocator)
759{
760 NumberUtil::stringify(&d_value, static_cast<bsls::Types::Int64>(value));
761}
762
763inline
764JsonNumber::JsonNumber(unsigned int value, const allocator_type& allocator)
765: d_value(allocator)
766{
767 NumberUtil::stringify(&d_value, static_cast<bsls::Types::Uint64>(value));
768}
769
770inline
772 const allocator_type& allocator)
773: d_value(allocator)
774{
775 NumberUtil::stringify(&d_value, value);
776}
777
778inline
780 const allocator_type& allocator)
781: d_value(allocator)
782{
783 NumberUtil::stringify(&d_value, value);
784}
785
786inline
787JsonNumber::JsonNumber(float value, const allocator_type& allocator)
788: d_value(allocator)
789{
792
793 NumberUtil::stringify(&d_value, value);
794}
795
796inline
797JsonNumber::JsonNumber(double value, const allocator_type& allocator)
798: d_value(allocator)
799{
802
803 NumberUtil::stringify(&d_value, value);
804}
805
806inline
816
817inline
819: d_value(bslmf::MovableRefUtil::move(text))
820{
822}
823
824inline
826 const allocator_type& allocator)
827: d_value(bslmf::MovableRefUtil::move(text), allocator)
828{
830}
831
832inline
834 const allocator_type& allocator)
835: d_value(original.d_value, allocator)
836{
837}
838
839inline
846
847inline
849 const allocator_type& allocator)
850: d_value(bslmf::MovableRefUtil::move(
851 bslmf::MovableRefUtil::access(original).d_value),
852 allocator)
853{
854}
855
856// MANIPULATORS
857inline
859{
860 d_value = rhs.d_value;
861 return *this;
862}
863
864inline
871
872inline
874{
875 NumberUtil::stringify(&d_value, static_cast<bsls::Types::Int64>(rhs));
876 return *this;
877}
878
879inline
881{
882 NumberUtil::stringify(&d_value, static_cast<bsls::Types::Uint64>(rhs));
883 return *this;
884}
885
886inline
888{
889 NumberUtil::stringify(&d_value, rhs);
890 return *this;
891}
892
893inline
895{
896 NumberUtil::stringify(&d_value, rhs);
897 return *this;
898}
899
900inline
902{
905
906 NumberUtil::stringify(&d_value, rhs);
907 return *this;
908}
909
910inline
912{
915
916 NumberUtil::stringify(&d_value, rhs);
917 return *this;
918}
919
920inline
929
930inline
932{
933 BSLS_ASSERT(d_value.get_allocator() == other.get_allocator());
934
935 bslalg::SwapUtil::swap(&d_value, &other.d_value);
936}
937
938// ACCESSORS
939inline
940bool JsonNumber::isEqual(const JsonNumber& other) const
941{
942 return NumberUtil::areEqual(d_value, other.d_value);
943}
944
945inline
947{
948 return NumberUtil::isIntegralNumber(d_value);
949}
950
951inline
953{
954 return d_value;
955}
956
957 // Integer Accessors
958
959// BDE_VERIFY pragma: push
960// BDE_VERIFY pragma: -FABC01 // not in alphabetic order
961
962inline
963int JsonNumber::asInt(int *result) const
964{
965 return NumberUtil::asInt(result, d_value);
966}
967
968inline
970{
971 return NumberUtil::asInt64(result, d_value);
972}
973
974inline
975int JsonNumber::asUint(unsigned int *result) const
976{
977 return NumberUtil::asUint(result, d_value);
978}
979
980inline
982{
983 return NumberUtil::asUint64(result, d_value);
984}
985
986inline
988{
989 return static_cast<float>(asDouble());
990}
991
992inline
994{
995 return NumberUtil::asDouble(d_value);
996}
997
998inline
1000{
1001 return NumberUtil::asDecimal64(d_value);
1002}
1003
1004 // 'Exact' Accessors
1005
1006inline
1008{
1009 return NumberUtil::asDecimal64Exact(result, d_value);
1010}
1011
1012// BDE_VERIFY pragma: pop
1013
1014#if defined(BSLS_COMPILERFEATURES_SUPPORT_OPERATOR_EXPLICIT)
1015
1016 // 'explicit' (conversion) operators
1017inline
1018JsonNumber::operator float() const
1019{
1020 return asFloat();
1021}
1022
1023inline
1024JsonNumber::operator double() const
1025{
1026 return asDouble();
1027}
1028
1029inline
1030JsonNumber::operator bdldfp::Decimal64() const
1031{
1032 return asDecimal64();
1033}
1034#endif
1035
1036 // Aspects
1037inline
1039{
1040 return d_value.get_allocator().mechanism();
1041}
1042
1043inline
1045{
1046 return d_value.get_allocator();
1047}
1048
1049} // close package namespace
1050
1051// FREE OPERATORS
1052inline
1053bsl::ostream& bdljsn::operator<<(bsl::ostream& stream,
1054 const bdljsn::JsonNumber& object)
1055{
1056 return object.print(stream, 0, -1);
1057}
1058
1059inline
1061 const bdljsn::JsonNumber& rhs)
1062{
1063 return lhs.value() == rhs.value();
1064}
1065
1066inline
1068 const bdljsn::JsonNumber& rhs)
1069{
1070 return lhs.value() != rhs.value();
1071}
1072
1073// FREE FUNCTIONS
1074template <class HASHALG>
1075inline
1076void bdljsn::hashAppend(HASHALG& hashAlgorithm,
1077 const bdljsn::JsonNumber& object)
1078{
1079 hashAppend(hashAlgorithm, object.value());
1080}
1081
1082inline
1084{
1085 bslalg::SwapUtil::swap(&a.d_value, &b.d_value);
1086}
1087
1088
1089
1090#endif // INCLUDED_BDLJSN_JSONNUMBER
1091
1092// ----------------------------------------------------------------------------
1093// Copyright 2022 Bloomberg Finance L.P.
1094//
1095// Licensed under the Apache License, Version 2.0 (the "License");
1096// you may not use this file except in compliance with the License.
1097// You may obtain a copy of the License at
1098//
1099// http://www.apache.org/licenses/LICENSE-2.0
1100//
1101// Unless required by applicable law or agreed to in writing, software
1102// distributed under the License is distributed on an "AS IS" BASIS,
1103// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1104// See the License for the specific language governing permissions and
1105// limitations under the License.
1106// ----------------------------- END-OF-FILE ----------------------------------
1107
1108/** @} */
1109/** @} */
1110/** @} */
Definition bdldfp_decimal.h:1834
Definition bdljsn_jsonnumber.h:408
JsonNumber()
Definition bdljsn_jsonnumber.h:729
JsonNumber & operator=(const JsonNumber &rhs)
Definition bdljsn_jsonnumber.h:858
@ k_INEXACT
Definition bdljsn_jsonnumber.h:428
@ k_UNDERFLOW
Definition bdljsn_jsonnumber.h:424
@ k_NOT_INTEGRAL
Definition bdljsn_jsonnumber.h:425
@ k_OVERFLOW
Definition bdljsn_jsonnumber.h:423
static bool isValidNumber(const bsl::string_view &text)
Definition bdljsn_jsonnumber.h:722
int asUint64(bsls::Types::Uint64 *result) const
Definition bdljsn_jsonnumber.h:981
allocator_type get_allocator() const
Return the allocator used by this object to supply memory.
Definition bdljsn_jsonnumber.h:1044
friend void swap(JsonNumber &, JsonNumber &)
BSLMF_NESTED_TRAIT_DECLARATION(JsonNumber, bslmf::IsBitwiseMoveable)
int asInt(int *result) const
Definition bdljsn_jsonnumber.h:963
int asDecimal64Exact(bdldfp::Decimal64 *result) const
Definition bdljsn_jsonnumber.h:1007
const bsl::string & value() const
Return the textual representation of this JsonNumber.
Definition bdljsn_jsonnumber.h:952
~JsonNumber()=default
float asFloat() const
Definition bdljsn_jsonnumber.h:987
int asInt64(bsls::Types::Int64 *result) const
Definition bdljsn_jsonnumber.h:969
bsl::allocator allocator_type
Definition bdljsn_jsonnumber.h:435
bdldfp::Decimal64 asDecimal64() const
Definition bdljsn_jsonnumber.h:999
bool isEqual(const JsonNumber &other) const
Definition bdljsn_jsonnumber.h:940
bslma::Allocator *BSLS_ANNOTATION_DEPRECATED allocator() const
Definition bdljsn_jsonnumber.h:1038
int asUint(unsigned int *result) const
Definition bdljsn_jsonnumber.h:975
double asDouble() const
Definition bdljsn_jsonnumber.h:993
bool isIntegral() const
Definition bdljsn_jsonnumber.h:946
bsl::ostream & print(bsl::ostream &stream, int level=0, int spacesPerLevel=4) const
Definition bslma_bslallocator.h:580
BloombergLP::bslma::Allocator * mechanism() const
Definition bslma_bslallocator.h:1126
Definition bslstl_stringview.h:441
Definition bslstl_string.h:1281
allocator_type get_allocator() const BSLS_KEYWORD_NOEXCEPT
Return the allocator used by this string to supply memory.
Definition bslstl_string.h:6723
static void swap(T *a, T *b)
Definition bslalg_swaputil.h:194
Definition bslma_allocator.h:457
Definition bslmf_movableref.h:751
#define BSLS_ANNOTATION_DEPRECATED
Definition bsls_annotation.h:324
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1804
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
#define BSLS_KEYWORD_NOEXCEPT
Definition bsls_keyword.h:632
void hashAppend(HASH_ALGORITHM &hashAlg, const baljsn::EncoderTestAddress &object)
Definition baljsn_encoder_testtypes.h:9236
Decimal_Type64 Decimal64
Definition bdldfp_decimal.h:715
Definition bdljsn_error.h:143
bool operator!=(const Error &lhs, const Error &rhs)
void swap(Error &a, Error &b)
bool operator==(const Error &lhs, const Error &rhs)
bsl::ostream & operator<<(bsl::ostream &stream, const Error &object)
void hashAppend(HASHALG &hashAlgorithm, const Error &object)
Definition bdlbb_blob.h:576
static bool isNan(float number)
static bool isInfinite(float number)
static bool isNan(Decimal32 x)
static bool isInf(Decimal32 x)
Definition bdljsn_numberutil.h:186
static bool isIntegralNumber(const bsl::string_view &value)
static int asUint64(Uint64 *result, const bsl::string_view &value)
static int asDecimal64Exact(bdldfp::Decimal64 *result, const bsl::string_view &value)
static bool isValidNumber(const bsl::string_view &value)
static int asUint(unsigned int *result, const bsl::string_view &value)
Definition bdljsn_numberutil.h:501
static double asDouble(const bsl::string_view &value)
Definition bdljsn_numberutil.h:460
static void stringify(bsl::string *result, Int64 value)
@ k_UNDERFLOW
Definition bdljsn_numberutil.h:196
@ k_NOT_INTEGRAL
Definition bdljsn_numberutil.h:197
@ k_INEXACT
Definition bdljsn_numberutil.h:200
@ k_OVERFLOW
Definition bdljsn_numberutil.h:195
static bool areEqual(const bsl::string_view &lhs, const bsl::string_view &rhs)
static bdldfp::Decimal64 asDecimal64(const bsl::string_view &value)
static int asInt(int *result, const bsl::string_view &value)
Definition bdljsn_numberutil.h:489
static int asInt64(Int64 *result, const bsl::string_view &value)
Definition bdljsn_numberutil.h:495
Definition bslmf_isbitwisemoveable.h:718
static MovableRef< t_TYPE > move(t_TYPE &reference) BSLS_KEYWORD_NOEXCEPT
Definition bslmf_movableref.h:1060
static t_TYPE & access(t_TYPE &ref) BSLS_KEYWORD_NOEXCEPT
Definition bslmf_movableref.h:1032
unsigned long long Uint64
Definition bsls_types.h:137
long long Int64
Definition bsls_types.h:132