ICU-7386 merge NumberFormat::EStyles into UNumberFormatStyles & improve NumberFormat::makeInstance() memory management

X-SVN-Rev: 29920
This commit is contained in:
Markus Scherer 2011-04-29 00:00:47 +00:00
parent 239da64700
commit 70ad6b4a74
8 changed files with 266 additions and 285 deletions

View File

@ -81,7 +81,7 @@ static const UChar kOther[]={ // "other"
// MessagePatternList ------------------------------------------------------ ***
template<typename T, int32_t stackCapacity>
class MessagePatternList {
class MessagePatternList : public UMemory {
public:
MessagePatternList() {}
void copyFrom(const MessagePatternList<T, stackCapacity> &other,

View File

@ -303,7 +303,7 @@ DecimalFormat::DecimalFormat(const UnicodeString& pattern,
DecimalFormat::DecimalFormat(const UnicodeString& pattern,
DecimalFormatSymbols* symbolsToAdopt,
NumberFormat::EStyles style,
UNumberFormatStyle style,
UErrorCode& status) {
init();
fStyle = style;
@ -338,7 +338,7 @@ DecimalFormat::init() {
fPad = 0;
fFormatWidth = 0;
fPadPosition = kPadBeforePrefix;
fStyle = NumberFormat::kNumberStyle;
fStyle = UNUM_DECIMAL;
fCurrencySignCount = 0;
fAffixPatternsForCurrency = NULL;
fAffixesForCurrency = NULL;
@ -418,7 +418,7 @@ DecimalFormat::construct(UErrorCode& status,
const UnicodeString* patternUsed;
UnicodeString currencyPluralPatternForOther;
// apply pattern
if (fStyle == NumberFormat::kPluralCurrencyStyle) {
if (fStyle == UNUM_CURRENCY_PLURAL) {
fCurrencyPluralInfo = new CurrencyPluralInfo(fSymbols->getLocale(), status);
if (U_FAILURE(status)) {
return;
@ -1686,7 +1686,7 @@ DecimalFormat::parseForCurrency(const UnicodeString& text,
ParsePosition tmpPos(origPos);
DigitList tmpDigitList;
UBool found;
if (fStyle == NumberFormat::kPluralCurrencyStyle) {
if (fStyle == UNUM_CURRENCY_PLURAL) {
found = subparse(text,
fNegPrefixPattern, fNegSuffixPattern,
fPosPrefixPattern, fPosSuffixPattern,
@ -3208,7 +3208,7 @@ int32_t DecimalFormat::appendAffix(UnicodeString& buf, double number,
if (fCurrencySignCount == fgCurrencySignCountInPluralFormat) {
UnicodeString pluralCount = fCurrencyPluralInfo->getPluralRules()->select(number);
AffixesForCurrency* oneSet;
if (fStyle == NumberFormat::kPluralCurrencyStyle) {
if (fStyle == UNUM_CURRENCY_PLURAL) {
oneSet = (AffixesForCurrency*)fPluralAffixesForCurrency->get(pluralCount);
} else {
oneSet = (AffixesForCurrency*)fAffixesForCurrency->get(pluralCount);
@ -3393,7 +3393,7 @@ DecimalFormat::appendAffixPattern(UnicodeString& appendTo,
UnicodeString&
DecimalFormat::toPattern(UnicodeString& result, UBool localized) const
{
if (fStyle == NumberFormat::kPluralCurrencyStyle) {
if (fStyle == UNUM_CURRENCY_PLURAL) {
// the prefix or suffix pattern might not be defined yet,
// so they can not be synthesized,
// instead, get them directly.

View File

@ -1,6 +1,6 @@
/*
*******************************************************************************
* Copyright (C) 1997-2010, International Business Machines Corporation and *
* Copyright (C) 1997-2011, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*
@ -35,6 +35,7 @@
#include "unicode/curramt.h"
#include "unicode/numsys.h"
#include "unicode/rbnf.h"
#include "charstr.h"
#include "winnmfmt.h"
#include "uresimp.h"
#include "uhash.h"
@ -44,6 +45,7 @@
#include "cstring.h"
#include "putilimp.h"
#include "umutex.h"
#include "mutex.h"
#include "digitlst.h"
#include <float.h>
@ -94,14 +96,19 @@ static const UChar gSlash = 0x2f;
static const int32_t gMaxIntegerDigits = DBL_MAX_10_EXP + DBL_DIG + 1;
static const int32_t gMinIntegerDigits = 127;
static const UChar * const gLastResortNumberPatterns[] =
{
gLastResortDecimalPat,
gLastResortCurrencyPat,
gLastResortPercentPat,
gLastResortScientificPat,
gLastResortIsoCurrencyPat,
gLastResortPluralCurrencyPat,
static const UChar * const gLastResortNumberPatterns[UNUM_FORMAT_STYLE_COUNT] = {
NULL, // UNUM_PATTERN_DECIMAL
gLastResortDecimalPat, // UNUM_DECIMAL
gLastResortCurrencyPat, // UNUM_CURRENCY
gLastResortPercentPat, // UNUM_PERCENT
gLastResortScientificPat, // UNUM_SCIENTIFIC
NULL, // UNUM_SPELLOUT
NULL, // UNUM_ORDINAL
NULL, // UNUM_DURATION
NULL, // UNUM_NUMBERING_SYSTEM
NULL, // UNUM_PATTERN_RULEBASED
gLastResortIsoCurrencyPat, // UNUM_CURRENCY_ISO
gLastResortPluralCurrencyPat // UNUM_CURRENCY_PLURAL
};
// Keys used for accessing resource bundles
@ -109,7 +116,24 @@ static const UChar * const gLastResortNumberPatterns[] =
static const char *gNumberElements = "NumberElements";
static const char *gLatn = "latn";
static const char *gPatterns = "patterns";
static const char *gFormatKeys[] = { "decimalFormat", "currencyFormat", "percentFormat", "scientificFormat" };
static const char *gFormatKeys[UNUM_FORMAT_STYLE_COUNT] = {
NULL, // UNUM_PATTERN_DECIMAL
"decimalFormat", // UNUM_DECIMAL
"currencyFormat", // UNUM_CURRENCY
"percentFormat", // UNUM_PERCENT
"scientificFormat", // UNUM_SCIENTIFIC
NULL, // UNUM_SPELLOUT
NULL, // UNUM_ORDINAL
NULL, // UNUM_DURATION
NULL, // UNUM_NUMBERING_SYSTEM
NULL, // UNUM_PATTERN_RULEBASED
// For UNUM_CURRENCY_ISO and UNUM_CURRENCY_PLURAL,
// the pattern is the same as the pattern of UNUM_CURRENCY
// except for replacing the single currency sign with
// double currency sign or triple currency sign.
"currencyFormat", // UNUM_CURRENCY_ISO
"currencyFormat" // UNUM_CURRENCY_PLURAL
};
// Static hashtable cache of NumberingSystem objects used by NumberFormat
static UHashtable * NumberingSystem_cache = NULL;
@ -630,7 +654,7 @@ NumberFormat::setParseIntegerOnly(UBool value)
NumberFormat* U_EXPORT2
NumberFormat::createInstance(UErrorCode& status)
{
return createInstance(Locale::getDefault(), kNumberStyle, status);
return createInstance(Locale::getDefault(), UNUM_DECIMAL, status);
}
// -------------------------------------
@ -639,7 +663,7 @@ NumberFormat::createInstance(UErrorCode& status)
NumberFormat* U_EXPORT2
NumberFormat::createInstance(const Locale& inLocale, UErrorCode& status)
{
return createInstance(inLocale, kNumberStyle, status);
return createInstance(inLocale, UNUM_DECIMAL, status);
}
// -------------------------------------
@ -657,7 +681,7 @@ NumberFormat::createCurrencyInstance(UErrorCode& status)
NumberFormat* U_EXPORT2
NumberFormat::createCurrencyInstance(const Locale& inLocale, UErrorCode& status)
{
return createInstance(inLocale, kCurrencyStyle, status);
return createInstance(inLocale, UNUM_CURRENCY, status);
}
// -------------------------------------
@ -666,7 +690,7 @@ NumberFormat::createCurrencyInstance(const Locale& inLocale, UErrorCode& status)
NumberFormat* U_EXPORT2
NumberFormat::createPercentInstance(UErrorCode& status)
{
return createInstance(Locale::getDefault(), kPercentStyle, status);
return createInstance(Locale::getDefault(), UNUM_PERCENT, status);
}
// -------------------------------------
@ -675,7 +699,7 @@ NumberFormat::createPercentInstance(UErrorCode& status)
NumberFormat* U_EXPORT2
NumberFormat::createPercentInstance(const Locale& inLocale, UErrorCode& status)
{
return createInstance(inLocale, kPercentStyle, status);
return createInstance(inLocale, UNUM_PERCENT, status);
}
// -------------------------------------
@ -684,7 +708,7 @@ NumberFormat::createPercentInstance(const Locale& inLocale, UErrorCode& status)
NumberFormat* U_EXPORT2
NumberFormat::createScientificInstance(UErrorCode& status)
{
return createInstance(Locale::getDefault(), kScientificStyle, status);
return createInstance(Locale::getDefault(), UNUM_SCIENTIFIC, status);
}
// -------------------------------------
@ -693,7 +717,7 @@ NumberFormat::createScientificInstance(UErrorCode& status)
NumberFormat* U_EXPORT2
NumberFormat::createScientificInstance(const Locale& inLocale, UErrorCode& status)
{
return createInstance(inLocale, kScientificStyle, status);
return createInstance(inLocale, UNUM_SCIENTIFIC, status);
}
// -------------------------------------
@ -717,8 +741,7 @@ NumberFormat::getAvailableLocales(int32_t& count)
class ICUNumberFormatFactory : public ICUResourceBundleFactory {
protected:
virtual UObject* handleCreate(const Locale& loc, int32_t kind, const ICUService* /* service */, UErrorCode& status) const {
// !!! kind is not an EStyles, need to determine how to handle this
return NumberFormat::makeInstance(loc, (NumberFormat::EStyles)kind, status);
return NumberFormat::makeInstance(loc, (UNumberFormatStyle)kind, status);
}
};
@ -751,7 +774,7 @@ public:
lkey.canonicalLocale(loc);
int32_t kind = lkey.kind();
UObject* result = _delegate->createFormat(loc, (UNumberFormatStyle)(kind+1));
UObject* result = _delegate->createFormat(loc, (UNumberFormatStyle)kind);
if (result == NULL) {
result = service->getKey((ICUServiceKey&)key /* cast away const */, NULL, this, status);
}
@ -803,7 +826,7 @@ public:
int32_t kind = lkey.kind();
Locale loc;
lkey.currentLocale(loc);
return NumberFormat::makeInstance(loc, (NumberFormat::EStyles)kind, status);
return NumberFormat::makeInstance(loc, (UNumberFormatStyle)kind, status);
}
virtual UBool isDefault() const {
@ -884,7 +907,7 @@ NumberFormat::getAvailableLocales(void)
// -------------------------------------
NumberFormat* U_EXPORT2
NumberFormat::createInstance(const Locale& loc, EStyles kind, UErrorCode& status)
NumberFormat::createInstance(const Locale& loc, UNumberFormatStyle kind, UErrorCode& status)
{
#if !UCONFIG_NO_SERVICE
UBool haveService;
@ -1043,35 +1066,51 @@ void NumberFormat::getEffectiveCurrency(UChar* result, UErrorCode& ec) const {
// Creates the NumberFormat instance of the specified style (number, currency,
// or percent) for the desired locale.
UBool
NumberFormat::isStyleSupported(UNumberFormatStyle style) {
return gLastResortNumberPatterns[style] != NULL;
}
NumberFormat*
NumberFormat::makeInstance(const Locale& desiredLocale,
EStyles style,
UNumberFormatStyle style,
UErrorCode& status)
{
if (U_FAILURE(status)) return NULL;
if (style < 0 || style >= kStyleCount) {
if (style < 0 || style >= UNUM_FORMAT_STYLE_COUNT) {
status = U_ILLEGAL_ARGUMENT_ERROR;
return NULL;
}
// Some styles are not supported. This is a result of merging
// the @draft ICU 4.2 NumberFormat::EStyles into the long-existing UNumberFormatStyle.
// Ticket #8503 is for reviewing/fixing/merging the two relevant implementations:
// this one and unum_open().
// The UNUM_PATTERN_ styles are not supported here
// because this method does not take a pattern string.
if (!isStyleSupported(style)) {
status = U_UNSUPPORTED_ERROR;
return NULL;
}
#ifdef U_WINDOWS
char buffer[8];
int32_t count = desiredLocale.getKeywordValue("compat", buffer, sizeof(buffer), status);
// if the locale has "@compat=host", create a host-specific NumberFormat
if (count > 0 && uprv_strcmp(buffer, "host") == 0) {
if (U_SUCCESS(status) && count > 0 && uprv_strcmp(buffer, "host") == 0) {
Win32NumberFormat *f = NULL;
UBool curr = TRUE;
switch (style) {
case kNumberStyle:
case UNUM_DECIMAL:
curr = FALSE;
// fall-through
case kCurrencyStyle:
case kIsoCurrencyStyle: // do not support plural formatting here
case kPluralCurrencyStyle:
case UNUM_CURRENCY:
case UNUM_CURRENCY_ISO: // do not support plural formatting here
case UNUM_CURRENCY_PLURAL:
f = new Win32NumberFormat(desiredLocale, curr, status);
if (U_SUCCESS(status)) {
@ -1087,55 +1126,47 @@ NumberFormat::makeInstance(const Locale& desiredLocale,
}
#endif
NumberFormat* f = NULL;
DecimalFormatSymbols* symbolsToAdopt = NULL;
LocalPointer<DecimalFormatSymbols> symbolsToAdopt;
UnicodeString pattern;
UResourceBundle *resource = ures_open(NULL, desiredLocale.getName(), &status);
NumberingSystem *ns = NULL;
UBool deleteSymbols = TRUE;
UHashtable * cache = NULL;
int32_t hashKey;
UBool getCache = FALSE;
UBool deleteNS = FALSE;
LocalUResourceBundlePointer ownedResource(ures_open(NULL, desiredLocale.getName(), &status));
if (U_FAILURE(status)) {
// We don't appear to have resource data available -- use the last-resort data
status = U_USING_FALLBACK_WARNING;
// When the data is unavailable, and locale isn't passed in, last resort data is used.
symbolsToAdopt = new DecimalFormatSymbols(status);
symbolsToAdopt.adoptInstead(new DecimalFormatSymbols(status));
if (symbolsToAdopt.isNull()) {
status = U_MEMORY_ALLOCATION_ERROR;
return NULL;
}
// Creates a DecimalFormat instance with the last resort number patterns.
pattern.setTo(TRUE, gLastResortNumberPatterns[style], -1);
}
else {
// Loads the decimal symbols of the desired locale.
symbolsToAdopt = new DecimalFormatSymbols(desiredLocale, status);
int32_t patLen = 0;
/* for ISOCURRENCYSTYLE and PLURALCURRENCYSTYLE,
* the pattern is the same as the pattern of CURRENCYSTYLE
* but by replacing the single currency sign with
* double currency sign or triple currency sign.
*/
int styleInNumberPattern = ((style == kIsoCurrencyStyle ||
style == kPluralCurrencyStyle) ?
kCurrencyStyle : style);
symbolsToAdopt.adoptInstead(new DecimalFormatSymbols(desiredLocale, status));
if (symbolsToAdopt.isNull()) {
status = U_MEMORY_ALLOCATION_ERROR;
return NULL;
}
UResourceBundle *resource = ownedResource.orphan();
resource = ures_getByKeyWithFallback(resource, gNumberElements, resource, &status);
// TODO : Get patterns on a per numbering system basis, for right now assumes "latn" for patterns
resource = ures_getByKeyWithFallback(resource, gLatn, resource, &status);
resource = ures_getByKeyWithFallback(resource, gPatterns, resource, &status);
ownedResource.adoptInstead(resource);
const UChar *patResStr = ures_getStringByKeyWithFallback(resource, gFormatKeys[styleInNumberPattern], &patLen, &status);
int32_t patLen = 0;
const UChar *patResStr = ures_getStringByKeyWithFallback(resource, gFormatKeys[style], &patLen, &status);
// Creates the specified decimal format style of the desired locale.
pattern.setTo(TRUE, patResStr, patLen);
}
if (U_FAILURE(status) || symbolsToAdopt == NULL) {
goto cleanup;
if (U_FAILURE(status)) {
return NULL;
}
if(style==kCurrencyStyle || style == kIsoCurrencyStyle){
if(style==UNUM_CURRENCY || style == UNUM_CURRENCY_ISO){
const UChar* currPattern = symbolsToAdopt->getCurrencyPattern();
if(currPattern!=NULL){
pattern.setTo(currPattern, u_strlen(currPattern));
@ -1143,75 +1174,60 @@ NumberFormat::makeInstance(const Locale& desiredLocale,
}
// Use numbering system cache hashtable
UMTX_CHECK(&nscacheMutex, (UBool)(cache != NumberingSystem_cache), getCache);
if (getCache) {
umtx_lock(&nscacheMutex);
cache = NumberingSystem_cache;
umtx_unlock(&nscacheMutex);
}
UHashtable *cache;
UMTX_CHECK(&nscacheMutex, NumberingSystem_cache, cache);
// Check cache we got, create if non-existant
status = U_ZERO_ERROR;
if (cache == NULL) {
cache = uhash_open(uhash_hashLong,
uhash_compareLong,
NULL,
&status);
if (cache == NULL || U_FAILURE(status)) {
if (U_FAILURE(status)) {
// cache not created - out of memory
status = U_ZERO_ERROR; // work without the cache
cache = NULL;
}
else {
} else {
// cache created
uhash_setValueDeleter(cache, deleteNumberingSystem);
// set final NumberingSystem_cache value
UHashtable* h = NULL;
UMTX_CHECK(&nscacheMutex, (UBool)(h != NumberingSystem_cache), getCache);
if (getCache) {
umtx_lock(&nscacheMutex);
h = NumberingSystem_cache;
umtx_unlock(&nscacheMutex);
}
if (h == NULL) {
umtx_lock(&nscacheMutex);
NumberingSystem_cache = h = cache;
cache = NULL;
Mutex lock(&nscacheMutex);
if (NumberingSystem_cache == NULL) {
NumberingSystem_cache = cache;
ucln_i18n_registerCleanup(UCLN_I18N_NUMFMT, numfmt_cleanup);
umtx_unlock(&nscacheMutex);
} else {
uhash_close(cache);
cache = NumberingSystem_cache;
}
if(cache != NULL) {
uhash_close(cache);
}
cache = h;
}
}
// Get cached numbering system
LocalPointer<NumberingSystem> ownedNs;
NumberingSystem *ns = NULL;
if (cache != NULL) {
hashKey = desiredLocale.hashCode();
// TODO: Bad hash key usage, see ticket #8504.
int32_t hashKey = desiredLocale.hashCode();
umtx_lock(&nscacheMutex);
Mutex lock(&nscacheMutex);
ns = (NumberingSystem *)uhash_iget(cache, hashKey);
if (ns == NULL) {
ns = NumberingSystem::createInstance(desiredLocale,status);
uhash_iput(cache, hashKey, (void*)ns, &status);
}
umtx_unlock(&nscacheMutex);
}
else {
ns = NumberingSystem::createInstance(desiredLocale,status);
deleteNS = TRUE;
} else {
ownedNs.adoptInstead(NumberingSystem::createInstance(desiredLocale,status));
ns = ownedNs.getAlias();
}
// check results of getting a numbering system
if ((ns == NULL) || (U_FAILURE(status))) {
goto cleanup;
if (U_FAILURE(status)) {
return NULL;
}
NumberFormat *f;
if (ns->isAlgorithmic()) {
UnicodeString nsDesc;
UnicodeString nsRuleSetGroup;
@ -1223,13 +1239,13 @@ NumberFormat::makeInstance(const Locale& desiredLocale,
int32_t firstSlash = nsDesc.indexOf(gSlash);
int32_t lastSlash = nsDesc.lastIndexOf(gSlash);
if ( lastSlash > firstSlash ) {
char nsLocID[ULOC_FULLNAME_CAPACITY];
CharString nsLocID;
nsDesc.extract(0,firstSlash,nsLocID,ULOC_FULLNAME_CAPACITY,US_INV);
nsLocID.appendInvariantChars(nsDesc.tempSubString(0, firstSlash), status);
nsRuleSetGroup.setTo(nsDesc,firstSlash+1,lastSlash-firstSlash-1);
nsRuleSetName.setTo(nsDesc,lastSlash+1);
nsLoc = Locale::createFromName(nsLocID);
nsLoc = Locale::createFromName(nsLocID.data());
UnicodeString SpelloutRules = UNICODE_STRING_SIMPLE("SpelloutRules");
if ( nsRuleSetGroup.compare(SpelloutRules) == 0 ) {
@ -1241,54 +1257,35 @@ NumberFormat::makeInstance(const Locale& desiredLocale,
}
RuleBasedNumberFormat *r = new RuleBasedNumberFormat(desiredRulesType,nsLoc,status);
if (U_FAILURE(status) || r == NULL) {
goto cleanup;
if (r == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
return NULL;
}
r->setDefaultRuleSet(nsRuleSetName,status);
f = (NumberFormat *) r;
f = r;
} else {
// replace single currency sign in the pattern with double currency sign
// if the style is kIsoCurrencyStyle
if (style == kIsoCurrencyStyle) {
// if the style is UNUM_CURRENCY_ISO
if (style == UNUM_CURRENCY_ISO) {
pattern.findAndReplace(gSingleCurrencySign, gDoubleCurrencySign);
}
f = new DecimalFormat(pattern, symbolsToAdopt, style, status);
if (U_FAILURE(status) || f == NULL) {
goto cleanup;
// "new DecimalFormat()" does not adopt the symbols if its memory allocation fails.
DecimalFormatSymbols *syms = symbolsToAdopt.orphan();
f = new DecimalFormat(pattern, syms, style, status);
if (f == NULL) {
delete syms;
status = U_MEMORY_ALLOCATION_ERROR;
return NULL;
}
deleteSymbols = FALSE;
}
f->setLocaleIDs(ures_getLocaleByType(resource, ULOC_VALID_LOCALE, &status),
ures_getLocaleByType(resource, ULOC_ACTUAL_LOCALE, &status));
cleanup:
ures_close(resource);
if (deleteNS && ns) {
delete ns;
}
f->setLocaleIDs(ures_getLocaleByType(ownedResource.getAlias(), ULOC_VALID_LOCALE, &status),
ures_getLocaleByType(ownedResource.getAlias(), ULOC_ACTUAL_LOCALE, &status));
if (U_FAILURE(status)) {
/* If f exists, then it will delete the symbols */
if (f==NULL) {
delete symbolsToAdopt;
}
else {
delete f;
}
delete f;
return NULL;
}
if (f == NULL || symbolsToAdopt == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
f = NULL;
}
if (deleteSymbols && symbolsToAdopt != NULL) {
delete symbolsToAdopt;
}
return f;
}

View File

@ -732,14 +732,14 @@ public:
* @param pattern a non-localized pattern string
* @param symbolsToAdopt the set of symbols to be used. The caller should not
* delete this object after making this call.
* @param style style of decimal format, kNumberStyle etc.
* @param style style of decimal format
* @param status Output param set to success/failure code. If the
* pattern is invalid this will be set to a failure code.
* @internal ICU 4.2
*/
DecimalFormat( const UnicodeString& pattern,
DecimalFormatSymbols* symbolsToAdopt,
NumberFormat::EStyles style,
UNumberFormatStyle style,
UErrorCode& status);
/**

View File

@ -1,6 +1,6 @@
/*
********************************************************************************
* Copyright (C) 1997-2010, International Business Machines Corporation and others.
* Copyright (C) 1997-2011, International Business Machines Corporation and others.
* All Rights Reserved.
********************************************************************************
*
@ -37,6 +37,8 @@
#include "unicode/locid.h"
#include "unicode/stringpiece.h"
class NumberFormatTest;
U_NAMESPACE_BEGIN
#if !UCONFIG_NO_SERVICE
@ -162,30 +164,6 @@ class StringEnumeration;
*/
class U_I18N_API NumberFormat : public Format {
public:
/**
* Constants for various number format styles.
* kNumberStyle specifies a normal number style of format.
* kCurrencyStyle specifies a currency format using currency symbol name,
* such as in "$1.00".
* kPercentStyle specifies a style of format to display percent.
* kScientificStyle specifies a style of format to display scientific number.
* kISOCurrencyStyle specifies a currency format using ISO currency code,
* such as in "USD1.00".
* kPluralCurrencyStyle specifies a currency format using currency plural
* names, such as in "1.00 US dollar" and "3.00 US dollars".
* @draft ICU 4.2
*/
enum EStyles {
kNumberStyle,
kCurrencyStyle,
kPercentStyle,
kScientificStyle,
kIsoCurrencyStyle,
kPluralCurrencyStyle,
kStyleCount // ALWAYS LAST ENUM: number of styles
};
/**
* Alignment Field constants used to construct a FieldPosition object.
* Signifies that the position of the integer part or fraction part of
@ -645,12 +623,14 @@ public:
/**
* Creates the specified decimal format style of the desired locale.
* @param desiredLocale the given locale.
* @param choice the given style.
* @param success Output param filled with success/failure status.
* @param style the given style.
* @param errorCode Output param filled with success/failure status.
* @return A new NumberFormat instance.
* @draft ICU 4.2
* @draft ICU 4.8
*/
static NumberFormat* U_EXPORT2 createInstance(const Locale& desiredLocale, EStyles choice, UErrorCode& success);
static NumberFormat* U_EXPORT2 createInstance(const Locale& desiredLocale,
UNumberFormatStyle style,
UErrorCode& errorCode);
/**
@ -921,14 +901,18 @@ protected:
private:
static UBool isStyleSupported(UNumberFormatStyle style);
/**
* Creates the specified decimal format style of the desired locale.
* @param desiredLocale the given locale.
* @param choice the given style.
* @param success Output param filled with success/failure status.
* @param style the given style.
* @param errorCode Output param filled with success/failure status.
* @return A new NumberFormat instance.
*/
static NumberFormat* makeInstance(const Locale& desiredLocale, EStyles choice, UErrorCode& success);
static NumberFormat* makeInstance(const Locale& desiredLocale,
UNumberFormatStyle style,
UErrorCode& errorCode);
UBool fGroupingUsed;
int32_t fMaxIntegerDigits;
@ -940,8 +924,9 @@ private:
// ISO currency code
UChar fCurrency[4];
friend class ICUNumberFormatFactory; // access to makeInstance, EStyles
friend class ICUNumberFormatFactory; // access to makeInstance
friend class ICUNumberFormatService;
friend class ::NumberFormatTest; // access to isStyleSupported()
};
#if !UCONFIG_NO_SERVICE

View File

@ -1,6 +1,6 @@
/*
*******************************************************************************
* Copyright (C) 1997-2010, International Business Machines Corporation and others.
* Copyright (C) 1997-2011, International Business Machines Corporation and others.
* All Rights Reserved.
* Modification History:
*
@ -134,19 +134,34 @@ typedef void* UNumberFormat;
*/
typedef enum UNumberFormatStyle {
/**
* Decimal format defined by pattern
* Decimal format defined by a pattern string.
* @stable ICU 3.0
*/
UNUM_PATTERN_DECIMAL=0,
/** Decimal format */
/**
* Decimal format ("normal" style).
* @stable ICU 2.0
*/
UNUM_DECIMAL=1,
/** Currency format */
/**
* Currency format with a currency symbol, e.g., "$1.00".
* @stable ICU 2.0
*/
UNUM_CURRENCY,
/** Percent format */
/**
* Percent format
* @stable ICU 2.0
*/
UNUM_PERCENT,
/** Scientific format */
/**
* Scientific format
* @stable ICU 2.1
*/
UNUM_SCIENTIFIC,
/** Spellout rule-based format */
/**
* Spellout rule-based format
* @stable ICU 2.0
*/
UNUM_SPELLOUT,
/**
* Ordinal rule-based format
@ -159,18 +174,40 @@ typedef enum UNumberFormatStyle {
*/
UNUM_DURATION,
/**
* Numbering system rule-based format
* Numbering system rule-based format
* @stable ICU 4.2
*/
UNUM_NUMBERING_SYSTEM,
/**
* Rule-based format defined by pattern
* Rule-based format defined by a pattern string.
* @stable ICU 3.0
*/
UNUM_PATTERN_RULEBASED,
/** Default format */
/**
* Currency format with an ISO currency code, e.g., "USD1.00".
* @draft ICU 4.8
*/
UNUM_CURRENCY_ISO,
/**
* Currency format with a pluralized currency name,
* e.g., "1.00 US dollar" and "3.00 US dollars".
* @draft ICU 4.8
*/
UNUM_CURRENCY_PLURAL,
/**
* One more than the highest number format style constant.
* @draft ICU 4.8
*/
UNUM_FORMAT_STYLE_COUNT,
/**
* Default format
* @stable ICU 2.0
*/
UNUM_DEFAULT = UNUM_DECIMAL,
/** (Alias for UNUM_PATTERN_DECIMAL) */
/**
* Alias for UNUM_PATTERN_DECIMAL
* @stable ICU 3.0
*/
UNUM_IGNORE = UNUM_PATTERN_DECIMAL
} UNumberFormatStyle;

View File

@ -38,78 +38,45 @@ unum_open( UNumberFormatStyle style,
int32_t patternLength,
const char* locale,
UParseError* parseErr,
UErrorCode* status)
{
if(U_FAILURE(*status))
{
return 0;
UErrorCode* status) {
if(U_FAILURE(*status)) {
return NULL;
}
UNumberFormat *retVal = 0;
NumberFormat *retVal = NULL;
switch(style) {
case UNUM_DECIMAL:
if(locale == 0)
retVal = (UNumberFormat*)NumberFormat::createInstance(*status);
else
retVal = (UNumberFormat*)NumberFormat::createInstance(Locale(locale),
*status);
break;
case UNUM_CURRENCY:
if(locale == 0)
retVal = (UNumberFormat*)NumberFormat::createCurrencyInstance(*status);
else
retVal = (UNumberFormat*)NumberFormat::createCurrencyInstance(Locale(locale),
*status);
break;
case UNUM_PERCENT:
if(locale == 0)
retVal = (UNumberFormat*)NumberFormat::createPercentInstance(*status);
else
retVal = (UNumberFormat*)NumberFormat::createPercentInstance(Locale(locale),
*status);
break;
case UNUM_SCIENTIFIC:
if(locale == 0)
retVal = (UNumberFormat*)NumberFormat::createScientificInstance(*status);
else
retVal = (UNumberFormat*)NumberFormat::createScientificInstance(Locale(locale),
*status);
retVal = NumberFormat::createInstance(Locale(locale), style, *status);
break;
case UNUM_PATTERN_DECIMAL: {
UParseError tErr;
/* UnicodeString can handle the case when patternLength = -1. */
const UnicodeString pat(pattern, patternLength);
DecimalFormatSymbols *syms = 0;
if(parseErr==NULL){
parseErr = &tErr;
}
if(locale == 0)
syms = new DecimalFormatSymbols(*status);
else
syms = new DecimalFormatSymbols(Locale(locale), *status);
if(syms == 0) {
DecimalFormatSymbols *syms = new DecimalFormatSymbols(Locale(locale), *status);
if(syms == NULL) {
*status = U_MEMORY_ALLOCATION_ERROR;
return 0;
return NULL;
}
if (U_FAILURE(*status)) {
delete syms;
return 0;
return NULL;
}
retVal = (UNumberFormat*)new DecimalFormat(pat, syms, *parseErr, *status);
if(retVal == 0) {
retVal = new DecimalFormat(pat, syms, *parseErr, *status);
if(retVal == NULL) {
delete syms;
}
} break;
} break;
#if U_HAVE_RBNF
case UNUM_PATTERN_RULEBASED: {
@ -121,36 +88,36 @@ unum_open( UNumberFormatStyle style,
parseErr = &tErr;
}
retVal = (UNumberFormat*)new RuleBasedNumberFormat(pat, Locale(locale), *parseErr, *status);
retVal = new RuleBasedNumberFormat(pat, Locale(locale), *parseErr, *status);
} break;
case UNUM_SPELLOUT:
retVal = (UNumberFormat*)new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale(locale), *status);
retVal = new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale(locale), *status);
break;
case UNUM_ORDINAL:
retVal = (UNumberFormat*)new RuleBasedNumberFormat(URBNF_ORDINAL, Locale(locale), *status);
retVal = new RuleBasedNumberFormat(URBNF_ORDINAL, Locale(locale), *status);
break;
case UNUM_DURATION:
retVal = (UNumberFormat*)new RuleBasedNumberFormat(URBNF_DURATION, Locale(locale), *status);
retVal = new RuleBasedNumberFormat(URBNF_DURATION, Locale(locale), *status);
break;
case UNUM_NUMBERING_SYSTEM:
retVal = (UNumberFormat*)new RuleBasedNumberFormat(URBNF_NUMBERING_SYSTEM, Locale(locale), *status);
retVal = new RuleBasedNumberFormat(URBNF_NUMBERING_SYSTEM, Locale(locale), *status);
break;
#endif
default:
*status = U_UNSUPPORTED_ERROR;
return 0;
return NULL;
}
if(retVal == 0 && U_SUCCESS(*status)) {
if(retVal == NULL && U_SUCCESS(*status)) {
*status = U_MEMORY_ALLOCATION_ERROR;
}
return retVal;
return reinterpret_cast<UNumberFormat *>(retVal);
}
U_CAPI void U_EXPORT2

View File

@ -15,6 +15,7 @@
#include "numfmtst.h"
#include "unicode/dcfmtsym.h"
#include "unicode/decimfmt.h"
#include "unicode/localpointer.h"
#include "unicode/ucurr.h"
#include "unicode/ustring.h"
#include "unicode/measfmt.h"
@ -37,6 +38,7 @@
//#define NUMFMTST_DEBUG 1
#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof(array[0]))
static const UChar EUR[] = {69,85,82,0}; // "EUR"
static const UChar ISO_CURRENCY_USD[] = {0x55, 0x53, 0x44, 0}; // "USD"
@ -2371,13 +2373,21 @@ void NumberFormatTest::TestHost()
#ifdef U_WINDOWS
Win32NumberTest::testLocales(this);
#endif
for (NumberFormat::EStyles k = NumberFormat::kNumberStyle;
k < NumberFormat::kStyleCount; k = (NumberFormat::EStyles)(k+1)) {
Locale loc("en_US@compat=host");
for (UNumberFormatStyle k = UNUM_DECIMAL;
k < UNUM_FORMAT_STYLE_COUNT; k = (UNumberFormatStyle)(k+1)) {
UErrorCode status = U_ZERO_ERROR;
Locale loc("en_US@compat=host");
NumberFormat *full = NumberFormat::createInstance(loc, status);
if (full == NULL || U_FAILURE(status)) {
dataerrln("FAIL: Can't create number instance for host - %s", u_errorName(status));
LocalPointer<NumberFormat> full(NumberFormat::createInstance(loc, k, status));
if (!NumberFormat::isStyleSupported(k)) {
if (status != U_UNSUPPORTED_ERROR) {
errln("FAIL: expected style %d to be unsupported - %s",
k, u_errorName(status));
}
continue;
}
if (full.isNull() || U_FAILURE(status)) {
dataerrln("FAIL: Can't create number instance of style %d for host - %s",
k, u_errorName(status));
return;
}
UnicodeString result1;
@ -2393,7 +2403,6 @@ void NumberFormatTest::TestHost()
errln("FAIL: Can't parse for host");
return;
}
delete full;
}
}
@ -2932,7 +2941,7 @@ NumberFormatTest::TestDecimalFormatCurrencyParse() {
void
NumberFormatTest::TestCurrencyIsoPluralFormat() {
const char* DATA[][6] = {
static const char* DATA[][6] = {
// the data are:
// locale,
// currency amount to be formatted,
@ -2958,17 +2967,15 @@ NumberFormatTest::TestCurrencyIsoPluralFormat() {
// test choice format
{"es_AR", "1", "INR", "\\u20B9\\u00A01,00", "INR\\u00A01,00", "1,00 rupia india"},
};
static const UNumberFormatStyle currencyStyles[] = {
UNUM_CURRENCY,
UNUM_CURRENCY_ISO,
UNUM_CURRENCY_PLURAL
};
for (uint32_t i=0; i<sizeof(DATA)/sizeof(DATA[0]); ++i) {
for (NumberFormat::EStyles k = NumberFormat::kCurrencyStyle;
k <= NumberFormat::kPluralCurrencyStyle;
k = (NumberFormat::EStyles)(k+1)) {
// k represents currency format style.
if ( k != NumberFormat::kCurrencyStyle &&
k != NumberFormat::kIsoCurrencyStyle &&
k != NumberFormat::kPluralCurrencyStyle ) {
continue;
}
for (int32_t i=0; i<LENGTHOF(DATA); ++i) {
for (int32_t kIndex = 0; kIndex < LENGTHOF(currencyStyles); ++kIndex) {
UNumberFormatStyle k = currencyStyles[kIndex];
const char* localeString = DATA[i][0];
double numberToBeFormat = atof(DATA[i][1]);
const char* currencyISOCode = DATA[i][2];
@ -2991,10 +2998,7 @@ NumberFormatTest::TestCurrencyIsoPluralFormat() {
UnicodeString strBuf;
numFmt->format(numberToBeFormat, strBuf);
int resultDataIndex = k;
if ( k == NumberFormat::kCurrencyStyle ) {
resultDataIndex = k+2;
}
int resultDataIndex = 3 + kIndex;
// DATA[i][resultDataIndex] is the currency format result
// using 'k' currency style.
UnicodeString formatResult = ctou(DATA[i][resultDataIndex]);
@ -3034,7 +3038,7 @@ NumberFormatTest::TestCurrencyIsoPluralFormat() {
void
NumberFormatTest::TestCurrencyParsing() {
const char* DATA[][6] = {
static const char* DATA[][6] = {
// the data are:
// locale,
// currency amount to be formatted,
@ -3057,6 +3061,11 @@ NumberFormatTest::TestCurrencyParsing() {
{"zh_TW", "1", "CNY", "\\uFFE51.00", "CNY1.00", "1.00 \\u4eba\\u6c11\\u5e63"},
{"ru_RU", "1", "RUB", "1,00\\u00A0\\u0440\\u0443\\u0431.", "1,00\\u00A0RUB", "1,00 \\u0420\\u043E\\u0441\\u0441\\u0438\\u0439\\u0441\\u043A\\u0438\\u0439 \\u0440\\u0443\\u0431\\u043B\\u044C"},
};
static const UNumberFormatStyle currencyStyles[] = {
UNUM_CURRENCY,
UNUM_CURRENCY_ISO,
UNUM_CURRENCY_PLURAL
};
#ifdef NUMFMTST_CACHE_DEBUG
int deadloop = 0;
@ -3064,15 +3073,8 @@ for (;;) {
printf("loop: %d\n", deadloop++);
#endif
for (uint32_t i=0; i<sizeof(DATA)/sizeof(DATA[0]); ++i) {
for (NumberFormat::EStyles k = NumberFormat::kCurrencyStyle;
k <= NumberFormat::kPluralCurrencyStyle;
k = (NumberFormat::EStyles)(k+1)) {
// k represents currency format style.
if ( k != NumberFormat::kCurrencyStyle &&
k != NumberFormat::kIsoCurrencyStyle &&
k != NumberFormat::kPluralCurrencyStyle ) {
continue;
}
for (int32_t kIndex = 0; kIndex < LENGTHOF(currencyStyles); ++kIndex) {
UNumberFormatStyle k = currencyStyles[kIndex];
const char* localeString = DATA[i][0];
double numberToBeFormat = atof(DATA[i][1]);
const char* currencyISOCode = DATA[i][2];
@ -3100,10 +3102,7 @@ for (;;) {
/*
UnicodeString strBuf;
numFmt->format(numberToBeFormat, strBuf);
int resultDataIndex = k;
if ( k == NumberFormat::kCurrencyStyle ) {
resultDataIndex = k+2;
}
int resultDataIndex = 3 + kIndex;
// DATA[i][resultDataIndex] is the currency format result
// using 'k' currency style.
UnicodeString formatResult = ctou(DATA[i][resultDataIndex]);
@ -5778,7 +5777,7 @@ NumberFormatTest::TestParseCurrencyInUCurr() {
for (uint32_t i=0; i<sizeof(DATA)/sizeof(DATA[0]); ++i) {
UnicodeString formatted = ctou(DATA[i]);
UErrorCode status = U_ZERO_ERROR;
NumberFormat* numFmt = NumberFormat::createInstance(locale, NumberFormat::kCurrencyStyle, status);
NumberFormat* numFmt = NumberFormat::createInstance(locale, UNUM_CURRENCY, status);
Formattable parseResult;
if (numFmt != NULL && U_SUCCESS(status)) {
numFmt->parse(formatted, parseResult, status);
@ -5799,7 +5798,7 @@ NumberFormatTest::TestParseCurrencyInUCurr() {
for (uint32_t i=0; i<sizeof(WRONG_DATA)/sizeof(WRONG_DATA[0]); ++i) {
UnicodeString formatted = ctou(WRONG_DATA[i]);
UErrorCode status = U_ZERO_ERROR;
NumberFormat* numFmt = NumberFormat::createInstance(locale, NumberFormat::kCurrencyStyle, status);
NumberFormat* numFmt = NumberFormat::createInstance(locale, UNUM_CURRENCY, status);
Formattable parseResult;
if (numFmt != NULL && U_SUCCESS(status)) {
numFmt->parse(formatted, parseResult, status);
@ -5919,7 +5918,7 @@ void NumberFormatTest::TestFieldPositionIterator() {
void NumberFormatTest::TestFormatAttributes() {
Locale locale("en_US");
UErrorCode status = U_ZERO_ERROR;
DecimalFormat *decFmt = (DecimalFormat *) NumberFormat::createInstance(locale, NumberFormat::kCurrencyStyle, status);
DecimalFormat *decFmt = (DecimalFormat *) NumberFormat::createInstance(locale, UNUM_CURRENCY, status);
if (failure(status, "NumberFormat::createInstance", TRUE)) return;
double val = 12345.67;
@ -5952,7 +5951,7 @@ void NumberFormatTest::TestFormatAttributes() {
}
delete decFmt;
decFmt = (DecimalFormat *) NumberFormat::createInstance(locale, NumberFormat::kScientificStyle, status);
decFmt = (DecimalFormat *) NumberFormat::createInstance(locale, UNUM_SCIENTIFIC, status);
val = -0.0000123;
{
int32_t expected[] = {
@ -6078,8 +6077,7 @@ void NumberFormatTest::TestDecimal() {
{
UErrorCode status = U_ZERO_ERROR;
NumberFormat *fmtr = NumberFormat::createInstance(
Locale::getUS(), NumberFormat::kNumberStyle, status);
NumberFormat *fmtr = NumberFormat::createInstance(Locale::getUS(), UNUM_DECIMAL, status);
if (U_FAILURE(status) || fmtr == NULL) {
dataerrln("Unable to create NumberFormat");
} else {
@ -6097,8 +6095,7 @@ void NumberFormatTest::TestDecimal() {
// Check formatting a DigitList. DigitList is internal, but this is
// a critical interface that must work.
UErrorCode status = U_ZERO_ERROR;
NumberFormat *fmtr = NumberFormat::createInstance(
Locale::getUS(), NumberFormat::kNumberStyle, status);
NumberFormat *fmtr = NumberFormat::createInstance(Locale::getUS(), UNUM_DECIMAL, status);
if (U_FAILURE(status) || fmtr == NULL) {
dataerrln("Unable to create NumberFormat");
} else {
@ -6129,8 +6126,7 @@ void NumberFormatTest::TestDecimal() {
{
// Check a parse with a formatter with a multiplier.
UErrorCode status = U_ZERO_ERROR;
NumberFormat *fmtr = NumberFormat::createInstance(
Locale::getUS(), NumberFormat::kPercentStyle, status);
NumberFormat *fmtr = NumberFormat::createInstance(Locale::getUS(), UNUM_PERCENT, status);
if (U_FAILURE(status) || fmtr == NULL) {
dataerrln("Unable to create NumberFormat");
} else {
@ -6147,8 +6143,7 @@ void NumberFormatTest::TestDecimal() {
{
// Check that a parse returns a decimal number with full accuracy
UErrorCode status = U_ZERO_ERROR;
NumberFormat *fmtr = NumberFormat::createInstance(
Locale::getUS(), NumberFormat::kNumberStyle, status);
NumberFormat *fmtr = NumberFormat::createInstance(Locale::getUS(), UNUM_DECIMAL, status);
if (U_FAILURE(status) || fmtr == NULL) {
dataerrln("Unable to create NumberFormat");
} else {