BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bdljsn_numberutil.h
Go to the documentation of this file.
1/// @file bdljsn_numberutil.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdljsn_numberutil.h -*-C++-*-
8#ifndef INCLUDED_BDLJSN_NUMBERUTIL
9#define INCLUDED_BDLJSN_NUMBERUTIL
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bdljsn_numberutil bdljsn_numberutil
15/// @brief Provide utilities converting between JSON text and numeric types.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdljsn
19/// @{
20/// @addtogroup bdljsn_numberutil
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdljsn_numberutil-purpose"> Purpose</a>
25/// * <a href="#bdljsn_numberutil-classes"> Classes </a>
26/// * <a href="#bdljsn_numberutil-description"> Description </a>
27/// * <a href="#bdljsn_numberutil-usage"> Usage </a>
28/// * <a href="#bdljsn_numberutil-example-1-interpreting-a-json-number-string"> Example 1: Interpreting a JSON Number String </a>
29///
30/// # Purpose {#bdljsn_numberutil-purpose}
31/// Provide utilities converting between JSON text and numeric types.
32///
33/// # Classes {#bdljsn_numberutil-classes}
34///
35/// - bdljsn::NumberUtil: conversion between JSON text and numeric types
36///
37/// # Description {#bdljsn_numberutil-description}
38/// This component provides a struct, `bdljsn::NumberUtil`, that is
39/// a namespace for a suite of functions for working with the JSON number text
40/// format. `bdljsn::NumberUtil` provides a function `isValidNumber` to
41/// determine whether a string is a valid JSON number. Many of the other
42/// operations in this component have, as a precondition, that `isValidNumber`
43/// is `true` for the text. For information about the JSON number specification
44/// and additional background on the behavior of numbers in `bdljsn` see
45/// {bdljsn_jsonnumber}.
46///
47/// Many of the operations in this component have `isValidNumber` as a
48/// precondition in order to provide simpler and more efficient implementations.
49/// In the context of `JsonNumber`, the text will always be validated prior to
50/// performing other operations.
51///
52/// ## Usage {#bdljsn_numberutil-usage}
53///
54///
55/// This section illustrates intended use of this component.
56///
57/// ### Example 1: Interpreting a JSON Number String {#bdljsn_numberutil-example-1-interpreting-a-json-number-string}
58///
59///
60/// This example demonstrates using `bdljsn::NumberUtil` to work with a JSON
61/// number string. Imagine we are given and array of strings for numbers we
62/// expect to be integers, for each string we want to render some properties for
63/// that number.
64///
65/// First, we define an interesting set of example data:
66/// @code
67/// const char *EXAMPLE_DATA[] = {
68/// // value converted int value & notes
69/// // ----- ---------------------------
70/// "NaN", // invalid number
71/// "INF", // invalid number
72/// "1", // 1, exact
73/// "1.5", // 1, not an integer
74/// "-9223372036854775809", // INT64_MIN, underflow
75/// "1.5e27", // INT64_MAX, overflow
76/// };
77///
78/// const int NUM_DATA = sizeof EXAMPLE_DATA / sizeof *EXAMPLE_DATA;
79/// @endcode
80/// Then, for each number, we first check whether it is a valid JSON Number
81/// (note that the behavior for the other methods is undefined unless the text
82/// is a valid JSON Number):
83/// @code
84/// for (int i = 0; i < NUM_DATA; ++i) {
85/// const char *EXAMPLE = EXAMPLE_DATA[i];
86/// bsl::cout << "\"" << EXAMPLE << "\": " << bsl::endl;
87/// if (!bdljsn::NumberUtil::isValidNumber(EXAMPLE)) {
88/// bsl::cout << " * is NOT a JSON Number" << bsl::endl;
89/// continue; // CONTINUE
90/// }
91/// @endcode
92/// Next we verify that the number is an integer. This will return an accurate
93/// result even when the integer cannot be represented.
94/// @code
95/// if (bdljsn::NumberUtil::isIntegralNumber(EXAMPLE)) {
96/// bsl::cout << " * is an integer" << bsl::endl;
97/// }
98/// else {
99/// bsl::cout << " * is not an integer" << bsl::endl;
100/// }
101/// @endcode
102/// Finally, we convert that number to an integer:
103/// @code
104/// bsls::Types::Int64 value;
105/// int rc = bdljsn::NumberUtil::asInt64(&value, EXAMPLE);
106///
107/// bsl::cout << " * value: " << value;
108///
109/// if (bdljsn::NumberUtil::k_NOT_INTEGRAL == rc) {
110/// bsl::cout << " (truncated)";
111/// }
112/// if (bdljsn::NumberUtil::k_OVERFLOW == rc) {
113/// bsl::cout << " (overflow)";
114/// }
115/// if (bdljsn::NumberUtil::k_UNDERFLOW == rc) {
116/// bsl::cout << " (underflow)";
117/// }
118/// bsl::cout << bsl::endl;
119/// }
120/// @endcode
121/// This will output the text:
122/// @code
123/// "NaN":
124/// * is NOT a JSON Number
125/// "INF":
126/// * is NOT a JSON Number
127/// "1":
128/// * is an integer
129/// * value: 1
130/// "1.5":
131/// * is not an integer
132/// * value: 1 (truncated)
133/// "-9223372036854775809":
134/// * is an integer
135/// * value: -9223372036854775808 (underflow)
136/// "1.5e27":
137/// * is an integer
138/// * value: 9223372036854775807 (overflow)
139/// @endcode
140/// @}
141/** @} */
142/** @} */
143
144/** @addtogroup bdl
145 * @{
146 */
147/** @addtogroup bdljsn
148 * @{
149 */
150/** @addtogroup bdljsn_numberutil
151 * @{
152 */
153
154#include <bdlscm_version.h>
155
156#include <bdlb_float.h>
158#include <bdldfp_decimal.h>
160
161#include <bsla_nodiscard.h>
162#include <bslmf_assert.h>
163#include <bslmf_selecttrait.h>
164
165#include <bsls_assert.h>
166#include <bsls_performancehint.h>
167#include <bsls_types.h>
168
169#include <bsl_cerrno.h> // `ERANGE`
170#include <bsl_string.h>
171#include <bsl_string_view.h>
172#include <bsl_type_traits.h>
173#include <bsl_iostream.h>
174
175
176namespace bdljsn {
177
178struct NumberUtil_ImpUtil;
179
180 // =================
181 // struct NumberUtil
182 // =================
183
184/// This `struct` provides a namespace for a suite of functions that convert
185/// between a JSON formated numeric value and various numerical types. The
186/// valid syntax for a JSON formatted numeric value is spelled out in
187/// `https://www.rfc-editor.org/rfc/rfc8259#section-6`.
188///
189/// See @ref bdljsn_numberutil
191
192 // PUBLIC TYPES
195
196 // PUBLIC CONSTANTS
197 enum {
198 // special integer conversion status values
199 k_OVERFLOW = -1, // the number is above the representable range
200 k_UNDERFLOW = -2, // the number is below the representable range
201 k_NOT_INTEGRAL = -3, // the number is not an integer
202
203 // special exact Decimal64 conversion status values
204 k_INEXACT = -4
205 };
206
207 // CLASS METHODS
208
209 // validation
210
211 /// Return `true` if the specified `value` is a valid integral JSON number.
212 ///
213 /// \note Note that this function may return `true` even if `value`
214 /// cannot be represented in a fundamental integral type.
215 ///
216 /// \pre The behavior is undefined unless `isValidNumber(value)` is `true`.
217 static bool isIntegralNumber(const bsl::string_view& value);
218
219 /// Return `true` if the specified `value` is a valid JSON number.
220 ///
221 /// \note Note that this function may return `true` even if `value` cannot be
222 /// represented in any particular number type.
223 static bool isValidNumber(const bsl::string_view& value);
224
225 // basic floating point conversions
226
227 /// Return the closest floating point representation to the specified
228 /// `value`. If `value` is outside the representable range, return +INF or -INF (as appropriate).
229 ///
230 /// \pre The behavior is undefined unless
231 /// `isValidNumber(value)` is `true`.
233 static double asDouble (const bsl::string_view& value);
234 static float asFloat (const bsl::string_view& value);
235
236 // exact floating point conversions
237
238 /// Load the specified `result` with the specified `value`, even if a
239 /// non-zero status is returned. Return 0 if `value` can be represented
240 /// exactly, and return `k_INEXACT` and load `result` with the closest
241 /// approximation of `value` if `value` cannot be represented exactly.
242 /// A `value` can be represented exactly as a `Decimal64` if, for the
243 /// significand and exponent of `value`,
244 /// `abs(significand) <= 9,999,999,999,999,999` and `-398 <= exponent <= 369`.
245 ///
246 /// \pre The behavior is undefined unless
247 /// `isValidNumber(value)` is `true`.
249 const bsl::string_view& value);
250
251 // typed integer conversions
252
253// BDE_VERIFY pragma: -FABC01 // not in alphabetic order
254
255 /// Load the specified `result` with the specified `value`, even if a
256 /// non-zero status is returned (truncating fractional digits if
257 /// necessary). Return 0 on success, `k_OVERFLOW` if `value` is larger
258 /// than can be represented by `result`, `k_UNDERFLOW` if `value` is
259 /// smaller than can be represented by `result`, and `k_NOT_INTEGRAL` if
260 /// `value` is not an integral number (i.e., there is a fractional
261 /// part). For underflow, `result` will be loaded with the minimum
262 /// representable value, for overflow, `result` will be loaded with the
263 /// maximum representable value, for non-integral values `result` will
264 /// be loaded with the integer part of `value` (truncating the fractional part of `value`).
265 ///
266 /// \pre The behavior is undefined unless `isValidNumber(value)` is `true`.
267 ///
268 /// \note Note that this operation will
269 /// correctly handle exponents (e.g., a `value` of
270 /// "0.00000000000000000001e20" will produce a `result` of 1).
271 static int asShort(short *result, const bsl::string_view& value);
272 static int asUshort(unsigned short *result, const bsl::string_view& value);
273 static int asInt (int *result, const bsl::string_view& value);
274 static int asUint (unsigned int *result, const bsl::string_view& value);
275 static int asLong (long *result, const bsl::string_view& value);
276 static int asUlong(unsigned long *result, const bsl::string_view& value);
277 static int asLonglong
278 (long long *result, const bsl::string_view& value);
279 static int asUlonglong
280 (unsigned long long *result, const bsl::string_view& value);
281 static int asInt64 (Int64 *result, const bsl::string_view& value);
282 static int asUint64(Uint64 *result, const bsl::string_view& value);
283
284// BDE_VERIFY pragma: +FABC01 // not in alphabetic order
285
286 // generic integer conversion
287
288 /// Load into the specified `result` (of the template parameter type
289 /// `t_INTEGER_TYPE`) with the specified `value`, even if a non-zero
290 /// status is returned (truncating fractional digits if necessary).
291 /// Return 0 on success, `k_OVERFLOW` if `value` is larger than can be
292 /// represented by `result`, `k_UNDERFLOW` if `value` is smaller than
293 /// can be represented by `result`, and `k_NOT_INTEGRAL` if `value` is
294 /// not an integral number (i.e., there is a fractional part). For
295 /// underflow, `result` will be loaded with the minimum representable
296 /// value, for overflow, `result` will be loaded with the maximum
297 /// representable value, for non-integral values `result` will be loaded
298 /// with the integer part of `value` (truncating the value to the
299 /// nearest integer). If the result is not an integer and also either
300 /// overflows or underflows, it is treated as an overflow or underflow
301 /// (respectively). The (template parameter) `t_INTEGER_TYPE` shall be
302 /// either a signed or unsigned integer type (that is not `bool`) where `sizeof(t_INTEGER_TYPE) <= 8`.
303 ///
304 /// \pre The behavior is undefined unless `isValidNumber(value)` is `true`.
305 ///
306 /// \note Note that this operation will
307 /// correctly handle exponents (e.g., a `value` of
308 /// "0.00000000000000000001e20" will produce a `result` of
309 /// 1).
310 template <class t_INTEGER_TYPE>
311 static int asInteger(t_INTEGER_TYPE *result,
312 const bsl::string_view& value);
313
314 // conversions to string
315
316 /// Load into the specified `result` a string representation of
317 /// specified numerical `value`.
318 static void stringify(bsl::string *result, long long value);
319 static void stringify(bsl::string *result, unsigned long long value);
320 static void stringify(bsl::string *result, double value);
321 static void stringify(bsl::string *result, const bdldfp::Decimal64& value);
322
323 // comparison
324
325 /// Return `true` if the specified `lhs` and `rhs` represent the same
326 /// numeric value, and `false` otherwise. This function will return
327 /// `true` for differing representations of the same number (e.g.,
328 /// `1.0`, "1", "0.1e+1" are all equivalent) *except* in cases where the
329 /// exponent cannot be represented by a 64-bit integer. If the exponent
330 /// is outside the range of a 64-bit integer, `true` will be returned if
331 /// `lhs == rhs`. For example, comparing "1e18446744073709551615" with
332 /// itself will return `true`, but comparing it to
333 /// "10e18446744073709551614" will return `false`.
334 ///
335 /// \pre The behavior is undefined unless `isValidNumber(lhs)` and `isValidNumber(rhs)`.
336 static bool areEqual(const bsl::string_view& lhs,
337 const bsl::string_view& rhs);
338};
339
340 // ==========================
341 // struct NumberUtil_IsSigned
342 // ==========================
343
344/// This class will be a `bsl::true_type` if the specified (template
345/// parameter type) `t_TYPE` is a signed type, and `bsl::false_type` otherwise. `t_TYPE` shall be an integral type.
346///
347/// \note Note that currently
348/// bsl::is_signed is not available for C++03 platforms.
349template <class t_TYPE>
351: bsl::integral_constant<bool, (t_TYPE(-1) < t_TYPE(0))> {
352};
353
354 // =========================
355 // struct NumberUtil_ImpUtil
356 // =========================
357
358/// [**PRIVATE**] This private implementation `struct` provides a namespace
359/// for a suite of functions used to help implement `NumberUtil`. These
360/// functions are private to this component and should not be used by
361/// clients.
362///
363/// See @ref bdljsn_numberutil
364struct NumberUtil_ImpUtil {
365
366 // PUBLIC CONSTANTS
367 enum {
368 k_EXPONENT_OUT_OF_RANGE = -1 // exponent is out of a supported range
369 };
370
371 // CLASS METHODS
372
373 /// Load the specified `result` by appending the specified `digits` to
374 /// the specified `startingValue`. Return 0 on success,
375 /// `NumberUtil::k_OVERFLOW` if the result cannot be represented in a
376 /// `Uint64`. For example, appending "345" to 12 will return a `result`
377 /// of 12345.
378 static int appendDigits(bsls::Types::Uint64 *result,
379 bsls::Types::Uint64 startingValue,
380 const bsl::string_view& digits);
381
382 /// These function overloads implement `NumberUtil::asInteger`, and are
383 /// documented there.
384 static int asInteger(bsls::Types::Uint64 *result,
385 const bsl::string_view& value);
386 template <class t_INTEGER_TYPE>
387 static int asInteger(t_INTEGER_TYPE *result,
388 const bsl::string_view& value);
389
390 /// These functions are the template dispatched implementations for the
391 /// `NumberUtil_ImpUtil::asInteger` template function, and serve to
392 /// distinguish the `signed` from the (default-case) `unsigned`
393 /// implementation. These functions are documented by
394 /// `NumberUtil::asInteger`.
395 template <class t_INTEGER_TYPE>
396 static int asIntegerDispatchImp(
397 t_INTEGER_TYPE *result,
398 const bsl::string_view& value,
399 bslmf::SelectTraitCase<NumberUtil_IsSigned>);
400 template <class t_INTEGER_TYPE>
401 static int asIntegerDispatchImp(t_INTEGER_TYPE *result,
402 const bsl::string_view& value,
403 bslmf::SelectTraitCase<>);
404
405 /// Decompose the specified `value` into constituent elements, loading
406 /// the specified `isNegative` with a flag indicating if `value` is
407 /// negative, the specified `isExponentNegative` with a flag indicating
408 /// whether the exponent of `value` is negative, the specified `integer`
409 /// with the integer portion of `value`, the specified `fraction` with
410 /// the fraction portion of `value`, the specified `exponent` with the
411 /// exponent portion of `value`, the specified `significantDigits` with
412 /// the significant digits of `value`, the specified
413 /// `significantDigitsBias` with a bias to add to the exponent when
414 /// considering the value of the significant digits, and the
415 /// `significantDigitsDotOffset` with the offset of the `.` character in
416 /// `significantDigits` (if one exists). The returned
417 /// `significantDigits` may include a `.` character (whose offset into
418 /// `significantDigits` is given by `significantDigitsOffset`) which
419 /// should simply be ignored when considering the significant digits.
420 /// If `significantDigits` does not include a `.` character,
421 /// `significantDigitsOffset` will be `bsl::string_view::npos`.
422 ///
423 /// \pre The behavior is undefined unless `NumberUtil::isValidNumber(value)` is `true`.
424 ///
425 /// \note Note that if `significantDigits[0]` is `0` then `value`
426 /// must be 0.
427 ///
428 /// For example, here are some examples of decompose results for an
429 /// input `value` (`isNegative` and `isExpNegative` are omitted for
430 /// readability):
431 /// @code
432 /// | value | int | frac | exp | sigDigit | sigDotOff | sigBias |
433 /// |----------|-------|-------|-----|----------|-----------|---------|
434 /// | "0.00" | "0" | "00" | "" | "0" | npos | 0 |
435 /// | "100e+1" | "100" | "" | "1" | "1" | npos | 2 |
436 /// | "0.020" | "0" | "020" | "" | "2" | npos | -2 |
437 /// | "1.12e5" | "1" | "12" | "5" | "1.12" | 1 | -2 |
438 /// | "34.50" | "34" | "50" | "" | "34.5" | 2 | -1 |
439 /// | "0.060" | "0" | "060" | "" | "6" | npos | -2 |
440 /// | "10e-2" | "0" | "1" | "2" | "1" | npos | 1 |
441 /// @endcode
442 /// Notice that the `.` is ignored when considering `significantDigits`
443 /// (so "34.5" is treated as "345", and the bias is -1).
444 ///
445 /// Finally, note that `significantDigits`, `significantDigitBias`, and
446 /// `significantDigitsDotOffset` are useful when considering a canonical
447 /// representation for a JSON Number, which consists of a whole number
448 /// (with leading and trailing zeros removed) and an exponent. This
449 /// canonical representation can be used when determining whether two
450 /// JSON numbers are equal. For example, "-12.30e-4" would have a
451 /// canonical representation -123e-5. This canonical representation can
452 /// be computed by taking the returned `significantDigits`, "12.3",
453 /// ignoring the `.` character at `significantDigitsOffset` and
454 /// incorporating `isNegative` to get the canonical significant digits
455 /// -123, then combining `exponent` ("4") with `isExponentNegative` to
456 /// get the exponent of -4 and then adding the returned
457 /// `significantDigitsBias` of -1 to that exponent to get the canonical
458 /// exponent of -5. Combining the canonical significant digits (-123)
459 /// and the canonical exponent (-5) results in the canonical
460 /// representation -123e-5.
461 static void decompose(
462 bool *isNegative,
463 bool *isExpNegative,
464 bsl::string_view *integer,
465 bsl::string_view *fraction,
466 bsl::string_view *exponent,
467 bsl::string_view *significantDigits,
468 bsls::Types::Int64 *significantDigitsBias,
469 bsl::string_view::size_type *significantDigitsDotOffset,
470 const bsl::string_view& value);
471
472 /// Log the specified `value` (for which `isValidNumber` should be
473 /// `true`) could not be correctly parsed into a binary floating point representation.
474 ///
475 /// \note Note that this function should be unreachable (and
476 /// no test input has been found for which it is needed) but exists to
477 /// record an issue in case some gap were found between the JSON number
478 /// specification and the underlying floating point parsing functions
479 /// (whose quality may be outside of our control and vary by platform).
480 static void logUnparseableJsonNumber(const bsl::string_view& value);
481};
482
483// ============================================================================
484// INLINE DEFINITIONS
485// ============================================================================
486
487 // -----------------
488 // struct NumberUtil
489 // -----------------
490
491// BDE_VERIFY pragma: -FABC01 // not in alphabetic order
492
493inline
494double NumberUtil::asDouble(const bsl::string_view& value)
495{
496 BSLS_ASSERT(NumberUtil::isValidNumber(value));
497
498 double result;
499
500 int rc = bdlb::NumericParseUtil::parseDouble(&result, value);
501 if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(0 != rc && ERANGE != rc)) {
502 // This should not be possible and no test has found a case where this
503 // occurs. However, to prevent a possible denial of service attack if
504 // some gap were to be found in the implementation of low-level
505 // floating point parsing functions and the JSON number spec, we
506 // provide in-contract defined behavior for optimized (production)
507 // builds.
508
509 BSLS_ASSERT_UNREACHABLE("Unparseable JSON number");
510 NumberUtil_ImpUtil::logUnparseableJsonNumber(value);
511 return bsl::numeric_limits<double>::quiet_NaN(); // RETURN
512 }
513 return result;
514}
515
516inline
517float NumberUtil::asFloat(const bsl::string_view& value)
518{
519 return static_cast<float>(asDouble(value));
520}
521
522inline
523int NumberUtil::asShort(short *result, const bsl::string_view& value)
524{
525 return asInteger(result, value);
526}
527
528inline
529int NumberUtil::asInt(int *result, const bsl::string_view& value)
530{
531 return asInteger(result, value);
532}
533
534inline
535int NumberUtil::asLong(long *result, const bsl::string_view& value)
536{
537 return asInteger(result, value);
538}
539
540inline
541int NumberUtil::asLonglong(long long *result, const bsl::string_view& value)
542{
543 return asInteger(result, value);
544}
545
546inline
547int NumberUtil::asInt64(Int64 *result, const bsl::string_view& value)
548{
549 return asInteger(result, value);
550}
551
552inline
553int NumberUtil::asUshort(unsigned short *result, const bsl::string_view& value)
554{
555 return asInteger(result, value);
556}
557
558inline
559int NumberUtil::asUint(unsigned int *result, const bsl::string_view& value)
560{
561 return asInteger(result, value);
562}
563
564inline
565int NumberUtil::asUlong(unsigned long *result, const bsl::string_view& value)
566{
567 return asInteger(result, value);
568}
569
570inline
571int NumberUtil::asUlonglong(unsigned long long *result,
572 const bsl::string_view& value)
573{
574 return asInteger(result, value);
575}
576
577template <class t_INTEGER_TYPE>
578int NumberUtil::asInteger(t_INTEGER_TYPE *result,
579 const bsl::string_view& value)
580{
581 BSLMF_ASSERT((bsl::is_integral<t_INTEGER_TYPE>::value &&
582 (sizeof(t_INTEGER_TYPE) <= 8) &&
583 !bsl::is_same<t_INTEGER_TYPE, bool>::value));
584 return NumberUtil_ImpUtil::asInteger(result, value);
585}
586
587// BDE_VERIFY pragma: +FABC01 // not in alphabetic order
588
589 // -------------------------
590 // struct NumberUtil_ImpUtil
591 // -------------------------
592
593inline
594int NumberUtil_ImpUtil::asInteger(bsls::Types::Uint64 *result,
595 const bsl::string_view& value)
596{
597 return NumberUtil::asUint64(result, value);
598}
599
600template <class t_TYPE>
601int NumberUtil_ImpUtil::asInteger(t_TYPE *result,
602 const bsl::string_view& value)
603{
604 BSLMF_ASSERT(bsl::is_integral<t_TYPE>::value);
605
606 typedef bslmf::SelectTrait<t_TYPE, NumberUtil_IsSigned> Selection;
607 return NumberUtil_ImpUtil::asIntegerDispatchImp(result,
608 value,
609 Selection());
610}
611
612template <class t_INTEGER_TYPE>
613int NumberUtil_ImpUtil::asIntegerDispatchImp(
614 t_INTEGER_TYPE *result,
615 const bsl::string_view& value,
616 bslmf::SelectTraitCase<NumberUtil_IsSigned>)
617{
618 BSLMF_ASSERT(bsl::is_integral<t_INTEGER_TYPE>::value);
619 BSLMF_ASSERT(bsl::numeric_limits<t_INTEGER_TYPE>::is_signed);
620
621 BSLS_ASSERT(NumberUtil::isValidNumber(value));
622
623 bsl::string_view positiveValue = value;
624
625 bool isNegative;
626 if ('-' == value[0]) {
627 isNegative = true;
628 positiveValue.remove_prefix(1);
629 }
630 else {
631 isNegative = false;
632 }
633
634 const bsls::Types::Uint64 maxValue = static_cast<bsls::Types::Uint64>(
635 bsl::numeric_limits<t_INTEGER_TYPE>::max());
636
637 bsls::Types::Uint64 tmp;
638
639 const int rc = NumberUtil::asUint64(&tmp, positiveValue);
640
641 if (isNegative) {
642 if (tmp > maxValue + 1) {
643 *result = bsl::numeric_limits<t_INTEGER_TYPE>::min();
644 return NumberUtil::k_UNDERFLOW; // RETURN
645 }
646 *result = static_cast<t_INTEGER_TYPE>(tmp * -1ll );
647 }
648 else {
649 if (tmp > maxValue) {
650 *result = static_cast<t_INTEGER_TYPE>(maxValue);
651 return NumberUtil::k_OVERFLOW; // RETURN
652 }
653 *result = static_cast<t_INTEGER_TYPE>(tmp);
654 }
655 return rc;
656}
657
658template <class t_INTEGER_TYPE>
659int NumberUtil_ImpUtil::asIntegerDispatchImp(t_INTEGER_TYPE *result,
660 const bsl::string_view& value,
662{
664 BSLMF_ASSERT(!bsl::numeric_limits<t_INTEGER_TYPE>::is_signed);
665
666 BSLS_ASSERT(NumberUtil::isValidNumber(value));
667
668 typedef bsls::Types::Uint64 Uint64;
669
670 Uint64 tmp;
671
672 int rc = NumberUtil::asUint64(&tmp, value);
673 if (tmp >
674 static_cast<Uint64>(bsl::numeric_limits<t_INTEGER_TYPE>::max())) {
675 *result = bsl::numeric_limits<t_INTEGER_TYPE>::max();
676 return NumberUtil::k_OVERFLOW; // RETURN
677 }
678 *result = static_cast<t_INTEGER_TYPE>(tmp);
679 return rc;
680}
681
682} // close package namespace
683
684
685#endif // INCLUDED_BDLJSN_NUMBERUTIL
686
687// ----------------------------------------------------------------------------
688// Copyright 2022 Bloomberg Finance L.P.
689//
690// Licensed under the Apache License, Version 2.0 (the "License");
691// you may not use this file except in compliance with the License.
692// You may obtain a copy of the License at
693//
694// http://www.apache.org/licenses/LICENSE-2.0
695//
696// Unless required by applicable law or agreed to in writing, software
697// distributed under the License is distributed on an "AS IS" BASIS,
698// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
699// See the License for the specific language governing permissions and
700// limitations under the License.
701// ----------------------------- END-OF-FILE ----------------------------------
702
703/** @} */
704/** @} */
705/** @} */
Definition bdldfp_decimal.h:1890
Definition bslstl_stringview.h:471
Definition bslstl_string.h:1252
#define BSLMF_ASSERT(expr)
Definition bslmf_assert.h:231
#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
Definition bdljsn_error.h:142
Definition bdljsn_numberutil.h:351
Definition bdljsn_numberutil.h:190
static bool isIntegralNumber(const bsl::string_view &value)
bsls::Types::Uint64 Uint64
Definition bdljsn_numberutil.h:193
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 int asInteger(t_INTEGER_TYPE *result, const bsl::string_view &value)
Definition bdljsn_numberutil.h:578
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 void stringify(bsl::string *result, const bdldfp::Decimal64 &value)
static float asFloat(const bsl::string_view &value)
Definition bdljsn_numberutil.h:517
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)
bsls::Types::Int64 Int64
Definition bdljsn_numberutil.h:194
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 void stringify(bsl::string *result, double value)
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 void stringify(bsl::string *result, unsigned 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_integralconstant.h:261
Definition bslmf_isintegral.h:140
Definition bslmf_selecttrait.h:438
unsigned long long Uint64
Definition bsls_types.h:139
long long Int64
Definition bsls_types.h:134