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