DecimalFormat::DecimalFormat(UErrorCode& status)
: DecimalFormat(nullptr, status) {
+ // Use the default locale and decimal pattern.
+ const char* localeName = Locale::getDefault().getName();
+ LocalPointer<NumberingSystem> ns(NumberingSystem::createInstance(status));
+ UnicodeString patternString = utils::getPatternForStyle(
+ localeName,
+ ns->getName(),
+ CLDR_PATTERN_STYLE_DECIMAL,
+ status);
+ setPropertiesFromPattern(patternString, IGNORE_ROUNDING_IF_CURRENCY, status);
+ refreshFormatter(status);
}
DecimalFormat::DecimalFormat(const UnicodeString& pattern, UErrorCode& status)
namespace {
-// NOTE: In Java, the method to get a pattern from the resource bundle exists in NumberFormat.
-// In C++, we have to implement that logic here.
-// TODO: Make Java and C++ consistent?
-
-enum CldrPatternStyle {
- CLDR_PATTERN_STYLE_DECIMAL,
- CLDR_PATTERN_STYLE_CURRENCY,
- CLDR_PATTERN_STYLE_ACCOUNTING,
- CLDR_PATTERN_STYLE_PERCENT
- // TODO: Consider scientific format.
-};
-
-const char16_t*
-doGetPattern(UResourceBundle* res, const char* nsName, const char* patternKey, UErrorCode& publicStatus,
- UErrorCode& localStatus) {
- // Construct the path into the resource bundle
- CharString key;
- key.append("NumberElements/", publicStatus);
- key.append(nsName, publicStatus);
- key.append("/patterns/", publicStatus);
- key.append(patternKey, publicStatus);
- if (U_FAILURE(publicStatus)) {
- return u"";
- }
- return ures_getStringByKeyWithFallback(res, key.data(), nullptr, &localStatus);
-}
-
-const char16_t* getPatternForStyle(const Locale& locale, const char* nsName, CldrPatternStyle style,
- UErrorCode& status) {
- const char* patternKey;
- switch (style) {
- case CLDR_PATTERN_STYLE_DECIMAL:
- patternKey = "decimalFormat";
- break;
- case CLDR_PATTERN_STYLE_CURRENCY:
- patternKey = "currencyFormat";
- break;
- case CLDR_PATTERN_STYLE_ACCOUNTING:
- patternKey = "accountingFormat";
- break;
- case CLDR_PATTERN_STYLE_PERCENT:
- default:
- patternKey = "percentFormat";
- break;
- }
- LocalUResourceBundlePointer res(ures_open(nullptr, locale.getName(), &status));
- if (U_FAILURE(status)) { return u""; }
-
- // Attempt to get the pattern with the native numbering system.
- UErrorCode localStatus = U_ZERO_ERROR;
- const char16_t* pattern;
- pattern = doGetPattern(res.getAlias(), nsName, patternKey, status, localStatus);
- if (U_FAILURE(status)) { return u""; }
-
- // Fall back to latn if native numbering system does not have the right pattern
- if (U_FAILURE(localStatus) && uprv_strcmp("latn", nsName) != 0) {
- localStatus = U_ZERO_ERROR;
- pattern = doGetPattern(res.getAlias(), "latn", patternKey, status, localStatus);
- if (U_FAILURE(status)) { return u""; }
- }
-
- return pattern;
-}
-
struct CurrencyFormatInfoResult {
bool exists;
const char16_t* pattern;
// TODO: Accept currency symbols from DecimalFormatSymbols?
// Pre-compute a few values for efficiency.
- bool isCurrency = unitIsCurrency(macros.unit);
- bool isNoUnit = unitIsNoUnit(macros.unit);
- bool isPercent = isNoUnit && unitIsPercent(macros.unit);
- bool isPermille = isNoUnit && unitIsPermille(macros.unit);
+ bool isCurrency = utils::unitIsCurrency(macros.unit);
+ bool isNoUnit = utils::unitIsNoUnit(macros.unit);
+ bool isPercent = isNoUnit && utils::unitIsPercent(macros.unit);
+ bool isPermille = isNoUnit && utils::unitIsPermille(macros.unit);
bool isCldrUnit = !isCurrency && !isNoUnit;
bool isAccounting =
macros.sign == UNUM_SIGN_ACCOUNTING || macros.sign == UNUM_SIGN_ACCOUNTING_ALWAYS ||
} else {
patternStyle = CLDR_PATTERN_STYLE_CURRENCY;
}
- pattern = getPatternForStyle(macros.locale, nsName, patternStyle, status);
+ pattern = utils::getPatternForStyle(macros.locale, nsName, patternStyle, status);
}
auto patternInfo = new ParsedPatternInfo();
fPatternInfo.adoptInstead(patternInfo);
// Get and append the next digit value
int8_t nextDigit = quantity.getDigit(i);
- length += insertDigitFromSymbols(
+ length += utils::insertDigitFromSymbols(
string, 0, nextDigit, *micros.symbols, UNUM_INTEGER_FIELD, status);
}
return length;
for (int i = 0; i < fractionCount; i++) {
// Get and append the next digit value
int8_t nextDigit = quantity.getDigit(-i - 1);
- length += insertDigitFromSymbols(
+ length += utils::insertDigitFromSymbols(
string, string.length(), nextDigit, *micros.symbols, UNUM_FRACTION_FIELD, status);
}
return length;
int32_t disp = std::abs(fExponent);
for (int j = 0; j < fHandler->fSettings.fMinExponentDigits || disp > 0; j++, disp /= 10) {
auto d = static_cast<int8_t>(disp % 10);
- i += insertDigitFromSymbols(output, i - j, d, *fHandler->fSymbols, UNUM_EXPONENT_FIELD, status);
+ i += utils::insertDigitFromSymbols(
+ output,
+ i - j,
+ d,
+ *fHandler->fSymbols,
+ UNUM_EXPONENT_FIELD,
+ status);
}
return i - rightIndex;
}
}
bool GeneratorHelpers::unit(const MacroProps& macros, UnicodeString& sb, UErrorCode& status) {
- if (unitIsCurrency(macros.unit)) {
+ if (utils::unitIsCurrency(macros.unit)) {
sb.append(u"currency/", -1);
blueprint_helpers::generateCurrencyOption({macros.unit, status}, sb, status);
return true;
- } else if (unitIsNoUnit(macros.unit)) {
- if (unitIsPercent(macros.unit)) {
+ } else if (utils::unitIsNoUnit(macros.unit)) {
+ if (utils::unitIsPercent(macros.unit)) {
sb.append(u"percent", -1);
return true;
- } else if (unitIsPermille(macros.unit)) {
+ } else if (utils::unitIsPermille(macros.unit)) {
sb.append(u"permille", -1);
return true;
} else {
bool GeneratorHelpers::perUnit(const MacroProps& macros, UnicodeString& sb, UErrorCode& status) {
// Per-units are currently expected to be only MeasureUnits.
- if (unitIsNoUnit(macros.perUnit)) {
- if (unitIsPercent(macros.perUnit) || unitIsPermille(macros.perUnit)) {
+ if (utils::unitIsNoUnit(macros.perUnit)) {
+ if (utils::unitIsPercent(macros.perUnit) || utils::unitIsPermille(macros.perUnit)) {
status = U_UNSUPPORTED_ERROR;
return false;
} else {
// Default value: ok to ignore
return false;
}
- } else if (unitIsCurrency(macros.perUnit)) {
+ } else if (utils::unitIsCurrency(macros.perUnit)) {
status = U_UNSUPPORTED_ERROR;
return false;
} else {
#include "decContext.h"
#include "decNumber.h"
#include "double-conversion.h"
+#include "uresimp.h"
+#include "ureslocs.h"
using namespace icu;
using namespace icu::number;
using icu::double_conversion::DoubleToStringConverter;
+namespace {
+
+const char16_t*
+doGetPattern(UResourceBundle* res, const char* nsName, const char* patternKey, UErrorCode& publicStatus,
+ UErrorCode& localStatus) {
+ // Construct the path into the resource bundle
+ CharString key;
+ key.append("NumberElements/", publicStatus);
+ key.append(nsName, publicStatus);
+ key.append("/patterns/", publicStatus);
+ key.append(patternKey, publicStatus);
+ if (U_FAILURE(publicStatus)) {
+ return u"";
+ }
+ return ures_getStringByKeyWithFallback(res, key.data(), nullptr, &localStatus);
+}
+
+}
+
+
+const char16_t* utils::getPatternForStyle(const Locale& locale, const char* nsName, CldrPatternStyle style,
+ UErrorCode& status) {
+ const char* patternKey;
+ switch (style) {
+ case CLDR_PATTERN_STYLE_DECIMAL:
+ patternKey = "decimalFormat";
+ break;
+ case CLDR_PATTERN_STYLE_CURRENCY:
+ patternKey = "currencyFormat";
+ break;
+ case CLDR_PATTERN_STYLE_ACCOUNTING:
+ patternKey = "accountingFormat";
+ break;
+ case CLDR_PATTERN_STYLE_PERCENT:
+ patternKey = "percentFormat";
+ break;
+ case CLDR_PATTERN_STYLE_SCIENTIFIC:
+ patternKey = "scientificFormat";
+ break;
+ default:
+ U_ASSERT(false);
+ }
+ LocalUResourceBundlePointer res(ures_open(nullptr, locale.getName(), &status));
+ if (U_FAILURE(status)) { return u""; }
+
+ // Attempt to get the pattern with the native numbering system.
+ UErrorCode localStatus = U_ZERO_ERROR;
+ const char16_t* pattern;
+ pattern = doGetPattern(res.getAlias(), nsName, patternKey, status, localStatus);
+ if (U_FAILURE(status)) { return u""; }
+
+ // Fall back to latn if native numbering system does not have the right pattern
+ if (U_FAILURE(localStatus) && uprv_strcmp("latn", nsName) != 0) {
+ localStatus = U_ZERO_ERROR;
+ pattern = doGetPattern(res.getAlias(), "latn", patternKey, status, localStatus);
+ if (U_FAILURE(status)) { return u""; }
+ }
+
+ return pattern;
+}
+
+
DecNum::DecNum() {
uprv_decContextDefault(&fContext, DEC_INIT_BASE);
uprv_decContextSetRounding(&fContext, DEC_ROUND_HALF_EVEN);
bool exhausted = false;
};
+enum CldrPatternStyle {
+ CLDR_PATTERN_STYLE_DECIMAL,
+ CLDR_PATTERN_STYLE_CURRENCY,
+ CLDR_PATTERN_STYLE_ACCOUNTING,
+ CLDR_PATTERN_STYLE_PERCENT,
+ CLDR_PATTERN_STYLE_SCIENTIFIC,
+ CLDR_PATTERN_STYLE_COUNT,
+};
+
+// Namespace for naked functions
+namespace utils {
+
inline int32_t insertDigitFromSymbols(NumberStringBuilder& output, int32_t index, int8_t digit,
const DecimalFormatSymbols& symbols, Field field,
UErrorCode& status) {
return uprv_strcmp("permille", unit.getSubtype()) == 0;
}
+// NOTE: In Java, this method is in NumberFormat.java
+const char16_t*
+getPatternForStyle(const Locale& locale, const char* nsName, CldrPatternStyle style, UErrorCode& status);
+
+} // namespace utils
+
/** A very thin C++ wrapper around decNumber.h */
class DecNum : public UMemory {
#include "sharednumberformat.h"
#include "unifiedcache.h"
#include "number_decimalquantity.h"
+#include "number_utils.h"
//#define FMT_DEBUG
// Keys used for accessing resource bundles
-static const char *gNumberElements = "NumberElements";
-static const char *gLatn = "latn";
-static const char *gPatterns = "patterns";
-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
+static const icu::number::impl::CldrPatternStyle gFormatCldrStyles[UNUM_FORMAT_STYLE_COUNT] = {
+ /* NULL */ icu::number::impl::CLDR_PATTERN_STYLE_COUNT, // UNUM_PATTERN_DECIMAL
+ icu::number::impl::CLDR_PATTERN_STYLE_DECIMAL, // UNUM_DECIMAL
+ icu::number::impl::CLDR_PATTERN_STYLE_CURRENCY, // UNUM_CURRENCY
+ icu::number::impl::CLDR_PATTERN_STYLE_PERCENT, // UNUM_PERCENT
+ icu::number::impl::CLDR_PATTERN_STYLE_SCIENTIFIC, // UNUM_SCIENTIFIC
+ /* NULL */ icu::number::impl::CLDR_PATTERN_STYLE_COUNT, // UNUM_SPELLOUT
+ /* NULL */ icu::number::impl::CLDR_PATTERN_STYLE_COUNT, // UNUM_ORDINAL
+ /* NULL */ icu::number::impl::CLDR_PATTERN_STYLE_COUNT, // UNUM_DURATION
+ /* NULL */ icu::number::impl::CLDR_PATTERN_STYLE_COUNT, // UNUM_NUMBERING_SYSTEM
+ /* NULL */ icu::number::impl::CLDR_PATTERN_STYLE_COUNT, // 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
- "accountingFormat", // UNUM_CURRENCY_ACCOUNTING
- "currencyFormat", // UNUM_CASH_CURRENCY
- NULL, // UNUM_DECIMAL_COMPACT_SHORT
- NULL, // UNUM_DECIMAL_COMPACT_LONG
- "currencyFormat", // UNUM_CURRENCY_STANDARD
+ icu::number::impl::CLDR_PATTERN_STYLE_CURRENCY, // UNUM_CURRENCY_ISO
+ icu::number::impl::CLDR_PATTERN_STYLE_CURRENCY, // UNUM_CURRENCY_PLURAL
+ icu::number::impl::CLDR_PATTERN_STYLE_ACCOUNTING, // UNUM_CURRENCY_ACCOUNTING
+ icu::number::impl::CLDR_PATTERN_STYLE_CURRENCY, // UNUM_CASH_CURRENCY
+ /* NULL */ icu::number::impl::CLDR_PATTERN_STYLE_COUNT, // UNUM_DECIMAL_COMPACT_SHORT
+ /* NULL */ icu::number::impl::CLDR_PATTERN_STYLE_COUNT, // UNUM_DECIMAL_COMPACT_LONG
+ icu::number::impl::CLDR_PATTERN_STYLE_CURRENCY, // UNUM_CURRENCY_STANDARD
};
// Static hashtable cache of NumberingSystem objects used by NumberFormat
return NULL;
}
- UResourceBundle *resource = ownedResource.orphan();
- UResourceBundle *numElements = ures_getByKeyWithFallback(resource, gNumberElements, NULL, &status);
- resource = ures_getByKeyWithFallback(numElements, ns->getName(), resource, &status);
- resource = ures_getByKeyWithFallback(resource, gPatterns, resource, &status);
- ownedResource.adoptInstead(resource);
-
- int32_t patLen = 0;
- const UChar *patResStr = ures_getStringByKeyWithFallback(resource, gFormatKeys[style], &patLen, &status);
-
- // Didn't find a pattern specific to the numbering system, so fall back to "latn"
- if ( status == U_MISSING_RESOURCE_ERROR && uprv_strcmp(gLatn,ns->getName())) {
- status = U_ZERO_ERROR;
- resource = ures_getByKeyWithFallback(numElements, gLatn, resource, &status);
- resource = ures_getByKeyWithFallback(resource, gPatterns, resource, &status);
- patResStr = ures_getStringByKeyWithFallback(resource, gFormatKeys[style], &patLen, &status);
- }
-
- ures_close(numElements);
-
- // Creates the specified decimal format style of the desired locale.
- pattern.setTo(TRUE, patResStr, patLen);
+ // Load the pattern from data using the common library function
+ const char16_t* patternPtr = number::impl::utils::getPatternForStyle(
+ desiredLocale,
+ ns->getName(),
+ gFormatCldrStyles[style],
+ status);
+ pattern = UnicodeString(TRUE, patternPtr, -1);
}
if (U_FAILURE(status)) {
return NULL;