BDE 4.39.x 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-asdecimal64exact"> Known Issues With asDecimal64Exact </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/// * `short`
120/// * `unsigned short`
121/// * `int`
122/// * `unsigned int`
123/// * `long`
124/// * `unsigned long`
125/// * `long long`
126/// * `unsigned long long`
127/// * `float`
128/// * `double`
129/// * `bdldfp::Decimal64`
130///
131/// In addition to named conversion functions (like `asInt` and `asDouble`) This
132/// component provides explicit conversion operations for floating point types
133/// (`float`, `double`, `Decimal64`) on platforms where explicit conversions are
134/// supported.
135///
136/// ### Handling Inexact Conversions: Floating Point Vs Integral Types {#bdljsn_jsonnumber-handling-inexact-conversions-floating-point-vs-integral-types}
137///
138///
139/// Converting a `bdlsjn::JsonNumber` to another representation may result in a
140/// value that is not the same as the original `bdljsn::JsonNumber`. Either the
141/// `bdljsn::JsonNumber` may represent a numeric value outside of the
142/// representable range of the requested type (i.e., it is too large, or too
143/// small), or the value may not be representable exactly. `bdljsn::JsonNumber`
144/// conversions will return the closest approximation of the
145/// `bdljsn::JsonNumber`, even when a non-zero status is returned indicating an
146/// inexact conversion.
147///
148/// All the provided conversions to integral types have signatures that require
149/// a return status, whereas conversion functions are provided for floating
150/// point types that do not return a status. This is because:
151///
152/// 1. Floating point representations have specific values to indicate a
153/// `bdljsn::JsonNumber` is outside of the representable range
154/// `(-INF, +INF)`.
155/// 2. Truncating the fractional part of a number to coerce a value to an
156/// integer is typically an error (the data being processed did not meet the
157/// programmer's expectation), whereas returning the closest floating point
158/// approximation to a `bdljsn::JsonNumber` is very often not an error.
159///
160/// ### Exact Decima64 Representations {#bdljsn_jsonnumber-exact-decima64-representations}
161///
162///
163/// For users requiring precise conversions to `bdldfp::Decimal64`, the function
164/// `asDecimal64Exact` returns additional status indicating whether the
165/// conversion is exact. An exact conversion for a `Decimal64` is one that
166/// preserves all the significant digits resulting in a decimal representation
167/// having the same numerical value as the original JSON text. Note that
168/// `asDecimal64Exact` has very similar performance to `asDecimal64` (i.e.,
169/// there is not a notable performance penalty to determining this property).
170///
171/// ### Known Issues With asDecimal64Exact {#bdljsn_jsonnumber-known-issues-with-asdecimal64exact}
172///
173///
174/// Currently `asDecimal64Exact` will return `bdljsn::JsonNumber::k_NOT_EXACT`
175/// if the input is 0 with an exponent outside of the range (`[-398, 369]`).
176/// For example, `0e-400`. This reflects the behavior of the underlying 3rd
177/// party implementation. Please contact BDE if this is a concern.
178///
179/// ## Usage {#bdljsn_jsonnumber-usage}
180///
181///
182/// This section illustrates intended use of this component.
183///
184/// ### Example 1: Creating JSON Number Object from User Input {#bdljsn_jsonnumber-example-1-creating-json-number-object-from-user-input}
185///
186///
187/// The specification of values for JSON numbers often starts with user input
188/// textual representations of those values. As the specifications for valid
189/// representation are complicated and not always intuitive it is prudent to
190/// validate that input using the `bdljsn::JsonNumber::isValidNumber` function;
191/// otherwise, one might try to create a `bdljsn::JsonNumber` object from an
192/// invalid specification and that leads to undefined behavior.
193///
194/// First, as a expedient for this example, we organize in an array input that
195/// might well be entered by some user:
196/// @code
197/// struct {
198/// const char *d_text_p;
199/// const char *d_description_p;
200/// bool d_expected;
201/// } USER_INPUT[] = {
202///
203/// // VALUE DESCRIPTION EXP
204/// // ---------------------- -------------------------------------- ---
205///
206/// // Invalid Input (that is valid in other contexts).
207///
208/// { "1.", "Not uncommon way to write `1`." , 0 }
209/// , { "1,000", "No commas allowed" , 0 }
210/// , { "01", "Leading '0', disallowed by JSON." , 0 }
211/// , { "", "0 per `atoi`, disallowed by JSON." , 0 }
212/// , { "Hello, world!", "0 per `atoi`, disallowed by JSON." , 0 }
213/// , { "NaN", "invalid number" , 0 }
214/// , { "INF", "invalid number" , 0 }
215/// , { "-INF", "invalid number" , 0 }
216/// , { "+INF", "invalid number" , 0 }
217///
218/// // Valid input (some surprising)
219///
220/// , { "1234567890", "Integral value" , 1 }
221/// , { "1234567890.123456", "Non-integral value" , 1 }
222/// , { "1234567890.1234567", "Beyond Decimal64 precision" , 1 }
223/// , { "-9223372036854775809", "INT64_MIN, underflow, but valid JSON", 1 }
224/// , { "1.5e27", "INT64_MAX, overflow, but valid JSON", 1 }
225/// , { "999999999999999999999999999999999999999999999999999999999999"
226/// "e"
227/// "999999999999999999999999999999999999999999999999999999999999",
228/// "astronomic value" , 1 }
229/// };
230///
231/// const bsl::size_t NUM_USER_INPUT = sizeof USER_INPUT / sizeof *USER_INPUT;
232/// @endcode
233/// Now, if and only if the input is valid, we use the input to construct a
234/// `bdljsn::JsonNumber` object and add that object to a vector for later
235/// processing.
236/// @code
237/// bsl::vector<bdljsn::JsonNumber> userInput; // when valid input
238///
239/// for (bsl::size_t ti = 0; ti < NUM_USER_INPUT; ++ti) {
240/// const char *TEXT = USER_INPUT[ti].d_text_p;
241/// const char *DESC = USER_INPUT[ti].d_description_p; (void) DESC;
242/// const bool EXP = USER_INPUT[ti].d_expected;
243///
244/// const bool isValid = bdljsn::JsonNumber::isValidNumber(TEXT);
245/// assert(EXP == isValid);
246///
247/// if (isValid) {
248/// userInput.push_back(bdljsn::JsonNumber(TEXT));
249/// }
250/// }
251/// @endcode
252/// Finally, we confirm that the vector has the expected number of elements:
253/// @code
254/// assert(6 == userInput.size());
255/// @endcode
256///
257/// ### Example 2: Using bdljsn::JsonNumber Objects {#bdljsn_jsonnumber-example-2-using-bdljsn-jsonnumber-objects}
258///
259///
260/// We saw in {Example 1} that `bdljsn::JsonNumber` objects can validly hold
261/// values numeric values that cannot be converted to any of the supported types
262/// (e.g., the "astronomic value") for arithmetic operations. Applications that
263/// accept arbitrary `bdljsn::JsonNumber` objects should be prepared to
264/// categorize the contained value and adapt their handling accordingly. In
265/// practice, applications may have some assurances of the contents of received
266/// `bdljsn::JsonNumber` objects. Here, we intentionally avoid such assumptions
267/// to explore the wide range of variations that can arise.
268///
269/// Legend, in the output below:
270///
271/// * "OK":
272/// - Means "OKay to use". In some cases, the numeric value of the
273/// arithmetic type is an approximation of JSON number and the application
274/// may have to allow for that difference.
275/// * "NG":
276/// - Means "No Good" (do not use). The JSON number is outside of the valid
277/// range of the arithmetic type.
278///
279/// First, we set up a framework (in this case, a `for` loop) for examining our
280/// input, the same `userInput` vector created in {Example 1}:
281/// @code
282/// for (bsl::size_t i = 0; i < userInput.size(); ++i) {
283/// const bdljsn::JsonNumber obj = userInput[i];
284/// @endcode
285/// Then, we categorize the value as integral or not:
286/// @code
287/// if (obj.isIntegral()) {
288/// bsl::cout << "Integral: ";
289/// @endcode
290/// If integral, we check if the value is a usable range. Let us assume that
291/// `long long` is as large a number as we can accept.
292///
293/// Then, we convert the JSON number to that type and check for overflow and
294/// underflow:
295/// @code
296/// long long value;
297/// int rc = obj.asLonglong(&value);
298/// switch (rc) {
299/// case 0: {
300/// bsl::cout << value << " : OK to USE" << bsl::endl;
301/// } break;
302/// case bdljsn::JsonNumber::k_OVERFLOW: {
303/// bsl::cout << obj.value() << ": NG too large" << bsl::endl;
304/// } break;
305/// case bdljsn::JsonNumber::k_UNDERFLOW: {
306/// bsl::cout << obj.value() << ": NG too small" << bsl::endl;
307/// } break;
308/// case bdljsn::JsonNumber::k_NOT_INTEGRAL: {
309/// assert(false && "reached");
310/// } break;
311/// }
312/// @endcode
313/// Next, if the value is not integral, we try to handle it as a floating point
314/// value -- a `bdldfp::Decimal64` in this example -- and further categorize it
315/// as exact/inexact, too large/small.
316/// @code
317/// } else {
318/// bsl::cout << "Not-Integral: ";
319///
320/// bdldfp::Decimal64 value;
321/// int rc = obj.asDecimal64Exact(&value);
322/// switch (rc) {
323/// case 0: {
324/// bsl::cout << value << " : exact: OK to USE";
325/// } break;
326/// case bdljsn::JsonNumber::k_INEXACT: {
327/// bsl::cout << value << ": inexact: USE approximation";
328/// } break;
329/// case bdljsn::JsonNumber::k_NOT_INTEGRAL: {
330/// assert(false && "reached");
331/// } break;
332/// }
333///
334/// const bdldfp::Decimal64 INF =
335/// bsl::numeric_limits<bdldfp::Decimal64>::infinity();
336///
337/// if ( INF == value) {
338/// bsl::cout << ": NG too large" << bsl::endl;
339/// } else if (-INF == value) {
340/// bsl::cout << ": NG too small" << bsl::endl;
341/// } else {
342/// bsl::cout << bsl::endl;
343/// }
344/// }
345/// }
346/// @endcode
347/// Finally, we observe for particular input:
348/// @code
349/// Integral: 1234567890 : OK to USE
350/// Not-Integral: 1234567890.123456 : exact: OK to USE
351/// Not-Integral: 1234567890.123457: inexact: USE approximation
352/// Integral: -9223372036854775809: NG too small
353/// Integral: 1.5e27: NG too large
354/// Integral: 999999999999999999999999999999999999999999999999999999999999e9999
355/// 99999999999999999999999999999999999999999999999999999999: NG too large
356/// @endcode
357/// @}
358/** @} */
359/** @} */
360
361/** @addtogroup bdl
362 * @{
363 */
364/** @addtogroup bdljsn
365 * @{
366 */
367/** @addtogroup bdljsn_jsonnumber
368 * @{
369 */
370
371#include <bdlscm_version.h>
372
373#include <bdljsn_numberutil.h>
374
375#include <bdlb_float.h>
376#include <bdldfp_decimal.h>
377#include <bdldfp_decimalutil.h>
378
379#include <bslalg_swaputil.h>
380
381#include <bslma_bslallocator.h>
382
383#include <bslmf_assert.h>
385#include <bslmf_isintegral.h>
387
388#include <bsls_annotation.h>
389#include <bsls_assert.h>
390#include <bsls_keyword.h> // `BSLS_KEYWORD_NOEXCEPT`
391#include <bsls_types.h> // `bsls::Types::Int64`, `bsls::Types::Uint64`
392
393#include <bsl_iosfwd.h>
394#include <bsl_string.h>
395
396
397namespace bdljsn {
398
399 // ================
400 // class JsonNumber
401 // ================
402
403/// This class defines a value-semantic class that represents a JSON number.
404/// Objects of this class have a value determined at construction and does
405/// not change except by assignment from or swap with another `JsonNumber`
406/// object. The value can be specified by supplying a string that conforms
407/// to the {JSON Textual Specification} or from one of the {Supported
408/// Types}. The value of a JSON object can be converted to any of those
409/// types; however, some of those conversions can be inexact.
410///
411/// See @ref bdljsn_jsonnumber
413
414 // PRIVATE TYPES
415 typedef NumberUtil Nu;
416
417 // DATA
418 bsl::string d_value;
419
420 // FRIENDS
421 friend void swap(JsonNumber& , JsonNumber& );
422
423 public:
424 // CONSTANTS
425 enum {
426 // special integer conversion status values
427 k_OVERFLOW = Nu::k_OVERFLOW, // above the representable range
428 k_UNDERFLOW = Nu::k_UNDERFLOW, // below the representable range
429 k_NOT_INTEGRAL = Nu::k_NOT_INTEGRAL, // the number is not an integer
430
431 // special exact Decimal64 conversion status values
433 };
434
435 // TRAITS
437
438 // TYPES
440
441 // CLASS METHODS
442
443 /// Return `true` if the specified `text` complies with the grammar of a
444 /// JSON number, and `false` otherwise. See the {JSON Textual
445 /// Specification}.
446 static bool isValidNumber(const bsl::string_view& text);
447
448 // CREATORS
449
450 /// Create a `JsonNumber` having the value "0". Optionally specify an
451 /// `allocator` (e.g., the address of a `bslma::Allocator` object) used
452 /// to supply memory.
453 JsonNumber();
454 explicit JsonNumber(const allocator_type& allocator);
455
456 /// Create a `JsonNumber` having the value of the specified `text`.
457 /// Optionally specify an `allocator` (e.g., the address of a
458 /// `bslma::Allocator` object) used to supply memory.
459 ///
460 /// \pre The behavior is undefined unless `isValidJsonNumber(text)` is `true`. See {JSON
461 /// Textual Specification}.
462 explicit JsonNumber(const char *text,
464 explicit JsonNumber(const bsl::string_view& text,
466
467 /// Create a `JsonNumber` object having the same value and the same
468 /// allocator as the specified `text`. The contents of the `value`
469 /// string becomes unspecified but valid, and its allocator remains unchanged.
470 ///
471 /// \pre The behavior is undefined unless `isValidNumber(text)`
472 /// is `true`. See {JSON Textual Specification}.
474
475 /// Create a `JsonNumber` object having the same value as the specified
476 /// `text`, using the specified `allocator` (e.g., the address of a
477 /// `bslma::Allocator` object) to supply memory. The allocator of the
478 /// `text` string remains unchanged. If the `text` and the newly
479 /// created object have the same allocator then the contents of `text`
480 /// string becomes unspecified but valid, and no exceptions will be
481 /// thrown; otherwise the `text` string is unchanged and an exception may be thrown.
482 ///
483 /// \pre The behavior is undefined unless
484 /// `isValidNumber(text)` is `true`. See {JSON Textual Specification}.
487
488 /// Create a `JsonNumber` having the specified `value`. Optionally
489 /// specify an `allocator` (e.g., the address of a `bslma::Allocator`
490 /// object) used to supply memory.
491 explicit JsonNumber(int value,
493 explicit JsonNumber(unsigned int value,
495 explicit JsonNumber(long value,
497 explicit JsonNumber(unsigned long value,
499 explicit JsonNumber(long long value,
501 explicit JsonNumber(unsigned long long value,
503
504 /// Create a `JsonNumber` having the specified `value`. Optionally
505 /// specify an `allocator` (e.g., the address of a `bslma::Allocator` object) used to supply memory.
506 ///
507 /// \pre The behavior is undefined if the
508 /// `value` is infinite (`INF`) or not-a-number (`NaN`).
509 explicit JsonNumber(float value,
511 explicit JsonNumber(double value,
515
516 /// Create a `JsonNumber` object having the same value as the specified
517 /// `original` object. Optionally specify an `allocator` (e.g., the
518 /// address of a `bslma::Allocator` object) used to supply memory.
519 JsonNumber(const JsonNumber& original,
521
522 /// Create a `JsonNumber` object having the same value and the same
523 /// allocator as the specified `original` object. The value of
524 /// `original` becomes unspecified but valid, and its allocator remains
525 /// unchanged.
527
528 /// Create a `JsonNumber` object having the same value as the specified
529 /// `original` object, using the specified `allocator` (e.g., the
530 /// address of a `bslma::Allocator` object) to supply memory. The
531 /// allocator of `original` remains unchanged. If `original` and the
532 /// newly created object have the same allocator then the value of
533 /// `original` becomes unspecified but valid, and no exceptions will be
534 /// thrown; otherwise `original` is unchanged (and an exception may be
535 /// thrown).
538
539 ~JsonNumber() = default;
540 // Destroy this object.
541
542 // MANIPULATORS
543
544 /// Assign to this object the value of the specified `rhs` object, and
545 /// return a non-`const` reference to this object.
546 JsonNumber& operator=(const JsonNumber& rhs);
547
548 /// Assign to this object the value of the specified `rhs` object, and
549 /// return a non-`const` reference to this object. The allocators of
550 /// this object and `rhs` both remain unchanged. If `rhs` and this
551 /// object have the same allocator then the value of `rhs` becomes
552 /// unspecified but valid, and no exceptions will be thrown; otherwise
553 /// `rhs` is unchanged (and an exception may be thrown).
555
556 /// Assign to this object the value of the specified `rhs`, and return a
557 /// non-`const` reference to this object.
558 JsonNumber& operator=(int rhs);
559 JsonNumber& operator=(unsigned int rhs);
560 JsonNumber& operator=(long rhs);
561 JsonNumber& operator=(unsigned long rhs);
562 JsonNumber& operator=(long long rhs);
563 JsonNumber& operator=(unsigned long long rhs);
564
565 /// Assign to this object the value of the specified `rhs`, and return a non-`const` reference to this object.
566 ///
567 /// \pre The behavior is undefined if
568 /// `rhs` is infinite (`INF`) or not-a-number (`NaN`).
569 JsonNumber& operator=(float rhs);
570 JsonNumber& operator=(double rhs);
572
573 /// Efficiently exchange the value of this object with the value of the
574 /// specified `other` object. This method provides the no-throw exception-safety guarantee.
575 ///
576 /// \pre The behavior is undefined unless this
577 /// object was created with the same allocator as `other`.
578 void swap(JsonNumber& other);
579
580 // ACCESSORS
581
582 /// Return `true` if this number and the specified `other` number
583 /// represent the same numeric value, and `false` otherwise. This
584 /// method will return `true` for differing representations of the same
585 /// number (e.g., `1.0`, "1", "0.1e+1" are all equivalent) *except* in
586 /// cases where the exponent cannot be represented by a 64-bit integer.
587 /// If the exponent is outside the range of a 64-bit integer, `true`
588 /// will be returned if `*this == other`. For example, comparing
589 /// "1e18446744073709551615" with itself will return `true`, but
590 /// comparing it to "10e18446744073709551614" will return `false`.
591 ///
592 /// \note Note that this method is more computationally expensive than the equality
593 /// and inequality operators.
594 bool isEqual(const JsonNumber& other) const;
595
596 /// Return `true` if the value of this `JsonNumber` is an (exact) integral value, or `false` otherwise.
597 ///
598 /// \note Note that this function may
599 /// return `true` even this number cannot be represented in a
600 /// fundamental integral type.
601 bool isIntegral() const;
602
603 /// Return the textual representation of this `JsonNumber`.
604 const bsl::string& value() const;
605
606// BDE_VERIFY pragma: push
607// BDE_VERIFY pragma: -FABC01 // not in alphabetic order
608
609 // Integer Accessors
610
611 /// Load into the specified `result` the integer value of this number.
612 /// Return 0 on success, `k_OVERFLOW` if `value` is larger than can be
613 /// represented by `result`, `k_UNDERFLOW` if `value` is smaller than
614 /// can be represented by `result`, and `k_NOT_INTEGRAL` if `value` is
615 /// not an integral number (i.e., there is a fractional part). For
616 /// underflow, `result` will be loaded with the minimum representable
617 /// value, for overflow, `result` will be loaded with the maximum
618 /// representable value, for non-integral values `result` will be loaded
619 /// with the integer part of `value` (truncating the fractional part).
620 /// If the result is not an integer and also either overflows or
621 /// underflows, it is treated as an overflow or underflow (respectively).
622 ///
623 /// \note Note that this operation returns an error status
624 /// value (unlike similar floating point conversions) because typically
625 /// it is an error if a conversion to an integer results in an in-exact
626 /// value.
627 int asShort (short *result) const;
628 int asInt (int *result) const;
629 int asLong (long *result) const;
630 int asLonglong (long long *result) const;
631 int asInt64 (bsls::Types::Int64 *result) const;
632 int asUshort (unsigned short *result) const;
633 int asUint (unsigned int *result) const;
634 int asUlong (unsigned long *result) const;
635 int asUlonglong(unsigned long long *result) const;
636 int asUint64 (bsls::Types::Uint64 *result) const;
637
638 /// Return the closest floating point representation to this number. If
639 /// this number is outside the representable range, return `+INF` or `-INF` (as appropriate).
640 ///
641 /// \note Note that values smaller than the smallest
642 /// representable non-zero value (a.k.a, `MIN`) are rounded to `MIN`
643 /// (positive or negative, as appropriate) or 0, whichever is the better
644 /// approximation.
645 float asFloat() const;
646 double asDouble() const;
648
649 // "Exact" Accessors
650
651 /// Load to the specified `result` the closest floating point
652 /// representation to this number, even if a non-zero status is
653 /// returned. Return 0 if this number can be represented exactly, and
654 /// return `k_INEXACT` and load `result` with the closest approximation
655 /// if `value` cannot be represented exactly. If this number is outside
656 /// the representable range, load `result` with `+INF` or `-INF` (as
657 /// appropriate). A number can be represented exactly as a `Decimal64`
658 /// if, for the significand and exponent,
659 /// `abs(significand) <= 9,999,999,999,999,999` and
660 /// `-398 <= exponent <= 369`.
661 int asDecimal64Exact(bdldfp::Decimal64 *result) const;
662
663// BDE_VERIFY pragma: pop
664
665 // `explicit` (conversion) operators
666
667#if defined(BSLS_COMPILERFEATURES_SUPPORT_OPERATOR_EXPLICIT)
668 /// Return the closest floating point representation to this number. If
669 /// this number is outside the representable range, return `+INF` or `-INF` (as appropriate).
670 ///
671 /// \note Note that the values returned by these
672 /// operators match those returned by `asFloat`, `asDouble`, and
673 /// `asDecimal64`, respectively.
674 explicit operator float() const;
675 explicit operator double() const;
676 explicit operator bdldfp::Decimal64() const;
677#endif
678
679 // Aspects
680
681 /// @deprecated Use @ref get_allocator() instead.
682 ///
683 /// Return `get_allocator().mechanism()`, i.e., the memory resource used
684 /// by this object to supply memory.
686
687 /// Return the allocator used by this object to supply memory.
689
690 /// Write the value of this object to the specified output `stream` in a
691 /// human-readable format, and return a non-`const` reference to
692 /// `stream`. Optionally specify an initial indentation `level`, whose
693 /// absolute value is incremented recursively for nested objects. If
694 /// `level` is specified, optionally specify `spacesPerLevel`, whose
695 /// absolute value indicates the number of spaces per indentation level
696 /// for this and all of its nested objects. If `level` is negative,
697 /// suppress indentation of the first line. If `spacesPerLevel` is
698 /// negative, format the entire output on one line, suppressing all but
699 /// the initial indentation (as governed by `level`). If `stream` is not valid on entry, this operation has no effect.
700 ///
701 /// \note Note that the
702 /// format is not fully specified, and can change without notice.
703 bsl::ostream& print(bsl::ostream& stream,
704 int level = 0,
705 int spacesPerLevel = 4) const;
706};
707
708// FREE OPERATORS
709
710/// Write the value of the specified `object` to the specified output
711/// `stream` in a single-line format, and return a non-`const` reference to
712/// `stream`. If `stream` is not valid on entry, this operation has no effect.
713///
714/// \note Note that this human-readable format is not fully specified and
715/// can change without notice. Also note that this method has the same
716/// behavior as `object.print(stream, 0, -1)`.
717bsl::ostream& operator<<(bsl::ostream& stream, const JsonNumber& object);
718
719/// Return `true` if the specified `lhs` and `rhs` objects have the same
720/// value, and `false` otherwise. Two `JsonNumber` objects have the same
721/// value if their `value` attributes are the same.
722bool operator==(const JsonNumber& lhs, const JsonNumber& rhs);
723
724/// Return `true` if the specified `lhs` and `rhs` objects do not have the
725/// same value, and `false` otherwise. Two `JsonNumber` objects do not have
726/// the same value if their `value` attributes are not the same.
727bool operator!=(const JsonNumber& lhs, const JsonNumber& rhs);
728
729// FREE FUNCTIONS
730
731/// Pass the specified `object` to the specified `hashAlgorithm`. This
732/// function integrates with the `bslh` modular hashing system and
733/// effectively provides a `bsl::hash` specialization for `JsonNumber`.
734template <class HASHALG>
735void hashAppend(HASHALG& hashAlgorithm, const JsonNumber& object);
736
737/// Exchange the values of the specified `a` and `b` objects. This function
738/// provides the no-throw exception-safety guarantee if the two objects were
739/// created with the same allocator and the basic guarantee otherwise.
740void swap(JsonNumber& a, JsonNumber& b);
741
742// ============================================================================
743// INLINE DEFINITIONS
744// ============================================================================
745
746 // -----------------
747 // struct JsonNumber
748 // -----------------
749
750// CLASS METHODS
751inline
753{
754 return NumberUtil::isValidNumber(text);
755}
756
757// CREATORS
758inline
760: d_value(1, '0')
761{
762}
763
764inline
766: d_value(1, '0', allocator)
767{
768}
769
770inline
771JsonNumber::JsonNumber(const char *text,
772 const allocator_type& allocator)
773: d_value(text, allocator)
774{
776}
777
778inline
780 const allocator_type& allocator)
781: d_value(text, allocator)
782{
784}
785
786inline
787JsonNumber::JsonNumber(int value, const allocator_type& allocator)
788: d_value(allocator)
789{
790 NumberUtil::stringify(&d_value, static_cast<long long>(value));
791}
792
793inline
794JsonNumber::JsonNumber(unsigned int value, const allocator_type& allocator)
795: d_value(allocator)
796{
797 NumberUtil::stringify(&d_value, static_cast<unsigned long long>(value));
798}
799
800inline
801JsonNumber::JsonNumber(long value, const allocator_type& allocator)
802: d_value(allocator)
803{
804 NumberUtil::stringify(&d_value, static_cast<long long>(value));
805}
806
807inline
808JsonNumber::JsonNumber(unsigned long value, const allocator_type& allocator)
809: d_value(allocator)
810{
811 NumberUtil::stringify(&d_value, static_cast<unsigned long long>(value));
812}
813
814inline
816 const allocator_type& allocator)
817: d_value(allocator)
818{
819 NumberUtil::stringify(&d_value, value);
820}
821
822inline
823JsonNumber::JsonNumber(unsigned long long value,
824 const allocator_type& allocator)
825: d_value(allocator)
826{
827 NumberUtil::stringify(&d_value, value);
828}
829
830inline
831JsonNumber::JsonNumber(float value, const allocator_type& allocator)
832: d_value(allocator)
833{
836
837 NumberUtil::stringify(&d_value, value);
838}
839
840inline
841JsonNumber::JsonNumber(double value, const allocator_type& allocator)
842: d_value(allocator)
843{
846
847 NumberUtil::stringify(&d_value, value);
848}
849
850inline
860
861inline
863: d_value(bslmf::MovableRefUtil::move(text))
864{
866}
867
868inline
870 const allocator_type& allocator)
871: d_value(bslmf::MovableRefUtil::move(text), allocator)
872{
874}
875
876inline
878 const allocator_type& allocator)
879: d_value(original.d_value, allocator)
880{
881}
882
883inline
890
891inline
893 const allocator_type& allocator)
894: d_value(bslmf::MovableRefUtil::move(
895 bslmf::MovableRefUtil::access(original).d_value),
896 allocator)
897{
898}
899
900// MANIPULATORS
901inline
903{
904 d_value = rhs.d_value;
905 return *this;
906}
907
908inline
915
916inline
918{
919 NumberUtil::stringify(&d_value, static_cast<long long>(rhs));
920 return *this;
921}
922
923inline
925{
926 NumberUtil::stringify(&d_value, static_cast<unsigned long long>(rhs));
927 return *this;
928}
929
930inline
932{
933 NumberUtil::stringify(&d_value, static_cast<long long>(rhs));
934 return *this;
935}
936
937inline
939{
940 NumberUtil::stringify(&d_value, static_cast<unsigned long long>(rhs));
941 return *this;
942}
943
944inline
946{
947 NumberUtil::stringify(&d_value, rhs);
948 return *this;
949}
950
951inline
952JsonNumber& JsonNumber::operator=(unsigned long long rhs)
953{
954 NumberUtil::stringify(&d_value, rhs);
955 return *this;
956}
957
958inline
960{
963
964 NumberUtil::stringify(&d_value, rhs);
965 return *this;
966}
967
968inline
970{
973
974 NumberUtil::stringify(&d_value, rhs);
975 return *this;
976}
977
978inline
987
988inline
990{
991 BSLS_ASSERT(d_value.get_allocator() == other.get_allocator());
992
993 bslalg::SwapUtil::swap(&d_value, &other.d_value);
994}
995
996// ACCESSORS
997inline
998bool JsonNumber::isEqual(const JsonNumber& other) const
999{
1000 return NumberUtil::areEqual(d_value, other.d_value);
1001}
1002
1003inline
1005{
1006 return NumberUtil::isIntegralNumber(d_value);
1007}
1008
1009inline
1011{
1012 return d_value;
1013}
1014
1015 // Integer Accessors
1016
1017// BDE_VERIFY pragma: push
1018// BDE_VERIFY pragma: -FABC01 // not in alphabetic order
1019
1020inline
1021int JsonNumber::asShort(short *result) const
1022{
1023 return NumberUtil::asShort(result, d_value);
1024}
1025
1026inline
1027int JsonNumber::asInt(int *result) const
1028{
1029 return NumberUtil::asInt(result, d_value);
1030}
1031
1032inline
1033int JsonNumber::asLong(long *result) const
1034{
1035 return NumberUtil::asLong(result, d_value);
1036}
1037
1038inline
1039int JsonNumber::asLonglong(long long *result) const
1040{
1041 return NumberUtil::asLonglong(result, d_value);
1042}
1043
1044inline
1046{
1047 return NumberUtil::asInt64(result, d_value);
1048}
1049
1050inline
1051int JsonNumber::asUshort(unsigned short *result) const
1052{
1053 return NumberUtil::asUshort(result, d_value);
1054}
1055
1056inline
1057int JsonNumber::asUint(unsigned int *result) const
1058{
1059 return NumberUtil::asUint(result, d_value);
1060}
1061
1062inline
1063int JsonNumber::asUlong(unsigned long *result) const
1064{
1065 return NumberUtil::asUlong(result, d_value);
1066}
1067
1068inline
1069int JsonNumber::asUlonglong(unsigned long long *result) const
1070{
1071 return NumberUtil::asUlonglong(result, d_value);
1072}
1073
1074inline
1076{
1077 return NumberUtil::asUint64(result, d_value);
1078}
1079
1080inline
1082{
1083 return static_cast<float>(asDouble());
1084}
1085
1086inline
1088{
1089 return NumberUtil::asDouble(d_value);
1090}
1091
1092inline
1097
1098 // "Exact" Accessors
1099
1100inline
1102{
1103 return NumberUtil::asDecimal64Exact(result, d_value);
1104}
1105
1106// BDE_VERIFY pragma: pop
1107
1108#if defined(BSLS_COMPILERFEATURES_SUPPORT_OPERATOR_EXPLICIT)
1109
1110 // `explicit` (conversion) operators
1111inline
1112JsonNumber::operator float() const
1113{
1114 return asFloat();
1115}
1116
1117inline
1118JsonNumber::operator double() const
1119{
1120 return asDouble();
1121}
1122
1123inline
1124JsonNumber::operator bdldfp::Decimal64() const
1125{
1126 return asDecimal64();
1127}
1128#endif
1129
1130 // Aspects
1131inline
1133{
1134 return d_value.get_allocator().mechanism();
1135}
1136
1137inline
1139{
1140 return d_value.get_allocator();
1141}
1142
1143} // close package namespace
1144
1145// FREE OPERATORS
1146inline
1147bsl::ostream& bdljsn::operator<<(bsl::ostream& stream,
1148 const bdljsn::JsonNumber& object)
1149{
1150 return object.print(stream, 0, -1);
1151}
1152
1153inline
1155 const bdljsn::JsonNumber& rhs)
1156{
1157 return lhs.value() == rhs.value();
1158}
1159
1160inline
1162 const bdljsn::JsonNumber& rhs)
1163{
1164 return lhs.value() != rhs.value();
1165}
1166
1167// FREE FUNCTIONS
1168template <class HASHALG>
1169inline
1170void bdljsn::hashAppend(HASHALG& hashAlgorithm,
1171 const bdljsn::JsonNumber& object)
1172{
1173 hashAppend(hashAlgorithm, object.value());
1174}
1175
1176inline
1178{
1179 bslalg::SwapUtil::swap(&a.d_value, &b.d_value);
1180}
1181
1182
1183
1184#endif // INCLUDED_BDLJSN_JSONNUMBER
1185
1186// ----------------------------------------------------------------------------
1187// Copyright 2022 Bloomberg Finance L.P.
1188//
1189// Licensed under the Apache License, Version 2.0 (the "License");
1190// you may not use this file except in compliance with the License.
1191// You may obtain a copy of the License at
1192//
1193// http://www.apache.org/licenses/LICENSE-2.0
1194//
1195// Unless required by applicable law or agreed to in writing, software
1196// distributed under the License is distributed on an "AS IS" BASIS,
1197// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1198// See the License for the specific language governing permissions and
1199// limitations under the License.
1200// ----------------------------- END-OF-FILE ----------------------------------
1201
1202/** @} */
1203/** @} */
1204/** @} */
Definition bdldfp_decimal.h:1890
Definition bdljsn_jsonnumber.h:412
int asUshort(unsigned short *result) const
Definition bdljsn_jsonnumber.h:1051
int asUlong(unsigned long *result) const
Definition bdljsn_jsonnumber.h:1063
JsonNumber()
Definition bdljsn_jsonnumber.h:759
JsonNumber & operator=(const JsonNumber &rhs)
Definition bdljsn_jsonnumber.h:902
static bool isValidNumber(const bsl::string_view &text)
Definition bdljsn_jsonnumber.h:752
int asUlonglong(unsigned long long *result) const
Definition bdljsn_jsonnumber.h:1069
int asUint64(bsls::Types::Uint64 *result) const
Definition bdljsn_jsonnumber.h:1075
allocator_type get_allocator() const
Return the allocator used by this object to supply memory.
Definition bdljsn_jsonnumber.h:1138
friend void swap(JsonNumber &, JsonNumber &)
BSLMF_NESTED_TRAIT_DECLARATION(JsonNumber, bslmf::IsBitwiseMoveable)
int asInt(int *result) const
Definition bdljsn_jsonnumber.h:1027
int asDecimal64Exact(bdldfp::Decimal64 *result) const
Definition bdljsn_jsonnumber.h:1101
const bsl::string & value() const
Return the textual representation of this JsonNumber.
Definition bdljsn_jsonnumber.h:1010
~JsonNumber()=default
float asFloat() const
Definition bdljsn_jsonnumber.h:1081
int asShort(short *result) const
Definition bdljsn_jsonnumber.h:1021
int asInt64(bsls::Types::Int64 *result) const
Definition bdljsn_jsonnumber.h:1045
bsl::allocator allocator_type
Definition bdljsn_jsonnumber.h:439
int asLong(long *result) const
Definition bdljsn_jsonnumber.h:1033
bdldfp::Decimal64 asDecimal64() const
Definition bdljsn_jsonnumber.h:1093
bool isEqual(const JsonNumber &other) const
Definition bdljsn_jsonnumber.h:998
@ k_INEXACT
Definition bdljsn_jsonnumber.h:432
@ k_UNDERFLOW
Definition bdljsn_jsonnumber.h:428
@ k_NOT_INTEGRAL
Definition bdljsn_jsonnumber.h:429
@ k_OVERFLOW
Definition bdljsn_jsonnumber.h:427
bslma::Allocator *BSLS_ANNOTATION_DEPRECATED allocator() const
Definition bdljsn_jsonnumber.h:1132
int asUint(unsigned int *result) const
Definition bdljsn_jsonnumber.h:1057
double asDouble() const
Definition bdljsn_jsonnumber.h:1087
bool isIntegral() const
Definition bdljsn_jsonnumber.h:1004
int asLonglong(long long *result) const
Definition bdljsn_jsonnumber.h:1039
bsl::ostream & print(bsl::ostream &stream, int level=0, int spacesPerLevel=4) const
Definition bslma_bslallocator.h:588
BloombergLP::bslma::Allocator * mechanism() const
Definition bslma_bslallocator.h:1146
Definition bslstl_stringview.h:471
Definition bslstl_string.h:1252
allocator_type get_allocator() const BSLS_KEYWORD_NOEXCEPT
Return the allocator used by this string to supply memory.
Definition bslstl_string.h:7423
static void swap(T *a, T *b)
Definition bslalg_swaputil.h:182
Definition bslma_allocator.h:545
Definition bslmf_movableref.h:752
#define BSLS_ANNOTATION_DEPRECATED
Definition bsls_annotation.h:324
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1976
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
#define BSLS_KEYWORD_NOEXCEPT
Definition bsls_keyword.h:674
void hashAppend(HASH_ALGORITHM &hashAlgorithm, const BigEndianInt16 &object)
Decimal_Type64 Decimal64
Definition bdldfp_decimal.h:750
Definition bdljsn_error.h:142
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)
ALLOCATOR const STRING_VIEW_LIKE_TYPE & rhs
Definition bslstl_string.h:3918
ALLOCATOR & lhs
Definition bslstl_string.h:3917
Definition bdlbb_blob.h:579
static bool isNan(float number)
static bool isInfinite(float number)
static bool isNan(Decimal32 x)
static bool isInf(Decimal32 x)
Definition bdljsn_numberutil.h:190
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)
@ k_UNDERFLOW
Definition bdljsn_numberutil.h:200
@ k_NOT_INTEGRAL
Definition bdljsn_numberutil.h:201
@ k_INEXACT
Definition bdljsn_numberutil.h:204
@ k_OVERFLOW
Definition bdljsn_numberutil.h:199
static bool isValidNumber(const bsl::string_view &value)
static int asUlonglong(unsigned long long *result, const bsl::string_view &value)
Definition bdljsn_numberutil.h:571
static int asUint(unsigned int *result, const bsl::string_view &value)
Definition bdljsn_numberutil.h:559
static double asDouble(const bsl::string_view &value)
Definition bdljsn_numberutil.h:494
static int asLonglong(long long *result, const bsl::string_view &value)
Definition bdljsn_numberutil.h:541
static bool areEqual(const bsl::string_view &lhs, const bsl::string_view &rhs)
static bdldfp::Decimal64 asDecimal64(const bsl::string_view &value)
static int asLong(long *result, const bsl::string_view &value)
Definition bdljsn_numberutil.h:535
static int asUlong(unsigned long *result, const bsl::string_view &value)
Definition bdljsn_numberutil.h:565
static int asShort(short *result, const bsl::string_view &value)
Definition bdljsn_numberutil.h:523
static int asInt(int *result, const bsl::string_view &value)
Definition bdljsn_numberutil.h:529
static void stringify(bsl::string *result, long long value)
static int asUshort(unsigned short *result, const bsl::string_view &value)
Definition bdljsn_numberutil.h:553
static int asInt64(Int64 *result, const bsl::string_view &value)
Definition bdljsn_numberutil.h:547
Definition bslmf_isbitwisemoveable.h:718
static MovableRef< t_TYPE > move(t_TYPE &reference) BSLS_KEYWORD_NOEXCEPT
Definition bslmf_movableref.h:1067
static t_TYPE & access(t_TYPE &ref) BSLS_KEYWORD_NOEXCEPT
Definition bslmf_movableref.h:1039
unsigned long long Uint64
Definition bsls_types.h:139
long long Int64
Definition bsls_types.h:134