• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <cmath>
13 #include <cstdlib>
14 #include <stdlib.h>
15 #include "unicode/errorcode.h"
16 #include "unicode/decimfmt.h"
17 #include "number_decimalquantity.h"
18 #include "number_types.h"
19 #include "numparse_impl.h"
20 #include "number_mapper.h"
21 #include "number_patternstring.h"
22 #include "putilimp.h"
23 #include "number_utils.h"
24 #include "number_utypes.h"
25 
26 using namespace icu;
27 using namespace icu::number;
28 using namespace icu::number::impl;
29 using namespace icu::numparse;
30 using namespace icu::numparse::impl;
31 using ERoundingMode = icu::DecimalFormat::ERoundingMode;
32 using EPadPosition = icu::DecimalFormat::EPadPosition;
33 
34 // MSVC warns C4805 when comparing bool with UBool
35 // TODO: Move this macro into a better place?
36 #if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
37 #define UBOOL_TO_BOOL(b) static_cast<bool>(b)
38 #else
39 #define UBOOL_TO_BOOL(b) b
40 #endif
41 
42 
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DecimalFormat)43 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DecimalFormat)
44 
45 
46 DecimalFormat::DecimalFormat(UErrorCode& status)
47         : DecimalFormat(nullptr, status) {
48     // Use the default locale and decimal pattern.
49     const char* localeName = Locale::getDefault().getName();
50     LocalPointer<NumberingSystem> ns(NumberingSystem::createInstance(status));
51     UnicodeString patternString = utils::getPatternForStyle(
52             localeName,
53             ns->getName(),
54             CLDR_PATTERN_STYLE_DECIMAL,
55             status);
56     setPropertiesFromPattern(patternString, IGNORE_ROUNDING_IF_CURRENCY, status);
57     touch(status);
58 }
59 
DecimalFormat(const UnicodeString & pattern,UErrorCode & status)60 DecimalFormat::DecimalFormat(const UnicodeString& pattern, UErrorCode& status)
61         : DecimalFormat(nullptr, status) {
62     setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status);
63     touch(status);
64 }
65 
DecimalFormat(const UnicodeString & pattern,DecimalFormatSymbols * symbolsToAdopt,UErrorCode & status)66 DecimalFormat::DecimalFormat(const UnicodeString& pattern, DecimalFormatSymbols* symbolsToAdopt,
67                              UErrorCode& status)
68         : DecimalFormat(symbolsToAdopt, status) {
69     setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status);
70     touch(status);
71 }
72 
DecimalFormat(const UnicodeString & pattern,DecimalFormatSymbols * symbolsToAdopt,UNumberFormatStyle style,UErrorCode & status)73 DecimalFormat::DecimalFormat(const UnicodeString& pattern, DecimalFormatSymbols* symbolsToAdopt,
74                              UNumberFormatStyle style, UErrorCode& status)
75         : DecimalFormat(symbolsToAdopt, status) {
76     // If choice is a currency type, ignore the rounding information.
77     if (style == UNumberFormatStyle::UNUM_CURRENCY || style == UNumberFormatStyle::UNUM_CURRENCY_ISO ||
78         style == UNumberFormatStyle::UNUM_CURRENCY_ACCOUNTING ||
79         style == UNumberFormatStyle::UNUM_CASH_CURRENCY ||
80         style == UNumberFormatStyle::UNUM_CURRENCY_STANDARD ||
81         style == UNumberFormatStyle::UNUM_CURRENCY_PLURAL) {
82         setPropertiesFromPattern(pattern, IGNORE_ROUNDING_ALWAYS, status);
83     } else {
84         setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status);
85     }
86     // Note: in Java, CurrencyPluralInfo is set in NumberFormat.java, but in C++, it is not set there,
87     // so we have to set it here.
88     if (style == UNumberFormatStyle::UNUM_CURRENCY_PLURAL) {
89         LocalPointer<CurrencyPluralInfo> cpi(
90                 new CurrencyPluralInfo(fields->symbols->getLocale(), status),
91                 status);
92         if (U_FAILURE(status)) { return; }
93         fields->properties->currencyPluralInfo.fPtr.adoptInstead(cpi.orphan());
94     }
95     touch(status);
96 }
97 
DecimalFormat(const DecimalFormatSymbols * symbolsToAdopt,UErrorCode & status)98 DecimalFormat::DecimalFormat(const DecimalFormatSymbols* symbolsToAdopt, UErrorCode& status) {
99     LocalPointer<const DecimalFormatSymbols> adoptedSymbols(symbolsToAdopt);
100     fields = new DecimalFormatFields();
101     if (U_FAILURE(status)) {
102         return;
103     }
104     if (fields == nullptr) {
105         status = U_MEMORY_ALLOCATION_ERROR;
106         return;
107     }
108     fields->properties.adoptInsteadAndCheckErrorCode(new DecimalFormatProperties(), status);
109     fields->exportedProperties.adoptInsteadAndCheckErrorCode(new DecimalFormatProperties(), status);
110     if (adoptedSymbols.isNull()) {
111         fields->symbols.adoptInsteadAndCheckErrorCode(new DecimalFormatSymbols(status), status);
112     } else {
113         fields->symbols.adoptInsteadAndCheckErrorCode(adoptedSymbols.orphan(), status);
114     }
115 }
116 
117 #if UCONFIG_HAVE_PARSEALLINPUT
118 
setParseAllInput(UNumberFormatAttributeValue value)119 void DecimalFormat::setParseAllInput(UNumberFormatAttributeValue value) {
120     if (value == fields->properties->parseAllInput) { return; }
121     fields->properties->parseAllInput = value;
122 }
123 
124 #endif
125 
126 DecimalFormat&
setAttribute(UNumberFormatAttribute attr,int32_t newValue,UErrorCode & status)127 DecimalFormat::setAttribute(UNumberFormatAttribute attr, int32_t newValue, UErrorCode& status) {
128     if (U_FAILURE(status)) { return *this; }
129 
130     switch (attr) {
131         case UNUM_LENIENT_PARSE:
132             setLenient(newValue != 0);
133             break;
134 
135         case UNUM_PARSE_INT_ONLY:
136             setParseIntegerOnly(newValue != 0);
137             break;
138 
139         case UNUM_GROUPING_USED:
140             setGroupingUsed(newValue != 0);
141             break;
142 
143         case UNUM_DECIMAL_ALWAYS_SHOWN:
144             setDecimalSeparatorAlwaysShown(newValue != 0);
145             break;
146 
147         case UNUM_MAX_INTEGER_DIGITS:
148             setMaximumIntegerDigits(newValue);
149             break;
150 
151         case UNUM_MIN_INTEGER_DIGITS:
152             setMinimumIntegerDigits(newValue);
153             break;
154 
155         case UNUM_INTEGER_DIGITS:
156             setMinimumIntegerDigits(newValue);
157             setMaximumIntegerDigits(newValue);
158             break;
159 
160         case UNUM_MAX_FRACTION_DIGITS:
161             setMaximumFractionDigits(newValue);
162             break;
163 
164         case UNUM_MIN_FRACTION_DIGITS:
165             setMinimumFractionDigits(newValue);
166             break;
167 
168         case UNUM_FRACTION_DIGITS:
169             setMinimumFractionDigits(newValue);
170             setMaximumFractionDigits(newValue);
171             break;
172 
173         case UNUM_SIGNIFICANT_DIGITS_USED:
174             setSignificantDigitsUsed(newValue != 0);
175             break;
176 
177         case UNUM_MAX_SIGNIFICANT_DIGITS:
178             setMaximumSignificantDigits(newValue);
179             break;
180 
181         case UNUM_MIN_SIGNIFICANT_DIGITS:
182             setMinimumSignificantDigits(newValue);
183             break;
184 
185         case UNUM_MULTIPLIER:
186             setMultiplier(newValue);
187             break;
188 
189         case UNUM_SCALE:
190             setMultiplierScale(newValue);
191             break;
192 
193         case UNUM_GROUPING_SIZE:
194             setGroupingSize(newValue);
195             break;
196 
197         case UNUM_ROUNDING_MODE:
198             setRoundingMode((DecimalFormat::ERoundingMode) newValue);
199             break;
200 
201         case UNUM_FORMAT_WIDTH:
202             setFormatWidth(newValue);
203             break;
204 
205         case UNUM_PADDING_POSITION:
206             /** The position at which padding will take place. */
207             setPadPosition((DecimalFormat::EPadPosition) newValue);
208             break;
209 
210         case UNUM_SECONDARY_GROUPING_SIZE:
211             setSecondaryGroupingSize(newValue);
212             break;
213 
214 #if UCONFIG_HAVE_PARSEALLINPUT
215         case UNUM_PARSE_ALL_INPUT:
216             setParseAllInput((UNumberFormatAttributeValue) newValue);
217             break;
218 #endif
219 
220         case UNUM_PARSE_NO_EXPONENT:
221             setParseNoExponent((UBool) newValue);
222             break;
223 
224         case UNUM_PARSE_DECIMAL_MARK_REQUIRED:
225             setDecimalPatternMatchRequired((UBool) newValue);
226             break;
227 
228         case UNUM_CURRENCY_USAGE:
229             setCurrencyUsage((UCurrencyUsage) newValue, &status);
230             break;
231 
232         case UNUM_MINIMUM_GROUPING_DIGITS:
233             setMinimumGroupingDigits(newValue);
234             break;
235 
236         case UNUM_PARSE_CASE_SENSITIVE:
237             setParseCaseSensitive(static_cast<UBool>(newValue));
238             break;
239 
240         case UNUM_SIGN_ALWAYS_SHOWN:
241             setSignAlwaysShown(static_cast<UBool>(newValue));
242             break;
243 
244         case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS:
245             setFormatFailIfMoreThanMaxDigits(static_cast<UBool>(newValue));
246             break;
247 
248         default:
249             status = U_UNSUPPORTED_ERROR;
250             break;
251     }
252     return *this;
253 }
254 
getAttribute(UNumberFormatAttribute attr,UErrorCode & status) const255 int32_t DecimalFormat::getAttribute(UNumberFormatAttribute attr, UErrorCode& status) const {
256     if (U_FAILURE(status)) { return -1; }
257     switch (attr) {
258         case UNUM_LENIENT_PARSE:
259             return isLenient();
260 
261         case UNUM_PARSE_INT_ONLY:
262             return isParseIntegerOnly();
263 
264         case UNUM_GROUPING_USED:
265             return isGroupingUsed();
266 
267         case UNUM_DECIMAL_ALWAYS_SHOWN:
268             return isDecimalSeparatorAlwaysShown();
269 
270         case UNUM_MAX_INTEGER_DIGITS:
271             return getMaximumIntegerDigits();
272 
273         case UNUM_MIN_INTEGER_DIGITS:
274             return getMinimumIntegerDigits();
275 
276         case UNUM_INTEGER_DIGITS:
277             // TBD: what should this return?
278             return getMinimumIntegerDigits();
279 
280         case UNUM_MAX_FRACTION_DIGITS:
281             return getMaximumFractionDigits();
282 
283         case UNUM_MIN_FRACTION_DIGITS:
284             return getMinimumFractionDigits();
285 
286         case UNUM_FRACTION_DIGITS:
287             // TBD: what should this return?
288             return getMinimumFractionDigits();
289 
290         case UNUM_SIGNIFICANT_DIGITS_USED:
291             return areSignificantDigitsUsed();
292 
293         case UNUM_MAX_SIGNIFICANT_DIGITS:
294             return getMaximumSignificantDigits();
295 
296         case UNUM_MIN_SIGNIFICANT_DIGITS:
297             return getMinimumSignificantDigits();
298 
299         case UNUM_MULTIPLIER:
300             return getMultiplier();
301 
302         case UNUM_SCALE:
303             return getMultiplierScale();
304 
305         case UNUM_GROUPING_SIZE:
306             return getGroupingSize();
307 
308         case UNUM_ROUNDING_MODE:
309             return getRoundingMode();
310 
311         case UNUM_FORMAT_WIDTH:
312             return getFormatWidth();
313 
314         case UNUM_PADDING_POSITION:
315             return getPadPosition();
316 
317         case UNUM_SECONDARY_GROUPING_SIZE:
318             return getSecondaryGroupingSize();
319 
320         case UNUM_PARSE_NO_EXPONENT:
321             return isParseNoExponent();
322 
323         case UNUM_PARSE_DECIMAL_MARK_REQUIRED:
324             return isDecimalPatternMatchRequired();
325 
326         case UNUM_CURRENCY_USAGE:
327             return getCurrencyUsage();
328 
329         case UNUM_MINIMUM_GROUPING_DIGITS:
330             return getMinimumGroupingDigits();
331 
332         case UNUM_PARSE_CASE_SENSITIVE:
333             return isParseCaseSensitive();
334 
335         case UNUM_SIGN_ALWAYS_SHOWN:
336             return isSignAlwaysShown();
337 
338         case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS:
339             return isFormatFailIfMoreThanMaxDigits();
340 
341         default:
342             status = U_UNSUPPORTED_ERROR;
343             break;
344     }
345 
346     return -1; /* undefined */
347 }
348 
setGroupingUsed(UBool enabled)349 void DecimalFormat::setGroupingUsed(UBool enabled) {
350     if (UBOOL_TO_BOOL(enabled) == fields->properties->groupingUsed) { return; }
351     NumberFormat::setGroupingUsed(enabled); // to set field for compatibility
352     fields->properties->groupingUsed = enabled;
353     touchNoError();
354 }
355 
setParseIntegerOnly(UBool value)356 void DecimalFormat::setParseIntegerOnly(UBool value) {
357     if (UBOOL_TO_BOOL(value) == fields->properties->parseIntegerOnly) { return; }
358     NumberFormat::setParseIntegerOnly(value); // to set field for compatibility
359     fields->properties->parseIntegerOnly = value;
360     touchNoError();
361 }
362 
setLenient(UBool enable)363 void DecimalFormat::setLenient(UBool enable) {
364     ParseMode mode = enable ? PARSE_MODE_LENIENT : PARSE_MODE_STRICT;
365     if (!fields->properties->parseMode.isNull() && mode == fields->properties->parseMode.getNoError()) { return; }
366     NumberFormat::setLenient(enable); // to set field for compatibility
367     fields->properties->parseMode = mode;
368     touchNoError();
369 }
370 
DecimalFormat(const UnicodeString & pattern,DecimalFormatSymbols * symbolsToAdopt,UParseError &,UErrorCode & status)371 DecimalFormat::DecimalFormat(const UnicodeString& pattern, DecimalFormatSymbols* symbolsToAdopt,
372                              UParseError&, UErrorCode& status)
373         : DecimalFormat(symbolsToAdopt, status) {
374     // TODO: What is parseError for?
375     setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status);
376     touch(status);
377 }
378 
DecimalFormat(const UnicodeString & pattern,const DecimalFormatSymbols & symbols,UErrorCode & status)379 DecimalFormat::DecimalFormat(const UnicodeString& pattern, const DecimalFormatSymbols& symbols,
380                              UErrorCode& status)
381         : DecimalFormat(new DecimalFormatSymbols(symbols), status) {
382     setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status);
383     touch(status);
384 }
385 
DecimalFormat(const DecimalFormat & source)386 DecimalFormat::DecimalFormat(const DecimalFormat& source) : NumberFormat(source) {
387     // Note: it is not safe to copy fields->formatter or fWarehouse directly because fields->formatter might have
388     // dangling pointers to fields inside fWarehouse. The safe thing is to re-construct fields->formatter from
389     // the property bag, despite being somewhat slower.
390     fields = new DecimalFormatFields();
391     if (fields == nullptr) {
392         return;
393     }
394     fields->properties.adoptInstead(new DecimalFormatProperties(*source.fields->properties));
395     fields->symbols.adoptInstead(new DecimalFormatSymbols(*source.fields->symbols));
396     fields->exportedProperties.adoptInstead(new DecimalFormatProperties());
397     if (fields->properties == nullptr || fields->symbols == nullptr || fields->exportedProperties == nullptr) {
398         return;
399     }
400     touchNoError();
401 }
402 
operator =(const DecimalFormat & rhs)403 DecimalFormat& DecimalFormat::operator=(const DecimalFormat& rhs) {
404     *fields->properties = *rhs.fields->properties;
405     fields->exportedProperties->clear();
406     fields->symbols.adoptInstead(new DecimalFormatSymbols(*rhs.fields->symbols));
407     touchNoError();
408     return *this;
409 }
410 
~DecimalFormat()411 DecimalFormat::~DecimalFormat() {
412     delete fields->atomicParser.exchange(nullptr);
413     delete fields->atomicCurrencyParser.exchange(nullptr);
414 	delete fields;
415 }
416 
clone() const417 Format* DecimalFormat::clone() const {
418     return new DecimalFormat(*this);
419 }
420 
operator ==(const Format & other) const421 UBool DecimalFormat::operator==(const Format& other) const {
422     auto* otherDF = dynamic_cast<const DecimalFormat*>(&other);
423     if (otherDF == nullptr) {
424         return false;
425     }
426     return *fields->properties == *otherDF->fields->properties && *fields->symbols == *otherDF->fields->symbols;
427 }
428 
format(double number,UnicodeString & appendTo,FieldPosition & pos) const429 UnicodeString& DecimalFormat::format(double number, UnicodeString& appendTo, FieldPosition& pos) const {
430     if (pos.getField() == FieldPosition::DONT_CARE && fastFormatDouble(number, appendTo)) {
431         return appendTo;
432     }
433     UErrorCode localStatus = U_ZERO_ERROR;
434     FormattedNumber output = fields->formatter->formatDouble(number, localStatus);
435     fieldPositionHelper(output, pos, appendTo.length(), localStatus);
436     auto appendable = UnicodeStringAppendable(appendTo);
437     output.appendTo(appendable);
438     return appendTo;
439 }
440 
format(double number,UnicodeString & appendTo,FieldPosition & pos,UErrorCode & status) const441 UnicodeString& DecimalFormat::format(double number, UnicodeString& appendTo, FieldPosition& pos,
442                                      UErrorCode& status) const {
443     if (pos.getField() == FieldPosition::DONT_CARE && fastFormatDouble(number, appendTo)) {
444         return appendTo;
445     }
446     FormattedNumber output = fields->formatter->formatDouble(number, status);
447     fieldPositionHelper(output, pos, appendTo.length(), status);
448     auto appendable = UnicodeStringAppendable(appendTo);
449     output.appendTo(appendable);
450     return appendTo;
451 }
452 
453 UnicodeString&
format(double number,UnicodeString & appendTo,FieldPositionIterator * posIter,UErrorCode & status) const454 DecimalFormat::format(double number, UnicodeString& appendTo, FieldPositionIterator* posIter,
455                       UErrorCode& status) const {
456     if (posIter == nullptr && fastFormatDouble(number, appendTo)) {
457         return appendTo;
458     }
459     FormattedNumber output = fields->formatter->formatDouble(number, status);
460     fieldPositionIteratorHelper(output, posIter, appendTo.length(), status);
461     auto appendable = UnicodeStringAppendable(appendTo);
462     output.appendTo(appendable);
463     return appendTo;
464 }
465 
format(int32_t number,UnicodeString & appendTo,FieldPosition & pos) const466 UnicodeString& DecimalFormat::format(int32_t number, UnicodeString& appendTo, FieldPosition& pos) const {
467     return format(static_cast<int64_t> (number), appendTo, pos);
468 }
469 
format(int32_t number,UnicodeString & appendTo,FieldPosition & pos,UErrorCode & status) const470 UnicodeString& DecimalFormat::format(int32_t number, UnicodeString& appendTo, FieldPosition& pos,
471                                      UErrorCode& status) const {
472     return format(static_cast<int64_t> (number), appendTo, pos, status);
473 }
474 
475 UnicodeString&
format(int32_t number,UnicodeString & appendTo,FieldPositionIterator * posIter,UErrorCode & status) const476 DecimalFormat::format(int32_t number, UnicodeString& appendTo, FieldPositionIterator* posIter,
477                       UErrorCode& status) const {
478     return format(static_cast<int64_t> (number), appendTo, posIter, status);
479 }
480 
format(int64_t number,UnicodeString & appendTo,FieldPosition & pos) const481 UnicodeString& DecimalFormat::format(int64_t number, UnicodeString& appendTo, FieldPosition& pos) const {
482     if (pos.getField() == FieldPosition::DONT_CARE && fastFormatInt64(number, appendTo)) {
483         return appendTo;
484     }
485     UErrorCode localStatus = U_ZERO_ERROR;
486     FormattedNumber output = fields->formatter->formatInt(number, localStatus);
487     fieldPositionHelper(output, pos, appendTo.length(), localStatus);
488     auto appendable = UnicodeStringAppendable(appendTo);
489     output.appendTo(appendable);
490     return appendTo;
491 }
492 
format(int64_t number,UnicodeString & appendTo,FieldPosition & pos,UErrorCode & status) const493 UnicodeString& DecimalFormat::format(int64_t number, UnicodeString& appendTo, FieldPosition& pos,
494                                      UErrorCode& status) const {
495     if (pos.getField() == FieldPosition::DONT_CARE && fastFormatInt64(number, appendTo)) {
496         return appendTo;
497     }
498     FormattedNumber output = fields->formatter->formatInt(number, status);
499     fieldPositionHelper(output, pos, appendTo.length(), status);
500     auto appendable = UnicodeStringAppendable(appendTo);
501     output.appendTo(appendable);
502     return appendTo;
503 }
504 
505 UnicodeString&
format(int64_t number,UnicodeString & appendTo,FieldPositionIterator * posIter,UErrorCode & status) const506 DecimalFormat::format(int64_t number, UnicodeString& appendTo, FieldPositionIterator* posIter,
507                       UErrorCode& status) const {
508     if (posIter == nullptr && fastFormatInt64(number, appendTo)) {
509         return appendTo;
510     }
511     FormattedNumber output = fields->formatter->formatInt(number, status);
512     fieldPositionIteratorHelper(output, posIter, appendTo.length(), status);
513     auto appendable = UnicodeStringAppendable(appendTo);
514     output.appendTo(appendable);
515     return appendTo;
516 }
517 
518 UnicodeString&
format(StringPiece number,UnicodeString & appendTo,FieldPositionIterator * posIter,UErrorCode & status) const519 DecimalFormat::format(StringPiece number, UnicodeString& appendTo, FieldPositionIterator* posIter,
520                       UErrorCode& status) const {
521     FormattedNumber output = fields->formatter->formatDecimal(number, status);
522     fieldPositionIteratorHelper(output, posIter, appendTo.length(), status);
523     auto appendable = UnicodeStringAppendable(appendTo);
524     output.appendTo(appendable);
525     return appendTo;
526 }
527 
format(const DecimalQuantity & number,UnicodeString & appendTo,FieldPositionIterator * posIter,UErrorCode & status) const528 UnicodeString& DecimalFormat::format(const DecimalQuantity& number, UnicodeString& appendTo,
529                                      FieldPositionIterator* posIter, UErrorCode& status) const {
530     FormattedNumber output = fields->formatter->formatDecimalQuantity(number, status);
531     fieldPositionIteratorHelper(output, posIter, appendTo.length(), status);
532     auto appendable = UnicodeStringAppendable(appendTo);
533     output.appendTo(appendable);
534     return appendTo;
535 }
536 
537 UnicodeString&
format(const DecimalQuantity & number,UnicodeString & appendTo,FieldPosition & pos,UErrorCode & status) const538 DecimalFormat::format(const DecimalQuantity& number, UnicodeString& appendTo, FieldPosition& pos,
539                       UErrorCode& status) const {
540     FormattedNumber output = fields->formatter->formatDecimalQuantity(number, status);
541     fieldPositionHelper(output, pos, appendTo.length(), status);
542     auto appendable = UnicodeStringAppendable(appendTo);
543     output.appendTo(appendable);
544     return appendTo;
545 }
546 
parse(const UnicodeString & text,Formattable & output,ParsePosition & parsePosition) const547 void DecimalFormat::parse(const UnicodeString& text, Formattable& output,
548                           ParsePosition& parsePosition) const {
549     if (parsePosition.getIndex() < 0 || parsePosition.getIndex() >= text.length()) {
550         return;
551     }
552 
553     ErrorCode status;
554     ParsedNumber result;
555     // Note: if this is a currency instance, currencies will be matched despite the fact that we are not in the
556     // parseCurrency method (backwards compatibility)
557     int32_t startIndex = parsePosition.getIndex();
558     const NumberParserImpl* parser = getParser(status);
559     if (U_FAILURE(status)) { return; }
560     parser->parse(text, startIndex, true, result, status);
561     // TODO: Do we need to check for fImpl->properties->parseAllInput (UCONFIG_HAVE_PARSEALLINPUT) here?
562     if (result.success()) {
563         parsePosition.setIndex(result.charEnd);
564         result.populateFormattable(output, parser->getParseFlags());
565     } else {
566         parsePosition.setErrorIndex(startIndex + result.charEnd);
567     }
568 }
569 
parseCurrency(const UnicodeString & text,ParsePosition & parsePosition) const570 CurrencyAmount* DecimalFormat::parseCurrency(const UnicodeString& text, ParsePosition& parsePosition) const {
571     if (parsePosition.getIndex() < 0 || parsePosition.getIndex() >= text.length()) {
572         return nullptr;
573     }
574 
575     ErrorCode status;
576     ParsedNumber result;
577     // Note: if this is a currency instance, currencies will be matched despite the fact that we are not in the
578     // parseCurrency method (backwards compatibility)
579     int32_t startIndex = parsePosition.getIndex();
580     const NumberParserImpl* parser = getCurrencyParser(status);
581     if (U_FAILURE(status)) { return nullptr; }
582     parser->parse(text, startIndex, true, result, status);
583     // TODO: Do we need to check for fImpl->properties->parseAllInput (UCONFIG_HAVE_PARSEALLINPUT) here?
584     if (result.success()) {
585         parsePosition.setIndex(result.charEnd);
586         Formattable formattable;
587         result.populateFormattable(formattable, parser->getParseFlags());
588         return new CurrencyAmount(formattable, result.currencyCode, status);
589     } else {
590         parsePosition.setErrorIndex(startIndex + result.charEnd);
591         return nullptr;
592     }
593 }
594 
getDecimalFormatSymbols(void) const595 const DecimalFormatSymbols* DecimalFormat::getDecimalFormatSymbols(void) const {
596     return fields->symbols.getAlias();
597 }
598 
adoptDecimalFormatSymbols(DecimalFormatSymbols * symbolsToAdopt)599 void DecimalFormat::adoptDecimalFormatSymbols(DecimalFormatSymbols* symbolsToAdopt) {
600     if (symbolsToAdopt == nullptr) {
601         return; // do not allow caller to set fields->symbols to NULL
602     }
603     fields->symbols.adoptInstead(symbolsToAdopt);
604     touchNoError();
605 }
606 
setDecimalFormatSymbols(const DecimalFormatSymbols & symbols)607 void DecimalFormat::setDecimalFormatSymbols(const DecimalFormatSymbols& symbols) {
608     fields->symbols.adoptInstead(new DecimalFormatSymbols(symbols));
609     touchNoError();
610 }
611 
getCurrencyPluralInfo(void) const612 const CurrencyPluralInfo* DecimalFormat::getCurrencyPluralInfo(void) const {
613     return fields->properties->currencyPluralInfo.fPtr.getAlias();
614 }
615 
adoptCurrencyPluralInfo(CurrencyPluralInfo * toAdopt)616 void DecimalFormat::adoptCurrencyPluralInfo(CurrencyPluralInfo* toAdopt) {
617     fields->properties->currencyPluralInfo.fPtr.adoptInstead(toAdopt);
618     touchNoError();
619 }
620 
setCurrencyPluralInfo(const CurrencyPluralInfo & info)621 void DecimalFormat::setCurrencyPluralInfo(const CurrencyPluralInfo& info) {
622     if (fields->properties->currencyPluralInfo.fPtr.isNull()) {
623         fields->properties->currencyPluralInfo.fPtr.adoptInstead(info.clone());
624     } else {
625         *fields->properties->currencyPluralInfo.fPtr = info; // copy-assignment operator
626     }
627     touchNoError();
628 }
629 
getPositivePrefix(UnicodeString & result) const630 UnicodeString& DecimalFormat::getPositivePrefix(UnicodeString& result) const {
631     ErrorCode localStatus;
632     fields->formatter->getAffixImpl(true, false, result, localStatus);
633     return result;
634 }
635 
setPositivePrefix(const UnicodeString & newValue)636 void DecimalFormat::setPositivePrefix(const UnicodeString& newValue) {
637     if (newValue == fields->properties->positivePrefix) { return; }
638     fields->properties->positivePrefix = newValue;
639     touchNoError();
640 }
641 
getNegativePrefix(UnicodeString & result) const642 UnicodeString& DecimalFormat::getNegativePrefix(UnicodeString& result) const {
643     ErrorCode localStatus;
644     fields->formatter->getAffixImpl(true, true, result, localStatus);
645     return result;
646 }
647 
setNegativePrefix(const UnicodeString & newValue)648 void DecimalFormat::setNegativePrefix(const UnicodeString& newValue) {
649     if (newValue == fields->properties->negativePrefix) { return; }
650     fields->properties->negativePrefix = newValue;
651     touchNoError();
652 }
653 
getPositiveSuffix(UnicodeString & result) const654 UnicodeString& DecimalFormat::getPositiveSuffix(UnicodeString& result) const {
655     ErrorCode localStatus;
656     fields->formatter->getAffixImpl(false, false, result, localStatus);
657     return result;
658 }
659 
setPositiveSuffix(const UnicodeString & newValue)660 void DecimalFormat::setPositiveSuffix(const UnicodeString& newValue) {
661     if (newValue == fields->properties->positiveSuffix) { return; }
662     fields->properties->positiveSuffix = newValue;
663     touchNoError();
664 }
665 
getNegativeSuffix(UnicodeString & result) const666 UnicodeString& DecimalFormat::getNegativeSuffix(UnicodeString& result) const {
667     ErrorCode localStatus;
668     fields->formatter->getAffixImpl(false, true, result, localStatus);
669     return result;
670 }
671 
setNegativeSuffix(const UnicodeString & newValue)672 void DecimalFormat::setNegativeSuffix(const UnicodeString& newValue) {
673     if (newValue == fields->properties->negativeSuffix) { return; }
674     fields->properties->negativeSuffix = newValue;
675     touchNoError();
676 }
677 
isSignAlwaysShown() const678 UBool DecimalFormat::isSignAlwaysShown() const {
679     return fields->properties->signAlwaysShown;
680 }
681 
setSignAlwaysShown(UBool value)682 void DecimalFormat::setSignAlwaysShown(UBool value) {
683     if (UBOOL_TO_BOOL(value) == fields->properties->signAlwaysShown) { return; }
684     fields->properties->signAlwaysShown = value;
685     touchNoError();
686 }
687 
getMultiplier(void) const688 int32_t DecimalFormat::getMultiplier(void) const {
689     if (fields->properties->multiplier != 1) {
690         return fields->properties->multiplier;
691     } else if (fields->properties->magnitudeMultiplier != 0) {
692         return static_cast<int32_t>(uprv_pow10(fields->properties->magnitudeMultiplier));
693     } else {
694         return 1;
695     }
696 }
697 
setMultiplier(int32_t multiplier)698 void DecimalFormat::setMultiplier(int32_t multiplier) {
699     if (multiplier == 0) {
700         multiplier = 1;     // one being the benign default value for a multiplier.
701     }
702 
703     // Try to convert to a magnitude multiplier first
704     int delta = 0;
705     int value = multiplier;
706     while (value != 1) {
707         delta++;
708         int temp = value / 10;
709         if (temp * 10 != value) {
710             delta = -1;
711             break;
712         }
713         value = temp;
714     }
715     if (delta != -1) {
716         fields->properties->magnitudeMultiplier = delta;
717         fields->properties->multiplier = 1;
718     } else {
719         fields->properties->magnitudeMultiplier = 0;
720         fields->properties->multiplier = multiplier;
721     }
722     touchNoError();
723 }
724 
getMultiplierScale() const725 int32_t DecimalFormat::getMultiplierScale() const {
726     return fields->properties->multiplierScale;
727 }
728 
setMultiplierScale(int32_t newValue)729 void DecimalFormat::setMultiplierScale(int32_t newValue) {
730     if (newValue == fields->properties->multiplierScale) { return; }
731     fields->properties->multiplierScale = newValue;
732     touchNoError();
733 }
734 
getRoundingIncrement(void) const735 double DecimalFormat::getRoundingIncrement(void) const {
736     return fields->exportedProperties->roundingIncrement;
737 }
738 
setRoundingIncrement(double newValue)739 void DecimalFormat::setRoundingIncrement(double newValue) {
740     if (newValue == fields->properties->roundingIncrement) { return; }
741     fields->properties->roundingIncrement = newValue;
742     touchNoError();
743 }
744 
getRoundingMode(void) const745 ERoundingMode DecimalFormat::getRoundingMode(void) const {
746     // UNumberFormatRoundingMode and ERoundingMode have the same values.
747     return static_cast<ERoundingMode>(fields->exportedProperties->roundingMode.getNoError());
748 }
749 
setRoundingMode(ERoundingMode roundingMode)750 void DecimalFormat::setRoundingMode(ERoundingMode roundingMode) {
751     auto uRoundingMode = static_cast<UNumberFormatRoundingMode>(roundingMode);
752     if (!fields->properties->roundingMode.isNull() && uRoundingMode == fields->properties->roundingMode.getNoError()) {
753         return;
754     }
755     NumberFormat::setMaximumIntegerDigits(roundingMode); // to set field for compatibility
756     fields->properties->roundingMode = uRoundingMode;
757     touchNoError();
758 }
759 
getFormatWidth(void) const760 int32_t DecimalFormat::getFormatWidth(void) const {
761     return fields->properties->formatWidth;
762 }
763 
setFormatWidth(int32_t width)764 void DecimalFormat::setFormatWidth(int32_t width) {
765     if (width == fields->properties->formatWidth) { return; }
766     fields->properties->formatWidth = width;
767     touchNoError();
768 }
769 
getPadCharacterString() const770 UnicodeString DecimalFormat::getPadCharacterString() const {
771     if (fields->properties->padString.isBogus()) {
772         // Readonly-alias the static string kFallbackPaddingString
773         return {TRUE, kFallbackPaddingString, -1};
774     } else {
775         return fields->properties->padString;
776     }
777 }
778 
setPadCharacter(const UnicodeString & padChar)779 void DecimalFormat::setPadCharacter(const UnicodeString& padChar) {
780     if (padChar == fields->properties->padString) { return; }
781     if (padChar.length() > 0) {
782         fields->properties->padString = UnicodeString(padChar.char32At(0));
783     } else {
784         fields->properties->padString.setToBogus();
785     }
786     touchNoError();
787 }
788 
getPadPosition(void) const789 EPadPosition DecimalFormat::getPadPosition(void) const {
790     if (fields->properties->padPosition.isNull()) {
791         return EPadPosition::kPadBeforePrefix;
792     } else {
793         // UNumberFormatPadPosition and EPadPosition have the same values.
794         return static_cast<EPadPosition>(fields->properties->padPosition.getNoError());
795     }
796 }
797 
setPadPosition(EPadPosition padPos)798 void DecimalFormat::setPadPosition(EPadPosition padPos) {
799     auto uPadPos = static_cast<UNumberFormatPadPosition>(padPos);
800     if (!fields->properties->padPosition.isNull() && uPadPos == fields->properties->padPosition.getNoError()) {
801         return;
802     }
803     fields->properties->padPosition = uPadPos;
804     touchNoError();
805 }
806 
isScientificNotation(void) const807 UBool DecimalFormat::isScientificNotation(void) const {
808     return fields->properties->minimumExponentDigits != -1;
809 }
810 
setScientificNotation(UBool useScientific)811 void DecimalFormat::setScientificNotation(UBool useScientific) {
812     int32_t minExp = useScientific ? 1 : -1;
813     if (fields->properties->minimumExponentDigits == minExp) { return; }
814     if (useScientific) {
815         fields->properties->minimumExponentDigits = 1;
816     } else {
817         fields->properties->minimumExponentDigits = -1;
818     }
819     touchNoError();
820 }
821 
getMinimumExponentDigits(void) const822 int8_t DecimalFormat::getMinimumExponentDigits(void) const {
823     return static_cast<int8_t>(fields->properties->minimumExponentDigits);
824 }
825 
setMinimumExponentDigits(int8_t minExpDig)826 void DecimalFormat::setMinimumExponentDigits(int8_t minExpDig) {
827     if (minExpDig == fields->properties->minimumExponentDigits) { return; }
828     fields->properties->minimumExponentDigits = minExpDig;
829     touchNoError();
830 }
831 
isExponentSignAlwaysShown(void) const832 UBool DecimalFormat::isExponentSignAlwaysShown(void) const {
833     return fields->properties->exponentSignAlwaysShown;
834 }
835 
setExponentSignAlwaysShown(UBool expSignAlways)836 void DecimalFormat::setExponentSignAlwaysShown(UBool expSignAlways) {
837     if (UBOOL_TO_BOOL(expSignAlways) == fields->properties->exponentSignAlwaysShown) { return; }
838     fields->properties->exponentSignAlwaysShown = expSignAlways;
839     touchNoError();
840 }
841 
getGroupingSize(void) const842 int32_t DecimalFormat::getGroupingSize(void) const {
843     if (fields->properties->groupingSize < 0) {
844         return 0;
845     }
846     return fields->properties->groupingSize;
847 }
848 
setGroupingSize(int32_t newValue)849 void DecimalFormat::setGroupingSize(int32_t newValue) {
850     if (newValue == fields->properties->groupingSize) { return; }
851     fields->properties->groupingSize = newValue;
852     touchNoError();
853 }
854 
getSecondaryGroupingSize(void) const855 int32_t DecimalFormat::getSecondaryGroupingSize(void) const {
856     int grouping2 = fields->properties->secondaryGroupingSize;
857     if (grouping2 < 0) {
858         return 0;
859     }
860     return grouping2;
861 }
862 
setSecondaryGroupingSize(int32_t newValue)863 void DecimalFormat::setSecondaryGroupingSize(int32_t newValue) {
864     if (newValue == fields->properties->secondaryGroupingSize) { return; }
865     fields->properties->secondaryGroupingSize = newValue;
866     touchNoError();
867 }
868 
getMinimumGroupingDigits() const869 int32_t DecimalFormat::getMinimumGroupingDigits() const {
870     return fields->properties->minimumGroupingDigits;
871 }
872 
setMinimumGroupingDigits(int32_t newValue)873 void DecimalFormat::setMinimumGroupingDigits(int32_t newValue) {
874     if (newValue == fields->properties->minimumGroupingDigits) { return; }
875     fields->properties->minimumGroupingDigits = newValue;
876     touchNoError();
877 }
878 
isDecimalSeparatorAlwaysShown(void) const879 UBool DecimalFormat::isDecimalSeparatorAlwaysShown(void) const {
880     return fields->properties->decimalSeparatorAlwaysShown;
881 }
882 
setDecimalSeparatorAlwaysShown(UBool newValue)883 void DecimalFormat::setDecimalSeparatorAlwaysShown(UBool newValue) {
884     if (UBOOL_TO_BOOL(newValue) == fields->properties->decimalSeparatorAlwaysShown) { return; }
885     fields->properties->decimalSeparatorAlwaysShown = newValue;
886     touchNoError();
887 }
888 
isDecimalPatternMatchRequired(void) const889 UBool DecimalFormat::isDecimalPatternMatchRequired(void) const {
890     return fields->properties->decimalPatternMatchRequired;
891 }
892 
setDecimalPatternMatchRequired(UBool newValue)893 void DecimalFormat::setDecimalPatternMatchRequired(UBool newValue) {
894     if (UBOOL_TO_BOOL(newValue) == fields->properties->decimalPatternMatchRequired) { return; }
895     fields->properties->decimalPatternMatchRequired = newValue;
896     touchNoError();
897 }
898 
isParseNoExponent() const899 UBool DecimalFormat::isParseNoExponent() const {
900     return fields->properties->parseNoExponent;
901 }
902 
setParseNoExponent(UBool value)903 void DecimalFormat::setParseNoExponent(UBool value) {
904     if (UBOOL_TO_BOOL(value) == fields->properties->parseNoExponent) { return; }
905     fields->properties->parseNoExponent = value;
906     touchNoError();
907 }
908 
isParseCaseSensitive() const909 UBool DecimalFormat::isParseCaseSensitive() const {
910     return fields->properties->parseCaseSensitive;
911 }
912 
setParseCaseSensitive(UBool value)913 void DecimalFormat::setParseCaseSensitive(UBool value) {
914     if (UBOOL_TO_BOOL(value) == fields->properties->parseCaseSensitive) { return; }
915     fields->properties->parseCaseSensitive = value;
916     touchNoError();
917 }
918 
isFormatFailIfMoreThanMaxDigits() const919 UBool DecimalFormat::isFormatFailIfMoreThanMaxDigits() const {
920     return fields->properties->formatFailIfMoreThanMaxDigits;
921 }
922 
setFormatFailIfMoreThanMaxDigits(UBool value)923 void DecimalFormat::setFormatFailIfMoreThanMaxDigits(UBool value) {
924     if (UBOOL_TO_BOOL(value) == fields->properties->formatFailIfMoreThanMaxDigits) { return; }
925     fields->properties->formatFailIfMoreThanMaxDigits = value;
926     touchNoError();
927 }
928 
toPattern(UnicodeString & result) const929 UnicodeString& DecimalFormat::toPattern(UnicodeString& result) const {
930     // Pull some properties from exportedProperties and others from properties
931     // to keep affix patterns intact.  In particular, pull rounding properties
932     // so that CurrencyUsage is reflected properly.
933     // TODO: Consider putting this logic in number_patternstring.cpp instead.
934     ErrorCode localStatus;
935     DecimalFormatProperties tprops(*fields->properties);
936     bool useCurrency = ((!tprops.currency.isNull()) || !tprops.currencyPluralInfo.fPtr.isNull() ||
937                         !tprops.currencyUsage.isNull() || AffixUtils::hasCurrencySymbols(
938             tprops.positivePrefixPattern, localStatus) || AffixUtils::hasCurrencySymbols(
939             tprops.positiveSuffixPattern, localStatus) || AffixUtils::hasCurrencySymbols(
940             tprops.negativePrefixPattern, localStatus) || AffixUtils::hasCurrencySymbols(
941             tprops.negativeSuffixPattern, localStatus));
942     if (useCurrency) {
943         tprops.minimumFractionDigits = fields->exportedProperties->minimumFractionDigits;
944         tprops.maximumFractionDigits = fields->exportedProperties->maximumFractionDigits;
945         tprops.roundingIncrement = fields->exportedProperties->roundingIncrement;
946     }
947     result = PatternStringUtils::propertiesToPatternString(tprops, localStatus);
948     return result;
949 }
950 
toLocalizedPattern(UnicodeString & result) const951 UnicodeString& DecimalFormat::toLocalizedPattern(UnicodeString& result) const {
952     ErrorCode localStatus;
953     result = toPattern(result);
954     result = PatternStringUtils::convertLocalized(result, *fields->symbols, true, localStatus);
955     return result;
956 }
957 
applyPattern(const UnicodeString & pattern,UParseError &,UErrorCode & status)958 void DecimalFormat::applyPattern(const UnicodeString& pattern, UParseError&, UErrorCode& status) {
959     // TODO: What is parseError for?
960     applyPattern(pattern, status);
961 }
962 
applyPattern(const UnicodeString & pattern,UErrorCode & status)963 void DecimalFormat::applyPattern(const UnicodeString& pattern, UErrorCode& status) {
964     setPropertiesFromPattern(pattern, IGNORE_ROUNDING_NEVER, status);
965     touch(status);
966 }
967 
applyLocalizedPattern(const UnicodeString & localizedPattern,UParseError &,UErrorCode & status)968 void DecimalFormat::applyLocalizedPattern(const UnicodeString& localizedPattern, UParseError&,
969                                           UErrorCode& status) {
970     // TODO: What is parseError for?
971     applyLocalizedPattern(localizedPattern, status);
972 }
973 
applyLocalizedPattern(const UnicodeString & localizedPattern,UErrorCode & status)974 void DecimalFormat::applyLocalizedPattern(const UnicodeString& localizedPattern, UErrorCode& status) {
975     if (U_SUCCESS(status)) {
976         UnicodeString pattern = PatternStringUtils::convertLocalized(
977                 localizedPattern, *fields->symbols, false, status);
978         applyPattern(pattern, status);
979     }
980 }
981 
setMaximumIntegerDigits(int32_t newValue)982 void DecimalFormat::setMaximumIntegerDigits(int32_t newValue) {
983     if (newValue == fields->properties->maximumIntegerDigits) { return; }
984     // For backwards compatibility, conflicting min/max need to keep the most recent setting.
985     int32_t min = fields->properties->minimumIntegerDigits;
986     if (min >= 0 && min > newValue) {
987         fields->properties->minimumIntegerDigits = newValue;
988     }
989     fields->properties->maximumIntegerDigits = newValue;
990     touchNoError();
991 }
992 
setMinimumIntegerDigits(int32_t newValue)993 void DecimalFormat::setMinimumIntegerDigits(int32_t newValue) {
994     if (newValue == fields->properties->minimumIntegerDigits) { return; }
995     // For backwards compatibility, conflicting min/max need to keep the most recent setting.
996     int32_t max = fields->properties->maximumIntegerDigits;
997     if (max >= 0 && max < newValue) {
998         fields->properties->maximumIntegerDigits = newValue;
999     }
1000     fields->properties->minimumIntegerDigits = newValue;
1001     touchNoError();
1002 }
1003 
setMaximumFractionDigits(int32_t newValue)1004 void DecimalFormat::setMaximumFractionDigits(int32_t newValue) {
1005     if (newValue == fields->properties->maximumFractionDigits) { return; }
1006     // For backwards compatibility, conflicting min/max need to keep the most recent setting.
1007     int32_t min = fields->properties->minimumFractionDigits;
1008     if (min >= 0 && min > newValue) {
1009         fields->properties->minimumFractionDigits = newValue;
1010     }
1011     fields->properties->maximumFractionDigits = newValue;
1012     touchNoError();
1013 }
1014 
setMinimumFractionDigits(int32_t newValue)1015 void DecimalFormat::setMinimumFractionDigits(int32_t newValue) {
1016     if (newValue == fields->properties->minimumFractionDigits) { return; }
1017     // For backwards compatibility, conflicting min/max need to keep the most recent setting.
1018     int32_t max = fields->properties->maximumFractionDigits;
1019     if (max >= 0 && max < newValue) {
1020         fields->properties->maximumFractionDigits = newValue;
1021     }
1022     fields->properties->minimumFractionDigits = newValue;
1023     touchNoError();
1024 }
1025 
getMinimumSignificantDigits() const1026 int32_t DecimalFormat::getMinimumSignificantDigits() const {
1027     return fields->exportedProperties->minimumSignificantDigits;
1028 }
1029 
getMaximumSignificantDigits() const1030 int32_t DecimalFormat::getMaximumSignificantDigits() const {
1031     return fields->exportedProperties->maximumSignificantDigits;
1032 }
1033 
setMinimumSignificantDigits(int32_t value)1034 void DecimalFormat::setMinimumSignificantDigits(int32_t value) {
1035     if (value == fields->properties->minimumSignificantDigits) { return; }
1036     int32_t max = fields->properties->maximumSignificantDigits;
1037     if (max >= 0 && max < value) {
1038         fields->properties->maximumSignificantDigits = value;
1039     }
1040     fields->properties->minimumSignificantDigits = value;
1041     touchNoError();
1042 }
1043 
setMaximumSignificantDigits(int32_t value)1044 void DecimalFormat::setMaximumSignificantDigits(int32_t value) {
1045     if (value == fields->properties->maximumSignificantDigits) { return; }
1046     int32_t min = fields->properties->minimumSignificantDigits;
1047     if (min >= 0 && min > value) {
1048         fields->properties->minimumSignificantDigits = value;
1049     }
1050     fields->properties->maximumSignificantDigits = value;
1051     touchNoError();
1052 }
1053 
areSignificantDigitsUsed() const1054 UBool DecimalFormat::areSignificantDigitsUsed() const {
1055     return fields->properties->minimumSignificantDigits != -1 || fields->properties->maximumSignificantDigits != -1;
1056 }
1057 
setSignificantDigitsUsed(UBool useSignificantDigits)1058 void DecimalFormat::setSignificantDigitsUsed(UBool useSignificantDigits) {
1059     // These are the default values from the old implementation.
1060     if (useSignificantDigits) {
1061         if (fields->properties->minimumSignificantDigits != -1 ||
1062             fields->properties->maximumSignificantDigits != -1) {
1063             return;
1064         }
1065     } else {
1066         if (fields->properties->minimumSignificantDigits == -1 &&
1067             fields->properties->maximumSignificantDigits == -1) {
1068             return;
1069         }
1070     }
1071     int32_t minSig = useSignificantDigits ? 1 : -1;
1072     int32_t maxSig = useSignificantDigits ? 6 : -1;
1073     fields->properties->minimumSignificantDigits = minSig;
1074     fields->properties->maximumSignificantDigits = maxSig;
1075     touchNoError();
1076 }
1077 
setCurrency(const char16_t * theCurrency,UErrorCode & ec)1078 void DecimalFormat::setCurrency(const char16_t* theCurrency, UErrorCode& ec) {
1079     CurrencyUnit currencyUnit(theCurrency, ec);
1080     if (U_FAILURE(ec)) { return; }
1081     if (!fields->properties->currency.isNull() && fields->properties->currency.getNoError() == currencyUnit) {
1082         return;
1083     }
1084     NumberFormat::setCurrency(theCurrency, ec); // to set field for compatibility
1085     fields->properties->currency = currencyUnit;
1086     // TODO: Set values in fields->symbols, too?
1087     touchNoError();
1088 }
1089 
setCurrency(const char16_t * theCurrency)1090 void DecimalFormat::setCurrency(const char16_t* theCurrency) {
1091     ErrorCode localStatus;
1092     setCurrency(theCurrency, localStatus);
1093 }
1094 
setCurrencyUsage(UCurrencyUsage newUsage,UErrorCode * ec)1095 void DecimalFormat::setCurrencyUsage(UCurrencyUsage newUsage, UErrorCode* ec) {
1096     if (U_FAILURE(*ec)) {
1097         return;
1098     }
1099     if (!fields->properties->currencyUsage.isNull() && newUsage == fields->properties->currencyUsage.getNoError()) {
1100         return;
1101     }
1102     fields->properties->currencyUsage = newUsage;
1103     touch(*ec);
1104 }
1105 
getCurrencyUsage() const1106 UCurrencyUsage DecimalFormat::getCurrencyUsage() const {
1107     // CurrencyUsage is not exported, so we have to get it from the input property bag.
1108     // TODO: Should we export CurrencyUsage instead?
1109     if (fields->properties->currencyUsage.isNull()) {
1110         return UCURR_USAGE_STANDARD;
1111     }
1112     return fields->properties->currencyUsage.getNoError();
1113 }
1114 
1115 void
formatToDecimalQuantity(double number,DecimalQuantity & output,UErrorCode & status) const1116 DecimalFormat::formatToDecimalQuantity(double number, DecimalQuantity& output, UErrorCode& status) const {
1117     fields->formatter->formatDouble(number, status).getDecimalQuantity(output, status);
1118 }
1119 
formatToDecimalQuantity(const Formattable & number,DecimalQuantity & output,UErrorCode & status) const1120 void DecimalFormat::formatToDecimalQuantity(const Formattable& number, DecimalQuantity& output,
1121                                             UErrorCode& status) const {
1122     UFormattedNumberData obj;
1123     number.populateDecimalQuantity(obj.quantity, status);
1124     fields->formatter->formatImpl(&obj, status);
1125     output = std::move(obj.quantity);
1126 }
1127 
toNumberFormatter() const1128 const number::LocalizedNumberFormatter& DecimalFormat::toNumberFormatter() const {
1129     return *fields->formatter;
1130 }
1131 
1132 /** Rebuilds the formatter object from the property bag. */
touch(UErrorCode & status)1133 void DecimalFormat::touch(UErrorCode& status) {
1134     if (fields->exportedProperties == nullptr) {
1135         // fields->exportedProperties is null only when the formatter is not ready yet.
1136         // The only time when this happens is during legacy deserialization.
1137         return;
1138     }
1139 
1140     // In C++, fields->symbols is the source of truth for the locale.
1141     Locale locale = fields->symbols->getLocale();
1142 
1143     // Note: The formatter is relatively cheap to create, and we need it to populate fields->exportedProperties,
1144     // so automatically compute it here. The parser is a bit more expensive and is not needed until the
1145     // parse method is called, so defer that until needed.
1146     // TODO: Only update the pieces that changed instead of re-computing the whole formatter?
1147     fields->formatter.adoptInstead(
1148             new LocalizedNumberFormatter(
1149                     NumberPropertyMapper::create(
1150                             *fields->properties, *fields->symbols, fields->warehouse, *fields->exportedProperties, status).locale(
1151                             locale)));
1152 
1153     // Do this after fields->exportedProperties are set up
1154     setupFastFormat();
1155 
1156     // Delete the parsers if they were made previously
1157     delete fields->atomicParser.exchange(nullptr);
1158     delete fields->atomicCurrencyParser.exchange(nullptr);
1159 
1160     // In order for the getters to work, we need to populate some fields in NumberFormat.
1161     NumberFormat::setCurrency(fields->exportedProperties->currency.get(status).getISOCurrency(), status);
1162     NumberFormat::setMaximumIntegerDigits(fields->exportedProperties->maximumIntegerDigits);
1163     NumberFormat::setMinimumIntegerDigits(fields->exportedProperties->minimumIntegerDigits);
1164     NumberFormat::setMaximumFractionDigits(fields->exportedProperties->maximumFractionDigits);
1165     NumberFormat::setMinimumFractionDigits(fields->exportedProperties->minimumFractionDigits);
1166     // fImpl->properties, not fields->exportedProperties, since this information comes from the pattern:
1167     NumberFormat::setGroupingUsed(fields->properties->groupingUsed);
1168 }
1169 
touchNoError()1170 void DecimalFormat::touchNoError() {
1171     UErrorCode localStatus = U_ZERO_ERROR;
1172     touch(localStatus);
1173 }
1174 
setPropertiesFromPattern(const UnicodeString & pattern,int32_t ignoreRounding,UErrorCode & status)1175 void DecimalFormat::setPropertiesFromPattern(const UnicodeString& pattern, int32_t ignoreRounding,
1176                                              UErrorCode& status) {
1177     if (U_SUCCESS(status)) {
1178         // Cast workaround to get around putting the enum in the public header file
1179         auto actualIgnoreRounding = static_cast<IgnoreRounding>(ignoreRounding);
1180         PatternParser::parseToExistingProperties(pattern, *fields->properties,  actualIgnoreRounding, status);
1181     }
1182 }
1183 
getParser(UErrorCode & status) const1184 const numparse::impl::NumberParserImpl* DecimalFormat::getParser(UErrorCode& status) const {
1185     // TODO: Move this into umutex.h? (similar logic also in numrange_fluent.cpp)
1186     // See ICU-20146
1187 
1188     if (U_FAILURE(status)) {
1189         return nullptr;
1190     }
1191 
1192     // First try to get the pre-computed parser
1193     auto* ptr = fields->atomicParser.load();
1194     if (ptr != nullptr) {
1195         return ptr;
1196     }
1197 
1198     // Try computing the parser on our own
1199     auto* temp = NumberParserImpl::createParserFromProperties(*fields->properties, *fields->symbols, false, status);
1200     if (U_FAILURE(status)) {
1201         return nullptr;
1202     }
1203     if (temp == nullptr) {
1204         status = U_MEMORY_ALLOCATION_ERROR;
1205         return nullptr;
1206     }
1207 
1208     // Note: ptr starts as nullptr; during compare_exchange,
1209     // it is set to what is actually stored in the atomic
1210     // if another thread beat us to computing the parser object.
1211     auto* nonConstThis = const_cast<DecimalFormat*>(this);
1212     if (!nonConstThis->fields->atomicParser.compare_exchange_strong(ptr, temp)) {
1213         // Another thread beat us to computing the parser
1214         delete temp;
1215         return ptr;
1216     } else {
1217         // Our copy of the parser got stored in the atomic
1218         return temp;
1219     }
1220 }
1221 
getCurrencyParser(UErrorCode & status) const1222 const numparse::impl::NumberParserImpl* DecimalFormat::getCurrencyParser(UErrorCode& status) const {
1223     if (U_FAILURE(status)) { return nullptr; }
1224 
1225     // First try to get the pre-computed parser
1226     auto* ptr = fields->atomicCurrencyParser.load();
1227     if (ptr != nullptr) {
1228         return ptr;
1229     }
1230 
1231     // Try computing the parser on our own
1232     auto* temp = NumberParserImpl::createParserFromProperties(*fields->properties, *fields->symbols, true, status);
1233     if (temp == nullptr) {
1234         status = U_MEMORY_ALLOCATION_ERROR;
1235         // although we may still dereference, call sites should be guarded
1236     }
1237 
1238     // Note: ptr starts as nullptr; during compare_exchange, it is set to what is actually stored in the
1239     // atomic if another thread beat us to computing the parser object.
1240     auto* nonConstThis = const_cast<DecimalFormat*>(this);
1241     if (!nonConstThis->fields->atomicCurrencyParser.compare_exchange_strong(ptr, temp)) {
1242         // Another thread beat us to computing the parser
1243         delete temp;
1244         return ptr;
1245     } else {
1246         // Our copy of the parser got stored in the atomic
1247         return temp;
1248     }
1249 }
1250 
1251 void
fieldPositionHelper(const number::FormattedNumber & formatted,FieldPosition & fieldPosition,int32_t offset,UErrorCode & status)1252 DecimalFormat::fieldPositionHelper(const number::FormattedNumber& formatted, FieldPosition& fieldPosition,
1253                                    int32_t offset, UErrorCode& status) {
1254     // always return first occurrence:
1255     fieldPosition.setBeginIndex(0);
1256     fieldPosition.setEndIndex(0);
1257     bool found = formatted.nextFieldPosition(fieldPosition, status);
1258     if (found && offset != 0) {
1259         FieldPositionOnlyHandler fpoh(fieldPosition);
1260         fpoh.shiftLast(offset);
1261     }
1262 }
1263 
1264 void
fieldPositionIteratorHelper(const number::FormattedNumber & formatted,FieldPositionIterator * fpi,int32_t offset,UErrorCode & status)1265 DecimalFormat::fieldPositionIteratorHelper(const number::FormattedNumber& formatted, FieldPositionIterator* fpi,
1266                                            int32_t offset, UErrorCode& status) {
1267     if (fpi != nullptr) {
1268         FieldPositionIteratorHandler fpih(fpi, status);
1269         fpih.setShift(offset);
1270         formatted.getAllFieldPositionsImpl(fpih, status);
1271     }
1272 }
1273 
1274 // To debug fast-format, change void(x) to printf(x)
1275 #define trace(x) void(x)
1276 
setupFastFormat()1277 void DecimalFormat::setupFastFormat() {
1278     // Check the majority of properties:
1279     if (!fields->properties->equalsDefaultExceptFastFormat()) {
1280         trace("no fast format: equality\n");
1281         fields->canUseFastFormat = false;
1282         return;
1283     }
1284 
1285     // Now check the remaining properties.
1286     // Nontrivial affixes:
1287     UBool trivialPP = fields->properties->positivePrefixPattern.isEmpty();
1288     UBool trivialPS = fields->properties->positiveSuffixPattern.isEmpty();
1289     UBool trivialNP = fields->properties->negativePrefixPattern.isBogus() || (
1290             fields->properties->negativePrefixPattern.length() == 1 &&
1291             fields->properties->negativePrefixPattern.charAt(0) == u'-');
1292     UBool trivialNS = fields->properties->negativeSuffixPattern.isEmpty();
1293     if (!trivialPP || !trivialPS || !trivialNP || !trivialNS) {
1294         trace("no fast format: affixes\n");
1295         fields->canUseFastFormat = false;
1296         return;
1297     }
1298 
1299     // Grouping (secondary grouping is forbidden in equalsDefaultExceptFastFormat):
1300     bool groupingUsed = fields->properties->groupingUsed;
1301     int32_t groupingSize = fields->properties->groupingSize;
1302     bool unusualGroupingSize = groupingSize > 0 && groupingSize != 3;
1303     const UnicodeString& groupingString = fields->symbols->getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol);
1304     if (groupingUsed && (unusualGroupingSize || groupingString.length() != 1)) {
1305         trace("no fast format: grouping\n");
1306         fields->canUseFastFormat = false;
1307         return;
1308     }
1309 
1310     // Integer length:
1311     int32_t minInt = fields->exportedProperties->minimumIntegerDigits;
1312     int32_t maxInt = fields->exportedProperties->maximumIntegerDigits;
1313     // Fastpath supports up to only 10 digits (length of INT32_MIN)
1314     if (minInt > 10) {
1315         trace("no fast format: integer\n");
1316         fields->canUseFastFormat = false;
1317         return;
1318     }
1319 
1320     // Fraction length (no fraction part allowed in fast path):
1321     int32_t minFrac = fields->exportedProperties->minimumFractionDigits;
1322     if (minFrac > 0) {
1323         trace("no fast format: fraction\n");
1324         fields->canUseFastFormat = false;
1325         return;
1326     }
1327 
1328     // Other symbols:
1329     const UnicodeString& minusSignString = fields->symbols->getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol);
1330     UChar32 codePointZero = fields->symbols->getCodePointZero();
1331     if (minusSignString.length() != 1 || U16_LENGTH(codePointZero) != 1) {
1332         trace("no fast format: symbols\n");
1333         fields->canUseFastFormat = false;
1334         return;
1335     }
1336 
1337     // Good to go!
1338     trace("can use fast format!\n");
1339     fields->canUseFastFormat = true;
1340     fields->fastData.cpZero = static_cast<char16_t>(codePointZero);
1341     fields->fastData.cpGroupingSeparator = groupingUsed && groupingSize == 3 ? groupingString.charAt(0) : 0;
1342     fields->fastData.cpMinusSign = minusSignString.charAt(0);
1343     fields->fastData.minInt = (minInt < 0 || minInt > 127) ? 0 : static_cast<int8_t>(minInt);
1344     fields->fastData.maxInt = (maxInt < 0 || maxInt > 127) ? 127 : static_cast<int8_t>(maxInt);
1345 }
1346 
fastFormatDouble(double input,UnicodeString & output) const1347 bool DecimalFormat::fastFormatDouble(double input, UnicodeString& output) const {
1348     if (!fields->canUseFastFormat) {
1349         return false;
1350     }
1351     if (std::isnan(input)
1352             || std::trunc(input) != input
1353             || input <= INT32_MIN
1354             || input > INT32_MAX) {
1355         return false;
1356     }
1357     doFastFormatInt32(static_cast<int32_t>(input), std::signbit(input), output);
1358     return true;
1359 }
1360 
fastFormatInt64(int64_t input,UnicodeString & output) const1361 bool DecimalFormat::fastFormatInt64(int64_t input, UnicodeString& output) const {
1362     if (!fields->canUseFastFormat) {
1363         return false;
1364     }
1365     if (input <= INT32_MIN || input > INT32_MAX) {
1366         return false;
1367     }
1368     doFastFormatInt32(static_cast<int32_t>(input), input < 0, output);
1369     return true;
1370 }
1371 
doFastFormatInt32(int32_t input,bool isNegative,UnicodeString & output) const1372 void DecimalFormat::doFastFormatInt32(int32_t input, bool isNegative, UnicodeString& output) const {
1373     U_ASSERT(fields->canUseFastFormat);
1374     if (isNegative) {
1375         output.append(fields->fastData.cpMinusSign);
1376         U_ASSERT(input != INT32_MIN);  // handled by callers
1377         input = -input;
1378     }
1379     // Cap at int32_t to make the buffer small and operations fast.
1380     // Longest string: "2,147,483,648" (13 chars in length)
1381     static constexpr int32_t localCapacity = 13;
1382     char16_t localBuffer[localCapacity];
1383     char16_t* ptr = localBuffer + localCapacity;
1384     int8_t group = 0;
1385     for (int8_t i = 0; i < fields->fastData.maxInt && (input != 0 || i < fields->fastData.minInt); i++) {
1386         if (group++ == 3 && fields->fastData.cpGroupingSeparator != 0) {
1387             *(--ptr) = fields->fastData.cpGroupingSeparator;
1388             group = 1;
1389         }
1390         std::div_t res = std::div(input, 10);
1391         *(--ptr) = static_cast<char16_t>(fields->fastData.cpZero + res.rem);
1392         input = res.quot;
1393     }
1394     int32_t len = localCapacity - static_cast<int32_t>(ptr - localBuffer);
1395     output.append(ptr, len);
1396 }
1397 
1398 
1399 #endif /* #if !UCONFIG_NO_FORMATTING */
1400