• 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 
truncateStart(uint32_t position,UErrorCode & status)111 void SimpleNumber::truncateStart(uint32_t position, UErrorCode& status) {
112     setMaximumIntegerDigits(position, status);
113 }
114 
setSign(USimpleNumberSign sign,UErrorCode & status)115 void SimpleNumber::setSign(USimpleNumberSign sign, UErrorCode& status) {
116     if (U_FAILURE(status)) {
117         return;
118     }
119     if (fData == nullptr) {
120         status = U_INVALID_STATE_ERROR;
121         return;
122     }
123     fSign = sign;
124 }
125 
126 
cleanup()127 void SimpleNumberFormatter::cleanup() {
128     delete fOwnedSymbols;
129     delete fMicros;
130     delete fPatternModifier;
131     fOwnedSymbols = nullptr;
132     fMicros = nullptr;
133     fPatternModifier = nullptr;
134 }
135 
forLocale(const icu::Locale & locale,UErrorCode & status)136 SimpleNumberFormatter SimpleNumberFormatter::forLocale(const icu::Locale &locale, UErrorCode &status) {
137     return SimpleNumberFormatter::forLocaleAndGroupingStrategy(locale, UNUM_GROUPING_AUTO, status);
138 }
139 
forLocaleAndGroupingStrategy(const icu::Locale & locale,UNumberGroupingStrategy groupingStrategy,UErrorCode & status)140 SimpleNumberFormatter SimpleNumberFormatter::forLocaleAndGroupingStrategy(
141         const icu::Locale &locale,
142         UNumberGroupingStrategy groupingStrategy,
143         UErrorCode &status) {
144     SimpleNumberFormatter retval;
145     retval.fOwnedSymbols = new DecimalFormatSymbols(locale, status);
146     if (U_FAILURE(status)) {
147         return retval;
148     }
149     if (retval.fOwnedSymbols == nullptr) {
150         status = U_MEMORY_ALLOCATION_ERROR;
151         return retval;
152     }
153     retval.initialize(locale, *retval.fOwnedSymbols, groupingStrategy, status);
154     return retval;
155 }
156 
157 
forLocaleAndSymbolsAndGroupingStrategy(const icu::Locale & locale,const DecimalFormatSymbols & symbols,UNumberGroupingStrategy groupingStrategy,UErrorCode & status)158 SimpleNumberFormatter SimpleNumberFormatter::forLocaleAndSymbolsAndGroupingStrategy(
159         const icu::Locale &locale,
160         const DecimalFormatSymbols &symbols,
161         UNumberGroupingStrategy groupingStrategy,
162         UErrorCode &status) {
163     SimpleNumberFormatter retval;
164     retval.initialize(locale, symbols, groupingStrategy, status);
165     return retval;
166 }
167 
168 
initialize(const icu::Locale & locale,const DecimalFormatSymbols & symbols,UNumberGroupingStrategy groupingStrategy,UErrorCode & status)169 void SimpleNumberFormatter::initialize(
170         const icu::Locale &locale,
171         const DecimalFormatSymbols &symbols,
172         UNumberGroupingStrategy groupingStrategy,
173         UErrorCode &status) {
174     if (U_FAILURE(status)) {
175         return;
176     }
177 
178     fMicros = new SimpleMicroProps();
179     if (fMicros == nullptr) {
180         status = U_MEMORY_ALLOCATION_ERROR;
181         return;
182     }
183     fMicros->symbols = &symbols;
184 
185     const auto* pattern = utils::getPatternForStyle(
186         locale,
187         symbols.getNumberingSystemName(),
188         CLDR_PATTERN_STYLE_DECIMAL,
189         status);
190     if (U_FAILURE(status)) {
191         return;
192     }
193 
194     ParsedPatternInfo patternInfo;
195     PatternParser::parseToPatternInfo(UnicodeString(pattern), patternInfo, status);
196     if (U_FAILURE(status)) {
197         return;
198     }
199 
200     auto grouper = Grouper::forStrategy(groupingStrategy);
201     grouper.setLocaleData(patternInfo, locale);
202     fMicros->grouping = grouper;
203 
204     MutablePatternModifier patternModifier(false);
205     patternModifier.setPatternInfo(&patternInfo, kUndefinedField);
206     patternModifier.setPatternAttributes(UNUM_SIGN_EXCEPT_ZERO, false, false);
207     patternModifier.setSymbols(fMicros->symbols, {}, UNUM_UNIT_WIDTH_SHORT, nullptr, status);
208 
209     fPatternModifier = new AdoptingSignumModifierStore(patternModifier.createImmutableForPlural(StandardPlural::COUNT, status));
210 
211     fGroupingStrategy = groupingStrategy;
212 }
213 
format(SimpleNumber value,UErrorCode & status) const214 FormattedNumber SimpleNumberFormatter::format(SimpleNumber value, UErrorCode &status) const {
215     formatImpl(value.fData, value.fSign, status);
216 
217     // Do not save the results object if we encountered a failure.
218     if (U_SUCCESS(status)) {
219         auto* temp = value.fData;
220         value.fData = nullptr;
221         return FormattedNumber(temp);
222     } else {
223         return FormattedNumber(status);
224     }
225 }
226 
formatImpl(UFormattedNumberData * data,USimpleNumberSign sign,UErrorCode & status) const227 void SimpleNumberFormatter::formatImpl(UFormattedNumberData* data, USimpleNumberSign sign, UErrorCode &status) const {
228     if (U_FAILURE(status)) {
229         return;
230     }
231     if (data == nullptr) {
232         status = U_ILLEGAL_ARGUMENT_ERROR;
233         return;
234     }
235     if (fPatternModifier == nullptr || fMicros == nullptr) {
236         status = U_INVALID_STATE_ERROR;
237         return;
238     }
239 
240     Signum signum;
241     if (sign == UNUM_SIMPLE_NUMBER_MINUS_SIGN) {
242         signum = SIGNUM_NEG;
243     } else if (sign == UNUM_SIMPLE_NUMBER_PLUS_SIGN) {
244         signum = SIGNUM_POS;
245     } else {
246         signum = SIGNUM_POS_ZERO;
247     }
248 
249     const Modifier* modifier = (*fPatternModifier)[signum];
250     auto length = NumberFormatterImpl::writeNumber(
251         *fMicros,
252         data->quantity,
253         data->getStringRef(),
254         0,
255         status);
256     length += modifier->apply(data->getStringRef(), 0, length, status);
257     data->getStringRef().writeTerminator(status);
258 }
259 
260 #endif /* #if !UCONFIG_NO_FORMATTING */
261