| Index: source/i18n/tmutfmt.cpp
|
| diff --git a/source/i18n/tmutfmt.cpp b/source/i18n/tmutfmt.cpp
|
| index 6dddc5437236c4179bc47554c432770f46f24efc..3251bc855235f3882eb9104ce149b2df3d603191 100644
|
| --- a/source/i18n/tmutfmt.cpp
|
| +++ b/source/i18n/tmutfmt.cpp
|
| @@ -1,22 +1,23 @@
|
| /*
|
| *******************************************************************************
|
| - * Copyright (C) 2008-2013, Google, International Business Machines Corporation
|
| + * Copyright (C) 2008-2014, Google, International Business Machines Corporation
|
| * and others. All Rights Reserved.
|
| *******************************************************************************
|
| */
|
|
|
| -#include "utypeinfo.h" // for 'typeid' to work
|
| -
|
| #include "unicode/tmutfmt.h"
|
|
|
| #if !UCONFIG_NO_FORMATTING
|
|
|
| +#include "unicode/decimfmt.h"
|
| +#include "plurrule_impl.h"
|
| #include "uvector.h"
|
| #include "charstr.h"
|
| #include "cmemory.h"
|
| #include "cstring.h"
|
| #include "hash.h"
|
| #include "uresimp.h"
|
| +#include "ureslocs.h"
|
| #include "unicode/msgfmt.h"
|
| #include "uassert.h"
|
|
|
| @@ -76,53 +77,59 @@ static const UChar PLURAL_COUNT_ZERO[] = {LOW_Z, LOW_E, LOW_R, LOW_O, 0};
|
| static const UChar PLURAL_COUNT_ONE[] = {LOW_O, LOW_N, LOW_E, 0};
|
| static const UChar PLURAL_COUNT_TWO[] = {LOW_T, LOW_W, LOW_O, 0};
|
|
|
| -TimeUnitFormat::TimeUnitFormat(UErrorCode& status)
|
| -: fNumberFormat(NULL),
|
| - fPluralRules(NULL) {
|
| - create(Locale::getDefault(), UTMUTFMT_FULL_STYLE, status);
|
| +TimeUnitFormat::TimeUnitFormat(UErrorCode& status) {
|
| + initMeasureFormat(Locale::getDefault(), UMEASFMT_WIDTH_WIDE, NULL, status);
|
| + create(UTMUTFMT_FULL_STYLE, status);
|
| }
|
|
|
|
|
| -TimeUnitFormat::TimeUnitFormat(const Locale& locale, UErrorCode& status)
|
| -: fNumberFormat(NULL),
|
| - fPluralRules(NULL) {
|
| - create(locale, UTMUTFMT_FULL_STYLE, status);
|
| +TimeUnitFormat::TimeUnitFormat(const Locale& locale, UErrorCode& status) {
|
| + initMeasureFormat(locale, UMEASFMT_WIDTH_WIDE, NULL, status);
|
| + create(UTMUTFMT_FULL_STYLE, status);
|
| }
|
|
|
|
|
| -TimeUnitFormat::TimeUnitFormat(const Locale& locale, UTimeUnitFormatStyle style, UErrorCode& status)
|
| -: fNumberFormat(NULL),
|
| - fPluralRules(NULL) {
|
| - create(locale, style, status);
|
| +TimeUnitFormat::TimeUnitFormat(const Locale& locale, UTimeUnitFormatStyle style, UErrorCode& status) {
|
| + switch (style) {
|
| + case UTMUTFMT_FULL_STYLE:
|
| + initMeasureFormat(locale, UMEASFMT_WIDTH_WIDE, NULL, status);
|
| + break;
|
| + case UTMUTFMT_ABBREVIATED_STYLE:
|
| + initMeasureFormat(locale, UMEASFMT_WIDTH_SHORT, NULL, status);
|
| + break;
|
| + default:
|
| + initMeasureFormat(locale, UMEASFMT_WIDTH_WIDE, NULL, status);
|
| + break;
|
| + }
|
| + create(style, status);
|
| }
|
|
|
| -
|
| TimeUnitFormat::TimeUnitFormat(const TimeUnitFormat& other)
|
| : MeasureFormat(other),
|
| - fNumberFormat(NULL),
|
| - fPluralRules(NULL),
|
| - fStyle(UTMUTFMT_FULL_STYLE)
|
| + fStyle(other.fStyle)
|
| {
|
| for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
|
| i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
|
| i = (TimeUnit::UTimeUnitFields)(i+1)) {
|
| - fTimeUnitToCountToPatterns[i] = NULL;
|
| - }
|
| - *this = other;
|
| + UErrorCode status = U_ZERO_ERROR;
|
| + fTimeUnitToCountToPatterns[i] = initHash(status);
|
| + if (U_SUCCESS(status)) {
|
| + copyHash(other.fTimeUnitToCountToPatterns[i], fTimeUnitToCountToPatterns[i], status);
|
| + } else {
|
| + delete fTimeUnitToCountToPatterns[i];
|
| + fTimeUnitToCountToPatterns[i] = NULL;
|
| + }
|
| + }
|
| }
|
|
|
|
|
| TimeUnitFormat::~TimeUnitFormat() {
|
| - delete fNumberFormat;
|
| - fNumberFormat = NULL;
|
| for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
|
| i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
|
| i = (TimeUnit::UTimeUnitFields)(i+1)) {
|
| deleteHash(fTimeUnitToCountToPatterns[i]);
|
| fTimeUnitToCountToPatterns[i] = NULL;
|
| }
|
| - delete fPluralRules;
|
| - fPluralRules = NULL;
|
| }
|
|
|
|
|
| @@ -137,20 +144,13 @@ TimeUnitFormat::operator=(const TimeUnitFormat& other) {
|
| if (this == &other) {
|
| return *this;
|
| }
|
| - delete fNumberFormat;
|
| + MeasureFormat::operator=(other);
|
| for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
|
| i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
|
| i = (TimeUnit::UTimeUnitFields)(i+1)) {
|
| deleteHash(fTimeUnitToCountToPatterns[i]);
|
| fTimeUnitToCountToPatterns[i] = NULL;
|
| }
|
| - delete fPluralRules;
|
| - if (other.fNumberFormat) {
|
| - fNumberFormat = (NumberFormat*)other.fNumberFormat->clone();
|
| - } else {
|
| - fNumberFormat = NULL;
|
| - }
|
| - fLocale = other.fLocale;
|
| for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
|
| i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
|
| i = (TimeUnit::UTimeUnitFields)(i+1)) {
|
| @@ -163,82 +163,15 @@ TimeUnitFormat::operator=(const TimeUnitFormat& other) {
|
| fTimeUnitToCountToPatterns[i] = NULL;
|
| }
|
| }
|
| - if (other.fPluralRules) {
|
| - fPluralRules = (PluralRules*)other.fPluralRules->clone();
|
| - } else {
|
| - fPluralRules = NULL;
|
| - }
|
| fStyle = other.fStyle;
|
| return *this;
|
| }
|
|
|
| -
|
| -UBool
|
| -TimeUnitFormat::operator==(const Format& other) const {
|
| - if (typeid(*this) == typeid(other)) {
|
| - TimeUnitFormat* fmt = (TimeUnitFormat*)&other;
|
| - UBool ret = ( ((fNumberFormat && fmt->fNumberFormat && *fNumberFormat == *fmt->fNumberFormat)
|
| - || fNumberFormat == fmt->fNumberFormat )
|
| - && fLocale == fmt->fLocale
|
| - && ((fPluralRules && fmt->fPluralRules && *fPluralRules == *fmt->fPluralRules)
|
| - || fPluralRules == fmt->fPluralRules)
|
| - && fStyle == fmt->fStyle);
|
| - if (ret) {
|
| - for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
|
| - i < TimeUnit::UTIMEUNIT_FIELD_COUNT && ret;
|
| - i = (TimeUnit::UTimeUnitFields)(i+1)) {
|
| - ret = fTimeUnitToCountToPatterns[i]->equals(*(fmt->fTimeUnitToCountToPatterns[i]));
|
| - }
|
| - }
|
| - return ret;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -
|
| -UnicodeString&
|
| -TimeUnitFormat::format(const Formattable& obj, UnicodeString& toAppendTo,
|
| - FieldPosition& pos, UErrorCode& status) const {
|
| - if (U_FAILURE(status)) {
|
| - return toAppendTo;
|
| - }
|
| - if (obj.getType() == Formattable::kObject) {
|
| - const UObject* formatObj = obj.getObject();
|
| - const TimeUnitAmount* amount = dynamic_cast<const TimeUnitAmount*>(formatObj);
|
| - if (amount != NULL){
|
| - Hashtable* countToPattern = fTimeUnitToCountToPatterns[amount->getTimeUnitField()];
|
| - double number;
|
| - const Formattable& amtNumber = amount->getNumber();
|
| - if (amtNumber.getType() == Formattable::kDouble) {
|
| - number = amtNumber.getDouble();
|
| - } else if (amtNumber.getType() == Formattable::kLong) {
|
| - number = amtNumber.getLong();
|
| - } else {
|
| - status = U_ILLEGAL_ARGUMENT_ERROR;
|
| - return toAppendTo;
|
| - }
|
| - UnicodeString count = fPluralRules->select(number);
|
| -#ifdef TMUTFMT_DEBUG
|
| - char result[1000];
|
| - count.extract(0, count.length(), result, "UTF-8");
|
| - std::cout << "number: " << number << "; format plural count: " << result << "\n";
|
| -#endif
|
| - MessageFormat* pattern = ((MessageFormat**)countToPattern->get(count))[fStyle];
|
| - Formattable formattable[1];
|
| - formattable[0].setDouble(number);
|
| - return pattern->format(formattable, 1, toAppendTo, pos, status);
|
| - }
|
| - }
|
| - status = U_ILLEGAL_ARGUMENT_ERROR;
|
| - return toAppendTo;
|
| -}
|
| -
|
| -
|
| void
|
| TimeUnitFormat::parseObject(const UnicodeString& source,
|
| Formattable& result,
|
| ParsePosition& pos) const {
|
| - double resultNumber = -1;
|
| + Formattable resultNumber(0.0);
|
| UBool withNumberFormat = false;
|
| TimeUnit::UTimeUnitFields resultTimeUnit = TimeUnit::UTIMEUNIT_FIELD_COUNT;
|
| int32_t oldPos = pos.getIndex();
|
| @@ -282,26 +215,21 @@ TimeUnitFormat::parseObject(const UnicodeString& source,
|
| #ifdef TMUTFMT_DEBUG
|
| std::cout << "parsed.getType: " << parsed.getType() << "\n";
|
| #endif
|
| - double tmpNumber = 0;
|
| + Formattable tmpNumber(0.0);
|
| if (pattern->getArgTypeCount() != 0) {
|
| - // pattern with Number as beginning, such as "{0} d".
|
| - // check to make sure that the timeUnit is consistent
|
| Formattable& temp = parsed[0];
|
| - if (temp.getType() == Formattable::kDouble) {
|
| - tmpNumber = temp.getDouble();
|
| - } else if (temp.getType() == Formattable::kLong) {
|
| - tmpNumber = temp.getLong();
|
| + if (temp.getType() == Formattable::kString) {
|
| + UnicodeString tmpString;
|
| + UErrorCode pStatus = U_ZERO_ERROR;
|
| + getNumberFormat().parse(temp.getString(tmpString), tmpNumber, pStatus);
|
| + if (U_FAILURE(pStatus)) {
|
| + continue;
|
| + }
|
| + } else if (temp.isNumeric()) {
|
| + tmpNumber = temp;
|
| } else {
|
| continue;
|
| }
|
| - UnicodeString select = fPluralRules->select(tmpNumber);
|
| - #ifdef TMUTFMT_DEBUG
|
| - select.extract(0, select.length(), res, "UTF-8");
|
| - std::cout << "parse plural select count: " << res << "\n";
|
| - #endif
|
| - if (*count != select) {
|
| - continue;
|
| - }
|
| }
|
| int32_t parseDistance = pos.getIndex() - oldPos;
|
| if (parseDistance > longestParseDistance) {
|
| @@ -327,15 +255,15 @@ TimeUnitFormat::parseObject(const UnicodeString& source,
|
| if (withNumberFormat == false && longestParseDistance != 0) {
|
| // set the number using plurrual count
|
| if (0 == countOfLongestMatch->compare(PLURAL_COUNT_ZERO, 4)) {
|
| - resultNumber = 0;
|
| + resultNumber = Formattable(0.0);
|
| } else if (0 == countOfLongestMatch->compare(PLURAL_COUNT_ONE, 3)) {
|
| - resultNumber = 1;
|
| + resultNumber = Formattable(1.0);
|
| } else if (0 == countOfLongestMatch->compare(PLURAL_COUNT_TWO, 3)) {
|
| - resultNumber = 2;
|
| + resultNumber = Formattable(2.0);
|
| } else {
|
| // should not happen.
|
| // TODO: how to handle?
|
| - resultNumber = 3;
|
| + resultNumber = Formattable(3.0);
|
| }
|
| }
|
| if (longestParseDistance == 0) {
|
| @@ -356,7 +284,15 @@ TimeUnitFormat::parseObject(const UnicodeString& source,
|
| }
|
|
|
| void
|
| -TimeUnitFormat::create(const Locale& locale, UTimeUnitFormatStyle style, UErrorCode& status) {
|
| +TimeUnitFormat::create(UTimeUnitFormatStyle style, UErrorCode& status) {
|
| + // fTimeUnitToCountToPatterns[] must have its elements initialized to NULL first
|
| + // before checking for failure status.
|
| + for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
|
| + i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
|
| + i = (TimeUnit::UTimeUnitFields)(i+1)) {
|
| + fTimeUnitToCountToPatterns[i] = NULL;
|
| + }
|
| +
|
| if (U_FAILURE(status)) {
|
| return;
|
| }
|
| @@ -365,12 +301,7 @@ TimeUnitFormat::create(const Locale& locale, UTimeUnitFormatStyle style, UErrorC
|
| return;
|
| }
|
| fStyle = style;
|
| - fLocale = locale;
|
| - for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
|
| - i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
|
| - i = (TimeUnit::UTimeUnitFields)(i+1)) {
|
| - fTimeUnitToCountToPatterns[i] = NULL;
|
| - }
|
| +
|
| //TODO: format() and parseObj() are const member functions,
|
| //so, can not do lazy initialization in C++.
|
| //setup has to be done in constructors.
|
| @@ -387,7 +318,7 @@ TimeUnitFormat::setup(UErrorCode& err) {
|
| initDataMembers(err);
|
|
|
| UVector pluralCounts(0, uhash_compareUnicodeString, 6, err);
|
| - StringEnumeration* keywords = fPluralRules->getKeywords(err);
|
| + StringEnumeration* keywords = getPluralRules().getKeywords(err);
|
| if (U_FAILURE(err)) {
|
| return;
|
| }
|
| @@ -408,11 +339,6 @@ TimeUnitFormat::initDataMembers(UErrorCode& err){
|
| if (U_FAILURE(err)) {
|
| return;
|
| }
|
| - if (fNumberFormat == NULL) {
|
| - fNumberFormat = NumberFormat::createInstance(fLocale, err);
|
| - }
|
| - delete fPluralRules;
|
| - fPluralRules = PluralRules::forLocale(fLocale, err);
|
| for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
|
| i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
|
| i = (TimeUnit::UTimeUnitFields)(i+1)) {
|
| @@ -433,7 +359,7 @@ TimeUnitFormat::readFromCurrentLocale(UTimeUnitFormatStyle style, const char* ke
|
| // status does not affect "err".
|
| UErrorCode status = U_ZERO_ERROR;
|
| UResourceBundle *rb, *unitsRes;
|
| - rb = ures_open(NULL, fLocale.getName(), &status);
|
| + rb = ures_open(U_ICUDATA_UNIT, getLocaleID(status), &status);
|
| unitsRes = ures_getByKey(rb, key, NULL, &status);
|
| unitsRes = ures_getByKey(unitsRes, "duration", unitsRes, &status);
|
| if (U_FAILURE(status)) {
|
| @@ -503,11 +429,8 @@ TimeUnitFormat::readFromCurrentLocale(UTimeUnitFormatStyle style, const char* ke
|
| if (!pluralCounts.contains(&pluralCountUniStr)) {
|
| continue;
|
| }
|
| - MessageFormat* messageFormat = new MessageFormat(pattern, fLocale, err);
|
| + MessageFormat* messageFormat = new MessageFormat(pattern, getLocale(err), err);
|
| if ( U_SUCCESS(err) ) {
|
| - if (fNumberFormat != NULL) {
|
| - messageFormat->setFormat(0, *fNumberFormat);
|
| - }
|
| MessageFormat** formatters = (MessageFormat**)countToPatterns->get(pluralCountUniStr);
|
| if (formatters == NULL) {
|
| formatters = (MessageFormat**)uprv_malloc(UTMUTFMT_FORMAT_STYLE_COUNT*sizeof(MessageFormat*));
|
| @@ -568,7 +491,7 @@ TimeUnitFormat::checkConsistency(UTimeUnitFormatStyle style, const char* key, UE
|
| // Following is consistency check to create pattern for each
|
| // plural rule in each time unit using above fall-back rule.
|
| //
|
| - StringEnumeration* keywords = fPluralRules->getKeywords(err);
|
| + StringEnumeration* keywords = getPluralRules().getKeywords(err);
|
| if (U_SUCCESS(err)) {
|
| const UnicodeString* pluralCount;
|
| while ((pluralCount = keywords->snext(err)) != NULL) {
|
| @@ -588,7 +511,7 @@ TimeUnitFormat::checkConsistency(UTimeUnitFormatStyle style, const char* key, UE
|
| MessageFormat** formatters = (MessageFormat**)countToPatterns->get(*pluralCount);
|
| if( formatters == NULL || formatters[style] == NULL ) {
|
| // look through parents
|
| - const char* localeName = fLocale.getName();
|
| + const char* localeName = getLocaleID(err);
|
| CharString pluralCountChars;
|
| pluralCountChars.appendInvariantChars(*pluralCount, err);
|
| searchInLocaleChain(style, key, localeName,
|
| @@ -632,7 +555,7 @@ TimeUnitFormat::searchInLocaleChain(UTimeUnitFormatStyle style, const char* key,
|
| ULOC_FULLNAME_CAPACITY, &status)) >= 0){
|
| // look for pattern for srcPluralCount in locale tree
|
| UResourceBundle *rb, *unitsRes, *countsToPatternRB;
|
| - rb = ures_open(NULL, parentLocale, &status);
|
| + rb = ures_open(U_ICUDATA_UNIT, parentLocale, &status);
|
| unitsRes = ures_getByKey(rb, key, NULL, &status);
|
| const char* timeUnitName = getTimeUnitName(srcTimeUnitField, status);
|
| countsToPatternRB = ures_getByKey(unitsRes, timeUnitName, NULL, &status);
|
| @@ -641,11 +564,8 @@ TimeUnitFormat::searchInLocaleChain(UTimeUnitFormatStyle style, const char* key,
|
| pattern = ures_getStringByKeyWithFallback(countsToPatternRB, searchPluralCount, &ptLength, &status);
|
| if (U_SUCCESS(status)) {
|
| //found
|
| - MessageFormat* messageFormat = new MessageFormat(UnicodeString(TRUE, pattern, ptLength), fLocale, err);
|
| + MessageFormat* messageFormat = new MessageFormat(UnicodeString(TRUE, pattern, ptLength), getLocale(err), err);
|
| if (U_SUCCESS(err)) {
|
| - if (fNumberFormat != NULL) {
|
| - messageFormat->setFormat(0, *fNumberFormat);
|
| - }
|
| MessageFormat** formatters = (MessageFormat**)countToPatterns->get(srcPluralCount);
|
| if (formatters == NULL) {
|
| formatters = (MessageFormat**)uprv_malloc(UTMUTFMT_FORMAT_STYLE_COUNT*sizeof(MessageFormat*));
|
| @@ -719,12 +639,9 @@ TimeUnitFormat::searchInLocaleChain(UTimeUnitFormatStyle style, const char* key,
|
| pattern = DEFAULT_PATTERN_FOR_YEAR;
|
| }
|
| if (pattern != NULL) {
|
| - messageFormat = new MessageFormat(UnicodeString(TRUE, pattern, -1), fLocale, err);
|
| + messageFormat = new MessageFormat(UnicodeString(TRUE, pattern, -1), getLocale(err), err);
|
| }
|
| if (U_SUCCESS(err)) {
|
| - if (fNumberFormat != NULL && messageFormat != NULL) {
|
| - messageFormat->setFormat(0, *fNumberFormat);
|
| - }
|
| MessageFormat** formatters = (MessageFormat**)countToPatterns->get(srcPluralCount);
|
| if (formatters == NULL) {
|
| formatters = (MessageFormat**)uprv_malloc(UTMUTFMT_FORMAT_STYLE_COUNT*sizeof(MessageFormat*));
|
| @@ -752,8 +669,7 @@ TimeUnitFormat::searchInLocaleChain(UTimeUnitFormatStyle style, const char* key,
|
|
|
| void
|
| TimeUnitFormat::setLocale(const Locale& locale, UErrorCode& status) {
|
| - if (U_SUCCESS(status) && fLocale != locale) {
|
| - fLocale = locale;
|
| + if (setMeasureFormatLocale(locale, status)) {
|
| setup(status);
|
| }
|
| }
|
| @@ -761,25 +677,10 @@ TimeUnitFormat::setLocale(const Locale& locale, UErrorCode& status) {
|
|
|
| void
|
| TimeUnitFormat::setNumberFormat(const NumberFormat& format, UErrorCode& status){
|
| - if (U_FAILURE(status) || (fNumberFormat && format == *fNumberFormat)) {
|
| + if (U_FAILURE(status)) {
|
| return;
|
| }
|
| - delete fNumberFormat;
|
| - fNumberFormat = (NumberFormat*)format.clone();
|
| - // reset the number formatter in the fTimeUnitToCountToPatterns map
|
| - for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
|
| - i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
|
| - i = (TimeUnit::UTimeUnitFields)(i+1)) {
|
| - int32_t pos = -1;
|
| - const UHashElement* elem = NULL;
|
| - while ((elem = fTimeUnitToCountToPatterns[i]->nextElement(pos)) != NULL){
|
| - const UHashTok keyTok = elem->value;
|
| - MessageFormat** pattern = (MessageFormat**)keyTok.pointer;
|
| -
|
| - pattern[UTMUTFMT_FULL_STYLE]->setFormat(0, format);
|
| - pattern[UTMUTFMT_ABBREVIATED_STYLE]->setFormat(0, format);
|
| - }
|
| - }
|
| + adoptNumberFormat((NumberFormat *)format.clone(), status);
|
| }
|
|
|
|
|
|
|