number_simple.cpp (7201B)
1 // © 2017 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 #include "unicode/numberformatter.h" 9 #include "unicode/simplenumberformatter.h" 10 #include "number_formatimpl.h" 11 #include "number_utils.h" 12 #include "number_patternmodifier.h" 13 #include "number_utypes.h" 14 15 using namespace icu; 16 using namespace icu::number; 17 using namespace icu::number::impl; 18 19 20 SimpleNumber 21 SimpleNumber::forInt64(int64_t value, UErrorCode& status) { 22 if (U_FAILURE(status)) { 23 return {}; 24 } 25 auto* results = new UFormattedNumberData(); 26 if (results == nullptr) { 27 status = U_MEMORY_ALLOCATION_ERROR; 28 return {}; 29 } 30 results->quantity.setToLong(value); 31 return SimpleNumber(results, status); 32 } 33 34 SimpleNumber::SimpleNumber(UFormattedNumberData* data, UErrorCode& status) : fData(data) { 35 if (U_FAILURE(status)) { 36 return; 37 } 38 if (fData == nullptr) { 39 status = U_ILLEGAL_ARGUMENT_ERROR; 40 return; 41 } 42 if (fData->quantity.isNegative()) { 43 fSign = UNUM_SIMPLE_NUMBER_MINUS_SIGN; 44 } else { 45 fSign = UNUM_SIMPLE_NUMBER_NO_SIGN; 46 } 47 } 48 49 void SimpleNumber::cleanup() { 50 delete fData; 51 fData = nullptr; 52 } 53 54 void SimpleNumber::multiplyByPowerOfTen(int32_t power, UErrorCode& status) { 55 if (U_FAILURE(status)) { 56 return; 57 } 58 if (fData == nullptr) { 59 status = U_INVALID_STATE_ERROR; 60 return; 61 } 62 fData->quantity.adjustMagnitude(power); 63 } 64 65 void SimpleNumber::roundTo(int32_t position, UNumberFormatRoundingMode roundingMode, UErrorCode& status) { 66 if (U_FAILURE(status)) { 67 return; 68 } 69 if (fData == nullptr) { 70 status = U_INVALID_STATE_ERROR; 71 return; 72 } 73 fData->quantity.roundToMagnitude(position, roundingMode, status); 74 } 75 76 void SimpleNumber::setMinimumIntegerDigits(uint32_t position, UErrorCode& status) { 77 if (U_FAILURE(status)) { 78 return; 79 } 80 if (fData == nullptr) { 81 status = U_INVALID_STATE_ERROR; 82 return; 83 } 84 fData->quantity.decreaseMinIntegerTo(position); 85 fData->quantity.increaseMinIntegerTo(position); 86 } 87 88 void SimpleNumber::setMinimumFractionDigits(uint32_t position, UErrorCode& status) { 89 if (U_FAILURE(status)) { 90 return; 91 } 92 if (fData == nullptr) { 93 status = U_INVALID_STATE_ERROR; 94 return; 95 } 96 fData->quantity.setMinFraction(position); 97 } 98 99 void SimpleNumber::setMaximumIntegerDigits(uint32_t position, UErrorCode& status) { 100 if (U_FAILURE(status)) { 101 return; 102 } 103 if (fData == nullptr) { 104 status = U_INVALID_STATE_ERROR; 105 return; 106 } 107 fData->quantity.decreaseMinIntegerTo(position); 108 fData->quantity.applyMaxInteger(position); 109 } 110 111 void SimpleNumber::setSign(USimpleNumberSign sign, UErrorCode& status) { 112 if (U_FAILURE(status)) { 113 return; 114 } 115 if (fData == nullptr) { 116 status = U_INVALID_STATE_ERROR; 117 return; 118 } 119 fSign = sign; 120 } 121 122 123 void SimpleNumberFormatter::cleanup() { 124 delete fOwnedSymbols; 125 delete fMicros; 126 delete fPatternModifier; 127 fOwnedSymbols = nullptr; 128 fMicros = nullptr; 129 fPatternModifier = nullptr; 130 } 131 132 SimpleNumberFormatter SimpleNumberFormatter::forLocale(const icu::Locale &locale, UErrorCode &status) { 133 return SimpleNumberFormatter::forLocaleAndGroupingStrategy(locale, UNUM_GROUPING_AUTO, status); 134 } 135 136 SimpleNumberFormatter SimpleNumberFormatter::forLocaleAndGroupingStrategy( 137 const icu::Locale &locale, 138 UNumberGroupingStrategy groupingStrategy, 139 UErrorCode &status) { 140 SimpleNumberFormatter retval; 141 retval.fOwnedSymbols = new DecimalFormatSymbols(locale, status); 142 if (U_FAILURE(status)) { 143 return retval; 144 } 145 if (retval.fOwnedSymbols == nullptr) { 146 status = U_MEMORY_ALLOCATION_ERROR; 147 return retval; 148 } 149 retval.initialize(locale, *retval.fOwnedSymbols, groupingStrategy, status); 150 return retval; 151 } 152 153 154 SimpleNumberFormatter SimpleNumberFormatter::forLocaleAndSymbolsAndGroupingStrategy( 155 const icu::Locale &locale, 156 const DecimalFormatSymbols &symbols, 157 UNumberGroupingStrategy groupingStrategy, 158 UErrorCode &status) { 159 SimpleNumberFormatter retval; 160 retval.initialize(locale, symbols, groupingStrategy, status); 161 return retval; 162 } 163 164 165 void SimpleNumberFormatter::initialize( 166 const icu::Locale &locale, 167 const DecimalFormatSymbols &symbols, 168 UNumberGroupingStrategy groupingStrategy, 169 UErrorCode &status) { 170 if (U_FAILURE(status)) { 171 return; 172 } 173 174 fMicros = new SimpleMicroProps(); 175 if (fMicros == nullptr) { 176 status = U_MEMORY_ALLOCATION_ERROR; 177 return; 178 } 179 fMicros->symbols = &symbols; 180 181 const auto* pattern = utils::getPatternForStyle( 182 locale, 183 symbols.getNumberingSystemName(), 184 CLDR_PATTERN_STYLE_DECIMAL, 185 status); 186 if (U_FAILURE(status)) { 187 return; 188 } 189 190 ParsedPatternInfo patternInfo; 191 PatternParser::parseToPatternInfo(UnicodeString(pattern), patternInfo, status); 192 if (U_FAILURE(status)) { 193 return; 194 } 195 196 auto grouper = Grouper::forStrategy(groupingStrategy); 197 grouper.setLocaleData(patternInfo, locale); 198 fMicros->grouping = grouper; 199 200 MutablePatternModifier patternModifier(false); 201 patternModifier.setPatternInfo(&patternInfo, kUndefinedField); 202 patternModifier.setPatternAttributes(UNUM_SIGN_EXCEPT_ZERO, false, false); 203 patternModifier.setSymbols(fMicros->symbols, {}, UNUM_UNIT_WIDTH_SHORT, nullptr, status); 204 205 fPatternModifier = new AdoptingSignumModifierStore(patternModifier.createImmutableForPlural(StandardPlural::COUNT, status)); 206 207 fGroupingStrategy = groupingStrategy; 208 } 209 210 FormattedNumber SimpleNumberFormatter::format(SimpleNumber value, UErrorCode &status) const { 211 formatImpl(value.fData, value.fSign, status); 212 213 // Do not save the results object if we encountered a failure. 214 if (U_SUCCESS(status)) { 215 auto* temp = value.fData; 216 value.fData = nullptr; 217 return FormattedNumber(temp); 218 } else { 219 return FormattedNumber(status); 220 } 221 } 222 223 void SimpleNumberFormatter::formatImpl(UFormattedNumberData* data, USimpleNumberSign sign, UErrorCode &status) const { 224 if (U_FAILURE(status)) { 225 return; 226 } 227 if (data == nullptr) { 228 status = U_ILLEGAL_ARGUMENT_ERROR; 229 return; 230 } 231 if (fPatternModifier == nullptr || fMicros == nullptr) { 232 status = U_INVALID_STATE_ERROR; 233 return; 234 } 235 236 Signum signum; 237 if (sign == UNUM_SIMPLE_NUMBER_MINUS_SIGN) { 238 signum = SIGNUM_NEG; 239 } else if (sign == UNUM_SIMPLE_NUMBER_PLUS_SIGN) { 240 signum = SIGNUM_POS; 241 } else { 242 signum = SIGNUM_POS_ZERO; 243 } 244 245 const Modifier* modifier = (*fPatternModifier)[signum]; 246 auto length = NumberFormatterImpl::writeNumber( 247 *fMicros, 248 data->quantity, 249 data->getStringRef(), 250 0, 251 status); 252 length += modifier->apply(data->getStringRef(), 0, length, status); 253 data->getStringRef().writeTerminator(status); 254 } 255 256 #endif /* #if !UCONFIG_NO_FORMATTING */