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 VS2015 warns C4805 when comparing bool with UBool, VS2017 no longer emits this warning.
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     if (U_FAILURE(status)) { return; }
49     // Use the default locale and decimal pattern.
50     const char* localeName = Locale::getDefault().getName();
51     LocalPointer<NumberingSystem> ns(NumberingSystem::createInstance(status));
52     UnicodeString patternString = utils::getPatternForStyle(
53             localeName,
54             ns->getName(),
55             CLDR_PATTERN_STYLE_DECIMAL,
56             status);
57     setPropertiesFromPattern(patternString, IGNORE_ROUNDING_IF_CURRENCY, status);
58     touch(status);
59 }
60 
DecimalFormat(const UnicodeString & pattern,UErrorCode & status)61 DecimalFormat::DecimalFormat(const UnicodeString& pattern, UErrorCode& status)
62         : DecimalFormat(nullptr, status) {
63     if (U_FAILURE(status)) { return; }
64     setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status);
65     touch(status);
66 }
67 
DecimalFormat(const UnicodeString & pattern,DecimalFormatSymbols * symbolsToAdopt,UErrorCode & status)68 DecimalFormat::DecimalFormat(const UnicodeString& pattern, DecimalFormatSymbols* symbolsToAdopt,
69                              UErrorCode& status)
70         : DecimalFormat(symbolsToAdopt, status) {
71     if (U_FAILURE(status)) { return; }
72     setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status);
73     touch(status);
74 }
75 
DecimalFormat(const UnicodeString & pattern,DecimalFormatSymbols * symbolsToAdopt,UNumberFormatStyle style,UErrorCode & status)76 DecimalFormat::DecimalFormat(const UnicodeString& pattern, DecimalFormatSymbols* symbolsToAdopt,
77                              UNumberFormatStyle style, UErrorCode& status)
78         : DecimalFormat(symbolsToAdopt, status) {
79     if (U_FAILURE(status)) { return; }
80     // If choice is a currency type, ignore the rounding information.
81     if (style == UNumberFormatStyle::UNUM_CURRENCY ||
82         style == UNumberFormatStyle::UNUM_CURRENCY_ISO ||
83         style == UNumberFormatStyle::UNUM_CURRENCY_ACCOUNTING ||
84         style == UNumberFormatStyle::UNUM_CASH_CURRENCY ||
85         style == UNumberFormatStyle::UNUM_CURRENCY_STANDARD ||
86         style == UNumberFormatStyle::UNUM_CURRENCY_PLURAL) {
87         setPropertiesFromPattern(pattern, IGNORE_ROUNDING_ALWAYS, status);
88     } else {
89         setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status);
90     }
91     // Note: in Java, CurrencyPluralInfo is set in NumberFormat.java, but in C++, it is not set there,
92     // so we have to set it here.
93     if (style == UNumberFormatStyle::UNUM_CURRENCY_PLURAL) {
94         LocalPointer<CurrencyPluralInfo> cpi(
95                 new CurrencyPluralInfo(fields->symbols->getLocale(), status),
96                 status);
97         if (U_FAILURE(status)) { return; }
98         fields->properties.currencyPluralInfo.fPtr.adoptInstead(cpi.orphan());
99     }
100     touch(status);
101 }
102 
DecimalFormat(const DecimalFormatSymbols * symbolsToAdopt,UErrorCode & status)103 DecimalFormat::DecimalFormat(const DecimalFormatSymbols* symbolsToAdopt, UErrorCode& status) {
104     // we must take ownership of symbolsToAdopt, even in a failure case.
105     LocalPointer<const DecimalFormatSymbols> adoptedSymbols(symbolsToAdopt);
106     if (U_FAILURE(status)) {
107         return;
108     }
109     fields = new DecimalFormatFields();
110     if (fields == nullptr) {
111         status = U_MEMORY_ALLOCATION_ERROR;
112         return;
113     }
114     if (adoptedSymbols.isNull()) {
115         fields->symbols.adoptInsteadAndCheckErrorCode(new DecimalFormatSymbols(status), status);
116     } else {
117         fields->symbols.adoptInsteadAndCheckErrorCode(adoptedSymbols.orphan(), status);
118     }
119     if (U_FAILURE(status)) {
120         delete fields;
121         fields = nullptr;
122     }
123 }
124 
125 #if UCONFIG_HAVE_PARSEALLINPUT
126 
setParseAllInput(UNumberFormatAttributeValue value)127 void DecimalFormat::setParseAllInput(UNumberFormatAttributeValue value) {
128     if (fields == nullptr) { return; }
129     if (value == fields->properties.parseAllInput) { return; }
130     fields->properties.parseAllInput = value;
131 }
132 
133 #endif
134 
135 DecimalFormat&
setAttribute(UNumberFormatAttribute attr,int32_t newValue,UErrorCode & status)136 DecimalFormat::setAttribute(UNumberFormatAttribute attr, int32_t newValue, UErrorCode& status) {
137     if (U_FAILURE(status)) { return *this; }
138 
139     if (fields == nullptr) {
140         // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
141         status = U_MEMORY_ALLOCATION_ERROR;
142         return *this;
143     }
144 
145     switch (attr) {
146         case UNUM_LENIENT_PARSE:
147             setLenient(newValue != 0);
148             break;
149 
150         case UNUM_PARSE_INT_ONLY:
151             setParseIntegerOnly(newValue != 0);
152             break;
153 
154         case UNUM_GROUPING_USED:
155             setGroupingUsed(newValue != 0);
156             break;
157 
158         case UNUM_DECIMAL_ALWAYS_SHOWN:
159             setDecimalSeparatorAlwaysShown(newValue != 0);
160             break;
161 
162         case UNUM_MAX_INTEGER_DIGITS:
163             setMaximumIntegerDigits(newValue);
164             break;
165 
166         case UNUM_MIN_INTEGER_DIGITS:
167             setMinimumIntegerDigits(newValue);
168             break;
169 
170         case UNUM_INTEGER_DIGITS:
171             setMinimumIntegerDigits(newValue);
172             setMaximumIntegerDigits(newValue);
173             break;
174 
175         case UNUM_MAX_FRACTION_DIGITS:
176             setMaximumFractionDigits(newValue);
177             break;
178 
179         case UNUM_MIN_FRACTION_DIGITS:
180             setMinimumFractionDigits(newValue);
181             break;
182 
183         case UNUM_FRACTION_DIGITS:
184             setMinimumFractionDigits(newValue);
185             setMaximumFractionDigits(newValue);
186             break;
187 
188         case UNUM_SIGNIFICANT_DIGITS_USED:
189             setSignificantDigitsUsed(newValue != 0);
190             break;
191 
192         case UNUM_MAX_SIGNIFICANT_DIGITS:
193             setMaximumSignificantDigits(newValue);
194             break;
195 
196         case UNUM_MIN_SIGNIFICANT_DIGITS:
197             setMinimumSignificantDigits(newValue);
198             break;
199 
200         case UNUM_MULTIPLIER:
201             setMultiplier(newValue);
202             break;
203 
204         case UNUM_SCALE:
205             setMultiplierScale(newValue);
206             break;
207 
208         case UNUM_GROUPING_SIZE:
209             setGroupingSize(newValue);
210             break;
211 
212         case UNUM_ROUNDING_MODE:
213             setRoundingMode((DecimalFormat::ERoundingMode) newValue);
214             break;
215 
216         case UNUM_FORMAT_WIDTH:
217             setFormatWidth(newValue);
218             break;
219 
220         case UNUM_PADDING_POSITION:
221             /** The position at which padding will take place. */
222             setPadPosition((DecimalFormat::EPadPosition) newValue);
223             break;
224 
225         case UNUM_SECONDARY_GROUPING_SIZE:
226             setSecondaryGroupingSize(newValue);
227             break;
228 
229 #if UCONFIG_HAVE_PARSEALLINPUT
230         case UNUM_PARSE_ALL_INPUT:
231             setParseAllInput((UNumberFormatAttributeValue) newValue);
232             break;
233 #endif
234 
235         case UNUM_PARSE_NO_EXPONENT:
236             setParseNoExponent((UBool) newValue);
237             break;
238 
239         case UNUM_PARSE_DECIMAL_MARK_REQUIRED:
240             setDecimalPatternMatchRequired((UBool) newValue);
241             break;
242 
243         case UNUM_CURRENCY_USAGE:
244             setCurrencyUsage((UCurrencyUsage) newValue, &status);
245             break;
246 
247         case UNUM_MINIMUM_GROUPING_DIGITS:
248             setMinimumGroupingDigits(newValue);
249             break;
250 
251         case UNUM_PARSE_CASE_SENSITIVE:
252             setParseCaseSensitive(static_cast<UBool>(newValue));
253             break;
254 
255         case UNUM_SIGN_ALWAYS_SHOWN:
256             setSignAlwaysShown(static_cast<UBool>(newValue));
257             break;
258 
259         case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS:
260             setFormatFailIfMoreThanMaxDigits(static_cast<UBool>(newValue));
261             break;
262 
263         default:
264             status = U_UNSUPPORTED_ERROR;
265             break;
266     }
267     return *this;
268 }
269 
getAttribute(UNumberFormatAttribute attr,UErrorCode & status) const270 int32_t DecimalFormat::getAttribute(UNumberFormatAttribute attr, UErrorCode& status) const {
271     if (U_FAILURE(status)) { return -1; }
272 
273     if (fields == nullptr) {
274         // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
275         status = U_MEMORY_ALLOCATION_ERROR;
276         return -1;
277     }
278 
279     switch (attr) {
280         case UNUM_LENIENT_PARSE:
281             return isLenient();
282 
283         case UNUM_PARSE_INT_ONLY:
284             return isParseIntegerOnly();
285 
286         case UNUM_GROUPING_USED:
287             return isGroupingUsed();
288 
289         case UNUM_DECIMAL_ALWAYS_SHOWN:
290             return isDecimalSeparatorAlwaysShown();
291 
292         case UNUM_MAX_INTEGER_DIGITS:
293             return getMaximumIntegerDigits();
294 
295         case UNUM_MIN_INTEGER_DIGITS:
296             return getMinimumIntegerDigits();
297 
298         case UNUM_INTEGER_DIGITS:
299             // TBD: what should this return?
300             return getMinimumIntegerDigits();
301 
302         case UNUM_MAX_FRACTION_DIGITS:
303             return getMaximumFractionDigits();
304 
305         case UNUM_MIN_FRACTION_DIGITS:
306             return getMinimumFractionDigits();
307 
308         case UNUM_FRACTION_DIGITS:
309             // TBD: what should this return?
310             return getMinimumFractionDigits();
311 
312         case UNUM_SIGNIFICANT_DIGITS_USED:
313             return areSignificantDigitsUsed();
314 
315         case UNUM_MAX_SIGNIFICANT_DIGITS:
316             return getMaximumSignificantDigits();
317 
318         case UNUM_MIN_SIGNIFICANT_DIGITS:
319             return getMinimumSignificantDigits();
320 
321         case UNUM_MULTIPLIER:
322             return getMultiplier();
323 
324         case UNUM_SCALE:
325             return getMultiplierScale();
326 
327         case UNUM_GROUPING_SIZE:
328             return getGroupingSize();
329 
330         case UNUM_ROUNDING_MODE:
331             return getRoundingMode();
332 
333         case UNUM_FORMAT_WIDTH:
334             return getFormatWidth();
335 
336         case UNUM_PADDING_POSITION:
337             return getPadPosition();
338 
339         case UNUM_SECONDARY_GROUPING_SIZE:
340             return getSecondaryGroupingSize();
341 
342         case UNUM_PARSE_NO_EXPONENT:
343             return isParseNoExponent();
344 
345         case UNUM_PARSE_DECIMAL_MARK_REQUIRED:
346             return isDecimalPatternMatchRequired();
347 
348         case UNUM_CURRENCY_USAGE:
349             return getCurrencyUsage();
350 
351         case UNUM_MINIMUM_GROUPING_DIGITS:
352             return getMinimumGroupingDigits();
353 
354         case UNUM_PARSE_CASE_SENSITIVE:
355             return isParseCaseSensitive();
356 
357         case UNUM_SIGN_ALWAYS_SHOWN:
358             return isSignAlwaysShown();
359 
360         case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS:
361             return isFormatFailIfMoreThanMaxDigits();
362 
363         default:
364             status = U_UNSUPPORTED_ERROR;
365             break;
366     }
367 
368     return -1; /* undefined */
369 }
370 
setGroupingUsed(UBool enabled)371 void DecimalFormat::setGroupingUsed(UBool enabled) {
372     if (fields == nullptr) {
373         return;
374     }
375     if (UBOOL_TO_BOOL(enabled) == fields->properties.groupingUsed) { return; }
376     NumberFormat::setGroupingUsed(enabled); // to set field for compatibility
377     fields->properties.groupingUsed = enabled;
378     touchNoError();
379 }
380 
setParseIntegerOnly(UBool value)381 void DecimalFormat::setParseIntegerOnly(UBool value) {
382     if (fields == nullptr) {
383         return;
384     }
385     if (UBOOL_TO_BOOL(value) == fields->properties.parseIntegerOnly) { return; }
386     NumberFormat::setParseIntegerOnly(value); // to set field for compatibility
387     fields->properties.parseIntegerOnly = value;
388     touchNoError();
389 }
390 
setLenient(UBool enable)391 void DecimalFormat::setLenient(UBool enable) {
392     if (fields == nullptr) {
393         return;
394     }
395     ParseMode mode = enable ? PARSE_MODE_LENIENT : PARSE_MODE_STRICT;
396     if (!fields->properties.parseMode.isNull() && mode == fields->properties.parseMode.getNoError()) { return; }
397     NumberFormat::setLenient(enable); // to set field for compatibility
398     fields->properties.parseMode = mode;
399     touchNoError();
400 }
401 
DecimalFormat(const UnicodeString & pattern,DecimalFormatSymbols * symbolsToAdopt,UParseError &,UErrorCode & status)402 DecimalFormat::DecimalFormat(const UnicodeString& pattern, DecimalFormatSymbols* symbolsToAdopt,
403                              UParseError&, UErrorCode& status)
404         : DecimalFormat(symbolsToAdopt, status) {
405     if (U_FAILURE(status)) { return; }
406     // TODO: What is parseError for?
407     setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status);
408     touch(status);
409 }
410 
DecimalFormat(const UnicodeString & pattern,const DecimalFormatSymbols & symbols,UErrorCode & status)411 DecimalFormat::DecimalFormat(const UnicodeString& pattern, const DecimalFormatSymbols& symbols,
412                              UErrorCode& status)
413         : DecimalFormat(nullptr, status) {
414     if (U_FAILURE(status)) { return; }
415     LocalPointer<DecimalFormatSymbols> dfs(new DecimalFormatSymbols(symbols), status);
416     if (U_FAILURE(status)) {
417         // If we failed to allocate DecimalFormatSymbols, then release fields and its members.
418         // We must have a fully complete fields object, we cannot have partially populated members.
419         delete fields;
420         fields = nullptr;
421         status = U_MEMORY_ALLOCATION_ERROR;
422         return;
423     }
424     fields->symbols.adoptInstead(dfs.orphan());
425     setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status);
426     touch(status);
427 }
428 
DecimalFormat(const DecimalFormat & source)429 DecimalFormat::DecimalFormat(const DecimalFormat& source) : NumberFormat(source) {
430     // If the object that we are copying from is invalid, no point in going further.
431     if (source.fields == nullptr) {
432         return;
433     }
434     // Note: it is not safe to copy fields->formatter or fWarehouse directly because fields->formatter might have
435     // dangling pointers to fields inside fWarehouse. The safe thing is to re-construct fields->formatter from
436     // the property bag, despite being somewhat slower.
437     fields = new DecimalFormatFields(source.fields->properties);
438     if (fields == nullptr) {
439         return; // no way to report an error.
440     }
441     UErrorCode status = U_ZERO_ERROR;
442     fields->symbols.adoptInsteadAndCheckErrorCode(new DecimalFormatSymbols(*source.fields->symbols), status);
443     // In order to simplify error handling logic in the various getters/setters/etc, we do not allow
444     // any partially populated DecimalFormatFields object. We must have a fully complete fields object
445     // or else we set it to nullptr.
446     if (U_FAILURE(status)) {
447         delete fields;
448         fields = nullptr;
449         return;
450     }
451     touch(status);
452 }
453 
operator =(const DecimalFormat & rhs)454 DecimalFormat& DecimalFormat::operator=(const DecimalFormat& rhs) {
455     // guard against self-assignment
456     if (this == &rhs) {
457         return *this;
458     }
459     // Make sure both objects are valid.
460     if (fields == nullptr || rhs.fields == nullptr) {
461         return *this; // unfortunately, no way to report an error.
462     }
463     fields->properties = rhs.fields->properties;
464     fields->exportedProperties.clear();
465     UErrorCode status = U_ZERO_ERROR;
466     LocalPointer<DecimalFormatSymbols> dfs(new DecimalFormatSymbols(*rhs.fields->symbols), status);
467     if (U_FAILURE(status)) {
468         // We failed to allocate DecimalFormatSymbols, release fields and its members.
469         // We must have a fully complete fields object, we cannot have partially populated members.
470         delete fields;
471         fields = nullptr;
472         return *this;
473     }
474     fields->symbols.adoptInstead(dfs.orphan());
475     touch(status);
476 
477     return *this;
478 }
479 
~DecimalFormat()480 DecimalFormat::~DecimalFormat() {
481     if (fields == nullptr) { return; }
482 
483     delete fields->atomicParser.exchange(nullptr);
484     delete fields->atomicCurrencyParser.exchange(nullptr);
485     delete fields;
486 }
487 
clone() const488 DecimalFormat* DecimalFormat::clone() const {
489     // can only clone valid objects.
490     if (fields == nullptr) {
491         return nullptr;
492     }
493     LocalPointer<DecimalFormat> df(new DecimalFormat(*this));
494     if (df.isValid() && df->fields != nullptr) {
495         return df.orphan();
496     }
497     return nullptr;
498 }
499 
operator ==(const Format & other) const500 UBool DecimalFormat::operator==(const Format& other) const {
501     auto* otherDF = dynamic_cast<const DecimalFormat*>(&other);
502     if (otherDF == nullptr) {
503         return false;
504     }
505     // If either object is in an invalid state, prevent dereferencing nullptr below.
506     // Additionally, invalid objects should not be considered equal to anything.
507     if (fields == nullptr || otherDF->fields == nullptr) {
508         return false;
509     }
510     return fields->properties == otherDF->fields->properties && *fields->symbols == *otherDF->fields->symbols;
511 }
512 
format(double number,UnicodeString & appendTo,FieldPosition & pos) const513 UnicodeString& DecimalFormat::format(double number, UnicodeString& appendTo, FieldPosition& pos) const {
514     if (fields == nullptr) {
515         appendTo.setToBogus();
516         return appendTo;
517     }
518     if (pos.getField() == FieldPosition::DONT_CARE && fastFormatDouble(number, appendTo)) {
519         return appendTo;
520     }
521     UErrorCode localStatus = U_ZERO_ERROR;
522     FormattedNumber output = fields->formatter.formatDouble(number, localStatus);
523     fieldPositionHelper(output, pos, appendTo.length(), localStatus);
524     auto appendable = UnicodeStringAppendable(appendTo);
525     output.appendTo(appendable, localStatus);
526     return appendTo;
527 }
528 
format(double number,UnicodeString & appendTo,FieldPosition & pos,UErrorCode & status) const529 UnicodeString& DecimalFormat::format(double number, UnicodeString& appendTo, FieldPosition& pos,
530                                      UErrorCode& status) const {
531     if (U_FAILURE(status)) {
532         return appendTo; // don't overwrite status if it's already a failure.
533     }
534     if (fields == nullptr) {
535         // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
536         status = U_MEMORY_ALLOCATION_ERROR;
537         appendTo.setToBogus();
538         return appendTo;
539     }
540     if (pos.getField() == FieldPosition::DONT_CARE && fastFormatDouble(number, appendTo)) {
541         return appendTo;
542     }
543     FormattedNumber output = fields->formatter.formatDouble(number, status);
544     fieldPositionHelper(output, pos, appendTo.length(), status);
545     auto appendable = UnicodeStringAppendable(appendTo);
546     output.appendTo(appendable, status);
547     return appendTo;
548 }
549 
550 UnicodeString&
format(double number,UnicodeString & appendTo,FieldPositionIterator * posIter,UErrorCode & status) const551 DecimalFormat::format(double number, UnicodeString& appendTo, FieldPositionIterator* posIter,
552                       UErrorCode& status) const {
553     if (U_FAILURE(status)) {
554         return appendTo; // don't overwrite status if it's already a failure.
555     }
556     if (fields == nullptr) {
557         // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
558         status = U_MEMORY_ALLOCATION_ERROR;
559         appendTo.setToBogus();
560         return appendTo;
561     }
562     if (posIter == nullptr && fastFormatDouble(number, appendTo)) {
563         return appendTo;
564     }
565     FormattedNumber output = fields->formatter.formatDouble(number, status);
566     fieldPositionIteratorHelper(output, posIter, appendTo.length(), status);
567     auto appendable = UnicodeStringAppendable(appendTo);
568     output.appendTo(appendable, status);
569     return appendTo;
570 }
571 
format(int32_t number,UnicodeString & appendTo,FieldPosition & pos) const572 UnicodeString& DecimalFormat::format(int32_t number, UnicodeString& appendTo, FieldPosition& pos) const {
573     return format(static_cast<int64_t> (number), appendTo, pos);
574 }
575 
format(int32_t number,UnicodeString & appendTo,FieldPosition & pos,UErrorCode & status) const576 UnicodeString& DecimalFormat::format(int32_t number, UnicodeString& appendTo, FieldPosition& pos,
577                                      UErrorCode& status) const {
578     return format(static_cast<int64_t> (number), appendTo, pos, status);
579 }
580 
581 UnicodeString&
format(int32_t number,UnicodeString & appendTo,FieldPositionIterator * posIter,UErrorCode & status) const582 DecimalFormat::format(int32_t number, UnicodeString& appendTo, FieldPositionIterator* posIter,
583                       UErrorCode& status) const {
584     return format(static_cast<int64_t> (number), appendTo, posIter, status);
585 }
586 
format(int64_t number,UnicodeString & appendTo,FieldPosition & pos) const587 UnicodeString& DecimalFormat::format(int64_t number, UnicodeString& appendTo, FieldPosition& pos) const {
588     if (fields == nullptr) {
589         appendTo.setToBogus();
590         return appendTo;
591     }
592     if (pos.getField() == FieldPosition::DONT_CARE && fastFormatInt64(number, appendTo)) {
593         return appendTo;
594     }
595     UErrorCode localStatus = U_ZERO_ERROR;
596     FormattedNumber output = fields->formatter.formatInt(number, localStatus);
597     fieldPositionHelper(output, pos, appendTo.length(), localStatus);
598     auto appendable = UnicodeStringAppendable(appendTo);
599     output.appendTo(appendable, localStatus);
600     return appendTo;
601 }
602 
format(int64_t number,UnicodeString & appendTo,FieldPosition & pos,UErrorCode & status) const603 UnicodeString& DecimalFormat::format(int64_t number, UnicodeString& appendTo, FieldPosition& pos,
604                                      UErrorCode& status) const {
605     if (U_FAILURE(status)) {
606         return appendTo; // don't overwrite status if it's already a failure.
607     }
608     if (fields == nullptr) {
609         // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
610         status = U_MEMORY_ALLOCATION_ERROR;
611         appendTo.setToBogus();
612         return appendTo;
613     }
614     if (pos.getField() == FieldPosition::DONT_CARE && fastFormatInt64(number, appendTo)) {
615         return appendTo;
616     }
617     FormattedNumber output = fields->formatter.formatInt(number, status);
618     fieldPositionHelper(output, pos, appendTo.length(), status);
619     auto appendable = UnicodeStringAppendable(appendTo);
620     output.appendTo(appendable, status);
621     return appendTo;
622 }
623 
624 UnicodeString&
format(int64_t number,UnicodeString & appendTo,FieldPositionIterator * posIter,UErrorCode & status) const625 DecimalFormat::format(int64_t number, UnicodeString& appendTo, FieldPositionIterator* posIter,
626                       UErrorCode& status) const {
627     if (U_FAILURE(status)) {
628         return appendTo; // don't overwrite status if it's already a failure.
629     }
630     if (fields == nullptr) {
631         // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
632         status = U_MEMORY_ALLOCATION_ERROR;
633         appendTo.setToBogus();
634         return appendTo;
635     }
636     if (posIter == nullptr && fastFormatInt64(number, appendTo)) {
637         return appendTo;
638     }
639     FormattedNumber output = fields->formatter.formatInt(number, status);
640     fieldPositionIteratorHelper(output, posIter, appendTo.length(), status);
641     auto appendable = UnicodeStringAppendable(appendTo);
642     output.appendTo(appendable, status);
643     return appendTo;
644 }
645 
646 UnicodeString&
format(StringPiece number,UnicodeString & appendTo,FieldPositionIterator * posIter,UErrorCode & status) const647 DecimalFormat::format(StringPiece number, UnicodeString& appendTo, FieldPositionIterator* posIter,
648                       UErrorCode& status) const {
649     if (U_FAILURE(status)) {
650         return appendTo; // don't overwrite status if it's already a failure.
651     }
652     if (fields == nullptr) {
653         // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
654         status = U_MEMORY_ALLOCATION_ERROR;
655         appendTo.setToBogus();
656         return appendTo;
657     }
658     FormattedNumber output = fields->formatter.formatDecimal(number, status);
659     fieldPositionIteratorHelper(output, posIter, appendTo.length(), status);
660     auto appendable = UnicodeStringAppendable(appendTo);
661     output.appendTo(appendable, status);
662     return appendTo;
663 }
664 
format(const DecimalQuantity & number,UnicodeString & appendTo,FieldPositionIterator * posIter,UErrorCode & status) const665 UnicodeString& DecimalFormat::format(const DecimalQuantity& number, UnicodeString& appendTo,
666                                      FieldPositionIterator* posIter, UErrorCode& status) const {
667     if (U_FAILURE(status)) {
668         return appendTo; // don't overwrite status if it's already a failure.
669     }
670     if (fields == nullptr) {
671         // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
672         status = U_MEMORY_ALLOCATION_ERROR;
673         appendTo.setToBogus();
674         return appendTo;
675     }
676     FormattedNumber output = fields->formatter.formatDecimalQuantity(number, status);
677     fieldPositionIteratorHelper(output, posIter, appendTo.length(), status);
678     auto appendable = UnicodeStringAppendable(appendTo);
679     output.appendTo(appendable, status);
680     return appendTo;
681 }
682 
683 UnicodeString&
format(const DecimalQuantity & number,UnicodeString & appendTo,FieldPosition & pos,UErrorCode & status) const684 DecimalFormat::format(const DecimalQuantity& number, UnicodeString& appendTo, FieldPosition& pos,
685                       UErrorCode& status) const {
686     if (U_FAILURE(status)) {
687         return appendTo; // don't overwrite status if it's already a failure.
688     }
689     if (fields == nullptr) {
690         // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
691         status = U_MEMORY_ALLOCATION_ERROR;
692         appendTo.setToBogus();
693         return appendTo;
694     }
695     FormattedNumber output = fields->formatter.formatDecimalQuantity(number, status);
696     fieldPositionHelper(output, pos, appendTo.length(), status);
697     auto appendable = UnicodeStringAppendable(appendTo);
698     output.appendTo(appendable, status);
699     return appendTo;
700 }
701 
parse(const UnicodeString & text,Formattable & output,ParsePosition & parsePosition) const702 void DecimalFormat::parse(const UnicodeString& text, Formattable& output,
703                           ParsePosition& parsePosition) const {
704     if (fields == nullptr) {
705         return;
706     }
707     if (parsePosition.getIndex() < 0 || parsePosition.getIndex() >= text.length()) {
708         if (parsePosition.getIndex() == text.length()) {
709             // If there is nothing to parse, it is an error
710             parsePosition.setErrorIndex(parsePosition.getIndex());
711         }
712         return;
713     }
714 
715     ErrorCode status;
716     ParsedNumber result;
717     // Note: if this is a currency instance, currencies will be matched despite the fact that we are not in the
718     // parseCurrency method (backwards compatibility)
719     int32_t startIndex = parsePosition.getIndex();
720     const NumberParserImpl* parser = getParser(status);
721     if (U_FAILURE(status)) {
722         return; // unfortunately no way to report back the error.
723     }
724     parser->parse(text, startIndex, true, result, status);
725     if (U_FAILURE(status)) {
726         return; // unfortunately no way to report back the error.
727     }
728     // TODO: Do we need to check for fImpl->properties->parseAllInput (UCONFIG_HAVE_PARSEALLINPUT) here?
729     if (result.success()) {
730         parsePosition.setIndex(result.charEnd);
731         result.populateFormattable(output, parser->getParseFlags());
732     } else {
733         parsePosition.setErrorIndex(startIndex + result.charEnd);
734     }
735 }
736 
parseCurrency(const UnicodeString & text,ParsePosition & parsePosition) const737 CurrencyAmount* DecimalFormat::parseCurrency(const UnicodeString& text, ParsePosition& parsePosition) const {
738     if (fields == nullptr) {
739         return nullptr;
740     }
741     if (parsePosition.getIndex() < 0 || parsePosition.getIndex() >= text.length()) {
742         return nullptr;
743     }
744 
745     ErrorCode status;
746     ParsedNumber result;
747     // Note: if this is a currency instance, currencies will be matched despite the fact that we are not in the
748     // parseCurrency method (backwards compatibility)
749     int32_t startIndex = parsePosition.getIndex();
750     const NumberParserImpl* parser = getCurrencyParser(status);
751     if (U_FAILURE(status)) {
752         return nullptr;
753     }
754     parser->parse(text, startIndex, true, result, status);
755     if (U_FAILURE(status)) {
756         return nullptr;
757     }
758     // TODO: Do we need to check for fImpl->properties->parseAllInput (UCONFIG_HAVE_PARSEALLINPUT) here?
759     if (result.success()) {
760         parsePosition.setIndex(result.charEnd);
761         Formattable formattable;
762         result.populateFormattable(formattable, parser->getParseFlags());
763         LocalPointer<CurrencyAmount> currencyAmount(
764             new CurrencyAmount(formattable, result.currencyCode, status), status);
765         if (U_FAILURE(status)) {
766             return nullptr;
767         }
768         return currencyAmount.orphan();
769     } else {
770         parsePosition.setErrorIndex(startIndex + result.charEnd);
771         return nullptr;
772     }
773 }
774 
getDecimalFormatSymbols(void) const775 const DecimalFormatSymbols* DecimalFormat::getDecimalFormatSymbols(void) const {
776     if (fields == nullptr) {
777         return nullptr;
778     }
779     return fields->symbols.getAlias();
780 }
781 
adoptDecimalFormatSymbols(DecimalFormatSymbols * symbolsToAdopt)782 void DecimalFormat::adoptDecimalFormatSymbols(DecimalFormatSymbols* symbolsToAdopt) {
783     if (symbolsToAdopt == nullptr) {
784         return; // do not allow caller to set fields->symbols to NULL
785     }
786     // we must take ownership of symbolsToAdopt, even in a failure case.
787     LocalPointer<DecimalFormatSymbols> dfs(symbolsToAdopt);
788     if (fields == nullptr) {
789         return;
790     }
791     fields->symbols.adoptInstead(dfs.orphan());
792     touchNoError();
793 }
794 
setDecimalFormatSymbols(const DecimalFormatSymbols & symbols)795 void DecimalFormat::setDecimalFormatSymbols(const DecimalFormatSymbols& symbols) {
796     if (fields == nullptr) {
797         return;
798     }
799     UErrorCode status = U_ZERO_ERROR;
800     LocalPointer<DecimalFormatSymbols> dfs(new DecimalFormatSymbols(symbols), status);
801     if (U_FAILURE(status)) {
802         // We failed to allocate DecimalFormatSymbols, release fields and its members.
803         // We must have a fully complete fields object, we cannot have partially populated members.
804         delete fields;
805         fields = nullptr;
806         return;
807     }
808     fields->symbols.adoptInstead(dfs.orphan());
809     touchNoError();
810 }
811 
getCurrencyPluralInfo(void) const812 const CurrencyPluralInfo* DecimalFormat::getCurrencyPluralInfo(void) const {
813     if (fields == nullptr) {
814         return nullptr;
815     }
816     return fields->properties.currencyPluralInfo.fPtr.getAlias();
817 }
818 
adoptCurrencyPluralInfo(CurrencyPluralInfo * toAdopt)819 void DecimalFormat::adoptCurrencyPluralInfo(CurrencyPluralInfo* toAdopt) {
820     // TODO: should we guard against nullptr input, like in adoptDecimalFormatSymbols?
821     // we must take ownership of toAdopt, even in a failure case.
822     LocalPointer<CurrencyPluralInfo> cpi(toAdopt);
823     if (fields == nullptr) {
824         return;
825     }
826     fields->properties.currencyPluralInfo.fPtr.adoptInstead(cpi.orphan());
827     touchNoError();
828 }
829 
setCurrencyPluralInfo(const CurrencyPluralInfo & info)830 void DecimalFormat::setCurrencyPluralInfo(const CurrencyPluralInfo& info) {
831     if (fields == nullptr) {
832         return;
833     }
834     if (fields->properties.currencyPluralInfo.fPtr.isNull()) {
835         // Note: clone() can fail with OOM error, but we have no way to report it. :(
836         fields->properties.currencyPluralInfo.fPtr.adoptInstead(info.clone());
837     } else {
838         *fields->properties.currencyPluralInfo.fPtr = info; // copy-assignment operator
839     }
840     touchNoError();
841 }
842 
getPositivePrefix(UnicodeString & result) const843 UnicodeString& DecimalFormat::getPositivePrefix(UnicodeString& result) const {
844     if (fields == nullptr) {
845         result.setToBogus();
846         return result;
847     }
848     UErrorCode status = U_ZERO_ERROR;
849     fields->formatter.getAffixImpl(true, false, result, status);
850     if (U_FAILURE(status)) { result.setToBogus(); }
851     return result;
852 }
853 
setPositivePrefix(const UnicodeString & newValue)854 void DecimalFormat::setPositivePrefix(const UnicodeString& newValue) {
855     if (fields == nullptr) {
856         return;
857     }
858     if (newValue == fields->properties.positivePrefix) { return; }
859     fields->properties.positivePrefix = newValue;
860     touchNoError();
861 }
862 
getNegativePrefix(UnicodeString & result) const863 UnicodeString& DecimalFormat::getNegativePrefix(UnicodeString& result) const {
864     if (fields == nullptr) {
865         result.setToBogus();
866         return result;
867     }
868     UErrorCode status = U_ZERO_ERROR;
869     fields->formatter.getAffixImpl(true, true, result, status);
870     if (U_FAILURE(status)) { result.setToBogus(); }
871     return result;
872 }
873 
setNegativePrefix(const UnicodeString & newValue)874 void DecimalFormat::setNegativePrefix(const UnicodeString& newValue) {
875     if (fields == nullptr) {
876         return;
877     }
878     if (newValue == fields->properties.negativePrefix) { return; }
879     fields->properties.negativePrefix = newValue;
880     touchNoError();
881 }
882 
getPositiveSuffix(UnicodeString & result) const883 UnicodeString& DecimalFormat::getPositiveSuffix(UnicodeString& result) const {
884     if (fields == nullptr) {
885         result.setToBogus();
886         return result;
887     }
888     UErrorCode status = U_ZERO_ERROR;
889     fields->formatter.getAffixImpl(false, false, result, status);
890     if (U_FAILURE(status)) { result.setToBogus(); }
891     return result;
892 }
893 
setPositiveSuffix(const UnicodeString & newValue)894 void DecimalFormat::setPositiveSuffix(const UnicodeString& newValue) {
895     if (fields == nullptr) {
896         return;
897     }
898     if (newValue == fields->properties.positiveSuffix) { return; }
899     fields->properties.positiveSuffix = newValue;
900     touchNoError();
901 }
902 
getNegativeSuffix(UnicodeString & result) const903 UnicodeString& DecimalFormat::getNegativeSuffix(UnicodeString& result) const {
904     if (fields == nullptr) {
905         result.setToBogus();
906         return result;
907     }
908     UErrorCode status = U_ZERO_ERROR;
909     fields->formatter.getAffixImpl(false, true, result, status);
910     if (U_FAILURE(status)) { result.setToBogus(); }
911     return result;
912 }
913 
setNegativeSuffix(const UnicodeString & newValue)914 void DecimalFormat::setNegativeSuffix(const UnicodeString& newValue) {
915     if (fields == nullptr) {
916         return;
917     }
918     if (newValue == fields->properties.negativeSuffix) { return; }
919     fields->properties.negativeSuffix = newValue;
920     touchNoError();
921 }
922 
isSignAlwaysShown() const923 UBool DecimalFormat::isSignAlwaysShown() const {
924     // Not much we can do to report an error.
925     if (fields == nullptr) {
926         return DecimalFormatProperties::getDefault().signAlwaysShown;
927     }
928     return fields->properties.signAlwaysShown;
929 }
930 
setSignAlwaysShown(UBool value)931 void DecimalFormat::setSignAlwaysShown(UBool value) {
932     if (fields == nullptr) { return; }
933     if (UBOOL_TO_BOOL(value) == fields->properties.signAlwaysShown) { return; }
934     fields->properties.signAlwaysShown = value;
935     touchNoError();
936 }
937 
getMultiplier(void) const938 int32_t DecimalFormat::getMultiplier(void) const {
939     const DecimalFormatProperties *dfp;
940     // Not much we can do to report an error.
941     if (fields == nullptr) {
942         // Fallback to using the default instance of DecimalFormatProperties.
943         dfp = &(DecimalFormatProperties::getDefault());
944     } else {
945         dfp = &fields->properties;
946     }
947     if (dfp->multiplier != 1) {
948         return dfp->multiplier;
949     } else if (dfp->magnitudeMultiplier != 0) {
950         return static_cast<int32_t>(uprv_pow10(dfp->magnitudeMultiplier));
951     } else {
952         return 1;
953     }
954 }
955 
setMultiplier(int32_t multiplier)956 void DecimalFormat::setMultiplier(int32_t multiplier) {
957     if (fields == nullptr) {
958          return;
959     }
960     if (multiplier == 0) {
961         multiplier = 1;     // one being the benign default value for a multiplier.
962     }
963 
964     // Try to convert to a magnitude multiplier first
965     int delta = 0;
966     int value = multiplier;
967     while (value != 1) {
968         delta++;
969         int temp = value / 10;
970         if (temp * 10 != value) {
971             delta = -1;
972             break;
973         }
974         value = temp;
975     }
976     if (delta != -1) {
977         fields->properties.magnitudeMultiplier = delta;
978         fields->properties.multiplier = 1;
979     } else {
980         fields->properties.magnitudeMultiplier = 0;
981         fields->properties.multiplier = multiplier;
982     }
983     touchNoError();
984 }
985 
getMultiplierScale() const986 int32_t DecimalFormat::getMultiplierScale() const {
987     // Not much we can do to report an error.
988     if (fields == nullptr) {
989         // Fallback to using the default instance of DecimalFormatProperties.
990         return DecimalFormatProperties::getDefault().multiplierScale;
991     }
992     return fields->properties.multiplierScale;
993 }
994 
setMultiplierScale(int32_t newValue)995 void DecimalFormat::setMultiplierScale(int32_t newValue) {
996     if (fields == nullptr) { return; }
997     if (newValue == fields->properties.multiplierScale) { return; }
998     fields->properties.multiplierScale = newValue;
999     touchNoError();
1000 }
1001 
getRoundingIncrement(void) const1002 double DecimalFormat::getRoundingIncrement(void) const {
1003     // Not much we can do to report an error.
1004     if (fields == nullptr) {
1005         // Fallback to using the default instance of DecimalFormatProperties.
1006         return DecimalFormatProperties::getDefault().roundingIncrement;
1007     }
1008     return fields->exportedProperties.roundingIncrement;
1009 }
1010 
setRoundingIncrement(double newValue)1011 void DecimalFormat::setRoundingIncrement(double newValue) {
1012     if (fields == nullptr) { return; }
1013     if (newValue == fields->properties.roundingIncrement) { return; }
1014     fields->properties.roundingIncrement = newValue;
1015     touchNoError();
1016 }
1017 
getRoundingMode(void) const1018 ERoundingMode DecimalFormat::getRoundingMode(void) const {
1019     // Not much we can do to report an error.
1020     if (fields == nullptr) {
1021         // Fallback to using the default instance of DecimalFormatProperties.
1022         return static_cast<ERoundingMode>(DecimalFormatProperties::getDefault().roundingMode.getNoError());
1023     }
1024     // UNumberFormatRoundingMode and ERoundingMode have the same values.
1025     return static_cast<ERoundingMode>(fields->exportedProperties.roundingMode.getNoError());
1026 }
1027 
setRoundingMode(ERoundingMode roundingMode)1028 void DecimalFormat::setRoundingMode(ERoundingMode roundingMode) {
1029     if (fields == nullptr) { return; }
1030     auto uRoundingMode = static_cast<UNumberFormatRoundingMode>(roundingMode);
1031     if (!fields->properties.roundingMode.isNull() && uRoundingMode == fields->properties.roundingMode.getNoError()) {
1032         return;
1033     }
1034     NumberFormat::setMaximumIntegerDigits(roundingMode); // to set field for compatibility
1035     fields->properties.roundingMode = uRoundingMode;
1036     touchNoError();
1037 }
1038 
getFormatWidth(void) const1039 int32_t DecimalFormat::getFormatWidth(void) const {
1040     // Not much we can do to report an error.
1041     if (fields == nullptr) {
1042         // Fallback to using the default instance of DecimalFormatProperties.
1043         return DecimalFormatProperties::getDefault().formatWidth;
1044     }
1045     return fields->properties.formatWidth;
1046 }
1047 
setFormatWidth(int32_t width)1048 void DecimalFormat::setFormatWidth(int32_t width) {
1049     if (fields == nullptr) { return; }
1050     if (width == fields->properties.formatWidth) { return; }
1051     fields->properties.formatWidth = width;
1052     touchNoError();
1053 }
1054 
getPadCharacterString() const1055 UnicodeString DecimalFormat::getPadCharacterString() const {
1056     if (fields == nullptr || fields->properties.padString.isBogus()) {
1057         // Readonly-alias the static string kFallbackPaddingString
1058         return {TRUE, kFallbackPaddingString, -1};
1059     } else {
1060         return fields->properties.padString;
1061     }
1062 }
1063 
setPadCharacter(const UnicodeString & padChar)1064 void DecimalFormat::setPadCharacter(const UnicodeString& padChar) {
1065     if (fields == nullptr) { return; }
1066     if (padChar == fields->properties.padString) { return; }
1067     if (padChar.length() > 0) {
1068         fields->properties.padString = UnicodeString(padChar.char32At(0));
1069     } else {
1070         fields->properties.padString.setToBogus();
1071     }
1072     touchNoError();
1073 }
1074 
getPadPosition(void) const1075 EPadPosition DecimalFormat::getPadPosition(void) const {
1076     if (fields == nullptr || fields->properties.padPosition.isNull()) {
1077         return EPadPosition::kPadBeforePrefix;
1078     } else {
1079         // UNumberFormatPadPosition and EPadPosition have the same values.
1080         return static_cast<EPadPosition>(fields->properties.padPosition.getNoError());
1081     }
1082 }
1083 
setPadPosition(EPadPosition padPos)1084 void DecimalFormat::setPadPosition(EPadPosition padPos) {
1085     if (fields == nullptr) { return; }
1086     auto uPadPos = static_cast<UNumberFormatPadPosition>(padPos);
1087     if (!fields->properties.padPosition.isNull() && uPadPos == fields->properties.padPosition.getNoError()) {
1088         return;
1089     }
1090     fields->properties.padPosition = uPadPos;
1091     touchNoError();
1092 }
1093 
isScientificNotation(void) const1094 UBool DecimalFormat::isScientificNotation(void) const {
1095     // Not much we can do to report an error.
1096     if (fields == nullptr) {
1097         // Fallback to using the default instance of DecimalFormatProperties.
1098         return (DecimalFormatProperties::getDefault().minimumExponentDigits != -1);
1099     }
1100     return (fields->properties.minimumExponentDigits != -1);
1101 }
1102 
setScientificNotation(UBool useScientific)1103 void DecimalFormat::setScientificNotation(UBool useScientific) {
1104     if (fields == nullptr) { return; }
1105     int32_t minExp = useScientific ? 1 : -1;
1106     if (fields->properties.minimumExponentDigits == minExp) { return; }
1107     if (useScientific) {
1108         fields->properties.minimumExponentDigits = 1;
1109     } else {
1110         fields->properties.minimumExponentDigits = -1;
1111     }
1112     touchNoError();
1113 }
1114 
getMinimumExponentDigits(void) const1115 int8_t DecimalFormat::getMinimumExponentDigits(void) const {
1116     // Not much we can do to report an error.
1117     if (fields == nullptr) {
1118         // Fallback to using the default instance of DecimalFormatProperties.
1119         return static_cast<int8_t>(DecimalFormatProperties::getDefault().minimumExponentDigits);
1120     }
1121     return static_cast<int8_t>(fields->properties.minimumExponentDigits);
1122 }
1123 
setMinimumExponentDigits(int8_t minExpDig)1124 void DecimalFormat::setMinimumExponentDigits(int8_t minExpDig) {
1125     if (fields == nullptr) { return; }
1126     if (minExpDig == fields->properties.minimumExponentDigits) { return; }
1127     fields->properties.minimumExponentDigits = minExpDig;
1128     touchNoError();
1129 }
1130 
isExponentSignAlwaysShown(void) const1131 UBool DecimalFormat::isExponentSignAlwaysShown(void) const {
1132     // Not much we can do to report an error.
1133     if (fields == nullptr) {
1134         // Fallback to using the default instance of DecimalFormatProperties.
1135         return DecimalFormatProperties::getDefault().exponentSignAlwaysShown;
1136     }
1137     return fields->properties.exponentSignAlwaysShown;
1138 }
1139 
setExponentSignAlwaysShown(UBool expSignAlways)1140 void DecimalFormat::setExponentSignAlwaysShown(UBool expSignAlways) {
1141     if (fields == nullptr) { return; }
1142     if (UBOOL_TO_BOOL(expSignAlways) == fields->properties.exponentSignAlwaysShown) { return; }
1143     fields->properties.exponentSignAlwaysShown = expSignAlways;
1144     touchNoError();
1145 }
1146 
getGroupingSize(void) const1147 int32_t DecimalFormat::getGroupingSize(void) const {
1148     int32_t groupingSize;
1149     // Not much we can do to report an error.
1150     if (fields == nullptr) {
1151         // Fallback to using the default instance of DecimalFormatProperties.
1152         groupingSize = DecimalFormatProperties::getDefault().groupingSize;
1153     } else {
1154         groupingSize = fields->properties.groupingSize;
1155     }
1156     if (groupingSize < 0) {
1157         return 0;
1158     }
1159     return groupingSize;
1160 }
1161 
setGroupingSize(int32_t newValue)1162 void DecimalFormat::setGroupingSize(int32_t newValue) {
1163     if (fields == nullptr) { return; }
1164     if (newValue == fields->properties.groupingSize) { return; }
1165     fields->properties.groupingSize = newValue;
1166     touchNoError();
1167 }
1168 
getSecondaryGroupingSize(void) const1169 int32_t DecimalFormat::getSecondaryGroupingSize(void) const {
1170     int32_t grouping2;
1171     // Not much we can do to report an error.
1172     if (fields == nullptr) {
1173         // Fallback to using the default instance of DecimalFormatProperties.
1174         grouping2 = DecimalFormatProperties::getDefault().secondaryGroupingSize;
1175     } else {
1176         grouping2 = fields->properties.secondaryGroupingSize;
1177     }
1178     if (grouping2 < 0) {
1179         return 0;
1180     }
1181     return grouping2;
1182 }
1183 
setSecondaryGroupingSize(int32_t newValue)1184 void DecimalFormat::setSecondaryGroupingSize(int32_t newValue) {
1185     if (fields == nullptr) { return; }
1186     if (newValue == fields->properties.secondaryGroupingSize) { return; }
1187     fields->properties.secondaryGroupingSize = newValue;
1188     touchNoError();
1189 }
1190 
getMinimumGroupingDigits() const1191 int32_t DecimalFormat::getMinimumGroupingDigits() const {
1192     // Not much we can do to report an error.
1193     if (fields == nullptr) {
1194         // Fallback to using the default instance of DecimalFormatProperties.
1195         return DecimalFormatProperties::getDefault().minimumGroupingDigits;
1196     }
1197     return fields->properties.minimumGroupingDigits;
1198 }
1199 
setMinimumGroupingDigits(int32_t newValue)1200 void DecimalFormat::setMinimumGroupingDigits(int32_t newValue) {
1201     if (fields == nullptr) { return; }
1202     if (newValue == fields->properties.minimumGroupingDigits) { return; }
1203     fields->properties.minimumGroupingDigits = newValue;
1204     touchNoError();
1205 }
1206 
isDecimalSeparatorAlwaysShown(void) const1207 UBool DecimalFormat::isDecimalSeparatorAlwaysShown(void) const {
1208     // Not much we can do to report an error.
1209     if (fields == nullptr) {
1210         // Fallback to using the default instance of DecimalFormatProperties.
1211         return DecimalFormatProperties::getDefault().decimalSeparatorAlwaysShown;
1212     }
1213     return fields->properties.decimalSeparatorAlwaysShown;
1214 }
1215 
setDecimalSeparatorAlwaysShown(UBool newValue)1216 void DecimalFormat::setDecimalSeparatorAlwaysShown(UBool newValue) {
1217     if (fields == nullptr) { return; }
1218     if (UBOOL_TO_BOOL(newValue) == fields->properties.decimalSeparatorAlwaysShown) { return; }
1219     fields->properties.decimalSeparatorAlwaysShown = newValue;
1220     touchNoError();
1221 }
1222 
isDecimalPatternMatchRequired(void) const1223 UBool DecimalFormat::isDecimalPatternMatchRequired(void) const {
1224     // Not much we can do to report an error.
1225     if (fields == nullptr) {
1226         // Fallback to using the default instance of DecimalFormatProperties.
1227         return DecimalFormatProperties::getDefault().decimalPatternMatchRequired;
1228     }
1229     return fields->properties.decimalPatternMatchRequired;
1230 }
1231 
setDecimalPatternMatchRequired(UBool newValue)1232 void DecimalFormat::setDecimalPatternMatchRequired(UBool newValue) {
1233     if (fields == nullptr) { return; }
1234     if (UBOOL_TO_BOOL(newValue) == fields->properties.decimalPatternMatchRequired) { return; }
1235     fields->properties.decimalPatternMatchRequired = newValue;
1236     touchNoError();
1237 }
1238 
isParseNoExponent() const1239 UBool DecimalFormat::isParseNoExponent() const {
1240     // Not much we can do to report an error.
1241     if (fields == nullptr) {
1242         // Fallback to using the default instance of DecimalFormatProperties.
1243         return DecimalFormatProperties::getDefault().parseNoExponent;
1244     }
1245     return fields->properties.parseNoExponent;
1246 }
1247 
setParseNoExponent(UBool value)1248 void DecimalFormat::setParseNoExponent(UBool value) {
1249     if (fields == nullptr) { return; }
1250     if (UBOOL_TO_BOOL(value) == fields->properties.parseNoExponent) { return; }
1251     fields->properties.parseNoExponent = value;
1252     touchNoError();
1253 }
1254 
isParseCaseSensitive() const1255 UBool DecimalFormat::isParseCaseSensitive() const {
1256     // Not much we can do to report an error.
1257     if (fields == nullptr) {
1258         // Fallback to using the default instance of DecimalFormatProperties.
1259         return DecimalFormatProperties::getDefault().parseCaseSensitive;
1260     }
1261     return fields->properties.parseCaseSensitive;
1262 }
1263 
setParseCaseSensitive(UBool value)1264 void DecimalFormat::setParseCaseSensitive(UBool value) {
1265     if (fields == nullptr) { return; }
1266     if (UBOOL_TO_BOOL(value) == fields->properties.parseCaseSensitive) { return; }
1267     fields->properties.parseCaseSensitive = value;
1268     touchNoError();
1269 }
1270 
isFormatFailIfMoreThanMaxDigits() const1271 UBool DecimalFormat::isFormatFailIfMoreThanMaxDigits() const {
1272     // Not much we can do to report an error.
1273     if (fields == nullptr) {
1274         // Fallback to using the default instance of DecimalFormatProperties.
1275         return DecimalFormatProperties::getDefault().formatFailIfMoreThanMaxDigits;
1276     }
1277     return fields->properties.formatFailIfMoreThanMaxDigits;
1278 }
1279 
setFormatFailIfMoreThanMaxDigits(UBool value)1280 void DecimalFormat::setFormatFailIfMoreThanMaxDigits(UBool value) {
1281     if (fields == nullptr) { return; }
1282     if (UBOOL_TO_BOOL(value) == fields->properties.formatFailIfMoreThanMaxDigits) { return; }
1283     fields->properties.formatFailIfMoreThanMaxDigits = value;
1284     touchNoError();
1285 }
1286 
toPattern(UnicodeString & result) const1287 UnicodeString& DecimalFormat::toPattern(UnicodeString& result) const {
1288     if (fields == nullptr) {
1289         // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
1290         result.setToBogus();
1291         return result;
1292     }
1293     // Pull some properties from exportedProperties and others from properties
1294     // to keep affix patterns intact.  In particular, pull rounding properties
1295     // so that CurrencyUsage is reflected properly.
1296     // TODO: Consider putting this logic in number_patternstring.cpp instead.
1297     ErrorCode localStatus;
1298     DecimalFormatProperties tprops(fields->properties);
1299     bool useCurrency = (
1300         !tprops.currency.isNull() ||
1301         !tprops.currencyPluralInfo.fPtr.isNull() ||
1302         !tprops.currencyUsage.isNull() ||
1303         AffixUtils::hasCurrencySymbols(tprops.positivePrefixPattern, localStatus) ||
1304         AffixUtils::hasCurrencySymbols(tprops.positiveSuffixPattern, localStatus) ||
1305         AffixUtils::hasCurrencySymbols(tprops.negativePrefixPattern, localStatus) ||
1306         AffixUtils::hasCurrencySymbols(tprops.negativeSuffixPattern, localStatus));
1307     if (useCurrency) {
1308         tprops.minimumFractionDigits = fields->exportedProperties.minimumFractionDigits;
1309         tprops.maximumFractionDigits = fields->exportedProperties.maximumFractionDigits;
1310         tprops.roundingIncrement = fields->exportedProperties.roundingIncrement;
1311     }
1312     result = PatternStringUtils::propertiesToPatternString(tprops, localStatus);
1313     return result;
1314 }
1315 
toLocalizedPattern(UnicodeString & result) const1316 UnicodeString& DecimalFormat::toLocalizedPattern(UnicodeString& result) const {
1317     if (fields == nullptr) {
1318         // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
1319         result.setToBogus();
1320         return result;
1321     }
1322     ErrorCode localStatus;
1323     result = toPattern(result);
1324     result = PatternStringUtils::convertLocalized(result, *fields->symbols, true, localStatus);
1325     return result;
1326 }
1327 
applyPattern(const UnicodeString & pattern,UParseError &,UErrorCode & status)1328 void DecimalFormat::applyPattern(const UnicodeString& pattern, UParseError&, UErrorCode& status) {
1329     // TODO: What is parseError for?
1330     applyPattern(pattern, status);
1331 }
1332 
applyPattern(const UnicodeString & pattern,UErrorCode & status)1333 void DecimalFormat::applyPattern(const UnicodeString& pattern, UErrorCode& status) {
1334     // don't overwrite status if it's already a failure.
1335     if (U_FAILURE(status)) { return; }
1336     if (fields == nullptr) {
1337         // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
1338         status = U_MEMORY_ALLOCATION_ERROR;
1339         return;
1340     }
1341     setPropertiesFromPattern(pattern, IGNORE_ROUNDING_NEVER, status);
1342     touch(status);
1343 }
1344 
applyLocalizedPattern(const UnicodeString & localizedPattern,UParseError &,UErrorCode & status)1345 void DecimalFormat::applyLocalizedPattern(const UnicodeString& localizedPattern, UParseError&,
1346                                           UErrorCode& status) {
1347     // TODO: What is parseError for?
1348     applyLocalizedPattern(localizedPattern, status);
1349 }
1350 
applyLocalizedPattern(const UnicodeString & localizedPattern,UErrorCode & status)1351 void DecimalFormat::applyLocalizedPattern(const UnicodeString& localizedPattern, UErrorCode& status) {
1352     // don't overwrite status if it's already a failure.
1353     if (U_FAILURE(status)) { return; }
1354     if (fields == nullptr) {
1355         // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
1356         status = U_MEMORY_ALLOCATION_ERROR;
1357         return;
1358     }
1359     UnicodeString pattern = PatternStringUtils::convertLocalized(
1360             localizedPattern, *fields->symbols, false, status);
1361     applyPattern(pattern, status);
1362 }
1363 
setMaximumIntegerDigits(int32_t newValue)1364 void DecimalFormat::setMaximumIntegerDigits(int32_t newValue) {
1365     if (fields == nullptr) { return; }
1366     if (newValue == fields->properties.maximumIntegerDigits) { return; }
1367     // For backwards compatibility, conflicting min/max need to keep the most recent setting.
1368     int32_t min = fields->properties.minimumIntegerDigits;
1369     if (min >= 0 && min > newValue) {
1370         fields->properties.minimumIntegerDigits = newValue;
1371     }
1372     fields->properties.maximumIntegerDigits = newValue;
1373     touchNoError();
1374 }
1375 
setMinimumIntegerDigits(int32_t newValue)1376 void DecimalFormat::setMinimumIntegerDigits(int32_t newValue) {
1377     if (fields == nullptr) { return; }
1378     if (newValue == fields->properties.minimumIntegerDigits) { return; }
1379     // For backwards compatibility, conflicting min/max need to keep the most recent setting.
1380     int32_t max = fields->properties.maximumIntegerDigits;
1381     if (max >= 0 && max < newValue) {
1382         fields->properties.maximumIntegerDigits = newValue;
1383     }
1384     fields->properties.minimumIntegerDigits = newValue;
1385     touchNoError();
1386 }
1387 
setMaximumFractionDigits(int32_t newValue)1388 void DecimalFormat::setMaximumFractionDigits(int32_t newValue) {
1389     if (fields == nullptr) { return; }
1390     if (newValue == fields->properties.maximumFractionDigits) { return; }
1391     // cap for backward compatibility, formerly 340, now 999
1392     if (newValue > kMaxIntFracSig) {
1393         newValue = kMaxIntFracSig;
1394     }
1395     // For backwards compatibility, conflicting min/max need to keep the most recent setting.
1396     int32_t min = fields->properties.minimumFractionDigits;
1397     if (min >= 0 && min > newValue) {
1398         fields->properties.minimumFractionDigits = newValue;
1399     }
1400     fields->properties.maximumFractionDigits = newValue;
1401     touchNoError();
1402 }
1403 
setMinimumFractionDigits(int32_t newValue)1404 void DecimalFormat::setMinimumFractionDigits(int32_t newValue) {
1405     if (fields == nullptr) { return; }
1406     if (newValue == fields->properties.minimumFractionDigits) { return; }
1407     // For backwards compatibility, conflicting min/max need to keep the most recent setting.
1408     int32_t max = fields->properties.maximumFractionDigits;
1409     if (max >= 0 && max < newValue) {
1410         fields->properties.maximumFractionDigits = newValue;
1411     }
1412     fields->properties.minimumFractionDigits = newValue;
1413     touchNoError();
1414 }
1415 
getMinimumSignificantDigits() const1416 int32_t DecimalFormat::getMinimumSignificantDigits() const {
1417     // Not much we can do to report an error.
1418     if (fields == nullptr) {
1419         // Fallback to using the default instance of DecimalFormatProperties.
1420         return DecimalFormatProperties::getDefault().minimumSignificantDigits;
1421     }
1422     return fields->exportedProperties.minimumSignificantDigits;
1423 }
1424 
getMaximumSignificantDigits() const1425 int32_t DecimalFormat::getMaximumSignificantDigits() const {
1426     // Not much we can do to report an error.
1427     if (fields == nullptr) {
1428         // Fallback to using the default instance of DecimalFormatProperties.
1429         return DecimalFormatProperties::getDefault().maximumSignificantDigits;
1430     }
1431     return fields->exportedProperties.maximumSignificantDigits;
1432 }
1433 
setMinimumSignificantDigits(int32_t value)1434 void DecimalFormat::setMinimumSignificantDigits(int32_t value) {
1435     if (fields == nullptr) { return; }
1436     if (value == fields->properties.minimumSignificantDigits) { return; }
1437     int32_t max = fields->properties.maximumSignificantDigits;
1438     if (max >= 0 && max < value) {
1439         fields->properties.maximumSignificantDigits = value;
1440     }
1441     fields->properties.minimumSignificantDigits = value;
1442     touchNoError();
1443 }
1444 
setMaximumSignificantDigits(int32_t value)1445 void DecimalFormat::setMaximumSignificantDigits(int32_t value) {
1446     if (fields == nullptr) { return; }
1447     if (value == fields->properties.maximumSignificantDigits) { return; }
1448     int32_t min = fields->properties.minimumSignificantDigits;
1449     if (min >= 0 && min > value) {
1450         fields->properties.minimumSignificantDigits = value;
1451     }
1452     fields->properties.maximumSignificantDigits = value;
1453     touchNoError();
1454 }
1455 
areSignificantDigitsUsed() const1456 UBool DecimalFormat::areSignificantDigitsUsed() const {
1457     const DecimalFormatProperties* dfp;
1458     // Not much we can do to report an error.
1459     if (fields == nullptr) {
1460         // Fallback to using the default instance of DecimalFormatProperties.
1461         dfp = &(DecimalFormatProperties::getDefault());
1462     } else {
1463         dfp = &fields->properties;
1464     }
1465     return dfp->minimumSignificantDigits != -1 || dfp->maximumSignificantDigits != -1;
1466 }
1467 
setSignificantDigitsUsed(UBool useSignificantDigits)1468 void DecimalFormat::setSignificantDigitsUsed(UBool useSignificantDigits) {
1469     if (fields == nullptr) { return; }
1470 
1471     // These are the default values from the old implementation.
1472     if (useSignificantDigits) {
1473         if (fields->properties.minimumSignificantDigits != -1 ||
1474             fields->properties.maximumSignificantDigits != -1) {
1475             return;
1476         }
1477     } else {
1478         if (fields->properties.minimumSignificantDigits == -1 &&
1479             fields->properties.maximumSignificantDigits == -1) {
1480             return;
1481         }
1482     }
1483     int32_t minSig = useSignificantDigits ? 1 : -1;
1484     int32_t maxSig = useSignificantDigits ? 6 : -1;
1485     fields->properties.minimumSignificantDigits = minSig;
1486     fields->properties.maximumSignificantDigits = maxSig;
1487     touchNoError();
1488 }
1489 
setCurrency(const char16_t * theCurrency,UErrorCode & ec)1490 void DecimalFormat::setCurrency(const char16_t* theCurrency, UErrorCode& ec) {
1491     // don't overwrite ec if it's already a failure.
1492     if (U_FAILURE(ec)) { return; }
1493     if (fields == nullptr) {
1494         // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
1495         ec = U_MEMORY_ALLOCATION_ERROR;
1496         return;
1497     }
1498     CurrencyUnit currencyUnit(theCurrency, ec);
1499     if (U_FAILURE(ec)) { return; }
1500     if (!fields->properties.currency.isNull() && fields->properties.currency.getNoError() == currencyUnit) {
1501         return;
1502     }
1503     NumberFormat::setCurrency(theCurrency, ec); // to set field for compatibility
1504     fields->properties.currency = currencyUnit;
1505     // TODO: Set values in fields->symbols, too?
1506     touchNoError();
1507 }
1508 
setCurrency(const char16_t * theCurrency)1509 void DecimalFormat::setCurrency(const char16_t* theCurrency) {
1510     ErrorCode localStatus;
1511     setCurrency(theCurrency, localStatus);
1512 }
1513 
setCurrencyUsage(UCurrencyUsage newUsage,UErrorCode * ec)1514 void DecimalFormat::setCurrencyUsage(UCurrencyUsage newUsage, UErrorCode* ec) {
1515     // don't overwrite ec if it's already a failure.
1516     if (U_FAILURE(*ec)) { return; }
1517     if (fields == nullptr) {
1518         // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
1519         *ec = U_MEMORY_ALLOCATION_ERROR;
1520         return;
1521     }
1522     if (!fields->properties.currencyUsage.isNull() && newUsage == fields->properties.currencyUsage.getNoError()) {
1523         return;
1524     }
1525     fields->properties.currencyUsage = newUsage;
1526     touch(*ec);
1527 }
1528 
getCurrencyUsage() const1529 UCurrencyUsage DecimalFormat::getCurrencyUsage() const {
1530     // CurrencyUsage is not exported, so we have to get it from the input property bag.
1531     // TODO: Should we export CurrencyUsage instead?
1532     if (fields == nullptr || fields->properties.currencyUsage.isNull()) {
1533         return UCURR_USAGE_STANDARD;
1534     }
1535     return fields->properties.currencyUsage.getNoError();
1536 }
1537 
1538 void
formatToDecimalQuantity(double number,DecimalQuantity & output,UErrorCode & status) const1539 DecimalFormat::formatToDecimalQuantity(double number, DecimalQuantity& output, UErrorCode& status) const {
1540     // don't overwrite status if it's already a failure.
1541     if (U_FAILURE(status)) { return; }
1542     if (fields == nullptr) {
1543         // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
1544         status = U_MEMORY_ALLOCATION_ERROR;
1545         return;
1546     }
1547     fields->formatter.formatDouble(number, status).getDecimalQuantity(output, status);
1548 }
1549 
formatToDecimalQuantity(const Formattable & number,DecimalQuantity & output,UErrorCode & status) const1550 void DecimalFormat::formatToDecimalQuantity(const Formattable& number, DecimalQuantity& output,
1551                                             UErrorCode& status) const {
1552     // don't overwrite status if it's already a failure.
1553     if (U_FAILURE(status)) { return; }
1554     if (fields == nullptr) {
1555         // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
1556         status = U_MEMORY_ALLOCATION_ERROR;
1557         return;
1558     }
1559     UFormattedNumberData obj;
1560     number.populateDecimalQuantity(obj.quantity, status);
1561     fields->formatter.formatImpl(&obj, status);
1562     output = std::move(obj.quantity);
1563 }
1564 
toNumberFormatter(UErrorCode & status) const1565 const number::LocalizedNumberFormatter* DecimalFormat::toNumberFormatter(UErrorCode& status) const {
1566     // We sometimes need to return nullptr here (see ICU-20380)
1567     if (U_FAILURE(status)) { return nullptr; }
1568     if (fields == nullptr) {
1569         // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
1570         status = U_MEMORY_ALLOCATION_ERROR;
1571         return nullptr;
1572     }
1573     return &fields->formatter;
1574 }
1575 
1576 /** Rebuilds the formatter object from the property bag. */
touch(UErrorCode & status)1577 void DecimalFormat::touch(UErrorCode& status) {
1578     if (U_FAILURE(status)) {
1579         return;
1580     }
1581     if (fields == nullptr) {
1582         // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
1583         // For regular construction, the caller should have checked the status variable for errors.
1584         // For copy construction, there is unfortunately nothing to report the error, so we need to guard against
1585         // this possible bad state here and set the status to an error.
1586         status = U_MEMORY_ALLOCATION_ERROR;
1587         return;
1588     }
1589 
1590     // In C++, fields->symbols is the source of truth for the locale.
1591     Locale locale = fields->symbols->getLocale();
1592 
1593     // Note: The formatter is relatively cheap to create, and we need it to populate fields->exportedProperties,
1594     // so automatically recompute it here. The parser is a bit more expensive and is not needed until the
1595     // parse method is called, so defer that until needed.
1596     // TODO: Only update the pieces that changed instead of re-computing the whole formatter?
1597 
1598     // Since memory has already been allocated for the formatter, we can move assign a stack-allocated object
1599     // and don't need to call new. (Which is slower and could possibly fail).
1600     fields->formatter = NumberPropertyMapper::create(
1601         fields->properties, *fields->symbols, fields->warehouse, fields->exportedProperties, status
1602     ).locale(locale);
1603 
1604     // Do this after fields->exportedProperties are set up
1605     setupFastFormat();
1606 
1607     // Delete the parsers if they were made previously
1608     delete fields->atomicParser.exchange(nullptr);
1609     delete fields->atomicCurrencyParser.exchange(nullptr);
1610 
1611     // In order for the getters to work, we need to populate some fields in NumberFormat.
1612     NumberFormat::setCurrency(fields->exportedProperties.currency.get(status).getISOCurrency(), status);
1613     NumberFormat::setMaximumIntegerDigits(fields->exportedProperties.maximumIntegerDigits);
1614     NumberFormat::setMinimumIntegerDigits(fields->exportedProperties.minimumIntegerDigits);
1615     NumberFormat::setMaximumFractionDigits(fields->exportedProperties.maximumFractionDigits);
1616     NumberFormat::setMinimumFractionDigits(fields->exportedProperties.minimumFractionDigits);
1617     // fImpl->properties, not fields->exportedProperties, since this information comes from the pattern:
1618     NumberFormat::setGroupingUsed(fields->properties.groupingUsed);
1619 }
1620 
touchNoError()1621 void DecimalFormat::touchNoError() {
1622     UErrorCode localStatus = U_ZERO_ERROR;
1623     touch(localStatus);
1624 }
1625 
setPropertiesFromPattern(const UnicodeString & pattern,int32_t ignoreRounding,UErrorCode & status)1626 void DecimalFormat::setPropertiesFromPattern(const UnicodeString& pattern, int32_t ignoreRounding,
1627                                              UErrorCode& status) {
1628     if (U_SUCCESS(status)) {
1629         // Cast workaround to get around putting the enum in the public header file
1630         auto actualIgnoreRounding = static_cast<IgnoreRounding>(ignoreRounding);
1631         PatternParser::parseToExistingProperties(pattern, fields->properties,  actualIgnoreRounding, status);
1632     }
1633 }
1634 
getParser(UErrorCode & status) const1635 const numparse::impl::NumberParserImpl* DecimalFormat::getParser(UErrorCode& status) const {
1636     // TODO: Move this into umutex.h? (similar logic also in numrange_fluent.cpp)
1637     // See ICU-20146
1638 
1639     if (U_FAILURE(status)) {
1640         return nullptr;
1641     }
1642 
1643     // First try to get the pre-computed parser
1644     auto* ptr = fields->atomicParser.load();
1645     if (ptr != nullptr) {
1646         return ptr;
1647     }
1648 
1649     // Try computing the parser on our own
1650     auto* temp = NumberParserImpl::createParserFromProperties(fields->properties, *fields->symbols, false, status);
1651     if (U_FAILURE(status)) {
1652         return nullptr;
1653     }
1654     if (temp == nullptr) {
1655         status = U_MEMORY_ALLOCATION_ERROR;
1656         return nullptr;
1657     }
1658 
1659     // Note: ptr starts as nullptr; during compare_exchange,
1660     // it is set to what is actually stored in the atomic
1661     // if another thread beat us to computing the parser object.
1662     auto* nonConstThis = const_cast<DecimalFormat*>(this);
1663     if (!nonConstThis->fields->atomicParser.compare_exchange_strong(ptr, temp)) {
1664         // Another thread beat us to computing the parser
1665         delete temp;
1666         return ptr;
1667     } else {
1668         // Our copy of the parser got stored in the atomic
1669         return temp;
1670     }
1671 }
1672 
getCurrencyParser(UErrorCode & status) const1673 const numparse::impl::NumberParserImpl* DecimalFormat::getCurrencyParser(UErrorCode& status) const {
1674     if (U_FAILURE(status)) { return nullptr; }
1675 
1676     // First try to get the pre-computed parser
1677     auto* ptr = fields->atomicCurrencyParser.load();
1678     if (ptr != nullptr) {
1679         return ptr;
1680     }
1681 
1682     // Try computing the parser on our own
1683     auto* temp = NumberParserImpl::createParserFromProperties(fields->properties, *fields->symbols, true, status);
1684     if (temp == nullptr) {
1685         status = U_MEMORY_ALLOCATION_ERROR;
1686         // although we may still dereference, call sites should be guarded
1687     }
1688 
1689     // Note: ptr starts as nullptr; during compare_exchange, it is set to what is actually stored in the
1690     // atomic if another thread beat us to computing the parser object.
1691     auto* nonConstThis = const_cast<DecimalFormat*>(this);
1692     if (!nonConstThis->fields->atomicCurrencyParser.compare_exchange_strong(ptr, temp)) {
1693         // Another thread beat us to computing the parser
1694         delete temp;
1695         return ptr;
1696     } else {
1697         // Our copy of the parser got stored in the atomic
1698         return temp;
1699     }
1700 }
1701 
1702 void
fieldPositionHelper(const number::FormattedNumber & formatted,FieldPosition & fieldPosition,int32_t offset,UErrorCode & status)1703 DecimalFormat::fieldPositionHelper(const number::FormattedNumber& formatted, FieldPosition& fieldPosition,
1704                                    int32_t offset, UErrorCode& status) {
1705     if (U_FAILURE(status)) { return; }
1706     // always return first occurrence:
1707     fieldPosition.setBeginIndex(0);
1708     fieldPosition.setEndIndex(0);
1709     bool found = formatted.nextFieldPosition(fieldPosition, status);
1710     if (found && offset != 0) {
1711         FieldPositionOnlyHandler fpoh(fieldPosition);
1712         fpoh.shiftLast(offset);
1713     }
1714 }
1715 
1716 void
fieldPositionIteratorHelper(const number::FormattedNumber & formatted,FieldPositionIterator * fpi,int32_t offset,UErrorCode & status)1717 DecimalFormat::fieldPositionIteratorHelper(const number::FormattedNumber& formatted, FieldPositionIterator* fpi,
1718                                            int32_t offset, UErrorCode& status) {
1719     if (U_SUCCESS(status) && (fpi != nullptr)) {
1720         FieldPositionIteratorHandler fpih(fpi, status);
1721         fpih.setShift(offset);
1722         formatted.getAllFieldPositionsImpl(fpih, status);
1723     }
1724 }
1725 
1726 // To debug fast-format, change void(x) to printf(x)
1727 #define trace(x) void(x)
1728 
setupFastFormat()1729 void DecimalFormat::setupFastFormat() {
1730     // Check the majority of properties:
1731     if (!fields->properties.equalsDefaultExceptFastFormat()) {
1732         trace("no fast format: equality\n");
1733         fields->canUseFastFormat = false;
1734         return;
1735     }
1736 
1737     // Now check the remaining properties.
1738     // Nontrivial affixes:
1739     UBool trivialPP = fields->properties.positivePrefixPattern.isEmpty();
1740     UBool trivialPS = fields->properties.positiveSuffixPattern.isEmpty();
1741     UBool trivialNP = fields->properties.negativePrefixPattern.isBogus() || (
1742             fields->properties.negativePrefixPattern.length() == 1 &&
1743             fields->properties.negativePrefixPattern.charAt(0) == u'-');
1744     UBool trivialNS = fields->properties.negativeSuffixPattern.isEmpty();
1745     if (!trivialPP || !trivialPS || !trivialNP || !trivialNS) {
1746         trace("no fast format: affixes\n");
1747         fields->canUseFastFormat = false;
1748         return;
1749     }
1750 
1751     // Grouping (secondary grouping is forbidden in equalsDefaultExceptFastFormat):
1752     bool groupingUsed = fields->properties.groupingUsed;
1753     int32_t groupingSize = fields->properties.groupingSize;
1754     bool unusualGroupingSize = groupingSize > 0 && groupingSize != 3;
1755     const UnicodeString& groupingString = fields->symbols->getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol);
1756     if (groupingUsed && (unusualGroupingSize || groupingString.length() != 1)) {
1757         trace("no fast format: grouping\n");
1758         fields->canUseFastFormat = false;
1759         return;
1760     }
1761 
1762     // Integer length:
1763     int32_t minInt = fields->exportedProperties.minimumIntegerDigits;
1764     int32_t maxInt = fields->exportedProperties.maximumIntegerDigits;
1765     // Fastpath supports up to only 10 digits (length of INT32_MIN)
1766     if (minInt > 10) {
1767         trace("no fast format: integer\n");
1768         fields->canUseFastFormat = false;
1769         return;
1770     }
1771 
1772     // Fraction length (no fraction part allowed in fast path):
1773     int32_t minFrac = fields->exportedProperties.minimumFractionDigits;
1774     if (minFrac > 0) {
1775         trace("no fast format: fraction\n");
1776         fields->canUseFastFormat = false;
1777         return;
1778     }
1779 
1780     // Other symbols:
1781     const UnicodeString& minusSignString = fields->symbols->getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol);
1782     UChar32 codePointZero = fields->symbols->getCodePointZero();
1783     if (minusSignString.length() != 1 || U16_LENGTH(codePointZero) != 1) {
1784         trace("no fast format: symbols\n");
1785         fields->canUseFastFormat = false;
1786         return;
1787     }
1788 
1789     // Good to go!
1790     trace("can use fast format!\n");
1791     fields->canUseFastFormat = true;
1792     fields->fastData.cpZero = static_cast<char16_t>(codePointZero);
1793     fields->fastData.cpGroupingSeparator = groupingUsed && groupingSize == 3 ? groupingString.charAt(0) : 0;
1794     fields->fastData.cpMinusSign = minusSignString.charAt(0);
1795     fields->fastData.minInt = (minInt < 0 || minInt > 127) ? 0 : static_cast<int8_t>(minInt);
1796     fields->fastData.maxInt = (maxInt < 0 || maxInt > 127) ? 127 : static_cast<int8_t>(maxInt);
1797 }
1798 
fastFormatDouble(double input,UnicodeString & output) const1799 bool DecimalFormat::fastFormatDouble(double input, UnicodeString& output) const {
1800     if (!fields->canUseFastFormat) {
1801         return false;
1802     }
1803     if (std::isnan(input)
1804             || std::trunc(input) != input
1805             || input <= INT32_MIN
1806             || input > INT32_MAX) {
1807         return false;
1808     }
1809     doFastFormatInt32(static_cast<int32_t>(input), std::signbit(input), output);
1810     return true;
1811 }
1812 
fastFormatInt64(int64_t input,UnicodeString & output) const1813 bool DecimalFormat::fastFormatInt64(int64_t input, UnicodeString& output) const {
1814     if (!fields->canUseFastFormat) {
1815         return false;
1816     }
1817     if (input <= INT32_MIN || input > INT32_MAX) {
1818         return false;
1819     }
1820     doFastFormatInt32(static_cast<int32_t>(input), input < 0, output);
1821     return true;
1822 }
1823 
doFastFormatInt32(int32_t input,bool isNegative,UnicodeString & output) const1824 void DecimalFormat::doFastFormatInt32(int32_t input, bool isNegative, UnicodeString& output) const {
1825     U_ASSERT(fields->canUseFastFormat);
1826     if (isNegative) {
1827         output.append(fields->fastData.cpMinusSign);
1828         U_ASSERT(input != INT32_MIN);  // handled by callers
1829         input = -input;
1830     }
1831     // Cap at int32_t to make the buffer small and operations fast.
1832     // Longest string: "2,147,483,648" (13 chars in length)
1833     static constexpr int32_t localCapacity = 13;
1834     char16_t localBuffer[localCapacity];
1835     char16_t* ptr = localBuffer + localCapacity;
1836     int8_t group = 0;
1837     for (int8_t i = 0; i < fields->fastData.maxInt && (input != 0 || i < fields->fastData.minInt); i++) {
1838         if (group++ == 3 && fields->fastData.cpGroupingSeparator != 0) {
1839             *(--ptr) = fields->fastData.cpGroupingSeparator;
1840             group = 1;
1841         }
1842         std::div_t res = std::div(input, 10);
1843         *(--ptr) = static_cast<char16_t>(fields->fastData.cpZero + res.rem);
1844         input = res.quot;
1845     }
1846     int32_t len = localCapacity - static_cast<int32_t>(ptr - localBuffer);
1847     output.append(ptr, len);
1848 }
1849 
1850 
1851 #endif /* #if !UCONFIG_NO_FORMATTING */
1852