1 // © 2018 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html 3 4 #include "unicode/utypes.h" 5 6 #if !UCONFIG_NO_FORMATTING 7 8 // Allow implicit conversion from char16_t* to UnicodeString for this file: 9 // Helpful in toString methods and elsewhere. 10 #define UNISTR_FROM_STRING_EXPLICIT 11 12 #include "numparse_types.h" 13 #include "number_decimalquantity.h" 14 #include "string_segment.h" 15 #include "putilimp.h" 16 #include <cmath> 17 18 using namespace icu; 19 using namespace icu::number; 20 using namespace icu::number::impl; 21 using namespace icu::numparse; 22 using namespace icu::numparse::impl; 23 24 ParsedNumber()25ParsedNumber::ParsedNumber() { 26 clear(); 27 } 28 clear()29void ParsedNumber::clear() { 30 quantity.bogus = true; 31 charEnd = 0; 32 flags = 0; 33 prefix.setToBogus(); 34 suffix.setToBogus(); 35 currencyCode[0] = 0; 36 } 37 setCharsConsumed(const StringSegment & segment)38void ParsedNumber::setCharsConsumed(const StringSegment& segment) { 39 charEnd = segment.getOffset(); 40 } 41 postProcess()42void ParsedNumber::postProcess() { 43 if (!quantity.bogus && 0 != (flags & FLAG_NEGATIVE)) { 44 quantity.negate(); 45 } 46 } 47 success() const48bool ParsedNumber::success() const { 49 return charEnd > 0 && 0 == (flags & FLAG_FAIL); 50 } 51 seenNumber() const52bool ParsedNumber::seenNumber() const { 53 return !quantity.bogus || 0 != (flags & FLAG_NAN) || 0 != (flags & FLAG_INFINITY); 54 } 55 getDouble(UErrorCode & status) const56double ParsedNumber::getDouble(UErrorCode& status) const { 57 bool sawNaN = 0 != (flags & FLAG_NAN); 58 bool sawInfinity = 0 != (flags & FLAG_INFINITY); 59 60 // Check for NaN, infinity, and -0.0 61 if (sawNaN) { 62 // Can't use NAN or std::nan because the byte pattern is platform-dependent; 63 // MSVC sets the sign bit, but Clang and GCC do not 64 return uprv_getNaN(); 65 } 66 if (sawInfinity) { 67 if (0 != (flags & FLAG_NEGATIVE)) { 68 return -INFINITY; 69 } else { 70 return INFINITY; 71 } 72 } 73 if (quantity.bogus) { 74 status = U_INVALID_STATE_ERROR; 75 return 0.0; 76 } 77 if (quantity.isZeroish() && quantity.isNegative()) { 78 return -0.0; 79 } 80 81 if (quantity.fitsInLong()) { 82 return static_cast<double>(quantity.toLong()); 83 } else { 84 return quantity.toDouble(); 85 } 86 } 87 populateFormattable(Formattable & output,parse_flags_t parseFlags) const88void ParsedNumber::populateFormattable(Formattable& output, parse_flags_t parseFlags) const { 89 bool sawNaN = 0 != (flags & FLAG_NAN); 90 bool sawInfinity = 0 != (flags & FLAG_INFINITY); 91 bool integerOnly = 0 != (parseFlags & PARSE_FLAG_INTEGER_ONLY); 92 93 // Check for NaN, infinity, and -0.0 94 if (sawNaN) { 95 // Can't use NAN or std::nan because the byte pattern is platform-dependent; 96 // MSVC sets the sign bit, but Clang and GCC do not 97 output.setDouble(uprv_getNaN()); 98 return; 99 } 100 if (sawInfinity) { 101 if (0 != (flags & FLAG_NEGATIVE)) { 102 output.setDouble(-INFINITY); 103 return; 104 } else { 105 output.setDouble(INFINITY); 106 return; 107 } 108 } 109 U_ASSERT(!quantity.bogus); 110 if (quantity.isZeroish() && quantity.isNegative() && !integerOnly) { 111 output.setDouble(-0.0); 112 return; 113 } 114 115 // All other numbers 116 output.adoptDecimalQuantity(new DecimalQuantity(quantity)); 117 } 118 isBetterThan(const ParsedNumber & other)119bool ParsedNumber::isBetterThan(const ParsedNumber& other) { 120 // Favor results with strictly more characters consumed. 121 return charEnd > other.charEnd; 122 } 123 124 125 126 #endif /* #if !UCONFIG_NO_FORMATTING */ 127