• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {};
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 
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.decreaseMinIntegerTo(position);
85     fData->quantity.increaseMinIntegerTo(position);
86 }
87 
setMinimumFractionDigits(uint32_t position,UErrorCode & status)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 
setMaximumIntegerDigits(uint32_t position,UErrorCode & status)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 
setSign(USimpleNumberSign sign,UErrorCode & status)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 
cleanup()123 void SimpleNumberFormatter::cleanup() {
124     delete fOwnedSymbols;
125     delete fMicros;
126     delete fPatternModifier;
127     fOwnedSymbols = nullptr;
128     fMicros = nullptr;
129     fPatternModifier = nullptr;
130 }
131 
forLocale(const icu::Locale & locale,UErrorCode & status)132 SimpleNumberFormatter SimpleNumberFormatter::forLocale(const icu::Locale &locale, UErrorCode &status) {
133     return SimpleNumberFormatter::forLocaleAndGroupingStrategy(locale, UNUM_GROUPING_AUTO, status);
134 }
135 
forLocaleAndGroupingStrategy(const icu::Locale & locale,UNumberGroupingStrategy groupingStrategy,UErrorCode & status)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 
forLocaleAndSymbolsAndGroupingStrategy(const icu::Locale & locale,const DecimalFormatSymbols & symbols,UNumberGroupingStrategy groupingStrategy,UErrorCode & status)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 
initialize(const icu::Locale & locale,const DecimalFormatSymbols & symbols,UNumberGroupingStrategy groupingStrategy,UErrorCode & status)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 
format(SimpleNumber value,UErrorCode & status) const210 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 
formatImpl(UFormattedNumberData * data,USimpleNumberSign sign,UErrorCode & status) const223 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 */
257