1 // © 2018 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 #include "unicode/utypes.h"
6 #if !UCONFIG_NO_FORMATTING
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
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"
24 #include "number_utils.h"
25 #include "number_utypes.h"
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
;
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)
40 #define UBOOL_TO_BOOL(b) b
44 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DecimalFormat
)
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(
56 CLDR_PATTERN_STYLE_DECIMAL
,
58 setPropertiesFromPattern(patternString
, IGNORE_ROUNDING_IF_CURRENCY
, status
);
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
);
69 DecimalFormat::DecimalFormat(const UnicodeString
& pattern
, DecimalFormatSymbols
* symbolsToAdopt
,
71 : DecimalFormat(symbolsToAdopt
, status
) {
72 if (U_FAILURE(status
)) { return; }
73 setPropertiesFromPattern(pattern
, IGNORE_ROUNDING_IF_CURRENCY
, status
);
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
);
90 setPropertiesFromPattern(pattern
, IGNORE_ROUNDING_IF_CURRENCY
, status
);
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
),
98 if (U_FAILURE(status
)) { return; }
99 fields
->properties
->currencyPluralInfo
.fPtr
.adoptInstead(cpi
.orphan());
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
)) {
110 fields
= new DecimalFormatFields();
111 if (fields
== nullptr) {
112 status
= U_MEMORY_ALLOCATION_ERROR
;
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
);
121 fields
->symbols
.adoptInsteadAndCheckErrorCode(adoptedSymbols
.orphan(), status
);
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()) {
129 status
= U_MEMORY_ALLOCATION_ERROR
;
133 #if UCONFIG_HAVE_PARSEALLINPUT
135 void DecimalFormat::setParseAllInput(UNumberFormatAttributeValue value
) {
136 if (fields
== nullptr) { return; }
137 if (value
== fields
->properties
->parseAllInput
) { return; }
138 fields
->properties
->parseAllInput
= value
;
144 DecimalFormat::setAttribute(UNumberFormatAttribute attr
, int32_t newValue
, UErrorCode
& status
) {
145 if (U_FAILURE(status
)) { return *this; }
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
;
154 case UNUM_LENIENT_PARSE
:
155 setLenient(newValue
!= 0);
158 case UNUM_PARSE_INT_ONLY
:
159 setParseIntegerOnly(newValue
!= 0);
162 case UNUM_GROUPING_USED
:
163 setGroupingUsed(newValue
!= 0);
166 case UNUM_DECIMAL_ALWAYS_SHOWN
:
167 setDecimalSeparatorAlwaysShown(newValue
!= 0);
170 case UNUM_MAX_INTEGER_DIGITS
:
171 setMaximumIntegerDigits(newValue
);
174 case UNUM_MIN_INTEGER_DIGITS
:
175 setMinimumIntegerDigits(newValue
);
178 case UNUM_INTEGER_DIGITS
:
179 setMinimumIntegerDigits(newValue
);
180 setMaximumIntegerDigits(newValue
);
183 case UNUM_MAX_FRACTION_DIGITS
:
184 setMaximumFractionDigits(newValue
);
187 case UNUM_MIN_FRACTION_DIGITS
:
188 setMinimumFractionDigits(newValue
);
191 case UNUM_FRACTION_DIGITS
:
192 setMinimumFractionDigits(newValue
);
193 setMaximumFractionDigits(newValue
);
196 case UNUM_SIGNIFICANT_DIGITS_USED
:
197 setSignificantDigitsUsed(newValue
!= 0);
200 case UNUM_MAX_SIGNIFICANT_DIGITS
:
201 setMaximumSignificantDigits(newValue
);
204 case UNUM_MIN_SIGNIFICANT_DIGITS
:
205 setMinimumSignificantDigits(newValue
);
208 case UNUM_MULTIPLIER
:
209 setMultiplier(newValue
);
213 setMultiplierScale(newValue
);
216 case UNUM_GROUPING_SIZE
:
217 setGroupingSize(newValue
);
220 case UNUM_ROUNDING_MODE
:
221 setRoundingMode((DecimalFormat::ERoundingMode
) newValue
);
224 case UNUM_FORMAT_WIDTH
:
225 setFormatWidth(newValue
);
228 case UNUM_PADDING_POSITION
:
229 /** The position at which padding will take place. */
230 setPadPosition((DecimalFormat::EPadPosition
) newValue
);
233 case UNUM_SECONDARY_GROUPING_SIZE
:
234 setSecondaryGroupingSize(newValue
);
237 #if UCONFIG_HAVE_PARSEALLINPUT
238 case UNUM_PARSE_ALL_INPUT
:
239 setParseAllInput((UNumberFormatAttributeValue
) newValue
);
243 case UNUM_PARSE_NO_EXPONENT
:
244 setParseNoExponent((UBool
) newValue
);
247 case UNUM_PARSE_DECIMAL_MARK_REQUIRED
:
248 setDecimalPatternMatchRequired((UBool
) newValue
);
251 case UNUM_CURRENCY_USAGE
:
252 setCurrencyUsage((UCurrencyUsage
) newValue
, &status
);
255 case UNUM_MINIMUM_GROUPING_DIGITS
:
256 setMinimumGroupingDigits(newValue
);
259 case UNUM_PARSE_CASE_SENSITIVE
:
260 setParseCaseSensitive(static_cast<UBool
>(newValue
));
263 case UNUM_SIGN_ALWAYS_SHOWN
:
264 setSignAlwaysShown(static_cast<UBool
>(newValue
));
267 case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS
:
268 setFormatFailIfMoreThanMaxDigits(static_cast<UBool
>(newValue
));
271 case UNUM_FORMAT_WITH_FULL_PRECISION
: // Apple addition for <rdar://problem/39240173>
273 bool boolVal
= UBOOL_TO_BOOL(static_cast<UBool
>(newValue
));
274 if (boolVal
!= fields
->properties
->formatFullPrecision
) {
275 fields
->properties
->formatFullPrecision
= boolVal
;
282 status
= U_UNSUPPORTED_ERROR
;
288 int32_t DecimalFormat::getAttribute(UNumberFormatAttribute attr
, UErrorCode
& status
) const {
289 if (U_FAILURE(status
)) { return -1; }
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
;
298 case UNUM_LENIENT_PARSE
:
301 case UNUM_PARSE_INT_ONLY
:
302 return isParseIntegerOnly();
304 case UNUM_GROUPING_USED
:
305 return isGroupingUsed();
307 case UNUM_DECIMAL_ALWAYS_SHOWN
:
308 return isDecimalSeparatorAlwaysShown();
310 case UNUM_MAX_INTEGER_DIGITS
:
311 return getMaximumIntegerDigits();
313 case UNUM_MIN_INTEGER_DIGITS
:
314 return getMinimumIntegerDigits();
316 case UNUM_INTEGER_DIGITS
:
317 // TBD: what should this return?
318 return getMinimumIntegerDigits();
320 case UNUM_MAX_FRACTION_DIGITS
:
321 return getMaximumFractionDigits();
323 case UNUM_MIN_FRACTION_DIGITS
:
324 return getMinimumFractionDigits();
326 case UNUM_FRACTION_DIGITS
:
327 // TBD: what should this return?
328 return getMinimumFractionDigits();
330 case UNUM_SIGNIFICANT_DIGITS_USED
:
331 return areSignificantDigitsUsed();
333 case UNUM_MAX_SIGNIFICANT_DIGITS
:
334 return getMaximumSignificantDigits();
336 case UNUM_MIN_SIGNIFICANT_DIGITS
:
337 return getMinimumSignificantDigits();
339 case UNUM_MULTIPLIER
:
340 return getMultiplier();
343 return getMultiplierScale();
345 case UNUM_GROUPING_SIZE
:
346 return getGroupingSize();
348 case UNUM_ROUNDING_MODE
:
349 return getRoundingMode();
351 case UNUM_FORMAT_WIDTH
:
352 return getFormatWidth();
354 case UNUM_PADDING_POSITION
:
355 return getPadPosition();
357 case UNUM_SECONDARY_GROUPING_SIZE
:
358 return getSecondaryGroupingSize();
360 case UNUM_PARSE_NO_EXPONENT
:
361 return isParseNoExponent();
363 case UNUM_PARSE_DECIMAL_MARK_REQUIRED
:
364 return isDecimalPatternMatchRequired();
366 case UNUM_CURRENCY_USAGE
:
367 return getCurrencyUsage();
369 case UNUM_MINIMUM_GROUPING_DIGITS
:
370 return getMinimumGroupingDigits();
372 case UNUM_PARSE_CASE_SENSITIVE
:
373 return isParseCaseSensitive();
375 case UNUM_SIGN_ALWAYS_SHOWN
:
376 return isSignAlwaysShown();
378 case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS
:
379 return isFormatFailIfMoreThanMaxDigits();
381 case UNUM_FORMAT_WITH_FULL_PRECISION
: // Apple addition for <rdar://problem/39240173>
382 return (UBool
)fields
->properties
->formatFullPrecision
;
385 status
= U_UNSUPPORTED_ERROR
;
389 return -1; /* undefined */
392 void DecimalFormat::setGroupingUsed(UBool enabled
) {
393 if (fields
== nullptr) {
396 if (UBOOL_TO_BOOL(enabled
) == fields
->properties
->groupingUsed
) { return; }
397 NumberFormat::setGroupingUsed(enabled
); // to set field for compatibility
398 fields
->properties
->groupingUsed
= enabled
;
402 void DecimalFormat::setParseIntegerOnly(UBool value
) {
403 if (fields
== nullptr) {
406 if (UBOOL_TO_BOOL(value
) == fields
->properties
->parseIntegerOnly
) { return; }
407 NumberFormat::setParseIntegerOnly(value
); // to set field for compatibility
408 fields
->properties
->parseIntegerOnly
= value
;
412 void DecimalFormat::setLenient(UBool enable
) {
413 if (fields
== nullptr) {
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
;
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
);
432 DecimalFormat::DecimalFormat(const UnicodeString
& pattern
, const DecimalFormatSymbols
& symbols
,
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.
442 status
= U_MEMORY_ALLOCATION_ERROR
;
445 fields
->symbols
.adoptInstead(dfs
.orphan());
446 setPropertiesFromPattern(pattern
, IGNORE_ROUNDING_IF_CURRENCY
, status
);
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) {
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.
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()) {
478 DecimalFormat
& DecimalFormat::operator=(const DecimalFormat
& rhs
) {
479 // guard against self-assignment
483 // Make sure both objects are valid.
484 if (fields
== nullptr || rhs
.fields
== nullptr) {
485 return *this; // unfortunately, no way to report an error.
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.
498 fields
->symbols
.adoptInstead(dfs
.orphan());
504 DecimalFormat::~DecimalFormat() {
505 if (fields
== nullptr) { return; }
507 delete fields
->atomicParser
.exchange(nullptr);
508 delete fields
->atomicCurrencyParser
.exchange(nullptr);
512 Format
* DecimalFormat::clone() const {
513 // can only clone valid objects.
514 if (fields
== nullptr) {
517 LocalPointer
<DecimalFormat
> df(new DecimalFormat(*this));
518 if (df
.isValid() && df
->fields
!= nullptr) {
524 UBool
DecimalFormat::operator==(const Format
& other
) const {
525 auto* otherDF
= dynamic_cast<const DecimalFormat
*>(&other
);
526 if (otherDF
== nullptr) {
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) {
534 return *fields
->properties
== *otherDF
->fields
->properties
&& *fields
->symbols
== *otherDF
->fields
->symbols
;
537 UnicodeString
& DecimalFormat::format(double number
, UnicodeString
& appendTo
, FieldPosition
& pos
) const {
538 if (fields
== nullptr) {
539 appendTo
.setToBogus();
542 if (pos
.getField() == FieldPosition::DONT_CARE
&& fastFormatDouble(number
, appendTo
)) {
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
);
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.
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();
564 if (pos
.getField() == FieldPosition::DONT_CARE
&& fastFormatDouble(number
, appendTo
)) {
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
);
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.
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();
586 if (posIter
== nullptr && fastFormatDouble(number
, appendTo
)) {
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
);
596 UnicodeString
& DecimalFormat::format(int32_t number
, UnicodeString
& appendTo
, FieldPosition
& pos
) const {
597 return format(static_cast<int64_t> (number
), appendTo
, pos
);
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
);
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
);
611 UnicodeString
& DecimalFormat::format(int64_t number
, UnicodeString
& appendTo
, FieldPosition
& pos
) const {
612 if (fields
== nullptr) {
613 appendTo
.setToBogus();
616 if (pos
.getField() == FieldPosition::DONT_CARE
&& fastFormatInt64(number
, appendTo
)) {
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
);
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.
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();
638 if (pos
.getField() == FieldPosition::DONT_CARE
&& fastFormatInt64(number
, appendTo
)) {
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
);
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.
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();
660 if (posIter
== nullptr && fastFormatInt64(number
, appendTo
)) {
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
);
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.
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();
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
);
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.
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();
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
);
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.
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();
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
);
726 void DecimalFormat::parse(const UnicodeString
& text
, Formattable
& output
,
727 ParsePosition
& parsePosition
) const {
728 if (fields
== nullptr) {
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());
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.
748 parser
->parse(text
, startIndex
, true, result
, status
);
749 if (U_FAILURE(status
)) {
750 return; // unfortunately no way to report back the error.
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());
757 parsePosition
.setErrorIndex(startIndex
+ result
.charEnd
);
761 CurrencyAmount
* DecimalFormat::parseCurrency(const UnicodeString
& text
, ParsePosition
& parsePosition
) const {
762 if (fields
== nullptr) {
765 if (parsePosition
.getIndex() < 0 || parsePosition
.getIndex() >= text
.length()) {
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
)) {
778 parser
->parse(text
, startIndex
, true, result
, status
);
779 if (U_FAILURE(status
)) {
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
)) {
792 return currencyAmount
.orphan();
794 parsePosition
.setErrorIndex(startIndex
+ result
.charEnd
);
799 const DecimalFormatSymbols
* DecimalFormat::getDecimalFormatSymbols(void) const {
800 if (fields
== nullptr) {
803 return fields
->symbols
.getAlias();
806 void DecimalFormat::adoptDecimalFormatSymbols(DecimalFormatSymbols
* symbolsToAdopt
) {
807 if (symbolsToAdopt
== nullptr) {
808 return; // do not allow caller to set fields->symbols to NULL
810 // we must take ownership of symbolsToAdopt, even in a failure case.
811 LocalPointer
<DecimalFormatSymbols
> dfs(symbolsToAdopt
);
812 if (fields
== nullptr) {
815 fields
->symbols
.adoptInstead(dfs
.orphan());
819 void DecimalFormat::setDecimalFormatSymbols(const DecimalFormatSymbols
& symbols
) {
820 if (fields
== nullptr) {
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.
832 fields
->symbols
.adoptInstead(dfs
.orphan());
836 const CurrencyPluralInfo
* DecimalFormat::getCurrencyPluralInfo(void) const {
837 if (fields
== nullptr) {
840 return fields
->properties
->currencyPluralInfo
.fPtr
.getAlias();
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) {
850 fields
->properties
->currencyPluralInfo
.fPtr
.adoptInstead(cpi
.orphan());
854 void DecimalFormat::setCurrencyPluralInfo(const CurrencyPluralInfo
& info
) {
855 if (fields
== nullptr) {
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());
862 *fields
->properties
->currencyPluralInfo
.fPtr
= info
; // copy-assignment operator
867 UnicodeString
& DecimalFormat::getPositivePrefix(UnicodeString
& result
) const {
868 if (fields
== nullptr) {
872 UErrorCode status
= U_ZERO_ERROR
;
873 fields
->formatter
->getAffixImpl(true, false, result
, status
);
874 if (U_FAILURE(status
)) { result
.setToBogus(); }
878 void DecimalFormat::setPositivePrefix(const UnicodeString
& newValue
) {
879 if (fields
== nullptr) {
882 if (newValue
== fields
->properties
->positivePrefix
) { return; }
883 fields
->properties
->positivePrefix
= newValue
;
887 UnicodeString
& DecimalFormat::getNegativePrefix(UnicodeString
& result
) const {
888 if (fields
== nullptr) {
892 UErrorCode status
= U_ZERO_ERROR
;
893 fields
->formatter
->getAffixImpl(true, true, result
, status
);
894 if (U_FAILURE(status
)) { result
.setToBogus(); }
898 void DecimalFormat::setNegativePrefix(const UnicodeString
& newValue
) {
899 if (fields
== nullptr) {
902 if (newValue
== fields
->properties
->negativePrefix
) { return; }
903 fields
->properties
->negativePrefix
= newValue
;
907 UnicodeString
& DecimalFormat::getPositiveSuffix(UnicodeString
& result
) const {
908 if (fields
== nullptr) {
912 UErrorCode status
= U_ZERO_ERROR
;
913 fields
->formatter
->getAffixImpl(false, false, result
, status
);
914 if (U_FAILURE(status
)) { result
.setToBogus(); }
918 void DecimalFormat::setPositiveSuffix(const UnicodeString
& newValue
) {
919 if (fields
== nullptr) {
922 if (newValue
== fields
->properties
->positiveSuffix
) { return; }
923 fields
->properties
->positiveSuffix
= newValue
;
927 UnicodeString
& DecimalFormat::getNegativeSuffix(UnicodeString
& result
) const {
928 if (fields
== nullptr) {
932 UErrorCode status
= U_ZERO_ERROR
;
933 fields
->formatter
->getAffixImpl(false, true, result
, status
);
934 if (U_FAILURE(status
)) { result
.setToBogus(); }
938 void DecimalFormat::setNegativeSuffix(const UnicodeString
& newValue
) {
939 if (fields
== nullptr) {
942 if (newValue
== fields
->properties
->negativeSuffix
) { return; }
943 fields
->properties
->negativeSuffix
= newValue
;
947 UBool
DecimalFormat::isSignAlwaysShown() const {
948 // Not much we can do to report an error.
949 if (fields
== nullptr) {
950 return DecimalFormatProperties::getDefault().signAlwaysShown
;
952 return fields
->properties
->signAlwaysShown
;
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
;
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());
969 dfp
= fields
->properties
.getAlias();
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
));
980 void DecimalFormat::setMultiplier(int32_t multiplier
) {
981 if (fields
== nullptr) {
984 if (multiplier
== 0) {
985 multiplier
= 1; // one being the benign default value for a multiplier.
988 // Try to convert to a magnitude multiplier first
990 int value
= multiplier
;
993 int temp
= value
/ 10;
994 if (temp
* 10 != value
) {
1001 fields
->properties
->magnitudeMultiplier
= delta
;
1002 fields
->properties
->multiplier
= 1;
1004 fields
->properties
->magnitudeMultiplier
= 0;
1005 fields
->properties
->multiplier
= multiplier
;
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
;
1016 return fields
->properties
->multiplierScale
;
1019 void DecimalFormat::setMultiplierScale(int32_t newValue
) {
1020 if (fields
== nullptr) { return; }
1021 if (newValue
== fields
->properties
->multiplierScale
) { return; }
1022 fields
->properties
->multiplierScale
= newValue
;
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
;
1032 return fields
->exportedProperties
->roundingIncrement
;
1035 void DecimalFormat::setRoundingIncrement(double newValue
) {
1036 if (fields
== nullptr) { return; }
1037 if (newValue
== fields
->properties
->roundingIncrement
) { return; }
1038 fields
->properties
->roundingIncrement
= newValue
;
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());
1048 // UNumberFormatRoundingMode and ERoundingMode have the same values.
1049 return static_cast<ERoundingMode
>(fields
->exportedProperties
->roundingMode
.getNoError());
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()) {
1058 NumberFormat::setMaximumIntegerDigits(roundingMode
); // to set field for compatibility
1059 fields
->properties
->roundingMode
= uRoundingMode
;
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
;
1069 return fields
->properties
->formatWidth
;
1072 void DecimalFormat::setFormatWidth(int32_t width
) {
1073 if (fields
== nullptr) { return; }
1074 if (width
== fields
->properties
->formatWidth
) { return; }
1075 fields
->properties
->formatWidth
= width
;
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};
1084 return fields
->properties
->padString
;
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));
1094 fields
->properties
->padString
.setToBogus();
1099 EPadPosition
DecimalFormat::getPadPosition(void) const {
1100 if (fields
== nullptr || fields
->properties
->padPosition
.isNull()) {
1101 return EPadPosition::kPadBeforePrefix
;
1103 // UNumberFormatPadPosition and EPadPosition have the same values.
1104 return static_cast<EPadPosition
>(fields
->properties
->padPosition
.getNoError());
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()) {
1114 fields
->properties
->padPosition
= uPadPos
;
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);
1124 return (fields
->properties
->minimumExponentDigits
!= -1);
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;
1134 fields
->properties
->minimumExponentDigits
= -1;
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
);
1145 return static_cast<int8_t>(fields
->properties
->minimumExponentDigits
);
1148 void DecimalFormat::setMinimumExponentDigits(int8_t minExpDig
) {
1149 if (fields
== nullptr) { return; }
1150 if (minExpDig
== fields
->properties
->minimumExponentDigits
) { return; }
1151 fields
->properties
->minimumExponentDigits
= minExpDig
;
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
;
1161 return fields
->properties
->exponentSignAlwaysShown
;
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
;
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
;
1178 groupingSize
= fields
->properties
->groupingSize
;
1180 if (groupingSize
< 0) {
1183 return groupingSize
;
1186 void DecimalFormat::setGroupingSize(int32_t newValue
) {
1187 if (fields
== nullptr) { return; }
1188 if (newValue
== fields
->properties
->groupingSize
) { return; }
1189 fields
->properties
->groupingSize
= newValue
;
1193 int32_t DecimalFormat::getSecondaryGroupingSize(void) const {
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
;
1200 grouping2
= fields
->properties
->secondaryGroupingSize
;
1202 if (grouping2
< 0) {
1208 void DecimalFormat::setSecondaryGroupingSize(int32_t newValue
) {
1209 if (fields
== nullptr) { return; }
1210 if (newValue
== fields
->properties
->secondaryGroupingSize
) { return; }
1211 fields
->properties
->secondaryGroupingSize
= newValue
;
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
;
1221 return fields
->properties
->minimumGroupingDigits
;
1224 void DecimalFormat::setMinimumGroupingDigits(int32_t newValue
) {
1225 if (fields
== nullptr) { return; }
1226 if (newValue
== fields
->properties
->minimumGroupingDigits
) { return; }
1227 fields
->properties
->minimumGroupingDigits
= newValue
;
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
;
1237 return fields
->properties
->decimalSeparatorAlwaysShown
;
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
;
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
;
1253 return fields
->properties
->decimalPatternMatchRequired
;
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
;
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
;
1269 return fields
->properties
->parseNoExponent
;
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
;
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
;
1285 return fields
->properties
->parseCaseSensitive
;
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
;
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
;
1301 return fields
->properties
->formatFailIfMoreThanMaxDigits
;
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
;
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();
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
));
1332 tprops
.minimumFractionDigits
= fields
->exportedProperties
->minimumFractionDigits
;
1333 tprops
.maximumFractionDigits
= fields
->exportedProperties
->maximumFractionDigits
;
1334 tprops
.roundingIncrement
= fields
->exportedProperties
->roundingIncrement
;
1336 result
= PatternStringUtils::propertiesToPatternString(tprops
, localStatus
);
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();
1346 ErrorCode localStatus
;
1347 result
= toPattern(result
);
1348 result
= PatternStringUtils::convertLocalized(result
, *fields
->symbols
, true, localStatus
);
1352 void DecimalFormat::applyPattern(const UnicodeString
& pattern
, UParseError
&, UErrorCode
& status
) {
1353 // TODO: What is parseError for?
1354 applyPattern(pattern
, status
);
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
;
1365 setPropertiesFromPattern(pattern
, IGNORE_ROUNDING_NEVER
, status
);
1369 void DecimalFormat::applyLocalizedPattern(const UnicodeString
& localizedPattern
, UParseError
&,
1370 UErrorCode
& status
) {
1371 // TODO: What is parseError for?
1372 applyLocalizedPattern(localizedPattern
, status
);
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
;
1383 UnicodeString pattern
= PatternStringUtils::convertLocalized(
1384 localizedPattern
, *fields
->symbols
, false, status
);
1385 applyPattern(pattern
, status
);
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
;
1396 fields
->properties
->maximumIntegerDigits
= newValue
;
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
;
1408 fields
->properties
->minimumIntegerDigits
= newValue
;
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) {
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
;
1424 fields
->properties
->maximumFractionDigits
= newValue
;
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
;
1436 fields
->properties
->minimumFractionDigits
= newValue
;
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
;
1446 return fields
->exportedProperties
->minimumSignificantDigits
;
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
;
1455 return fields
->exportedProperties
->maximumSignificantDigits
;
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
;
1465 fields
->properties
->minimumSignificantDigits
= value
;
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
;
1476 fields
->properties
->maximumSignificantDigits
= value
;
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());
1487 dfp
= fields
->properties
.getAlias();
1489 return dfp
->minimumSignificantDigits
!= -1 || dfp
->maximumSignificantDigits
!= -1;
1492 void DecimalFormat::setSignificantDigitsUsed(UBool useSignificantDigits
) {
1493 if (fields
== nullptr) { return; }
1495 // These are the default values from the old implementation.
1496 if (useSignificantDigits
) {
1497 if (fields
->properties
->minimumSignificantDigits
!= -1 ||
1498 fields
->properties
->maximumSignificantDigits
!= -1) {
1502 if (fields
->properties
->minimumSignificantDigits
== -1 &&
1503 fields
->properties
->maximumSignificantDigits
== -1) {
1507 int32_t minSig
= useSignificantDigits
? 1 : -1;
1508 int32_t maxSig
= useSignificantDigits
? 6 : -1;
1509 fields
->properties
->minimumSignificantDigits
= minSig
;
1510 fields
->properties
->maximumSignificantDigits
= maxSig
;
1514 // Group-set several settings used for numbers in date formats. Apple rdar://50064762
1516 // setGroupingUsed(FALSE);
1517 // setDecimalSeparatorAlwaysShown(FALSE);
1518 // setParseIntegerOnly(TRUE);
1519 // setMinimumFractionDigits(0);
1520 void DecimalFormat::setDateSettings(void) {
1521 if (fields
== nullptr) {
1524 UBool didChange
= FALSE
;
1526 if (fields
->properties
->groupingUsed
) {
1527 NumberFormat::setGroupingUsed(FALSE
); // to set field for compatibility
1528 fields
->properties
->groupingUsed
= false;
1532 if (fields
->properties
->decimalSeparatorAlwaysShown
) {
1533 fields
->properties
->decimalSeparatorAlwaysShown
= false;
1537 if (!fields
->properties
->parseIntegerOnly
) {
1538 NumberFormat::setParseIntegerOnly(TRUE
); // to set field for compatibility
1539 fields
->properties
->parseIntegerOnly
= true;
1543 if (fields
->properties
->minimumFractionDigits
!= 0) {
1544 fields
->properties
->minimumFractionDigits
= 0;
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
;
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) {
1568 theCurrency
= localeCurr
;
1572 CurrencyUnit
currencyUnit(theCurrency
, ec
);
1573 if (U_FAILURE(ec
)) { return; }
1574 if (!fields
->properties
->currency
.isNull() && fields
->properties
->currency
.getNoError() == currencyUnit
) {
1577 NumberFormat::setCurrency(theCurrency
, ec
); // to set field for compatibility
1578 fields
->properties
->currency
= currencyUnit
;
1579 // TODO: Set values in fields->symbols, too?
1583 void DecimalFormat::setCurrency(const char16_t* theCurrency
) {
1584 ErrorCode localStatus
;
1585 setCurrency(theCurrency
, localStatus
);
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
;
1596 if (!fields
->properties
->currencyUsage
.isNull() && newUsage
== fields
->properties
->currencyUsage
.getNoError()) {
1599 fields
->properties
->currencyUsage
= newUsage
;
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
;
1609 return fields
->properties
->currencyUsage
.getNoError();
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
;
1621 fields
->formatter
->formatDouble(number
, status
).getDecimalQuantity(output
, status
);
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
;
1633 UFormattedNumberData obj
;
1634 number
.populateDecimalQuantity(obj
.quantity
, status
);
1635 fields
->formatter
->formatImpl(&obj
, status
);
1636 output
= std::move(obj
.quantity
);
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
;
1647 return &*fields
->formatter
;
1650 const number::LocalizedNumberFormatter
& DecimalFormat::toNumberFormatter() const {
1651 UErrorCode localStatus
= U_ZERO_ERROR
;
1652 return *toNumberFormatter(localStatus
);
1655 // Apple <rdar://problem/49955427>
1656 void DecimalFormat::setDFSShallowCopy(UBool shallow
) {
1657 if (fields
!= nullptr && fields
->formatter
!= nullptr) {
1658 fields
->formatter
->setDFSShallowCopy(shallow
);
1662 /** Rebuilds the formatter object from the property bag. */
1663 void DecimalFormat::touch(UErrorCode
& status
) {
1664 if (U_FAILURE(status
)) {
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
;
1676 // In C++, fields->symbols is the source of truth for the locale.
1677 Locale locale
= fields
->symbols
->getLocale();
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?
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(
1690 // Do this after fields->exportedProperties are set up
1693 // Delete the parsers if they were made previously
1694 delete fields
->atomicParser
.exchange(nullptr);
1695 delete fields
->atomicCurrencyParser
.exchange(nullptr);
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", ...)
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
);
1721 void DecimalFormat::touchNoError() {
1722 UErrorCode localStatus
= U_ZERO_ERROR
;
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
);
1735 const numparse::impl::NumberParserImpl
* DecimalFormat::getParser(UErrorCode
& status
) const {
1736 // TODO: Move this into umutex.h? (similar logic also in numrange_fluent.cpp)
1739 if (U_FAILURE(status
)) {
1743 // First try to get the pre-computed parser
1744 auto* ptr
= fields
->atomicParser
.load();
1745 if (ptr
!= nullptr) {
1749 // Try computing the parser on our own
1750 auto* temp
= NumberParserImpl::createParserFromProperties(*fields
->properties
, *fields
->symbols
, false, status
);
1751 if (U_FAILURE(status
)) {
1754 if (temp
== nullptr) {
1755 status
= U_MEMORY_ALLOCATION_ERROR
;
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
1768 // Our copy of the parser got stored in the atomic
1773 const numparse::impl::NumberParserImpl
* DecimalFormat::getCurrencyParser(UErrorCode
& status
) const {
1774 if (U_FAILURE(status
)) { return nullptr; }
1776 // First try to get the pre-computed parser
1777 auto* ptr
= fields
->atomicCurrencyParser
.load();
1778 if (ptr
!= nullptr) {
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
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
1797 // Our copy of the parser got stored in the atomic
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
);
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
);
1826 // To debug fast-format, change void(x) to printf(x)
1827 #define trace(x) void(x)
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;
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;
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;
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)
1867 trace("no fast format: integer\n");
1868 fields
->canUseFastFormat
= false;
1872 // Fraction length (no fraction part allowed in fast path):
1873 int32_t minFrac
= fields
->exportedProperties
->minimumFractionDigits
;
1875 trace("no fast format: fraction\n");
1876 fields
->canUseFastFormat
= false;
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;
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
);
1899 bool DecimalFormat::fastFormatDouble(double input
, UnicodeString
& output
) const {
1900 if (!fields
->canUseFastFormat
) {
1903 if (std::isnan(input
)
1904 || std::trunc(input
) != input
1905 || input
<= INT32_MIN
1906 || input
> INT32_MAX
) {
1909 doFastFormatInt32(static_cast<int32_t>(input
), std::signbit(input
), output
);
1913 bool DecimalFormat::fastFormatInt64(int64_t input
, UnicodeString
& output
) const {
1914 if (!fields
->canUseFastFormat
) {
1917 if (input
<= INT32_MIN
|| input
> INT32_MAX
) {
1920 doFastFormatInt32(static_cast<int32_t>(input
), input
< 0, output
);
1924 void DecimalFormat::doFastFormatInt32(int32_t input
, bool isNegative
, UnicodeString
& output
) const {
1925 U_ASSERT(fields
->canUseFastFormat
);
1927 output
.append(fields
->fastData
.cpMinusSign
);
1928 U_ASSERT(input
!= INT32_MIN
); // handled by callers
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
;
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
;
1943 std::div_t res
= std::div(input
, 10);
1944 *(--ptr
) = static_cast<char16_t>(fields
->fastData
.cpZero
+ res
.rem
);
1947 int32_t len
= localCapacity
- static_cast<int32_t>(ptr
- localBuffer
);
1948 output
.append(ptr
, len
);
1952 #endif /* #if !UCONFIG_NO_FORMATTING */