xref: /aosp_15_r20/external/cronet/third_party/icu/source/i18n/number_simple.cpp (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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
forInt64(int64_t value,UErrorCode & status)21 SimpleNumber::forInt64(int64_t value, UErrorCode& status) {
22     if (U_FAILURE(status)) {
23         return SimpleNumber();
24     }
25     auto results = new UFormattedNumberData();
26     if (results == nullptr) {
27         status = U_MEMORY_ALLOCATION_ERROR;
28         return SimpleNumber();
29     }
30     results->quantity.setToLong(value);
31     return SimpleNumber(results, status);
32 }
33 
SimpleNumber(UFormattedNumberData * data,UErrorCode & status)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 
cleanup()49 void SimpleNumber::cleanup() {
50     delete fData;
51     fData = nullptr;
52 }
53 
multiplyByPowerOfTen(int32_t power,UErrorCode & status)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 
roundTo(int32_t position,UNumberFormatRoundingMode roundingMode,UErrorCode & status)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 
setMinimumIntegerDigits(uint32_t position,UErrorCode & status)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.setMinInteger(position);
85 }
86 
setMinimumFractionDigits(uint32_t position,UErrorCode & status)87 void SimpleNumber::setMinimumFractionDigits(uint32_t position, UErrorCode& status) {
88     if (U_FAILURE(status)) {
89         return;
90     }
91     if (fData == nullptr) {
92         status = U_INVALID_STATE_ERROR;
93         return;
94     }
95     fData->quantity.setMinFraction(position);
96 }
97 
truncateStart(uint32_t position,UErrorCode & status)98 void SimpleNumber::truncateStart(uint32_t position, UErrorCode& status) {
99     if (U_FAILURE(status)) {
100         return;
101     }
102     if (fData == nullptr) {
103         status = U_INVALID_STATE_ERROR;
104         return;
105     }
106     fData->quantity.applyMaxInteger(position);
107 }
108 
setSign(USimpleNumberSign sign,UErrorCode & status)109 void SimpleNumber::setSign(USimpleNumberSign sign, UErrorCode& status) {
110     if (U_FAILURE(status)) {
111         return;
112     }
113     if (fData == nullptr) {
114         status = U_INVALID_STATE_ERROR;
115         return;
116     }
117     fSign = sign;
118 }
119 
120 
cleanup()121 void SimpleNumberFormatter::cleanup() {
122     delete fOwnedSymbols;
123     delete fMicros;
124     delete fPatternModifier;
125     fOwnedSymbols = nullptr;
126     fMicros = nullptr;
127     fPatternModifier = nullptr;
128 }
129 
forLocale(const icu::Locale & locale,UErrorCode & status)130 SimpleNumberFormatter SimpleNumberFormatter::forLocale(const icu::Locale &locale, UErrorCode &status) {
131     return SimpleNumberFormatter::forLocaleAndGroupingStrategy(locale, UNUM_GROUPING_AUTO, status);
132 }
133 
forLocaleAndGroupingStrategy(const icu::Locale & locale,UNumberGroupingStrategy groupingStrategy,UErrorCode & status)134 SimpleNumberFormatter SimpleNumberFormatter::forLocaleAndGroupingStrategy(
135         const icu::Locale &locale,
136         UNumberGroupingStrategy groupingStrategy,
137         UErrorCode &status) {
138     SimpleNumberFormatter retval;
139     retval.fOwnedSymbols = new DecimalFormatSymbols(locale, status);
140     if (U_FAILURE(status)) {
141         return retval;
142     }
143     if (retval.fOwnedSymbols == nullptr) {
144         status = U_MEMORY_ALLOCATION_ERROR;
145         return retval;
146     }
147     retval.initialize(locale, *retval.fOwnedSymbols, groupingStrategy, status);
148     return retval;
149 }
150 
151 
forLocaleAndSymbolsAndGroupingStrategy(const icu::Locale & locale,const DecimalFormatSymbols & symbols,UNumberGroupingStrategy groupingStrategy,UErrorCode & status)152 SimpleNumberFormatter SimpleNumberFormatter::forLocaleAndSymbolsAndGroupingStrategy(
153         const icu::Locale &locale,
154         const DecimalFormatSymbols &symbols,
155         UNumberGroupingStrategy groupingStrategy,
156         UErrorCode &status) {
157     SimpleNumberFormatter retval;
158     retval.initialize(locale, symbols, groupingStrategy, status);
159     return retval;
160 }
161 
162 
initialize(const icu::Locale & locale,const DecimalFormatSymbols & symbols,UNumberGroupingStrategy groupingStrategy,UErrorCode & status)163 void SimpleNumberFormatter::initialize(
164         const icu::Locale &locale,
165         const DecimalFormatSymbols &symbols,
166         UNumberGroupingStrategy groupingStrategy,
167         UErrorCode &status) {
168     if (U_FAILURE(status)) {
169         return;
170     }
171 
172     fMicros = new SimpleMicroProps();
173     if (fMicros == nullptr) {
174         status = U_MEMORY_ALLOCATION_ERROR;
175         return;
176     }
177     fMicros->symbols = &symbols;
178 
179     auto pattern = utils::getPatternForStyle(
180         locale,
181         symbols.getNumberingSystemName(),
182         CLDR_PATTERN_STYLE_DECIMAL,
183         status);
184     if (U_FAILURE(status)) {
185         return;
186     }
187 
188     ParsedPatternInfo patternInfo;
189     PatternParser::parseToPatternInfo(UnicodeString(pattern), patternInfo, status);
190     if (U_FAILURE(status)) {
191         return;
192     }
193 
194     auto grouper = Grouper::forStrategy(groupingStrategy);
195     grouper.setLocaleData(patternInfo, locale);
196     fMicros->grouping = grouper;
197 
198     MutablePatternModifier patternModifier(false);
199     patternModifier.setPatternInfo(&patternInfo, kUndefinedField);
200     patternModifier.setPatternAttributes(UNUM_SIGN_EXCEPT_ZERO, false, false);
201     patternModifier.setSymbols(fMicros->symbols, {}, UNUM_UNIT_WIDTH_SHORT, nullptr, status);
202 
203     fPatternModifier = new AdoptingSignumModifierStore(patternModifier.createImmutableForPlural(StandardPlural::COUNT, status));
204 
205     fGroupingStrategy = groupingStrategy;
206     return;
207 }
208 
format(SimpleNumber value,UErrorCode & status) const209 FormattedNumber SimpleNumberFormatter::format(SimpleNumber value, UErrorCode &status) const {
210     formatImpl(value.fData, value.fSign, status);
211 
212     // Do not save the results object if we encountered a failure.
213     if (U_SUCCESS(status)) {
214         auto temp = value.fData;
215         value.fData = nullptr;
216         return FormattedNumber(temp);
217     } else {
218         return FormattedNumber(status);
219     }
220 }
221 
formatImpl(UFormattedNumberData * data,USimpleNumberSign sign,UErrorCode & status) const222 void SimpleNumberFormatter::formatImpl(UFormattedNumberData* data, USimpleNumberSign sign, UErrorCode &status) const {
223     if (U_FAILURE(status)) {
224         return;
225     }
226     if (data == nullptr) {
227         status = U_ILLEGAL_ARGUMENT_ERROR;
228         return;
229     }
230     if (fPatternModifier == nullptr || fMicros == nullptr) {
231         status = U_INVALID_STATE_ERROR;
232         return;
233     }
234 
235     Signum signum;
236     if (sign == UNUM_SIMPLE_NUMBER_MINUS_SIGN) {
237         signum = SIGNUM_NEG;
238     } else if (sign == UNUM_SIMPLE_NUMBER_PLUS_SIGN) {
239         signum = SIGNUM_POS;
240     } else {
241         signum = SIGNUM_POS_ZERO;
242     }
243 
244     const Modifier* modifier = (*fPatternModifier)[signum];
245     auto length = NumberFormatterImpl::writeNumber(
246         *fMicros,
247         data->quantity,
248         data->getStringRef(),
249         0,
250         status);
251     length += modifier->apply(data->getStringRef(), 0, length, status);
252     data->getStringRef().writeTerminator(status);
253 }
254 
255 #endif /* #if !UCONFIG_NO_FORMATTING */
256