2 *******************************************************************************
3 * Copyright (C) 1997-2014, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 *******************************************************************************
9 * Modification History:
11 * Date Name Description
12 * 02/19/97 aliu Converted from java.
13 * 03/18/97 clhuang Implemented with C++ APIs.
14 * 04/17/97 aliu Enlarged MAX_INTEGER_DIGITS to fully accomodate the
15 * largest double, by default.
16 * Changed DigitCount to int per code review.
17 * 07/20/98 stephen Changed operator== to check for grouping
18 * Changed setMaxIntegerDigits per Java implementation.
19 * Changed setMinIntegerDigits per Java implementation.
20 * Changed setMinFractionDigits per Java implementation.
21 * Changed setMaxFractionDigits per Java implementation.
22 ********************************************************************************
25 #include "unicode/utypes.h"
27 #if !UCONFIG_NO_FORMATTING
29 #include "unicode/numfmt.h"
30 #include "unicode/locid.h"
31 #include "unicode/dcfmtsym.h"
32 #include "unicode/decimfmt.h"
33 #include "unicode/ustring.h"
34 #include "unicode/ucurr.h"
35 #include "unicode/curramt.h"
36 #include "unicode/numsys.h"
37 #include "unicode/rbnf.h"
38 #include "unicode/localpointer.h"
39 #include "unicode/udisplaycontext.h"
54 #include "sharednumberformat.h"
55 #include "unifiedcache.h"
61 static inline void debugout(UnicodeString s
) {
63 s
.extract((int32_t) 0, s
.length(), buf
);
66 #define debug(x) printf("%s", x);
72 // If no number pattern can be located for a locale, this is the last
73 // resort. The patterns are same as the ones in root locale.
74 static const UChar gLastResortDecimalPat
[] = {
75 0x23, 0x2C, 0x23, 0x23, 0x30, 0x2E, 0x23, 0x23, 0x23, 0 /* "#,##0.###" */
77 static const UChar gLastResortCurrencyPat
[] = {
78 0xA4, 0xA0, 0x23, 0x2C, 0x23, 0x23, 0x30, 0x2E, 0x30, 0x30, 0 /* "\u00A4\u00A0#,##0.00" */
80 static const UChar gLastResortPercentPat
[] = {
81 0x23, 0x2C, 0x23, 0x23, 0x30, 0x25, 0 /* "#,##0%" */
83 static const UChar gLastResortScientificPat
[] = {
84 0x23, 0x45, 0x30, 0 /* "#E0" */
86 static const UChar gLastResortIsoCurrencyPat
[] = {
87 0xA4, 0xA4, 0xA0, 0x23, 0x2C, 0x23, 0x23, 0x30, 0x2E, 0x30, 0x30, 0 /* "\u00A4\u00A4\u00A0#,##0.00" */
89 static const UChar gLastResortPluralCurrencyPat
[] = {
90 0x23, 0x2C, 0x23, 0x23, 0x30, 0x2E, 0x23, 0x23, 0x23, 0x20, 0xA4, 0xA4, 0xA4, 0 /* "#,##0.### \u00A4\u00A4\u00A4*/
92 static const UChar gLastResortAccountingCurrencyPat
[] = {
93 0xA4, 0xA0, 0x23, 0x2C, 0x23, 0x23, 0x30, 0x2E, 0x30, 0x30, 0 /* "\u00A4\u00A0#,##0.00" */
96 static const UChar gSingleCurrencySign
[] = {0xA4, 0};
97 static const UChar gDoubleCurrencySign
[] = {0xA4, 0xA4, 0};
99 static const UChar gSlash
= 0x2f;
101 // If the maximum base 10 exponent were 4, then the largest number would
102 // be 99,999 which has 5 digits.
103 // On IEEE754 systems gMaxIntegerDigits is 308 + possible denormalized 15 digits + rounding digit
104 // With big decimal, the max exponent is 999,999,999 and the max number of digits is the same, 999,999,999
105 const int32_t icu::NumberFormat::gDefaultMaxIntegerDigits
= 2000000000;
106 const int32_t icu::NumberFormat::gDefaultMinIntegerDigits
= 127;
108 static const UChar
* const gLastResortNumberPatterns
[UNUM_FORMAT_STYLE_COUNT
] = {
109 NULL
, // UNUM_PATTERN_DECIMAL
110 gLastResortDecimalPat
, // UNUM_DECIMAL
111 gLastResortCurrencyPat
, // UNUM_CURRENCY
112 gLastResortPercentPat
, // UNUM_PERCENT
113 gLastResortScientificPat
, // UNUM_SCIENTIFIC
114 NULL
, // UNUM_SPELLOUT
115 NULL
, // UNUM_ORDINAL
116 NULL
, // UNUM_DURATION
117 NULL
, // UNUM_NUMBERING_SYSTEM
118 NULL
, // UNUM_PATTERN_RULEBASED
119 gLastResortIsoCurrencyPat
, // UNUM_CURRENCY_ISO
120 gLastResortPluralCurrencyPat
, // UNUM_CURRENCY_PLURAL
121 gLastResortAccountingCurrencyPat
, // UNUM_CURRENCY_ACCOUNTING
122 gLastResortCurrencyPat
, // UNUM_CASH_CURRENCY
123 NULL
, // UNUM_DECIMAL_COMPACT_SHORT
124 NULL
, // UNUM_DECIMAL_COMPACT_LONG
127 // Keys used for accessing resource bundles
129 static const char *gNumberElements
= "NumberElements";
130 static const char *gLatn
= "latn";
131 static const char *gPatterns
= "patterns";
132 static const char *gFormatKeys
[UNUM_FORMAT_STYLE_COUNT
] = {
133 NULL
, // UNUM_PATTERN_DECIMAL
134 "decimalFormat", // UNUM_DECIMAL
135 "currencyFormat", // UNUM_CURRENCY
136 "percentFormat", // UNUM_PERCENT
137 "scientificFormat", // UNUM_SCIENTIFIC
138 NULL
, // UNUM_SPELLOUT
139 NULL
, // UNUM_ORDINAL
140 NULL
, // UNUM_DURATION
141 NULL
, // UNUM_NUMBERING_SYSTEM
142 NULL
, // UNUM_PATTERN_RULEBASED
143 // For UNUM_CURRENCY_ISO and UNUM_CURRENCY_PLURAL,
144 // the pattern is the same as the pattern of UNUM_CURRENCY
145 // except for replacing the single currency sign with
146 // double currency sign or triple currency sign.
147 "currencyFormat", // UNUM_CURRENCY_ISO
148 "currencyFormat", // UNUM_CURRENCY_PLURAL
149 "accountingFormat", // UNUM_CURRENCY_ACCOUNTING
150 "currencyFormat", // UNUM_CASH_CURRENCY
151 NULL
, // UNUM_DECIMAL_COMPACT_SHORT
152 NULL
, // UNUM_DECIMAL_COMPACT_LONG
155 // Static hashtable cache of NumberingSystem objects used by NumberFormat
156 static UHashtable
* NumberingSystem_cache
= NULL
;
157 static UMutex nscacheMutex
= U_MUTEX_INITIALIZER
;
158 static icu::UInitOnce gNSCacheInitOnce
= U_INITONCE_INITIALIZER
;
160 #if !UCONFIG_NO_SERVICE
161 static icu::ICULocaleService
* gService
= NULL
;
162 static icu::UInitOnce gServiceInitOnce
= U_INITONCE_INITIALIZER
;
166 * Release all static memory held by Number Format.
169 static void U_CALLCONV
170 deleteNumberingSystem(void *obj
) {
171 delete (icu::NumberingSystem
*)obj
;
174 static UBool U_CALLCONV
numfmt_cleanup(void) {
175 #if !UCONFIG_NO_SERVICE
176 gServiceInitOnce
.reset();
182 gNSCacheInitOnce
.reset();
183 if (NumberingSystem_cache
) {
184 // delete NumberingSystem_cache;
185 uhash_close(NumberingSystem_cache
);
186 NumberingSystem_cache
= NULL
;
192 // *****************************************************************************
193 // class NumberFormat
194 // *****************************************************************************
198 UOBJECT_DEFINE_ABSTRACT_RTTI_IMPLEMENTATION(NumberFormat
)
200 #if !UCONFIG_NO_SERVICE
201 // -------------------------------------
202 // SimpleNumberFormatFactory implementation
203 NumberFormatFactory::~NumberFormatFactory() {}
204 SimpleNumberFormatFactory::SimpleNumberFormatFactory(const Locale
& locale
, UBool visible
)
207 LocaleUtility::initNameFromLocale(locale
, _id
);
210 SimpleNumberFormatFactory::~SimpleNumberFormatFactory() {}
212 UBool
SimpleNumberFormatFactory::visible(void) const {
216 const UnicodeString
*
217 SimpleNumberFormatFactory::getSupportedIDs(int32_t &count
, UErrorCode
& status
) const
219 if (U_SUCCESS(status
)) {
226 #endif /* #if !UCONFIG_NO_SERVICE */
228 // -------------------------------------
229 // default constructor
230 NumberFormat::NumberFormat()
231 : fGroupingUsed(TRUE
),
232 fMaxIntegerDigits(gDefaultMaxIntegerDigits
),
233 fMinIntegerDigits(1),
234 fMaxFractionDigits(3), // invariant, >= minFractionDigits
235 fMinFractionDigits(0),
236 fParseIntegerOnly(FALSE
),
238 fCapitalizationContext(UDISPCTX_CAPITALIZATION_NONE
)
243 // -------------------------------------
245 NumberFormat::~NumberFormat()
249 SharedNumberFormat::~SharedNumberFormat() {
253 // -------------------------------------
256 NumberFormat::NumberFormat(const NumberFormat
&source
)
262 // -------------------------------------
263 // assignment operator
266 NumberFormat::operator=(const NumberFormat
& rhs
)
270 Format::operator=(rhs
);
271 fGroupingUsed
= rhs
.fGroupingUsed
;
272 fMaxIntegerDigits
= rhs
.fMaxIntegerDigits
;
273 fMinIntegerDigits
= rhs
.fMinIntegerDigits
;
274 fMaxFractionDigits
= rhs
.fMaxFractionDigits
;
275 fMinFractionDigits
= rhs
.fMinFractionDigits
;
276 fParseIntegerOnly
= rhs
.fParseIntegerOnly
;
277 u_strncpy(fCurrency
, rhs
.fCurrency
, 4);
278 fLenient
= rhs
.fLenient
;
279 fCapitalizationContext
= rhs
.fCapitalizationContext
;
284 // -------------------------------------
287 NumberFormat::operator==(const Format
& that
) const
289 // Format::operator== guarantees this cast is safe
290 NumberFormat
* other
= (NumberFormat
*)&that
;
293 // This code makes it easy to determine why two format objects that should
296 if (!Format::operator==(that
)) {
297 if (first
) { printf("[ "); first
= FALSE
; } else { printf(", "); }
300 if (!(fMaxIntegerDigits
== other
->fMaxIntegerDigits
&&
301 fMinIntegerDigits
== other
->fMinIntegerDigits
)) {
302 if (first
) { printf("[ "); first
= FALSE
; } else { printf(", "); }
303 debug("Integer digits !=");
305 if (!(fMaxFractionDigits
== other
->fMaxFractionDigits
&&
306 fMinFractionDigits
== other
->fMinFractionDigits
)) {
307 if (first
) { printf("[ "); first
= FALSE
; } else { printf(", "); }
308 debug("Fraction digits !=");
310 if (!(fGroupingUsed
== other
->fGroupingUsed
)) {
311 if (first
) { printf("[ "); first
= FALSE
; } else { printf(", "); }
312 debug("fGroupingUsed != ");
314 if (!(fParseIntegerOnly
== other
->fParseIntegerOnly
)) {
315 if (first
) { printf("[ "); first
= FALSE
; } else { printf(", "); }
316 debug("fParseIntegerOnly != ");
318 if (!(u_strcmp(fCurrency
, other
->fCurrency
) == 0)) {
319 if (first
) { printf("[ "); first
= FALSE
; } else { printf(", "); }
320 debug("fCurrency !=");
322 if (!(fLenient
== other
->fLenient
)) {
323 if (first
) { printf("[ "); first
= FALSE
; } else { printf(", "); }
324 debug("fLenient != ");
326 if (!(fCapitalizationContext
== other
->fCapitalizationContext
)) {
327 if (first
) { printf("[ "); first
= FALSE
; } else { printf(", "); }
328 debug("fCapitalizationContext != ");
330 if (!first
) { printf(" ]"); }
333 return ((this == &that
) ||
334 ((Format::operator==(that
) &&
335 fMaxIntegerDigits
== other
->fMaxIntegerDigits
&&
336 fMinIntegerDigits
== other
->fMinIntegerDigits
&&
337 fMaxFractionDigits
== other
->fMaxFractionDigits
&&
338 fMinFractionDigits
== other
->fMinFractionDigits
&&
339 fGroupingUsed
== other
->fGroupingUsed
&&
340 fParseIntegerOnly
== other
->fParseIntegerOnly
&&
341 u_strcmp(fCurrency
, other
->fCurrency
) == 0 &&
342 fLenient
== other
->fLenient
&&
343 fCapitalizationContext
== other
->fCapitalizationContext
)));
346 // -------------------------------------
347 // Default implementation sets unsupported error; subclasses should
351 NumberFormat::format(double /* unused number */,
352 UnicodeString
& toAppendTo
,
353 FieldPositionIterator
* /* unused posIter */,
354 UErrorCode
& status
) const
356 if (!U_FAILURE(status
)) {
357 status
= U_UNSUPPORTED_ERROR
;
362 // -------------------------------------
363 // Default implementation sets unsupported error; subclasses should
367 NumberFormat::format(int32_t /* unused number */,
368 UnicodeString
& toAppendTo
,
369 FieldPositionIterator
* /* unused posIter */,
370 UErrorCode
& status
) const
372 if (!U_FAILURE(status
)) {
373 status
= U_UNSUPPORTED_ERROR
;
378 // -------------------------------------
379 // Default implementation sets unsupported error; subclasses should
383 NumberFormat::format(int64_t /* unused number */,
384 UnicodeString
& toAppendTo
,
385 FieldPositionIterator
* /* unused posIter */,
386 UErrorCode
& status
) const
388 if (!U_FAILURE(status
)) {
389 status
= U_UNSUPPORTED_ERROR
;
394 // ------------------------------------------
395 // These functions add the status code, just fall back to the non-status versions
397 NumberFormat::format(double number
,
398 UnicodeString
& appendTo
,
400 UErrorCode
&status
) const {
401 if(U_SUCCESS(status
)) {
402 return format(number
,appendTo
,pos
);
409 NumberFormat::format(int32_t number
,
410 UnicodeString
& appendTo
,
412 UErrorCode
&status
) const {
413 if(U_SUCCESS(status
)) {
414 return format(number
,appendTo
,pos
);
421 NumberFormat::format(int64_t number
,
422 UnicodeString
& appendTo
,
424 UErrorCode
&status
) const {
425 if(U_SUCCESS(status
)) {
426 return format(number
,appendTo
,pos
);
434 // -------------------------------------
435 // Decimal Number format() default implementation
436 // Subclasses do not normally override this function, but rather the DigitList
437 // formatting functions..
438 // The expected call chain from here is
440 // NumberFormat::format(Formattable ->
441 // DecimalFormat::format(DigitList
443 // Or, for subclasses of Formattable that do not know about DigitList,
445 // NumberFormat::format(Formattable ->
446 // NumberFormat::format(DigitList ->
447 // XXXFormat::format(double
450 NumberFormat::format(const StringPiece
&decimalNum
,
451 UnicodeString
& toAppendTo
,
452 FieldPositionIterator
* fpi
,
453 UErrorCode
& status
) const
456 f
.setDecimalNumber(decimalNum
, status
);
457 format(f
, toAppendTo
, fpi
, status
);
463 // Formats the number object and save the format
464 // result in the toAppendTo string buffer.
466 // utility to save/restore state, used in two overloads
467 // of format(const Formattable&...) below.
469 * Old purpose of ArgExtractor was to avoid const. Not thread safe!
471 * keeping it around as a shim.
474 const Formattable
* num
;
479 ArgExtractor(const NumberFormat
& nf
, const Formattable
& obj
, UErrorCode
& status
);
482 const Formattable
* number(void) const;
483 const UChar
*iso(void) const;
484 UBool
wasCurrency(void) const;
487 inline const Formattable
*
488 ArgExtractor::number(void) const {
493 ArgExtractor::wasCurrency(void) const {
498 ArgExtractor::iso(void) const {
502 ArgExtractor::ArgExtractor(const NumberFormat
& /*nf*/, const Formattable
& obj
, UErrorCode
& /*status*/)
503 : num(&obj
), fWasCurrency(FALSE
) {
505 const UObject
* o
= obj
.getObject(); // most commonly o==NULL
506 const CurrencyAmount
* amt
;
507 if (o
!= NULL
&& (amt
= dynamic_cast<const CurrencyAmount
*>(o
)) != NULL
) {
508 // getISOCurrency() returns a pointer to internal storage, so we
509 // copy it to retain it across the call to setCurrency().
510 //const UChar* curr = amt->getISOCurrency();
511 u_strcpy(save
, amt
->getISOCurrency());
512 num
= &amt
->getNumber();
519 ArgExtractor::~ArgExtractor() {
522 UnicodeString
& NumberFormat::format(const DigitList
&number
,
523 UnicodeString
& appendTo
,
524 FieldPositionIterator
* posIter
,
525 UErrorCode
& status
) const {
526 // DecimalFormat overrides this function, and handles DigitList based big decimals.
527 // Other subclasses (ChoiceFormat, RuleBasedNumberFormat) do not (yet) handle DigitLists,
528 // so this default implementation falls back to formatting decimal numbers as doubles.
529 if (U_FAILURE(status
)) {
532 double dnum
= number
.getDouble();
533 format(dnum
, appendTo
, posIter
, status
);
540 NumberFormat::format(const DigitList
&number
,
541 UnicodeString
& appendTo
,
543 UErrorCode
&status
) const {
544 // DecimalFormat overrides this function, and handles DigitList based big decimals.
545 // Other subclasses (ChoiceFormat, RuleBasedNumberFormat) do not (yet) handle DigitLists,
546 // so this default implementation falls back to formatting decimal numbers as doubles.
547 if (U_FAILURE(status
)) {
550 double dnum
= number
.getDouble();
551 format(dnum
, appendTo
, pos
, status
);
556 NumberFormat::format(const Formattable
& obj
,
557 UnicodeString
& appendTo
,
559 UErrorCode
& status
) const
561 if (U_FAILURE(status
)) return appendTo
;
563 ArgExtractor
arg(*this, obj
, status
);
564 const Formattable
*n
= arg
.number();
565 const UChar
*iso
= arg
.iso();
567 if(arg
.wasCurrency() && u_strcmp(iso
, getCurrency())) {
568 // trying to format a different currency.
569 // Right now, we clone.
570 LocalPointer
<NumberFormat
> cloneFmt((NumberFormat
*)this->clone());
571 cloneFmt
->setCurrency(iso
, status
);
572 // next line should NOT recurse, because n is numeric whereas obj was a wrapper around currency amount.
573 return cloneFmt
->format(*n
, appendTo
, pos
, status
);
576 if (n
->isNumeric() && n
->getDigitList() != NULL
) {
577 // Decimal Number. We will have a DigitList available if the value was
578 // set to a decimal number, or if the value originated with a parse.
580 // The default implementation for formatting a DigitList converts it
581 // to a double, and formats that, allowing formatting classes that don't
582 // know about DigitList to continue to operate as they had.
584 // DecimalFormat overrides the DigitList formatting functions.
585 format(*n
->getDigitList(), appendTo
, pos
, status
);
587 switch (n
->getType()) {
588 case Formattable::kDouble
:
589 format(n
->getDouble(), appendTo
, pos
);
591 case Formattable::kLong
:
592 format(n
->getLong(), appendTo
, pos
);
594 case Formattable::kInt64
:
595 format(n
->getInt64(), appendTo
, pos
);
598 status
= U_INVALID_FORMAT_ERROR
;
606 // -------------------------------------x
607 // Formats the number object and save the format
608 // result in the toAppendTo string buffer.
611 NumberFormat::format(const Formattable
& obj
,
612 UnicodeString
& appendTo
,
613 FieldPositionIterator
* posIter
,
614 UErrorCode
& status
) const
616 if (U_FAILURE(status
)) return appendTo
;
618 ArgExtractor
arg(*this, obj
, status
);
619 const Formattable
*n
= arg
.number();
620 const UChar
*iso
= arg
.iso();
622 if(arg
.wasCurrency() && u_strcmp(iso
, getCurrency())) {
623 // trying to format a different currency.
624 // Right now, we clone.
625 LocalPointer
<NumberFormat
> cloneFmt((NumberFormat
*)this->clone());
626 cloneFmt
->setCurrency(iso
, status
);
627 // next line should NOT recurse, because n is numeric whereas obj was a wrapper around currency amount.
628 return cloneFmt
->format(*n
, appendTo
, posIter
, status
);
631 if (n
->isNumeric() && n
->getDigitList() != NULL
) {
633 format(*n
->getDigitList(), appendTo
, posIter
, status
);
635 switch (n
->getType()) {
636 case Formattable::kDouble
:
637 format(n
->getDouble(), appendTo
, posIter
, status
);
639 case Formattable::kLong
:
640 format(n
->getLong(), appendTo
, posIter
, status
);
642 case Formattable::kInt64
:
643 format(n
->getInt64(), appendTo
, posIter
, status
);
646 status
= U_INVALID_FORMAT_ERROR
;
654 // -------------------------------------
657 NumberFormat::format(int64_t number
,
658 UnicodeString
& appendTo
,
659 FieldPosition
& pos
) const
661 // default so we don't introduce a new abstract method
662 return format((int32_t)number
, appendTo
, pos
);
665 // -------------------------------------
666 // Parses the string and save the result object as well
667 // as the final parsed position.
670 NumberFormat::parseObject(const UnicodeString
& source
,
672 ParsePosition
& parse_pos
) const
674 parse(source
, result
, parse_pos
);
677 // -------------------------------------
678 // Formats a double number and save the result in a string.
681 NumberFormat::format(double number
, UnicodeString
& appendTo
) const
683 FieldPosition
pos(0);
684 return format(number
, appendTo
, pos
);
687 // -------------------------------------
688 // Formats a long number and save the result in a string.
691 NumberFormat::format(int32_t number
, UnicodeString
& appendTo
) const
693 FieldPosition
pos(0);
694 return format(number
, appendTo
, pos
);
697 // -------------------------------------
698 // Formats a long number and save the result in a string.
701 NumberFormat::format(int64_t number
, UnicodeString
& appendTo
) const
703 FieldPosition
pos(0);
704 return format(number
, appendTo
, pos
);
707 // -------------------------------------
708 // Parses the text and save the result object. If the returned
709 // parse position is 0, that means the parsing failed, the status
710 // code needs to be set to failure. Ignores the returned parse
711 // position, otherwise.
714 NumberFormat::parse(const UnicodeString
& text
,
716 UErrorCode
& status
) const
718 if (U_FAILURE(status
)) return;
720 ParsePosition
parsePosition(0);
721 parse(text
, result
, parsePosition
);
722 if (parsePosition
.getIndex() == 0) {
723 status
= U_INVALID_FORMAT_ERROR
;
727 CurrencyAmount
* NumberFormat::parseCurrency(const UnicodeString
& text
,
728 ParsePosition
& pos
) const {
729 // Default implementation only -- subclasses should override
730 Formattable parseResult
;
731 int32_t start
= pos
.getIndex();
732 parse(text
, parseResult
, pos
);
733 if (pos
.getIndex() != start
) {
735 UErrorCode ec
= U_ZERO_ERROR
;
736 getEffectiveCurrency(curr
, ec
);
738 LocalPointer
<CurrencyAmount
> currAmt(new CurrencyAmount(parseResult
, curr
, ec
), ec
);
740 pos
.setIndex(start
); // indicate failure
742 return currAmt
.orphan();
749 // -------------------------------------
750 // Sets to only parse integers.
753 NumberFormat::setParseIntegerOnly(UBool value
)
755 fParseIntegerOnly
= value
;
758 // -------------------------------------
759 // Sets whether lenient parse is enabled.
762 NumberFormat::setLenient(UBool enable
)
767 // -------------------------------------
768 // Create a number style NumberFormat instance with the default locale.
770 NumberFormat
* U_EXPORT2
771 NumberFormat::createInstance(UErrorCode
& status
)
773 return createInstance(Locale::getDefault(), UNUM_DECIMAL
, status
);
776 // -------------------------------------
777 // Create a number style NumberFormat instance with the inLocale locale.
779 NumberFormat
* U_EXPORT2
780 NumberFormat::createInstance(const Locale
& inLocale
, UErrorCode
& status
)
782 return createInstance(inLocale
, UNUM_DECIMAL
, status
);
785 // -------------------------------------
786 // Create a currency style NumberFormat instance with the default locale.
788 NumberFormat
* U_EXPORT2
789 NumberFormat::createCurrencyInstance(UErrorCode
& status
)
791 return createCurrencyInstance(Locale::getDefault(), status
);
794 // -------------------------------------
795 // Create a currency style NumberFormat instance with the inLocale locale.
797 NumberFormat
* U_EXPORT2
798 NumberFormat::createCurrencyInstance(const Locale
& inLocale
, UErrorCode
& status
)
800 return createInstance(inLocale
, UNUM_CURRENCY
, status
);
803 // -------------------------------------
804 // Create a percent style NumberFormat instance with the default locale.
806 NumberFormat
* U_EXPORT2
807 NumberFormat::createPercentInstance(UErrorCode
& status
)
809 return createInstance(Locale::getDefault(), UNUM_PERCENT
, status
);
812 // -------------------------------------
813 // Create a percent style NumberFormat instance with the inLocale locale.
815 NumberFormat
* U_EXPORT2
816 NumberFormat::createPercentInstance(const Locale
& inLocale
, UErrorCode
& status
)
818 return createInstance(inLocale
, UNUM_PERCENT
, status
);
821 // -------------------------------------
822 // Create a scientific style NumberFormat instance with the default locale.
824 NumberFormat
* U_EXPORT2
825 NumberFormat::createScientificInstance(UErrorCode
& status
)
827 return createInstance(Locale::getDefault(), UNUM_SCIENTIFIC
, status
);
830 // -------------------------------------
831 // Create a scientific style NumberFormat instance with the inLocale locale.
833 NumberFormat
* U_EXPORT2
834 NumberFormat::createScientificInstance(const Locale
& inLocale
, UErrorCode
& status
)
836 return createInstance(inLocale
, UNUM_SCIENTIFIC
, status
);
839 // -------------------------------------
841 const Locale
* U_EXPORT2
842 NumberFormat::getAvailableLocales(int32_t& count
)
844 return Locale::getAvailableLocales(count
);
847 // ------------------------------------------
851 //-------------------------------------------
853 #if !UCONFIG_NO_SERVICE
855 // -------------------------------------
857 class ICUNumberFormatFactory
: public ICUResourceBundleFactory
{
859 virtual ~ICUNumberFormatFactory();
861 virtual UObject
* handleCreate(const Locale
& loc
, int32_t kind
, const ICUService
* /* service */, UErrorCode
& status
) const {
862 return NumberFormat::makeInstance(loc
, (UNumberFormatStyle
)kind
, status
);
866 ICUNumberFormatFactory::~ICUNumberFormatFactory() {}
868 // -------------------------------------
870 class NFFactory
: public LocaleKeyFactory
{
872 NumberFormatFactory
* _delegate
;
876 NFFactory(NumberFormatFactory
* delegate
)
877 : LocaleKeyFactory(delegate
->visible() ? VISIBLE
: INVISIBLE
)
878 , _delegate(delegate
)
883 virtual ~NFFactory();
885 virtual UObject
* create(const ICUServiceKey
& key
, const ICUService
* service
, UErrorCode
& status
) const
887 if (handlesKey(key
, status
)) {
888 const LocaleKey
& lkey
= (const LocaleKey
&)key
;
890 lkey
.canonicalLocale(loc
);
891 int32_t kind
= lkey
.kind();
893 UObject
* result
= _delegate
->createFormat(loc
, (UNumberFormatStyle
)kind
);
894 if (result
== NULL
) {
895 result
= service
->getKey((ICUServiceKey
&)key
/* cast away const */, NULL
, this, status
);
904 * Return the set of ids that this factory supports (visible or
905 * otherwise). This can be called often and might need to be
906 * cached if it is expensive to create.
908 virtual const Hashtable
* getSupportedIDs(UErrorCode
& status
) const
910 if (U_SUCCESS(status
)) {
913 const UnicodeString
* const idlist
= _delegate
->getSupportedIDs(count
, status
);
914 ((NFFactory
*)this)->_ids
= new Hashtable(status
); /* cast away const */
916 for (int i
= 0; i
< count
; ++i
) {
917 _ids
->put(idlist
[i
], (void*)this, status
);
927 NFFactory::~NFFactory()
933 class ICUNumberFormatService
: public ICULocaleService
{
935 ICUNumberFormatService()
936 : ICULocaleService(UNICODE_STRING_SIMPLE("Number Format"))
938 UErrorCode status
= U_ZERO_ERROR
;
939 registerFactory(new ICUNumberFormatFactory(), status
);
942 virtual ~ICUNumberFormatService();
944 virtual UObject
* cloneInstance(UObject
* instance
) const {
945 return ((NumberFormat
*)instance
)->clone();
948 virtual UObject
* handleDefault(const ICUServiceKey
& key
, UnicodeString
* /* actualID */, UErrorCode
& status
) const {
949 LocaleKey
& lkey
= (LocaleKey
&)key
;
950 int32_t kind
= lkey
.kind();
952 lkey
.currentLocale(loc
);
953 return NumberFormat::makeInstance(loc
, (UNumberFormatStyle
)kind
, status
);
956 virtual UBool
isDefault() const {
957 return countFactories() == 1;
961 ICUNumberFormatService::~ICUNumberFormatService() {}
963 // -------------------------------------
965 static void U_CALLCONV
initNumberFormatService() {
966 U_ASSERT(gService
== NULL
);
967 ucln_i18n_registerCleanup(UCLN_I18N_NUMFMT
, numfmt_cleanup
);
968 gService
= new ICUNumberFormatService();
971 static ICULocaleService
*
972 getNumberFormatService(void)
974 umtx_initOnce(gServiceInitOnce
, &initNumberFormatService
);
978 static UBool
haveService() {
979 return !gServiceInitOnce
.isReset() && (getNumberFormatService() != NULL
);
982 // -------------------------------------
984 URegistryKey U_EXPORT2
985 NumberFormat::registerFactory(NumberFormatFactory
* toAdopt
, UErrorCode
& status
)
987 ICULocaleService
*service
= getNumberFormatService();
989 NFFactory
*tempnnf
= new NFFactory(toAdopt
);
990 if (tempnnf
!= NULL
) {
991 return service
->registerFactory(tempnnf
, status
);
994 status
= U_MEMORY_ALLOCATION_ERROR
;
998 // -------------------------------------
1001 NumberFormat::unregister(URegistryKey key
, UErrorCode
& status
)
1003 if (U_FAILURE(status
)) {
1006 if (haveService()) {
1007 return gService
->unregister(key
, status
);
1009 status
= U_ILLEGAL_ARGUMENT_ERROR
;
1014 // -------------------------------------
1015 StringEnumeration
* U_EXPORT2
1016 NumberFormat::getAvailableLocales(void)
1018 ICULocaleService
*service
= getNumberFormatService();
1020 return service
->getAvailableLocales();
1022 return NULL
; // no way to return error condition
1024 #endif /* UCONFIG_NO_SERVICE */
1025 // -------------------------------------
1027 enum { kKeyValueLenMax
= 32 };
1030 NumberFormat::internalCreateInstance(const Locale
& loc
, UNumberFormatStyle kind
, UErrorCode
& status
) {
1031 if (kind
== UNUM_CURRENCY
) {
1032 char cfKeyValue
[kKeyValueLenMax
] = {0};
1033 UErrorCode kvStatus
= U_ZERO_ERROR
;
1034 int32_t kLen
= loc
.getKeywordValue("cf", cfKeyValue
, kKeyValueLenMax
, kvStatus
);
1035 if (U_SUCCESS(kvStatus
) && kLen
> 0 && uprv_strcmp(cfKeyValue
,"account")==0) {
1036 kind
= UNUM_CURRENCY_ACCOUNTING
;
1039 #if !UCONFIG_NO_SERVICE
1040 if (haveService()) {
1041 return (NumberFormat
*)gService
->get(loc
, kind
, status
);
1044 return makeInstance(loc
, kind
, status
);
1047 NumberFormat
* U_EXPORT2
1048 NumberFormat::createInstance(const Locale
& loc
, UNumberFormatStyle kind
, UErrorCode
& status
) {
1049 if (kind
!= UNUM_DECIMAL
) {
1050 return internalCreateInstance(loc
, kind
, status
);
1052 const SharedNumberFormat
*shared
= createSharedInstance(loc
, kind
, status
);
1053 if (U_FAILURE(status
)) {
1056 NumberFormat
*result
= static_cast<NumberFormat
*>((*shared
)->clone());
1057 shared
->removeRef();
1058 if (result
== NULL
) {
1059 status
= U_MEMORY_ALLOCATION_ERROR
;
1065 // -------------------------------------
1066 // Checks if the thousand/10 thousand grouping is used in the
1067 // NumberFormat instance.
1070 NumberFormat::isGroupingUsed() const
1072 return fGroupingUsed
;
1075 // -------------------------------------
1076 // Sets to use the thousand/10 thousand grouping in the
1077 // NumberFormat instance.
1080 NumberFormat::setGroupingUsed(UBool newValue
)
1082 fGroupingUsed
= newValue
;
1085 // -------------------------------------
1086 // Gets the maximum number of digits for the integral part for
1087 // this NumberFormat instance.
1089 int32_t NumberFormat::getMaximumIntegerDigits() const
1091 return fMaxIntegerDigits
;
1094 // -------------------------------------
1095 // Sets the maximum number of digits for the integral part for
1096 // this NumberFormat instance.
1099 NumberFormat::setMaximumIntegerDigits(int32_t newValue
)
1101 fMaxIntegerDigits
= uprv_max(0, uprv_min(newValue
, gDefaultMaxIntegerDigits
));
1102 if(fMinIntegerDigits
> fMaxIntegerDigits
)
1103 fMinIntegerDigits
= fMaxIntegerDigits
;
1106 // -------------------------------------
1107 // Gets the minimum number of digits for the integral part for
1108 // this NumberFormat instance.
1111 NumberFormat::getMinimumIntegerDigits() const
1113 return fMinIntegerDigits
;
1116 // -------------------------------------
1117 // Sets the minimum number of digits for the integral part for
1118 // this NumberFormat instance.
1121 NumberFormat::setMinimumIntegerDigits(int32_t newValue
)
1123 fMinIntegerDigits
= uprv_max(0, uprv_min(newValue
, gDefaultMinIntegerDigits
));
1124 if(fMinIntegerDigits
> fMaxIntegerDigits
)
1125 fMaxIntegerDigits
= fMinIntegerDigits
;
1128 // -------------------------------------
1129 // Gets the maximum number of digits for the fractional part for
1130 // this NumberFormat instance.
1133 NumberFormat::getMaximumFractionDigits() const
1135 return fMaxFractionDigits
;
1138 // -------------------------------------
1139 // Sets the maximum number of digits for the fractional part for
1140 // this NumberFormat instance.
1143 NumberFormat::setMaximumFractionDigits(int32_t newValue
)
1145 fMaxFractionDigits
= uprv_max(0, uprv_min(newValue
, gDefaultMaxIntegerDigits
));
1146 if(fMaxFractionDigits
< fMinFractionDigits
)
1147 fMinFractionDigits
= fMaxFractionDigits
;
1150 // -------------------------------------
1151 // Gets the minimum number of digits for the fractional part for
1152 // this NumberFormat instance.
1155 NumberFormat::getMinimumFractionDigits() const
1157 return fMinFractionDigits
;
1160 // -------------------------------------
1161 // Sets the minimum number of digits for the fractional part for
1162 // this NumberFormat instance.
1165 NumberFormat::setMinimumFractionDigits(int32_t newValue
)
1167 fMinFractionDigits
= uprv_max(0, uprv_min(newValue
, gDefaultMinIntegerDigits
));
1168 if (fMaxFractionDigits
< fMinFractionDigits
)
1169 fMaxFractionDigits
= fMinFractionDigits
;
1172 // -------------------------------------
1174 void NumberFormat::setCurrency(const UChar
* theCurrency
, UErrorCode
& ec
) {
1175 if (U_FAILURE(ec
)) {
1179 u_strncpy(fCurrency
, theCurrency
, 3);
1186 const UChar
* NumberFormat::getCurrency() const {
1190 void NumberFormat::getEffectiveCurrency(UChar
* result
, UErrorCode
& ec
) const {
1191 const UChar
* c
= getCurrency();
1193 u_strncpy(result
, c
, 3);
1196 const char* loc
= getLocaleID(ULOC_VALID_LOCALE
, ec
);
1198 loc
= uloc_getDefault();
1200 ucurr_forLocale(loc
, result
, 4, &ec
);
1204 //----------------------------------------------------------------------
1207 void NumberFormat::setContext(UDisplayContext value
, UErrorCode
& status
)
1209 if (U_FAILURE(status
))
1211 if ( (UDisplayContextType
)((uint32_t)value
>> 8) == UDISPCTX_TYPE_CAPITALIZATION
) {
1212 fCapitalizationContext
= value
;
1214 status
= U_ILLEGAL_ARGUMENT_ERROR
;
1219 UDisplayContext
NumberFormat::getContext(UDisplayContextType type
, UErrorCode
& status
) const
1221 if (U_FAILURE(status
))
1222 return (UDisplayContext
)0;
1223 if (type
!= UDISPCTX_TYPE_CAPITALIZATION
) {
1224 status
= U_ILLEGAL_ARGUMENT_ERROR
;
1225 return (UDisplayContext
)0;
1227 return fCapitalizationContext
;
1231 // -------------------------------------
1232 // Creates the NumberFormat instance of the specified style (number, currency,
1233 // or percent) for the desired locale.
1235 static void U_CALLCONV
nscacheInit() {
1236 U_ASSERT(NumberingSystem_cache
== NULL
);
1237 ucln_i18n_registerCleanup(UCLN_I18N_NUMFMT
, numfmt_cleanup
);
1238 UErrorCode status
= U_ZERO_ERROR
;
1239 NumberingSystem_cache
= uhash_open(uhash_hashLong
,
1243 if (U_FAILURE(status
)) {
1244 // Number Format code will run with no cache if creation fails.
1245 NumberingSystem_cache
= NULL
;
1248 uhash_setValueDeleter(NumberingSystem_cache
, deleteNumberingSystem
);
1251 template<> U_I18N_API
1252 const SharedNumberFormat
*LocaleCacheKey
<SharedNumberFormat
>::createObject(
1253 const void * /*unused*/, UErrorCode
&status
) const {
1254 const char *localeId
= fLoc
.getName();
1255 NumberFormat
*nf
= NumberFormat::internalCreateInstance(
1256 localeId
, UNUM_DECIMAL
, status
);
1257 if (U_FAILURE(status
)) {
1260 SharedNumberFormat
*result
= new SharedNumberFormat(nf
);
1261 if (result
== NULL
) {
1262 status
= U_MEMORY_ALLOCATION_ERROR
;
1270 const SharedNumberFormat
* U_EXPORT2
1271 NumberFormat::createSharedInstance(const Locale
& loc
, UNumberFormatStyle kind
, UErrorCode
& status
) {
1272 if (U_FAILURE(status
)) {
1275 if (kind
!= UNUM_DECIMAL
) {
1276 status
= U_UNSUPPORTED_ERROR
;
1279 const SharedNumberFormat
*result
= NULL
;
1280 UnifiedCache::getByLocale(loc
, result
, status
);
1285 NumberFormat::isStyleSupported(UNumberFormatStyle style
) {
1286 return gLastResortNumberPatterns
[style
] != NULL
;
1290 NumberFormat::makeInstance(const Locale
& desiredLocale
,
1291 UNumberFormatStyle style
,
1292 UErrorCode
& status
) {
1293 return makeInstance(desiredLocale
, style
, false, status
);
1297 NumberFormat::makeInstance(const Locale
& desiredLocale
,
1298 UNumberFormatStyle style
,
1299 UBool mustBeDecimalFormat
,
1300 UErrorCode
& status
) {
1301 if (U_FAILURE(status
)) return NULL
;
1303 if (style
< 0 || style
>= UNUM_FORMAT_STYLE_COUNT
) {
1304 status
= U_ILLEGAL_ARGUMENT_ERROR
;
1308 // Some styles are not supported. This is a result of merging
1309 // the @draft ICU 4.2 NumberFormat::EStyles into the long-existing UNumberFormatStyle.
1310 // Ticket #8503 is for reviewing/fixing/merging the two relevant implementations:
1311 // this one and unum_open().
1312 // The UNUM_PATTERN_ styles are not supported here
1313 // because this method does not take a pattern string.
1314 if (!isStyleSupported(style
)) {
1315 status
= U_UNSUPPORTED_ERROR
;
1319 #if U_PLATFORM_USES_ONLY_WIN32_API
1320 if (!mustBeDecimalFormat
) {
1322 int32_t count
= desiredLocale
.getKeywordValue("compat", buffer
, sizeof(buffer
), status
);
1324 // if the locale has "@compat=host", create a host-specific NumberFormat
1325 if (U_SUCCESS(status
) && count
> 0 && uprv_strcmp(buffer
, "host") == 0) {
1326 Win32NumberFormat
*f
= NULL
;
1335 case UNUM_CURRENCY_ISO
: // do not support plural formatting here
1336 case UNUM_CURRENCY_PLURAL
:
1337 case UNUM_CURRENCY_ACCOUNTING
:
1338 case UNUM_CASH_CURRENCY
:
1339 f
= new Win32NumberFormat(desiredLocale
, curr
, status
);
1341 if (U_SUCCESS(status
)) {
1353 // Use numbering system cache hashtable
1354 umtx_initOnce(gNSCacheInitOnce
, &nscacheInit
);
1356 // Get cached numbering system
1357 LocalPointer
<NumberingSystem
> ownedNs
;
1358 NumberingSystem
*ns
= NULL
;
1359 if (NumberingSystem_cache
!= NULL
) {
1360 // TODO: Bad hash key usage, see ticket #8504.
1361 int32_t hashKey
= desiredLocale
.hashCode();
1363 Mutex
lock(&nscacheMutex
);
1364 ns
= (NumberingSystem
*)uhash_iget(NumberingSystem_cache
, hashKey
);
1366 ns
= NumberingSystem::createInstance(desiredLocale
,status
);
1367 uhash_iput(NumberingSystem_cache
, hashKey
, (void*)ns
, &status
);
1370 ownedNs
.adoptInstead(NumberingSystem::createInstance(desiredLocale
,status
));
1371 ns
= ownedNs
.getAlias();
1374 // check results of getting a numbering system
1375 if (U_FAILURE(status
)) {
1379 if (mustBeDecimalFormat
&& ns
->isAlgorithmic()) {
1380 status
= U_UNSUPPORTED_ERROR
;
1384 LocalPointer
<DecimalFormatSymbols
> symbolsToAdopt
;
1385 UnicodeString pattern
;
1386 LocalUResourceBundlePointer
ownedResource(ures_open(NULL
, desiredLocale
.getName(), &status
));
1387 if (U_FAILURE(status
)) {
1391 // Loads the decimal symbols of the desired locale.
1392 symbolsToAdopt
.adoptInsteadAndCheckErrorCode(new DecimalFormatSymbols(desiredLocale
, status
), status
);
1393 if (U_FAILURE(status
)) {
1397 UResourceBundle
*resource
= ownedResource
.orphan();
1398 UResourceBundle
*numElements
= ures_getByKeyWithFallback(resource
, gNumberElements
, NULL
, &status
);
1399 resource
= ures_getByKeyWithFallback(numElements
, ns
->getName(), resource
, &status
);
1400 resource
= ures_getByKeyWithFallback(resource
, gPatterns
, resource
, &status
);
1401 ownedResource
.adoptInstead(resource
);
1404 const UChar
*patResStr
= ures_getStringByKeyWithFallback(resource
, gFormatKeys
[style
], &patLen
, &status
);
1406 // Didn't find a pattern specific to the numbering system, so fall back to "latn"
1407 if ( status
== U_MISSING_RESOURCE_ERROR
&& uprv_strcmp(gLatn
,ns
->getName())) {
1408 status
= U_ZERO_ERROR
;
1409 resource
= ures_getByKeyWithFallback(numElements
, gLatn
, resource
, &status
);
1410 resource
= ures_getByKeyWithFallback(resource
, gPatterns
, resource
, &status
);
1411 patResStr
= ures_getStringByKeyWithFallback(resource
, gFormatKeys
[style
], &patLen
, &status
);
1414 ures_close(numElements
);
1416 // Creates the specified decimal format style of the desired locale.
1417 pattern
.setTo(TRUE
, patResStr
, patLen
);
1419 if (U_FAILURE(status
)) {
1422 if(style
==UNUM_CURRENCY
|| style
== UNUM_CURRENCY_ISO
|| style
== UNUM_CURRENCY_ACCOUNTING
1423 || style
== UNUM_CASH_CURRENCY
){
1424 const UChar
* currPattern
= symbolsToAdopt
->getCurrencyPattern();
1425 if(currPattern
!=NULL
){
1426 pattern
.setTo(currPattern
, u_strlen(currPattern
));
1432 if (ns
->isAlgorithmic()) {
1433 UnicodeString nsDesc
;
1434 UnicodeString nsRuleSetGroup
;
1435 UnicodeString nsRuleSetName
;
1437 URBNFRuleSetTag desiredRulesType
= URBNF_NUMBERING_SYSTEM
;
1439 nsDesc
.setTo(ns
->getDescription());
1440 int32_t firstSlash
= nsDesc
.indexOf(gSlash
);
1441 int32_t lastSlash
= nsDesc
.lastIndexOf(gSlash
);
1442 if ( lastSlash
> firstSlash
) {
1445 nsLocID
.appendInvariantChars(nsDesc
.tempSubString(0, firstSlash
), status
);
1446 nsRuleSetGroup
.setTo(nsDesc
,firstSlash
+1,lastSlash
-firstSlash
-1);
1447 nsRuleSetName
.setTo(nsDesc
,lastSlash
+1);
1449 nsLoc
= Locale::createFromName(nsLocID
.data());
1451 UnicodeString SpelloutRules
= UNICODE_STRING_SIMPLE("SpelloutRules");
1452 if ( nsRuleSetGroup
.compare(SpelloutRules
) == 0 ) {
1453 desiredRulesType
= URBNF_SPELLOUT
;
1456 nsLoc
= desiredLocale
;
1457 nsRuleSetName
.setTo(nsDesc
);
1460 RuleBasedNumberFormat
*r
= new RuleBasedNumberFormat(desiredRulesType
,nsLoc
,status
);
1462 status
= U_MEMORY_ALLOCATION_ERROR
;
1465 r
->setDefaultRuleSet(nsRuleSetName
,status
);
1468 // replace single currency sign in the pattern with double currency sign
1469 // if the style is UNUM_CURRENCY_ISO
1470 if (style
== UNUM_CURRENCY_ISO
) {
1471 pattern
.findAndReplace(UnicodeString(TRUE
, gSingleCurrencySign
, 1),
1472 UnicodeString(TRUE
, gDoubleCurrencySign
, 2));
1475 // "new DecimalFormat()" does not adopt the symbols if its memory allocation fails.
1476 DecimalFormatSymbols
*syms
= symbolsToAdopt
.orphan();
1477 DecimalFormat
* df
= new DecimalFormat(pattern
, syms
, style
, status
);
1479 // if it is cash currency style, setCurrencyUsage with usage
1480 if (style
== UNUM_CASH_CURRENCY
){
1481 df
->setCurrencyUsage(UCURR_USAGE_CASH
, &status
);
1484 if (U_FAILURE(status
)) {
1492 status
= U_MEMORY_ALLOCATION_ERROR
;
1497 f
->setLocaleIDs(ures_getLocaleByType(ownedResource
.getAlias(), ULOC_VALID_LOCALE
, &status
),
1498 ures_getLocaleByType(ownedResource
.getAlias(), ULOC_ACTUAL_LOCALE
, &status
));
1499 if (U_FAILURE(status
)) {
1508 #endif /* #if !UCONFIG_NO_FORMATTING */