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