ICU-10640 Add C++ MeasureFormat API.

X-SVN-Rev: 35069
This commit is contained in:
Travis Keep 2014-02-04 00:29:17 +00:00
parent d8b2004576
commit 0a42d4959f
28 changed files with 3103 additions and 289 deletions

2
.gitattributes vendored
View File

@ -77,6 +77,7 @@ icu4c/source/extra/uconv/uconv.vcxproj -text
icu4c/source/extra/uconv/uconv.vcxproj.filters -text
icu4c/source/i18n/i18n.vcxproj -text
icu4c/source/i18n/i18n.vcxproj.filters -text
icu4c/source/i18n/measunit.cpp -text
icu4c/source/i18n/quantityformatter.cpp -text
icu4c/source/i18n/quantityformatter.h -text
icu4c/source/io/io.vcxproj -text
@ -146,6 +147,7 @@ icu4c/source/test/cintltst/cintltst.vcxproj -text
icu4c/source/test/cintltst/cintltst.vcxproj.filters -text
icu4c/source/test/intltest/intltest.vcxproj -text
icu4c/source/test/intltest/intltest.vcxproj.filters -text
icu4c/source/test/intltest/measfmttest.cpp -text
icu4c/source/test/intltest/simplepatternformattertest.cpp -text
icu4c/source/test/iotest/iotest.vcxproj -text
icu4c/source/test/iotest/iotest.vcxproj.filters -text

View File

@ -253,6 +253,10 @@ ListFormatter::~ListFormatter() {
/**
* Joins first and second using the pattern pat.
* On entry offset is an offset into first or -1 if offset unspecified.
* On exit offset is offset of second in result if recordOffset was set
* Otherwise if it was >=0 it is set to point into result where it used
* to point into first.
*/
static void joinStrings(
const SimplePatternFormatter& pat,
@ -260,7 +264,7 @@ static void joinStrings(
const UnicodeString& second,
UnicodeString &result,
UBool recordOffset,
int32_t offset,
int32_t &offset,
UErrorCode& errorCode) {
if (U_FAILURE(errorCode)) {
return;
@ -375,7 +379,9 @@ UnicodeString& ListFormatter::format(
offset,
errorCode);
if (U_SUCCESS(errorCode)) {
offset += appendTo.length();
if (offset >= 0) {
offset += appendTo.length();
}
appendTo += temp[npos];
}
return appendTo;

View File

@ -87,7 +87,7 @@ uspoof.o uspoof_impl.o uspoof_build.o uspoof_conf.o uspoof_wsconf.o decfmtst.o s
ztrans.o zrule.o vzone.o fphdlimp.o fpositer.o locdspnm.o \
decNumber.o decContext.o alphaindex.o tznames.o tznames_impl.o tzgnames.o \
tzfmt.o compactdecimalformat.o gender.o region.o scriptset.o identifier_info.o \
uregion.o reldatefmt.o quantityformatter.o
uregion.o reldatefmt.o quantityformatter.o measunit.o
## Header files to install
HEADERS = $(srcdir)/unicode/*.h

View File

@ -1,6 +1,6 @@
/*
**********************************************************************
* Copyright (c) 2004-2012 International Business Machines
* Copyright (c) 2004-2014 International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
* Author: Alan Liu
@ -21,7 +21,7 @@
U_NAMESPACE_BEGIN
CurrencyFormat::CurrencyFormat(const Locale& locale, UErrorCode& ec) :
fmt(NULL)
MeasureFormat(locale, UMEASFMT_WIDTH_WIDE, ec), fmt(NULL)
{
fmt = NumberFormat::createCurrencyInstance(locale, ec);
}
@ -36,17 +36,6 @@ CurrencyFormat::~CurrencyFormat() {
delete fmt;
}
UBool CurrencyFormat::operator==(const Format& other) const {
if (this == &other) {
return TRUE;
}
if (typeid(*this) != typeid(other)) {
return FALSE;
}
const CurrencyFormat* c = (const CurrencyFormat*) &other;
return *fmt == *c->fmt;
}
Format* CurrencyFormat::clone() const {
return new CurrencyFormat(*this);
}

View File

@ -1,6 +1,6 @@
/*
**********************************************************************
* Copyright (c) 2004-2010, International Business Machines
* Copyright (c) 2004-2014, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
* Author: Alan Liu
@ -52,11 +52,6 @@ class CurrencyFormat : public MeasureFormat {
*/
virtual ~CurrencyFormat();
/**
* Override Format API.
*/
virtual UBool operator==(const Format& other) const;
/**
* Override Format API.
*/

View File

@ -1,6 +1,6 @@
/*
**********************************************************************
* Copyright (c) 2004-2012, International Business Machines
* Copyright (c) 2004-2014, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
* Author: Alan Liu
@ -24,6 +24,9 @@ CurrencyUnit::CurrencyUnit(const UChar* _isoCode, UErrorCode& ec) {
if (U_SUCCESS(ec)) {
if (_isoCode && u_strlen(_isoCode)==3) {
u_strcpy(isoCode, _isoCode);
char simpleIsoCode[4];
u_UCharsToChars(isoCode, simpleIsoCode, 4);
initCurrency(simpleIsoCode);
} else {
ec = U_ILLEGAL_ARGUMENT_ERROR;
}
@ -32,13 +35,15 @@ CurrencyUnit::CurrencyUnit(const UChar* _isoCode, UErrorCode& ec) {
CurrencyUnit::CurrencyUnit(const CurrencyUnit& other) :
MeasureUnit(other) {
*this = other;
u_strcpy(isoCode, other.isoCode);
}
CurrencyUnit& CurrencyUnit::operator=(const CurrencyUnit& other) {
if (this != &other) {
u_strcpy(isoCode, other.isoCode);
if (this == &other) {
return *this;
}
MeasureUnit::operator=(other);
u_strcpy(isoCode, other.isoCode);
return *this;
}
@ -49,12 +54,6 @@ UObject* CurrencyUnit::clone() const {
CurrencyUnit::~CurrencyUnit() {
}
UBool CurrencyUnit::operator==(const UObject& other) const {
const CurrencyUnit& c = (const CurrencyUnit&) other;
return typeid(*this) == typeid(other) &&
u_strcmp(isoCode, c.isoCode) == 0;
}
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CurrencyUnit)
U_NAMESPACE_END

View File

@ -1,6 +1,6 @@
/*
**********************************************************************
* Copyright (c) 2004-2011, International Business Machines
* Copyright (c) 2004-2014, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
* Author: Alan Liu
@ -13,13 +13,772 @@
#if !UCONFIG_NO_FORMATTING
#include "unicode/measfmt.h"
#include "unicode/numfmt.h"
#include "currfmt.h"
#include "unicode/localpointer.h"
#include "quantityformatter.h"
#include "unicode/plurrule.h"
#include "unicode/decimfmt.h"
#include "lrucache.h"
#include "uresimp.h"
#include "unicode/ures.h"
#include "cstring.h"
#include "mutex.h"
#include "ucln_in.h"
#include "unicode/listformatter.h"
#include "charstr.h"
#include "unicode/putil.h"
#include "unicode/smpdtfmt.h"
#include "sharedptr.h"
#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
#define MEAS_UNIT_COUNT 46
static icu::LRUCache *gCache = NULL;
static UMutex gCacheMutex = U_MUTEX_INITIALIZER;
static icu::UInitOnce gCacheInitOnce = U_INITONCE_INITIALIZER;
U_CDECL_BEGIN
static UBool U_CALLCONV measfmt_cleanup() {
gCacheInitOnce.reset();
if (gCache) {
delete gCache;
gCache = NULL;
}
return TRUE;
}
U_CDECL_END
U_NAMESPACE_BEGIN
MeasureFormat::MeasureFormat() {}
class UnitFormatters : public UMemory {
public:
UnitFormatters() { }
QuantityFormatter formatters[MEAS_UNIT_COUNT][UMEASFMT_WIDTH_NARROW + 1];
private:
UnitFormatters(const UnitFormatters &other);
UnitFormatters &operator=(const UnitFormatters &other);
};
MeasureFormat::~MeasureFormat() {}
class NumericDateFormatters : public UMemory {
public:
SimpleDateFormat hourMinute;
SimpleDateFormat minuteSecond;
SimpleDateFormat hourMinuteSecond;
NumericDateFormatters(
const UnicodeString &hm,
const UnicodeString &ms,
const UnicodeString &hms,
UErrorCode &status) :
hourMinute(hm, status),
minuteSecond(ms, status),
hourMinuteSecond(hms, status) {
const TimeZone *gmt = TimeZone::getGMT();
hourMinute.setTimeZone(*gmt);
minuteSecond.setTimeZone(*gmt);
hourMinuteSecond.setTimeZone(*gmt);
}
private:
NumericDateFormatters(const NumericDateFormatters &other);
NumericDateFormatters &operator=(const NumericDateFormatters &other);
};
class MeasureFormatData : public SharedObject {
public:
SharedPtr<UnitFormatters> unitFormatters;
SharedPtr<PluralRules> pluralRules;
SharedPtr<NumberFormat> numberFormat;
SharedPtr<NumberFormat> currencyFormats[UMEASFMT_WIDTH_NARROW + 1];
SharedPtr<NumericDateFormatters> numericDateFormatters;
virtual ~MeasureFormatData();
private:
MeasureFormatData &operator=(const MeasureFormatData& other);
};
MeasureFormatData::~MeasureFormatData() {
}
static int32_t widthToIndex(UMeasureFormatWidth width) {
if (width > UMEASFMT_WIDTH_NARROW) {
return UMEASFMT_WIDTH_NARROW;
}
return width;
}
static UBool isCurrency(const MeasureUnit &unit) {
return (uprv_strcmp(unit.getType(), "currency") == 0);
}
static UBool getString(
const UResourceBundle *resource,
UnicodeString &result,
UErrorCode &status) {
int32_t len = 0;
const UChar *resStr = ures_getString(resource, &len, &status);
if (U_FAILURE(status)) {
return FALSE;
}
result.setTo(TRUE, resStr, len);
return TRUE;
}
static UBool load(
const UResourceBundle *resource,
UnitFormatters &unitFormatters,
UErrorCode &status) {
if (U_FAILURE(status)) {
return FALSE;
}
static const char *widthPath[] = {"units", "unitsShort", "unitsNarrow"};
MeasureUnit *units = NULL;
int32_t unitCount = MeasureUnit::getAvailable(units, 0, status);
while (status == U_BUFFER_OVERFLOW_ERROR) {
status = U_ZERO_ERROR;
delete [] units;
units = new MeasureUnit[unitCount];
if (units == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
return FALSE;
}
unitCount = MeasureUnit::getAvailable(units, unitCount, status);
}
for (int32_t currentWidth = 0; currentWidth <= UMEASFMT_WIDTH_NARROW; ++currentWidth) {
// Be sure status is clear since next resource bundle lookup may fail.
if (U_FAILURE(status)) {
delete [] units;
return FALSE;
}
LocalUResourceBundlePointer widthBundle(
ures_getByKeyWithFallback(
resource, widthPath[currentWidth], NULL, &status));
// We may not have data for all widths in all locales.
if (status == U_MISSING_RESOURCE_ERROR) {
status = U_ZERO_ERROR;
continue;
}
for (int32_t currentUnit = 0; currentUnit < unitCount; ++currentUnit) {
// Be sure status is clear next lookup may fail.
if (U_FAILURE(status)) {
delete [] units;
return FALSE;
}
if (isCurrency(units[currentUnit])) {
continue;
}
CharString pathBuffer;
pathBuffer.append(units[currentUnit].getType(), status)
.append("/", status)
.append(units[currentUnit].getSubtype(), status);
LocalUResourceBundlePointer unitBundle(
ures_getByKeyWithFallback(
widthBundle.getAlias(),
pathBuffer.data(),
NULL,
&status));
// We may not have data for all units in all widths
if (status == U_MISSING_RESOURCE_ERROR) {
status = U_ZERO_ERROR;
continue;
}
// We must have the unit bundle to proceed
if (U_FAILURE(status)) {
delete [] units;
return FALSE;
}
int32_t size = ures_getSize(unitBundle.getAlias());
for (int32_t plIndex = 0; plIndex < size; ++plIndex) {
LocalUResourceBundlePointer pluralBundle(
ures_getByIndex(
unitBundle.getAlias(), plIndex, NULL, &status));
if (U_FAILURE(status)) {
delete [] units;
return FALSE;
}
UnicodeString rawPattern;
getString(pluralBundle.getAlias(), rawPattern, status);
unitFormatters.formatters[units[currentUnit].getIndex()][currentWidth].add(
ures_getKey(pluralBundle.getAlias()),
rawPattern,
status);
}
}
}
delete [] units;
return U_SUCCESS(status);
}
static UnicodeString loadNumericDateFormatterPattern(
const UResourceBundle *resource,
const char *pattern,
UErrorCode &status) {
UnicodeString result;
if (U_FAILURE(status)) {
return result;
}
CharString chs;
chs.append("durationUnits", status)
.append("/", status).append(pattern, status);
LocalUResourceBundlePointer patternBundle(
ures_getByKeyWithFallback(
resource,
chs.data(),
NULL,
&status));
if (U_FAILURE(status)) {
return result;
}
getString(patternBundle.getAlias(), result, status);
// Replace 'h' with 'H'
int32_t len = result.length();
UChar *buffer = result.getBuffer(len);
for (int32_t i = 0; i < len; ++i) {
if (buffer[i] == 0x68) { // 'h'
buffer[i] = 0x48; // 'H'
}
}
result.releaseBuffer(len);
return result;
}
static NumericDateFormatters *loadNumericDateFormatters(
const UResourceBundle *resource,
UErrorCode &status) {
if (U_FAILURE(status)) {
return NULL;
}
NumericDateFormatters *result = new NumericDateFormatters(
loadNumericDateFormatterPattern(resource, "hm", status),
loadNumericDateFormatterPattern(resource, "ms", status),
loadNumericDateFormatterPattern(resource, "hms", status),
status);
if (U_FAILURE(status)) {
delete result;
return NULL;
}
return result;
}
static SharedObject *U_CALLCONV createData(
const char *localeId, UErrorCode &status) {
LocalUResourceBundlePointer topLevel(ures_open(NULL, localeId, &status));
static UNumberFormatStyle currencyStyles[] = {
UNUM_CURRENCY_PLURAL, UNUM_CURRENCY_ISO, UNUM_CURRENCY};
if (U_FAILURE(status)) {
return NULL;
}
LocalPointer<MeasureFormatData> result(new MeasureFormatData());
LocalPointer<UnitFormatters> unitFormatters(new UnitFormatters());
if (result.getAlias() == NULL
|| unitFormatters.getAlias() == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
return NULL;
}
if (!load(
topLevel.getAlias(),
*unitFormatters,
status)) {
return NULL;
}
if (!result->unitFormatters.reset(unitFormatters.orphan())) {
status = U_MEMORY_ALLOCATION_ERROR;
return NULL;
}
LocalPointer<NumericDateFormatters> ndf(
loadNumericDateFormatters(topLevel.getAlias(), status));
if (U_FAILURE(status)) {
return NULL;
}
if (!result->numericDateFormatters.reset(ndf.orphan())) {
status = U_MEMORY_ALLOCATION_ERROR;
return NULL;
}
LocalPointer<PluralRules> pr(PluralRules::forLocale(localeId, status));
if (U_FAILURE(status)) {
return NULL;
}
if (!result->pluralRules.reset(pr.orphan())) {
status = U_MEMORY_ALLOCATION_ERROR;
return NULL;
}
LocalPointer<NumberFormat> nf(
NumberFormat::createInstance(localeId, status));
if (U_FAILURE(status)) {
return NULL;
}
if (!result->numberFormat.reset(nf.orphan())) {
status = U_MEMORY_ALLOCATION_ERROR;
return NULL;
}
for (int32_t i = 0; i <= UMEASFMT_WIDTH_NARROW; ++i) {
LocalPointer<NumberFormat> cf(
NumberFormat::createInstance(
localeId, currencyStyles[i], status));
if (U_FAILURE(status)) {
return NULL;
}
if (!result->currencyFormats[i].reset(cf.orphan())) {
status = U_MEMORY_ALLOCATION_ERROR;
return NULL;
}
}
return result.orphan();
}
static void U_CALLCONV cacheInit(UErrorCode &status) {
U_ASSERT(gCache == NULL);
U_ASSERT(MeasureUnit::getIndexCount() == MEAS_UNIT_COUNT);
ucln_i18n_registerCleanup(UCLN_I18N_MEASFMT, measfmt_cleanup);
gCache = new SimpleLRUCache(100, &createData, status);
if (U_FAILURE(status)) {
delete gCache;
gCache = NULL;
}
}
static void getFromCache(
const char *locale,
const MeasureFormatData *&ptr,
UErrorCode &status) {
umtx_initOnce(gCacheInitOnce, &cacheInit, status);
if (U_FAILURE(status)) {
return;
}
Mutex lock(&gCacheMutex);
gCache->get(locale, ptr, status);
}
static int32_t toHMS(
const Measure *measures,
int32_t measureCount,
Formattable *hms,
UErrorCode &status) {
if (U_FAILURE(status)) {
return 0;
}
int32_t result = 0;
LocalPointer<MeasureUnit> hourUnit(MeasureUnit::createHour(status));
LocalPointer<MeasureUnit> minuteUnit(MeasureUnit::createMinute(status));
LocalPointer<MeasureUnit> secondUnit(MeasureUnit::createSecond(status));
if (U_FAILURE(status)) {
return 0;
}
int32_t count = 0;
for (int32_t i = 0; i < measureCount; ++i) {
if (measures[i].getUnit() == *hourUnit) {
if ((result & 1) == 0) {
++count;
} else {
return 0;
}
hms[0] = measures[i].getNumber();
result |= 1;
} else if (measures[i].getUnit() == *minuteUnit) {
if ((result & 2) == 0) {
++count;
} else {
return 0;
}
hms[1] = measures[i].getNumber();
result |= 2;
} else if (measures[i].getUnit() == *secondUnit) {
if ((result & 4) == 0) {
++count;
} else {
return 0;
}
hms[2] = measures[i].getNumber();
result |= 4;
} else {
return 0;
}
}
return result;
}
MeasureFormat::MeasureFormat(
const Locale &locale, UMeasureFormatWidth w, UErrorCode &status)
: ptr(NULL), width(w) {
initMeasureFormat(locale, w, status);
}
MeasureFormat::MeasureFormat(
const Locale &locale,
UMeasureFormatWidth w,
NumberFormat *nfToAdopt,
UErrorCode &status)
: ptr(NULL), width(w) {
initMeasureFormat(locale, w, status);
adoptNumberFormat(nfToAdopt, status);
}
MeasureFormat::MeasureFormat(const MeasureFormat &other)
: Format(other), ptr(other.ptr), width(other.width) {
ptr->addRef();
}
MeasureFormat &MeasureFormat::operator=(const MeasureFormat &other) {
if (this == &other) {
return *this;
}
Format::operator=(other);
SharedObject::copyPtr(other.ptr, ptr);
width = other.width;
return *this;
}
MeasureFormat::MeasureFormat() : ptr(NULL), width(UMEASFMT_WIDTH_WIDE) {
}
MeasureFormat::~MeasureFormat() {
if (ptr != NULL) {
ptr->removeRef();
}
}
UBool MeasureFormat::operator==(const Format &other) const {
const MeasureFormat *rhs = dynamic_cast<const MeasureFormat *>(&other);
if (rhs == NULL) {
return FALSE;
}
// Same objects are equivalent
if (this == rhs) {
return TRUE;
}
// differing widths aren't equivalent
if (width != rhs->width) {
return FALSE;
}
// Width the same, same shared data -> equivlanet
if (ptr == rhs->ptr) {
return TRUE;
}
// Width same, but differing shred data. Depends on locale
// and number format objects being the same.
UErrorCode status = U_ZERO_ERROR;
const char *localeId = getLocaleID(status);
const char *rhsLocaleId = rhs->getLocaleID(status);
if (U_FAILURE(status)) {
// On failure, assume not equal
return FALSE;
}
return (uprv_strcmp(localeId, rhsLocaleId) == 0
&& *ptr->numberFormat == *rhs->ptr->numberFormat);
}
Format *MeasureFormat::clone() const {
return new MeasureFormat(*this);
}
UnicodeString &MeasureFormat::format(
const Formattable &obj,
UnicodeString &appendTo,
FieldPosition &pos,
UErrorCode &status) const {
if (U_FAILURE(status)) return appendTo;
if (obj.getType() == Formattable::kObject) {
const UObject* formatObj = obj.getObject();
const Measure* amount = dynamic_cast<const Measure*>(formatObj);
if (amount != NULL) {
return formatMeasure(*amount, appendTo, pos, status);
}
}
status = U_ILLEGAL_ARGUMENT_ERROR;
return appendTo;
}
void MeasureFormat::parseObject(
const UnicodeString & /*source*/,
Formattable & /*result*/,
ParsePosition& /*pos*/) const {
return;
}
UnicodeString &MeasureFormat::formatMeasures(
const Measure *measures,
int32_t measureCount,
UnicodeString &appendTo,
FieldPosition &pos,
UErrorCode &status) const {
static const char *listStyles[] = {"unit", "unit-short", "unit-narrow"};
if (U_FAILURE(status)) {
return appendTo;
}
if (measureCount == 0) {
return appendTo;
}
if (measureCount == 1) {
return formatMeasure(measures[0], appendTo, pos, status);
}
if (width == UMEASFMT_WIDTH_NUMERIC) {
Formattable hms[3];
int32_t bitMap = toHMS(measures, measureCount, hms, status);
if (bitMap > 0) {
return formatNumeric(hms, bitMap, appendTo, status);
}
}
LocalPointer<ListFormatter> lf(
ListFormatter::createInstance(
getLocale(status),
listStyles[widthToIndex(width)],
status));
if (U_FAILURE(status)) {
return appendTo;
}
if (pos.getField() != FieldPosition::DONT_CARE) {
return formatMeasuresSlowTrack(
measures, measureCount, *lf, appendTo, pos, status);
}
UnicodeString *results = new UnicodeString[measureCount];
if (results == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
return appendTo;
}
for (int32_t i = 0; i < measureCount; ++i) {
formatMeasure(measures[i], results[i], pos, status);
}
lf->format(results, measureCount, appendTo, status);
delete [] results;
return appendTo;
}
void MeasureFormat::initMeasureFormat(
const Locale &locale, UMeasureFormatWidth w, UErrorCode &status) {
if (U_FAILURE(status)) {
return;
}
const char *name = locale.getName();
setLocaleIDs(name, name);
width = w;
getFromCache(name, ptr, status);
}
void MeasureFormat::adoptNumberFormat(NumberFormat *nfToAdopt, UErrorCode &status) {
if (U_FAILURE(status)) {
return;
}
MeasureFormatData* wptr = SharedObject::copyOnWrite(ptr);
if (wptr == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
if (!wptr->numberFormat.reset(nfToAdopt)) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
}
UBool MeasureFormat::setMeasureFormatLocale(const Locale &locale, UErrorCode &status) {
if (U_FAILURE(status) || locale == getLocale(status)) {
return FALSE;
}
initMeasureFormat(locale, width, status);
return U_SUCCESS(status);
}
const NumberFormat &MeasureFormat::getNumberFormat() const {
return *ptr->numberFormat;
}
const PluralRules &MeasureFormat::getPluralRules() const {
return *ptr->pluralRules;
}
Locale MeasureFormat::getLocale(UErrorCode &status) const {
return Format::getLocale(ULOC_VALID_LOCALE, status);
}
const char *MeasureFormat::getLocaleID(UErrorCode &status) const {
return Format::getLocaleID(ULOC_VALID_LOCALE, status);
}
UnicodeString &MeasureFormat::formatMeasure(
const Measure &measure,
UnicodeString &appendTo,
FieldPosition &pos,
UErrorCode &status) const {
if (U_FAILURE(status)) {
return appendTo;
}
const Formattable& amtNumber = measure.getNumber();
const MeasureUnit& amtUnit = measure.getUnit();
if (isCurrency(amtUnit)) {
UChar isoCode[4];
u_charsToUChars(amtUnit.getSubtype(), isoCode, 4);
return ptr->currencyFormats[widthToIndex(width)]->format(
new CurrencyAmount(amtNumber, isoCode, status),
appendTo,
pos,
status);
}
const QuantityFormatter *quantityFormatter = getQuantityFormatter(
amtUnit.getIndex(), widthToIndex(width), status);
if (U_FAILURE(status)) {
return appendTo;
}
return quantityFormatter->format(
amtNumber,
*ptr->numberFormat,
*ptr->pluralRules, appendTo,
pos,
status);
}
UnicodeString &MeasureFormat::formatNumeric(
const Formattable *hms, // always length 3
int32_t bitMap, // 1=hourset, 2=minuteset, 4=secondset
UnicodeString &appendTo,
UErrorCode &status) const {
if (U_FAILURE(status)) {
return appendTo;
}
UDate millis =
(UDate) (((hms[0].getDouble(status) * 60.0
+ hms[1].getDouble(status)) * 60.0
+ hms[2].getDouble(status)) * 1000.0);
switch (bitMap) {
case 5: // hs
case 7: // hms
return formatNumeric(
millis,
ptr->numericDateFormatters->hourMinuteSecond,
UDAT_SECOND_FIELD,
hms[2],
appendTo,
status);
break;
case 6: // ms
return formatNumeric(
millis,
ptr->numericDateFormatters->minuteSecond,
UDAT_SECOND_FIELD,
hms[2],
appendTo,
status);
break;
case 3: // hm
return formatNumeric(
millis,
ptr->numericDateFormatters->hourMinute,
UDAT_MINUTE_FIELD,
hms[1],
appendTo,
status);
break;
default:
status = U_INTERNAL_PROGRAM_ERROR;
return appendTo;
break;
}
return appendTo;
}
UnicodeString &MeasureFormat::formatNumeric(
UDate date,
const DateFormat &dateFmt,
UDateFormatField smallestField,
const Formattable &smallestAmount,
UnicodeString &appendTo,
UErrorCode &status) const {
if (U_FAILURE(status)) {
return appendTo;
}
UnicodeString smallestAmountFormatted;
ptr->numberFormat->format(
smallestAmount, smallestAmountFormatted, status);
FieldPosition smallestFieldPosition(smallestField);
UnicodeString draft;
dateFmt.format(date, draft, smallestFieldPosition, status);
if (smallestFieldPosition.getBeginIndex() != 0 ||
smallestFieldPosition.getEndIndex() != 0) {
appendTo.append(draft, 0, smallestFieldPosition.getBeginIndex());
appendTo.append(smallestAmountFormatted);
appendTo.append(
draft,
smallestFieldPosition.getEndIndex(),
draft.length());
} else {
appendTo.append(draft);
}
return appendTo;
}
const QuantityFormatter *MeasureFormat::getQuantityFormatter(
int32_t index,
int32_t widthIndex,
UErrorCode &status) const {
if (U_FAILURE(status)) {
return NULL;
}
const QuantityFormatter *formatters =
ptr->unitFormatters->formatters[index];
if (formatters[widthIndex].isValid()) {
return &formatters[widthIndex];
}
if (formatters[UMEASFMT_WIDTH_SHORT].isValid()) {
return &formatters[UMEASFMT_WIDTH_SHORT];
}
if (formatters[UMEASFMT_WIDTH_WIDE].isValid()) {
return &formatters[UMEASFMT_WIDTH_WIDE];
}
status = U_MISSING_RESOURCE_ERROR;
return NULL;
}
UnicodeString &MeasureFormat::formatMeasuresSlowTrack(
const Measure *measures,
int32_t measureCount,
const ListFormatter& lf,
UnicodeString& appendTo,
FieldPosition& pos,
UErrorCode& status) const {
if (U_FAILURE(status)) {
return appendTo;
}
FieldPosition dontCare(FieldPosition::DONT_CARE);
FieldPosition fpos(pos.getField());
UnicodeString *results = new UnicodeString[measureCount];
int32_t fieldPositionFoundIndex = -1;
for (int32_t i = 0; i < measureCount; ++i) {
if (fieldPositionFoundIndex == -1) {
formatMeasure(measures[i], results[i], fpos, status);
if (U_FAILURE(status)) {
delete [] results;
return appendTo;
}
if (fpos.getBeginIndex() != 0 || fpos.getEndIndex() != 0) {
fieldPositionFoundIndex = i;
}
} else {
formatMeasure(measures[i], results[i], dontCare, status);
}
}
int32_t offset;
lf.format(
results,
measureCount,
appendTo,
fieldPositionFoundIndex,
offset,
status);
if (U_FAILURE(status)) {
delete [] results;
return appendTo;
}
if (offset != -1) {
pos.setBeginIndex(fpos.getBeginIndex() + offset);
pos.setEndIndex(fpos.getEndIndex() + offset);
}
delete [] results;
return appendTo;
}
MeasureFormat* U_EXPORT2 MeasureFormat::createCurrencyFormat(const Locale& locale,
UErrorCode& ec) {

View File

@ -0,0 +1,734 @@
/*
**********************************************************************
* Copyright (c) 2004-2014, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
* Author: Alan Liu
* Created: April 26, 2004
* Since: ICU 3.0
**********************************************************************
*/
#include "unicode/measunit.h"
#include "unicode/uenum.h"
#include "ustrenum.h"
#include "cstring.h"
#include "uassert.h"
#define LENGTHOF(array) (int32_t)(sizeof(array) / sizeof((array)[0]))
U_NAMESPACE_BEGIN
static const int32_t gOffsets[] = {
0,
1,
4,
10,
270,
278,
288,
292,
295,
298,
301,
303,
306
};
static const int32_t gIndexes[] = {
0,
1,
4,
10,
10,
18,
28,
32,
35,
38,
41,
43,
46
};
static const char * const gTypes[] = {
"acceleration",
"angle",
"area",
"currency",
"duration",
"length",
"mass",
"power",
"pressure",
"speed",
"temperature",
"volume"
};
static const char * const gSubTypes[] = {
"g-force",
"arc-minute",
"arc-second",
"degree",
"acre",
"hectare",
"square-foot",
"square-kilometer",
"square-meter",
"square-mile",
"ADP",
"AED",
"AFA",
"AFN",
"ALL",
"AMD",
"ANG",
"AOA",
"AON",
"AOR",
"ARA",
"ARP",
"ARS",
"ATS",
"AUD",
"AWG",
"AYM",
"AZM",
"AZN",
"BAD",
"BAM",
"BBD",
"BDT",
"BEC",
"BEF",
"BEL",
"BGL",
"BGN",
"BHD",
"BIF",
"BMD",
"BND",
"BOB",
"BOV",
"BRC",
"BRE",
"BRL",
"BRN",
"BRR",
"BSD",
"BTN",
"BWP",
"BYB",
"BYR",
"BZD",
"CAD",
"CDF",
"CHC",
"CHE",
"CHF",
"CHW",
"CLF",
"CLP",
"CNY",
"COP",
"COU",
"CRC",
"CSD",
"CSK",
"CUC",
"CUP",
"CVE",
"CYP",
"CZK",
"DDM",
"DEM",
"DJF",
"DKK",
"DOP",
"DZD",
"ECS",
"ECV",
"EEK",
"EGP",
"ERN",
"ESA",
"ESB",
"ESP",
"ETB",
"EUR",
"FIM",
"FJD",
"FKP",
"FRF",
"GBP",
"GEK",
"GEL",
"GHC",
"GHP",
"GHS",
"GIP",
"GMD",
"GNF",
"GQE",
"GRD",
"GTQ",
"GWP",
"GYD",
"HKD",
"HNL",
"HRD",
"HRK",
"HTG",
"HUF",
"IDR",
"IEP",
"ILS",
"INR",
"IQD",
"IRR",
"ISK",
"ITL",
"JMD",
"JOD",
"JPY",
"KES",
"KGS",
"KHR",
"KMF",
"KPW",
"KRW",
"KWD",
"KYD",
"KZT",
"LAK",
"LBP",
"LKR",
"LRD",
"LSL",
"LTL",
"LTT",
"LUC",
"LUF",
"LUL",
"LVL",
"LVR",
"LYD",
"MAD",
"MDL",
"MGA",
"MGF",
"MKD",
"MLF",
"MMK",
"MNT",
"MOP",
"MRO",
"MTL",
"MUR",
"MVR",
"MWK",
"MXN",
"MXV",
"MYR",
"MZM",
"MZN",
"NAD",
"NGN",
"NIO",
"NLG",
"NOK",
"NPR",
"NZD",
"OMR",
"PAB",
"PEI",
"PEN",
"PES",
"PGK",
"PHP",
"PKR",
"PLN",
"PLZ",
"PTE",
"PYG",
"QAR",
"ROL",
"RON",
"RSD",
"RUB",
"RUR",
"RWF",
"SAR",
"SBD",
"SCR",
"SDD",
"SDG",
"SEK",
"SGD",
"SHP",
"SIT",
"SKK",
"SLL",
"SOS",
"SRD",
"SRG",
"SSP",
"STD",
"SVC",
"SYP",
"SZL",
"THB",
"TJR",
"TJS",
"TMM",
"TMT",
"TND",
"TOP",
"TPE",
"TRL",
"TRY",
"TTD",
"TWD",
"TZS",
"UAH",
"UAK",
"UGX",
"USD",
"USN",
"USS",
"UYI",
"UYU",
"UZS",
"VEB",
"VEF",
"VND",
"VUV",
"WST",
"XAF",
"XAG",
"XAU",
"XBA",
"XBB",
"XBC",
"XBD",
"XCD",
"XDR",
"XEU",
"XOF",
"XPD",
"XPF",
"XPT",
"XSU",
"XTS",
"XUA",
"XXX",
"YDD",
"YER",
"YUM",
"YUN",
"ZAL",
"ZAR",
"ZMK",
"ZMW",
"ZRN",
"ZRZ",
"ZWD",
"ZWL",
"ZWN",
"ZWR",
"day",
"hour",
"millisecond",
"minute",
"month",
"second",
"week",
"year",
"centimeter",
"foot",
"inch",
"kilometer",
"light-year",
"meter",
"mile",
"millimeter",
"picometer",
"yard",
"gram",
"kilogram",
"ounce",
"pound",
"horsepower",
"kilowatt",
"watt",
"hectopascal",
"inch-hg",
"millibar",
"kilometer-per-hour",
"meter-per-second",
"mile-per-hour",
"celsius",
"fahrenheit",
"cubic-kilometer",
"cubic-mile",
"liter"
};
MeasureUnit *MeasureUnit::createGForce(UErrorCode &status) {
return MeasureUnit::create(0, 0, status);
}
MeasureUnit *MeasureUnit::createArcMinute(UErrorCode &status) {
return MeasureUnit::create(1, 0, status);
}
MeasureUnit *MeasureUnit::createArcSecond(UErrorCode &status) {
return MeasureUnit::create(1, 1, status);
}
MeasureUnit *MeasureUnit::createDegree(UErrorCode &status) {
return MeasureUnit::create(1, 2, status);
}
MeasureUnit *MeasureUnit::createAcre(UErrorCode &status) {
return MeasureUnit::create(2, 0, status);
}
MeasureUnit *MeasureUnit::createHectare(UErrorCode &status) {
return MeasureUnit::create(2, 1, status);
}
MeasureUnit *MeasureUnit::createSquareFoot(UErrorCode &status) {
return MeasureUnit::create(2, 2, status);
}
MeasureUnit *MeasureUnit::createSquareKilometer(UErrorCode &status) {
return MeasureUnit::create(2, 3, status);
}
MeasureUnit *MeasureUnit::createSquareMeter(UErrorCode &status) {
return MeasureUnit::create(2, 4, status);
}
MeasureUnit *MeasureUnit::createSquareMile(UErrorCode &status) {
return MeasureUnit::create(2, 5, status);
}
MeasureUnit *MeasureUnit::createDay(UErrorCode &status) {
return MeasureUnit::create(4, 0, status);
}
MeasureUnit *MeasureUnit::createHour(UErrorCode &status) {
return MeasureUnit::create(4, 1, status);
}
MeasureUnit *MeasureUnit::createMillisecond(UErrorCode &status) {
return MeasureUnit::create(4, 2, status);
}
MeasureUnit *MeasureUnit::createMinute(UErrorCode &status) {
return MeasureUnit::create(4, 3, status);
}
MeasureUnit *MeasureUnit::createMonth(UErrorCode &status) {
return MeasureUnit::create(4, 4, status);
}
MeasureUnit *MeasureUnit::createSecond(UErrorCode &status) {
return MeasureUnit::create(4, 5, status);
}
MeasureUnit *MeasureUnit::createWeek(UErrorCode &status) {
return MeasureUnit::create(4, 6, status);
}
MeasureUnit *MeasureUnit::createYear(UErrorCode &status) {
return MeasureUnit::create(4, 7, status);
}
MeasureUnit *MeasureUnit::createCentimeter(UErrorCode &status) {
return MeasureUnit::create(5, 0, status);
}
MeasureUnit *MeasureUnit::createFoot(UErrorCode &status) {
return MeasureUnit::create(5, 1, status);
}
MeasureUnit *MeasureUnit::createInch(UErrorCode &status) {
return MeasureUnit::create(5, 2, status);
}
MeasureUnit *MeasureUnit::createKilometer(UErrorCode &status) {
return MeasureUnit::create(5, 3, status);
}
MeasureUnit *MeasureUnit::createLightYear(UErrorCode &status) {
return MeasureUnit::create(5, 4, status);
}
MeasureUnit *MeasureUnit::createMeter(UErrorCode &status) {
return MeasureUnit::create(5, 5, status);
}
MeasureUnit *MeasureUnit::createMile(UErrorCode &status) {
return MeasureUnit::create(5, 6, status);
}
MeasureUnit *MeasureUnit::createMillimeter(UErrorCode &status) {
return MeasureUnit::create(5, 7, status);
}
MeasureUnit *MeasureUnit::createPicometer(UErrorCode &status) {
return MeasureUnit::create(5, 8, status);
}
MeasureUnit *MeasureUnit::createYard(UErrorCode &status) {
return MeasureUnit::create(5, 9, status);
}
MeasureUnit *MeasureUnit::createGram(UErrorCode &status) {
return MeasureUnit::create(6, 0, status);
}
MeasureUnit *MeasureUnit::createKilogram(UErrorCode &status) {
return MeasureUnit::create(6, 1, status);
}
MeasureUnit *MeasureUnit::createOunce(UErrorCode &status) {
return MeasureUnit::create(6, 2, status);
}
MeasureUnit *MeasureUnit::createPound(UErrorCode &status) {
return MeasureUnit::create(6, 3, status);
}
MeasureUnit *MeasureUnit::createHorsepower(UErrorCode &status) {
return MeasureUnit::create(7, 0, status);
}
MeasureUnit *MeasureUnit::createKilowatt(UErrorCode &status) {
return MeasureUnit::create(7, 1, status);
}
MeasureUnit *MeasureUnit::createWatt(UErrorCode &status) {
return MeasureUnit::create(7, 2, status);
}
MeasureUnit *MeasureUnit::createHectopascal(UErrorCode &status) {
return MeasureUnit::create(8, 0, status);
}
MeasureUnit *MeasureUnit::createInchHg(UErrorCode &status) {
return MeasureUnit::create(8, 1, status);
}
MeasureUnit *MeasureUnit::createMillibar(UErrorCode &status) {
return MeasureUnit::create(8, 2, status);
}
MeasureUnit *MeasureUnit::createKilometerPerHour(UErrorCode &status) {
return MeasureUnit::create(9, 0, status);
}
MeasureUnit *MeasureUnit::createMeterPerSecond(UErrorCode &status) {
return MeasureUnit::create(9, 1, status);
}
MeasureUnit *MeasureUnit::createMilePerHour(UErrorCode &status) {
return MeasureUnit::create(9, 2, status);
}
MeasureUnit *MeasureUnit::createCelsius(UErrorCode &status) {
return MeasureUnit::create(10, 0, status);
}
MeasureUnit *MeasureUnit::createFahrenheit(UErrorCode &status) {
return MeasureUnit::create(10, 1, status);
}
MeasureUnit *MeasureUnit::createCubicKilometer(UErrorCode &status) {
return MeasureUnit::create(11, 0, status);
}
MeasureUnit *MeasureUnit::createCubicMile(UErrorCode &status) {
return MeasureUnit::create(11, 1, status);
}
MeasureUnit *MeasureUnit::createLiter(UErrorCode &status) {
return MeasureUnit::create(11, 2, status);
}
static int32_t binarySearch(
const char * const * array, int32_t start, int32_t end, const char * key) {
while (start < end) {
int32_t mid = (start + end) / 2;
int32_t cmp = uprv_strcmp(array[mid], key);
if (cmp < 0) {
start = mid + 1;
continue;
}
if (cmp == 0) {
return mid;
}
end = mid;
}
return -1;
}
MeasureUnit::MeasureUnit(const MeasureUnit &other)
: fTypeId(other.fTypeId), fSubTypeId(other.fSubTypeId) {
uprv_strcpy(fCurrency, other.fCurrency);
}
MeasureUnit &MeasureUnit::operator=(const MeasureUnit &other) {
if (this == &other) {
return *this;
}
fTypeId = other.fTypeId;
fSubTypeId = other.fSubTypeId;
uprv_strcpy(fCurrency, other.fCurrency);
return *this;
}
UObject *MeasureUnit::clone() const {
return new MeasureUnit(*this);
}
MeasureUnit::~MeasureUnit() {
}
const char *MeasureUnit::getType() const {
return gTypes[fTypeId];
}
const char *MeasureUnit::getSubtype() const {
return fCurrency[0] == 0 ? gSubTypes[getOffset()] : fCurrency;
}
UBool MeasureUnit::operator==(const UObject& other) const {
const MeasureUnit *rhs = dynamic_cast<const MeasureUnit*>(&other);
if (rhs == NULL) {
return FALSE;
}
return (
fTypeId == rhs->fTypeId
&& fSubTypeId == rhs->fSubTypeId
&& uprv_strcmp(fCurrency, rhs->fCurrency) == 0);
}
int32_t MeasureUnit::getIndex() const {
return gIndexes[fTypeId] + fSubTypeId;
}
int32_t MeasureUnit::getAvailable(
MeasureUnit *dest,
int32_t destCapacity,
UErrorCode &errorCode) {
if (U_FAILURE(errorCode)) {
return 0;
}
if (destCapacity < LENGTHOF(gSubTypes)) {
errorCode = U_BUFFER_OVERFLOW_ERROR;
return LENGTHOF(gSubTypes);
}
int32_t idx = 0;
for (int32_t typeIdx = 0; typeIdx < LENGTHOF(gTypes); ++typeIdx) {
int32_t len = gOffsets[typeIdx + 1] - gOffsets[typeIdx];
for (int32_t subTypeIdx = 0; subTypeIdx < len; ++subTypeIdx) {
dest[idx].setTo(typeIdx, subTypeIdx);
++idx;
}
}
U_ASSERT(idx == LENGTHOF(gSubTypes));
return LENGTHOF(gSubTypes);
}
int32_t MeasureUnit::getAvailable(
const char *type,
MeasureUnit *dest,
int32_t destCapacity,
UErrorCode &errorCode) {
if (U_FAILURE(errorCode)) {
return 0;
}
int32_t typeIdx = binarySearch(gTypes, 0, LENGTHOF(gTypes), type);
if (typeIdx == -1) {
return 0;
}
int32_t len = gOffsets[typeIdx + 1] - gOffsets[typeIdx];
if (destCapacity < len) {
errorCode = U_BUFFER_OVERFLOW_ERROR;
return len;
}
for (int subTypeIdx = 0; subTypeIdx < len; ++subTypeIdx) {
dest[subTypeIdx].setTo(typeIdx, subTypeIdx);
}
return len;
}
StringEnumeration* MeasureUnit::getAvailableTypes(UErrorCode &errorCode) {
UEnumeration *uenum = uenum_openCharStringsEnumeration(
gTypes, LENGTHOF(gTypes), &errorCode);
if (U_FAILURE(errorCode)) {
uenum_close(uenum);
return NULL;
}
StringEnumeration *result = new UStringEnumeration(uenum);
if (result == NULL) {
errorCode = U_MEMORY_ALLOCATION_ERROR;
uenum_close(uenum);
return NULL;
}
return result;
}
int32_t MeasureUnit::getIndexCount() {
return gIndexes[LENGTHOF(gIndexes) - 1];
}
MeasureUnit *MeasureUnit::create(int typeId, int subTypeId, UErrorCode &status) {
if (U_FAILURE(status)) {
return NULL;
}
MeasureUnit *result = new MeasureUnit(typeId, subTypeId);
if (result == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
}
return result;
}
void MeasureUnit::initTime(const char *timeId) {
int32_t result = binarySearch(gTypes, 0, LENGTHOF(gTypes), "duration");
U_ASSERT(result != -1);
fTypeId = result;
result = binarySearch(gSubTypes, gOffsets[fTypeId], gOffsets[fTypeId + 1], timeId);
U_ASSERT(result != -1);
fSubTypeId = result - gOffsets[fTypeId];
}
void MeasureUnit::initCurrency(const char *isoCurrency) {
int32_t result = binarySearch(gTypes, 0, LENGTHOF(gTypes), "currency");
U_ASSERT(result != -1);
fTypeId = result;
result = binarySearch(
gSubTypes, gOffsets[fTypeId], gOffsets[fTypeId + 1], isoCurrency);
if (result != -1) {
fSubTypeId = result - gOffsets[fTypeId];
} else {
uprv_strncpy(fCurrency, isoCurrency, LENGTHOF(fCurrency));
}
}
void MeasureUnit::setTo(int32_t typeId, int32_t subTypeId) {
fTypeId = typeId;
fSubTypeId = subTypeId;
fCurrency[0] = 0;
}
int32_t MeasureUnit::getOffset() const {
return gOffsets[fTypeId] + fSubTypeId;
}
U_NAMESPACE_END

View File

@ -1,6 +1,6 @@
/*
**********************************************************************
* Copyright (c) 2004-2012, International Business Machines
* Copyright (c) 2004-2014, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
* Author: Alan Liu
@ -44,6 +44,10 @@ Measure& Measure::operator=(const Measure& other) {
return *this;
}
UObject *Measure::clone() const {
return new Measure(*this);
}
Measure::~Measure() {
delete unit;
}
@ -55,13 +59,6 @@ UBool Measure::operator==(const UObject& other) const {
(unit != NULL && *unit == m->getUnit());
}
//----------------------------------------------------------------------
// MeasureUnit implementation
MeasureUnit:: MeasureUnit() {}
MeasureUnit::~MeasureUnit() {}
U_NAMESPACE_END
#endif // !UCONFIG_NO_FORMATTING

View File

@ -15,6 +15,7 @@
#include "unicode/plurrule.h"
#include "charstr.h"
#include "unicode/fmtable.h"
#include "unicode/fieldpos.h"
#define LENGTHOF(array) (int32_t)(sizeof(array) / sizeof((array)[0]))
@ -107,11 +108,16 @@ UBool QuantityFormatter::add(
return TRUE;
}
UBool QuantityFormatter::isValid() const {
return formatters[0] != NULL;
}
UnicodeString &QuantityFormatter::format(
const Formattable& quantity,
const NumberFormat &fmt,
const PluralRules &rules,
UnicodeString &appendTo,
FieldPosition &pos,
UErrorCode &status) const {
if (U_FAILURE(status)) {
return appendTo;
@ -154,9 +160,18 @@ UnicodeString &QuantityFormatter::format(
return appendTo;
}
UnicodeString formattedNumber;
FieldPosition pos(0);
fmt.format(quantity, formattedNumber, pos, status);
return pattern->format(formattedNumber, appendTo, status);
FieldPosition fpos(pos.getField());
fmt.format(quantity, formattedNumber, fpos, status);
const UnicodeString *params[1] = {&formattedNumber};
int32_t offsets[1];
pattern->format(params, LENGTHOF(params), appendTo, offsets, LENGTHOF(offsets), status);
if (offsets[0] != -1) {
if (fpos.getBeginIndex() != 0 || fpos.getEndIndex() != 0) {
pos.setBeginIndex(fpos.getBeginIndex() + offsets[0]);
pos.setEndIndex(fpos.getEndIndex() + offsets[0]);
}
}
return appendTo;
}
U_NAMESPACE_END

View File

@ -19,6 +19,7 @@ class UnicodeString;
class PluralRules;
class NumberFormat;
class Formattable;
class FieldPosition;
/**
* A plural aware formatter that is good for expressing a single quantity and
@ -74,6 +75,11 @@ public:
const UnicodeString &rawPattern,
UErrorCode &status);
/**
* returns TRUE if this object has at least the "other" variant.
*/
UBool isValid() const;
/**
* Formats a quantity with this object appending the result to appendTo.
* At least the "other" variant must be added to this object for this
@ -91,6 +97,7 @@ public:
const NumberFormat &fmt,
const PluralRules &rules,
UnicodeString &appendTo,
FieldPosition &pos,
UErrorCode &status) const;
private:

View File

@ -22,7 +22,6 @@
#include "uresimp.h"
#include "unicode/ures.h"
#include "cstring.h"
#include "plurrule_impl.h"
#include "ucln_in.h"
#include "mutex.h"
#include "charstr.h"
@ -648,11 +647,13 @@ UnicodeString& RelativeDateTimeFormatter::format(
return appendTo;
}
int32_t bFuture = direction == UDAT_DIRECTION_NEXT ? 1 : 0;
FieldPosition pos(FieldPosition::DONT_CARE);
return ptr->quantitativeUnits->data[unit][bFuture].format(
quantity,
*ptr->numberFormat,
*ptr->pluralRules,
appendTo,
pos,
status);
}

View File

@ -1,6 +1,6 @@
/*
*******************************************************************************
* Copyright (C) 2008-2012, Google, International Business Machines Corporation and
* Copyright (C) 2008-2014, Google, International Business Machines Corporation and
* others. All Rights Reserved.
*******************************************************************************
*/
@ -8,6 +8,7 @@
#include "utypeinfo.h" // for 'typeid' to work
#include "unicode/tmunit.h"
#include "uassert.h"
#if !UCONFIG_NO_FORMATTING
@ -70,44 +71,58 @@ TimeUnit::createInstance(TimeUnit::UTimeUnitFields timeUnitField,
TimeUnit::TimeUnit(TimeUnit::UTimeUnitFields timeUnitField) {
fTimeUnitField = timeUnitField;
switch (fTimeUnitField) {
case UTIMEUNIT_YEAR:
initTime("year");
break;
case UTIMEUNIT_MONTH:
initTime("month");
break;
case UTIMEUNIT_DAY:
initTime("day");
break;
case UTIMEUNIT_WEEK:
initTime("week");
break;
case UTIMEUNIT_HOUR:
initTime("hour");
break;
case UTIMEUNIT_MINUTE:
initTime("minute");
break;
case UTIMEUNIT_SECOND:
initTime("second");
break;
default:
U_ASSERT(false);
break;
}
}
TimeUnit::TimeUnit(const TimeUnit& other)
: MeasureUnit(other) {
*this = other;
: MeasureUnit(other), fTimeUnitField(other.fTimeUnitField) {
}
UObject*
TimeUnit::clone() const {
return new TimeUnit(*this);
}
TimeUnit&
TimeUnit::operator=(const TimeUnit& other) {
if (this == &other) {
return *this;
}
MeasureUnit::operator=(other);
fTimeUnitField = other.fTimeUnitField;
return *this;
}
UBool
TimeUnit::operator==(const UObject& other) const {
return (typeid(*this) == typeid(other)
&& fTimeUnitField == ((TimeUnit*)&other)->fTimeUnitField);
}
TimeUnit::UTimeUnitFields
TimeUnit::getTimeUnitField() const {
return fTimeUnitField;
}
TimeUnit::~TimeUnit() {
}

View File

@ -1,6 +1,6 @@
/*
*******************************************************************************
* Copyright (C) 2008-2013, Google, International Business Machines Corporation
* Copyright (C) 2008-2014, Google, International Business Machines Corporation
* and others. All Rights Reserved.
*******************************************************************************
*/
@ -78,53 +78,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, 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, 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, status);
break;
case UTMUTFMT_ABBREVIATED_STYLE:
initMeasureFormat(locale, UMEASFMT_WIDTH_SHORT, status);
break;
default:
initMeasureFormat(locale, UMEASFMT_WIDTH_WIDE, 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;
}
@ -139,20 +145,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)) {
@ -165,92 +164,10 @@ 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()];
const Formattable& amtNumber = amount->getNumber();
UnicodeString formattedNumber;
fNumberFormat->format(amtNumber, formattedNumber, status);
if (U_FAILURE(status)) {
return toAppendTo;
}
UnicodeString count;
const DecimalFormat* decfmt = dynamic_cast<const DecimalFormat*>(fNumberFormat);
if (decfmt != NULL) {
FixedDecimal fd = decfmt->getFixedDecimal(amtNumber, status);
if (U_FAILURE(status)) {
return toAppendTo;
}
count = fPluralRules->select(fd);
} else {
if (amtNumber.getType() == Formattable::kDouble) {
count = fPluralRules->select(amtNumber.getDouble());
} else if (amtNumber.getType() == Formattable::kLong) {
count = fPluralRules->select(amtNumber.getLong());
} else if (amtNumber.getType() == Formattable::kInt64) {
count = fPluralRules->select((double) amtNumber.getInt64());
} else {
status = U_ILLEGAL_ARGUMENT_ERROR;
return toAppendTo;
}
}
#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].setString(formattedNumber);
return pattern->format(formattable, 1, toAppendTo, pos, status);
}
}
status = U_ILLEGAL_ARGUMENT_ERROR;
return toAppendTo;
}
void
TimeUnitFormat::parseObject(const UnicodeString& source,
Formattable& result,
@ -305,7 +222,7 @@ TimeUnitFormat::parseObject(const UnicodeString& source,
if (temp.getType() == Formattable::kString) {
UnicodeString tmpString;
UErrorCode pStatus = U_ZERO_ERROR;
fNumberFormat->parse(temp.getString(tmpString), tmpNumber, pStatus);
getNumberFormat().parse(temp.getString(tmpString), tmpNumber, pStatus);
if (U_FAILURE(pStatus)) {
continue;
}
@ -368,7 +285,7 @@ TimeUnitFormat::parseObject(const UnicodeString& source,
}
void
TimeUnitFormat::create(const Locale& locale, UTimeUnitFormatStyle style, UErrorCode& status) {
TimeUnitFormat::create(UTimeUnitFormatStyle style, UErrorCode& status) {
if (U_FAILURE(status)) {
return;
}
@ -377,12 +294,12 @@ 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.
@ -399,7 +316,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;
}
@ -420,11 +337,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)) {
@ -445,7 +357,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(NULL, getLocaleID(status), &status);
unitsRes = ures_getByKey(rb, key, NULL, &status);
unitsRes = ures_getByKey(unitsRes, "duration", unitsRes, &status);
if (U_FAILURE(status)) {
@ -515,7 +427,7 @@ 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) ) {
MessageFormat** formatters = (MessageFormat**)countToPatterns->get(pluralCountUniStr);
if (formatters == NULL) {
@ -577,7 +489,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) {
@ -597,7 +509,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,
@ -650,7 +562,7 @@ 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)) {
MessageFormat** formatters = (MessageFormat**)countToPatterns->get(srcPluralCount);
if (formatters == NULL) {
@ -725,7 +637,7 @@ 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)) {
MessageFormat** formatters = (MessageFormat**)countToPatterns->get(srcPluralCount);
@ -755,8 +667,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);
}
}
@ -764,11 +675,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();
adoptNumberFormat((NumberFormat *)format.clone(), status);
}

View File

@ -1,7 +1,7 @@
/*
******************************************************************************
* *
* Copyright (C) 2001-2013, International Business Machines *
* Copyright (C) 2001-2014, International Business Machines *
* Corporation and others. All Rights Reserved. *
* *
******************************************************************************
@ -26,7 +26,6 @@ as the functions are suppose to be called.
It's usually best to have child dependencies called first. */
typedef enum ECleanupI18NType {
UCLN_I18N_START = -1,
UCLN_I18N_RELDATEFMT,
UCLN_I18N_IDENTIFIER_INFO,
UCLN_I18N_SPOOF,
UCLN_I18N_TRANSLITERATOR,
@ -46,6 +45,8 @@ typedef enum ECleanupI18NType {
UCLN_I18N_CURRENCY,
UCLN_I18N_DECFMT,
UCLN_I18N_NUMFMT,
UCLN_I18N_RELDATEFMT,
UCLN_I18N_MEASFMT,
UCLN_I18N_SMPDTFMT,
UCLN_I18N_USEARCH,
UCLN_I18N_COLLATOR,

View File

@ -1,6 +1,6 @@
/*
**********************************************************************
* Copyright (c) 2004-2006, International Business Machines
* Copyright (c) 2004-2014, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
* Author: Alan Liu
@ -69,13 +69,6 @@ class U_I18N_API CurrencyUnit: public MeasureUnit {
*/
virtual ~CurrencyUnit();
/**
* Equality operator. Return true if this object is equal
* to the given object.
* @stable ICU 3.0
*/
UBool operator==(const UObject& other) const;
/**
* Returns a unique class ID for this object POLYMORPHICALLY.
* This method implements a simple form of RTTI used by ICU.

View File

@ -1,6 +1,6 @@
/*
**********************************************************************
* Copyright (c) 2004-2011, International Business Machines
* Copyright (c) 2004-2014, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
* Author: Alan Liu
@ -12,27 +12,74 @@
#define MEASUREFORMAT_H
#include "unicode/utypes.h"
#include "unicode/measure.h"
#if !UCONFIG_NO_FORMATTING
#include "unicode/format.h"
#include "unicode/udat.h"
/**
* \file
* \brief C++ API: Formatter for measure objects.
*/
/**
* Constants for various widths.
* There are 3 widths: Wide, Short, Narrow.
* For example, for English, when formatting "3 hours"
* Wide is "3 hours"; short is "3 hrs"; narrow is "3h"
* @draft ICU 53
*/
enum UMeasureFormatWidth {
// Wide, short, and narrow must be first and in this order.
/**
* Spell out measure units.
* @draft ICU 53
*/
UMEASFMT_WIDTH_WIDE,
/**
* Abbreviate measure units.
* @draft ICU 53
*/
UMEASFMT_WIDTH_SHORT,
/**
* Use symbols for measure units when possible.
* @draft ICU 53
*/
UMEASFMT_WIDTH_NARROW,
/**
* Completely omit measure units when possible. For example, format
* '5 hours, 37 minutes' as '5:37'
* @draft ICU 53
*/
UMEASFMT_WIDTH_NUMERIC,
/**
* Count of values in this enum.
* @draft ICU 53
*/
UMEASFMT_WIDTH_COUNT
};
/** @draft ICU 53 */
typedef enum UMeasureFormatWidth UMeasureFormatWidth;
U_NAMESPACE_BEGIN
class NumberFormat;
class PluralRules;
class MeasureFormatData;
class QuantityFormatter;
class ListFormatter;
class DateFormat;
/**
*
* A formatter for measure objects. This is an abstract base class.
*
* <p>To format or parse a measure object, first create a formatter
* object using a MeasureFormat factory method. Then use that
* object's format and parse methods.
*
* <p>This is an abstract class.
* A formatter for measure objects.
*
* @see Format
* @author Alan Liu
@ -40,12 +87,96 @@ U_NAMESPACE_BEGIN
*/
class U_I18N_API MeasureFormat : public Format {
public:
using Format::parseObject;
using Format::format;
/**
* Constructor.
* @draft ICU 53.
*/
MeasureFormat(
const Locale &locale, UMeasureFormatWidth width, UErrorCode &status);
/**
* Constructor.
* @draft ICU 53.
*/
MeasureFormat(
const Locale &locale,
UMeasureFormatWidth width,
NumberFormat *nfToAdopt,
UErrorCode &status);
/**
* Copy constructor.
* @draft ICU 53.
*/
MeasureFormat(const MeasureFormat &other);
/**
* Assignment operator.
* @draft ICU 53.
*/
MeasureFormat &operator=(const MeasureFormat &rhs);
/**
* Destructor.
* @stable ICU 3.0
*/
virtual ~MeasureFormat();
/**
* Return true if given Format objects are semantically equal.
* @draft ICU 53
*/
virtual UBool operator==(const Format &other) const;
/**
* Clones this object polymorphically.
* @draft ICU 53
*/
virtual Format *clone() const;
/**
* Formats object to produce a string.
* @draft ICU 53
*/
virtual UnicodeString &format(
const Formattable &obj,
UnicodeString &appendTo,
FieldPosition &pos,
UErrorCode &status) const;
/**
* Parse a string to produce an object. This implementation sets
* status to U_UNSUPPORTED_ERROR.
*
* @draft ICU 53
*/
virtual void parseObject(
const UnicodeString &source,
Formattable &reslt,
ParsePosition &pos) const;
/**
* Formats measure objects to produce a string.
* @param measures measure objects.
* @param measureCount the number of measure objects.
* @param appendTo formatted string appended here.
* @param pos the field position.
* @param status the error.
* @return appendTo reference
*
* @draft ICU 53
*/
UnicodeString &formatMeasures(
const Measure *measures,
int32_t measureCount,
UnicodeString &appendTo,
FieldPosition &pos,
UErrorCode &status) const;
/**
* Return a formatter for CurrencyAmount objects in the given
* locale.
@ -67,12 +198,99 @@ class U_I18N_API MeasureFormat : public Format {
static MeasureFormat* U_EXPORT2 createCurrencyFormat(UErrorCode& ec);
protected:
/**
* Default constructor.
* @stable ICU 3.0
*/
MeasureFormat();
#ifndef U_HIDE_INTERNAL_API
/**
* ICU use only.
* Initialize MeasureFormat class from base class.
* @internal.
*/
void initMeasureFormat(const Locale &locale, UMeasureFormatWidth width, UErrorCode &status);
/**
* ICU use only.
* Allows subclass to change locale. Note that this method also changes
* the NumberFormat object. Returns TRUE if locale changed; FALSE if no
* change was made.
* @internal.
*/
UBool setMeasureFormatLocale(const Locale &locale, UErrorCode &status);
/**
* ICU use only.
* Let subclass change NumberFormat.
* @internal.
*/
void adoptNumberFormat(NumberFormat *nfToAdopt, UErrorCode &status);
/**
* ICU use only.
* @internal.
*/
const NumberFormat &getNumberFormat() const;
/**
* ICU use only.
* @internal.
*/
const PluralRules &getPluralRules() const;
/**
* ICU use only.
* @internal.
*/
Locale getLocale(UErrorCode &status) const;
/**
* ICU use only.
* @internal.
*/
const char *getLocaleID(UErrorCode &status) const;
#endif /* U_HIDE_INTERNAL_API */
private:
const MeasureFormatData *ptr;
UMeasureFormatWidth width;
const QuantityFormatter *getQuantityFormatter(
int32_t index,
int32_t widthIndex,
UErrorCode &status) const;
UnicodeString &formatMeasure(
const Measure &measure,
UnicodeString &appendTo,
FieldPosition &pos,
UErrorCode &status) const;
UnicodeString &formatMeasuresSlowTrack(
const Measure *measures,
int32_t measureCount,
const ListFormatter& lf,
UnicodeString& appendTo,
FieldPosition& pos,
UErrorCode& status) const;
UnicodeString &formatNumeric(
const Formattable *hms, // always length 3
int32_t bitMap, // 1=hourset, 2=minuteset, 4=secondset
UnicodeString &appendTo,
UErrorCode &status) const;
UnicodeString &formatNumeric(
UDate date,
const DateFormat &dateFmt,
UDateFormatField smallestField,
const Formattable &smallestAmount,
UnicodeString &appendTo,
UErrorCode &status) const;
};
U_NAMESPACE_END

View File

@ -1,6 +1,6 @@
/*
**********************************************************************
* Copyright (c) 2004-2006, International Business Machines
* Copyright (c) 2004-2014, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
* Author: Alan Liu
@ -12,10 +12,7 @@
#define __MEASUREUNIT_H__
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#include "unicode/fmtable.h"
#include "unicode/unistr.h"
/**
* \file
@ -24,48 +21,312 @@
U_NAMESPACE_BEGIN
class StringEnumeration;
/**
* A unit such as length, mass, volume, currency, etc. A unit is
* coupled with a numeric amount to produce a Measure.
*
* <p>This is an abstract class.
*
* @author Alan Liu
* @stable ICU 3.0
*/
class U_I18N_API MeasureUnit: public UObject {
public:
/**
* Return a polymorphic clone of this object. The result will
* Default constructor.
* @stable ICU 3.0
*/
MeasureUnit() : fTypeId(0), fSubTypeId(0) {
fCurrency[0] = 0;
}
/**
* Copy constructor.
* @draft ICU 53
*/
MeasureUnit(const MeasureUnit &other);
/**
* Assignment operator.
* @draft ICU 53.
*/
MeasureUnit &operator=(const MeasureUnit &other);
/**
* Returns a polymorphic clone of this object. The result will
* have the same class as returned by getDynamicClassID().
* @stable ICU 3.0
*/
virtual UObject* clone() const = 0;
virtual UObject* clone() const;
/**
* Destructor
* @stable ICU 3.0
*/
virtual ~MeasureUnit();
/**
* Equality operator. Return true if this object is equal
* to the given object.
* @stable ICU 3.0
*/
virtual UBool operator==(const UObject& other) const = 0;
virtual UBool operator==(const UObject& other) const;
/**
* Inequality operator. Return true if this object is not equal
* to the given object.
* @draft ICU 53
*/
UBool operator!=(const UObject& other) const {
return !(*this == other);
}
/**
* Get the type.
* @draft ICU 53
*/
const char *getType() const;
/**
* Get the sub type.
* @draft ICU 53
*/
const char *getSubtype() const;
/**
* getAvailable gets all of the available units.
* If there are too many units to fit into destCapacity then the
* error code is set to U_BUFFER_OVERFLOW_ERROR.
*
* @param destArray destination buffer.
* @param destCapacity number of MeasureUnit instances available at dest.
* @param errorCode ICU error code.
* @return number of available units.
* @draft ICU 53
*/
static int32_t getAvailable(
MeasureUnit *destArray,
int32_t destCapacity,
UErrorCode &errorCode);
/**
* getAvailable gets all of the available units for a specific type.
* If there are too many units to fit into destCapacity then the
* error code is set to U_BUFFER_OVERFLOW_ERROR.
*
* @param type the type
* @param destArray destination buffer.
* @param destCapacity number of MeasureUnit instances available at dest.
* @param errorCode ICU error code.
* @return number of available units for type.
* @draft ICU 53
*/
static int32_t getAvailable(
const char *type,
MeasureUnit *destArray,
int32_t destCapacity,
UErrorCode &errorCode);
/**
* getAvailableTypes gets all of the available types. Caller owns the
* returned StringEnumeration and must delete it when finished using it.
*
* @param errorCode ICU error code.
* @return the types.
* @draft ICU 53
*/
static StringEnumeration* getAvailableTypes(UErrorCode &errorCode);
#ifndef U_HIDE_INTERNAL_API
/**
* ICU use only.
* Returns associated array index for this measure unit. Only valid for
* non-currency measure units.
* @internal
*/
int32_t getIndex() const;
/**
* ICU use only.
* Returns maximum value from getIndex plus 1.
* @internal
*/
static int32_t getIndexCount();
#endif /* U_HIDE_INTERNAL_API */
// Start generated createXXX methods
/** Constant for unit of acceleration: g-force */
static MeasureUnit *createGForce(UErrorCode &status);
/** Constant for unit of angle: arc-minute */
static MeasureUnit *createArcMinute(UErrorCode &status);
/** Constant for unit of angle: arc-second */
static MeasureUnit *createArcSecond(UErrorCode &status);
/** Constant for unit of angle: degree */
static MeasureUnit *createDegree(UErrorCode &status);
/** Constant for unit of area: acre */
static MeasureUnit *createAcre(UErrorCode &status);
/** Constant for unit of area: hectare */
static MeasureUnit *createHectare(UErrorCode &status);
/** Constant for unit of area: square-foot */
static MeasureUnit *createSquareFoot(UErrorCode &status);
/** Constant for unit of area: square-kilometer */
static MeasureUnit *createSquareKilometer(UErrorCode &status);
/** Constant for unit of area: square-meter */
static MeasureUnit *createSquareMeter(UErrorCode &status);
/** Constant for unit of area: square-mile */
static MeasureUnit *createSquareMile(UErrorCode &status);
/** Constant for unit of duration: day */
static MeasureUnit *createDay(UErrorCode &status);
/** Constant for unit of duration: hour */
static MeasureUnit *createHour(UErrorCode &status);
/** Constant for unit of duration: millisecond */
static MeasureUnit *createMillisecond(UErrorCode &status);
/** Constant for unit of duration: minute */
static MeasureUnit *createMinute(UErrorCode &status);
/** Constant for unit of duration: month */
static MeasureUnit *createMonth(UErrorCode &status);
/** Constant for unit of duration: second */
static MeasureUnit *createSecond(UErrorCode &status);
/** Constant for unit of duration: week */
static MeasureUnit *createWeek(UErrorCode &status);
/** Constant for unit of duration: year */
static MeasureUnit *createYear(UErrorCode &status);
/** Constant for unit of length: centimeter */
static MeasureUnit *createCentimeter(UErrorCode &status);
/** Constant for unit of length: foot */
static MeasureUnit *createFoot(UErrorCode &status);
/** Constant for unit of length: inch */
static MeasureUnit *createInch(UErrorCode &status);
/** Constant for unit of length: kilometer */
static MeasureUnit *createKilometer(UErrorCode &status);
/** Constant for unit of length: light-year */
static MeasureUnit *createLightYear(UErrorCode &status);
/** Constant for unit of length: meter */
static MeasureUnit *createMeter(UErrorCode &status);
/** Constant for unit of length: mile */
static MeasureUnit *createMile(UErrorCode &status);
/** Constant for unit of length: millimeter */
static MeasureUnit *createMillimeter(UErrorCode &status);
/** Constant for unit of length: picometer */
static MeasureUnit *createPicometer(UErrorCode &status);
/** Constant for unit of length: yard */
static MeasureUnit *createYard(UErrorCode &status);
/** Constant for unit of mass: gram */
static MeasureUnit *createGram(UErrorCode &status);
/** Constant for unit of mass: kilogram */
static MeasureUnit *createKilogram(UErrorCode &status);
/** Constant for unit of mass: ounce */
static MeasureUnit *createOunce(UErrorCode &status);
/** Constant for unit of mass: pound */
static MeasureUnit *createPound(UErrorCode &status);
/** Constant for unit of power: horsepower */
static MeasureUnit *createHorsepower(UErrorCode &status);
/** Constant for unit of power: kilowatt */
static MeasureUnit *createKilowatt(UErrorCode &status);
/** Constant for unit of power: watt */
static MeasureUnit *createWatt(UErrorCode &status);
/** Constant for unit of pressure: hectopascal */
static MeasureUnit *createHectopascal(UErrorCode &status);
/** Constant for unit of pressure: inch-hg */
static MeasureUnit *createInchHg(UErrorCode &status);
/** Constant for unit of pressure: millibar */
static MeasureUnit *createMillibar(UErrorCode &status);
/** Constant for unit of speed: kilometer-per-hour */
static MeasureUnit *createKilometerPerHour(UErrorCode &status);
/** Constant for unit of speed: meter-per-second */
static MeasureUnit *createMeterPerSecond(UErrorCode &status);
/** Constant for unit of speed: mile-per-hour */
static MeasureUnit *createMilePerHour(UErrorCode &status);
/** Constant for unit of temperature: celsius */
static MeasureUnit *createCelsius(UErrorCode &status);
/** Constant for unit of temperature: fahrenheit */
static MeasureUnit *createFahrenheit(UErrorCode &status);
/** Constant for unit of volume: cubic-kilometer */
static MeasureUnit *createCubicKilometer(UErrorCode &status);
/** Constant for unit of volume: cubic-mile */
static MeasureUnit *createCubicMile(UErrorCode &status);
/** Constant for unit of volume: liter */
static MeasureUnit *createLiter(UErrorCode &status);
protected:
#ifndef U_HIDE_INTERNAL_API
/**
* Default constructor.
* @stable ICU 3.0
* For ICU use only.
* @internal
*/
MeasureUnit();
void initTime(const char *timeId);
/**
* For ICU use only.
* @internal
*/
void initCurrency(const char *isoCurrency);
#endif
private:
int32_t fTypeId;
int32_t fSubTypeId;
char fCurrency[4];
MeasureUnit(int32_t typeId, int32_t subTypeId) : fTypeId(typeId), fSubTypeId(subTypeId) {
fCurrency[0] = 0;
}
void setTo(int32_t typeId, int32_t subTypeId);
int32_t getOffset() const;
static MeasureUnit *create(int typeId, int subTypeId, UErrorCode &status);
};
U_NAMESPACE_END
// NOTE: There is no measunit.cpp. For implementation, see measure.cpp. [alan]
#endif // !UCONFIG_NO_FORMATTING
#endif // __MEASUREUNIT_H__

View File

@ -1,6 +1,6 @@
/*
**********************************************************************
* Copyright (c) 2004-2006, International Business Machines
* Copyright (c) 2004-2014, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
* Author: Alan Liu
@ -74,7 +74,7 @@ class U_I18N_API Measure: public UObject {
* have the same class as returned by getDynamicClassID().
* @stable ICU 3.0
*/
virtual UObject* clone() const = 0;
virtual UObject* clone() const;
/**
* Destructor

View File

@ -1,6 +1,6 @@
/*
*******************************************************************************
* Copyright (C) 2009-2010, Google, International Business Machines Corporation and *
* Copyright (C) 2009-2014, Google, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
@ -76,20 +76,6 @@ public:
*/
TimeUnit& operator=(const TimeUnit& other);
/**
* Equality operator.
* @return true if 2 objects are the same.
* @stable ICU 4.2
*/
virtual UBool operator==(const UObject& other) const;
/**
* Non-Equality operator.
* @return true if 2 objects are not the same.
* @stable ICU 4.2
*/
UBool operator!=(const UObject& other) const;
/**
* Returns a unique class ID for this object POLYMORPHICALLY.
* This method implements a simple form of RTTI used by ICU.
@ -134,12 +120,6 @@ private:
};
inline UBool
TimeUnit::operator!=(const UObject& other) const {
return !operator==(other);
}
U_NAMESPACE_END
#endif /* #if !UCONFIG_NO_FORMATTING */

View File

@ -1,6 +1,6 @@
/*
*******************************************************************************
* Copyright (C) 2008-2013, Google, International Business Machines Corporation
* Copyright (C) 2008-2014, Google, International Business Machines Corporation
* and others. All Rights Reserved.
*******************************************************************************
*/
@ -125,16 +125,6 @@ public:
*/
TimeUnitFormat& operator=(const TimeUnitFormat& other);
/**
* Return true if the given Format objects are semantically equal. Objects
* of different subclasses are considered unequal.
* @param other the object to be compared with.
* @return true if the given Format objects are semantically equal.
* @stable ICU 4.2
*/
virtual UBool operator==(const Format& other) const;
/**
* Return true if the given Format objects are not semantically equal.
* Objects of different subclasses are considered unequal.
@ -161,22 +151,6 @@ public:
*/
void setNumberFormat(const NumberFormat& format, UErrorCode& status);
using MeasureFormat::format;
/**
* Format a TimeUnitAmount.
* If the formattable object is not a time unit amount object,
* or the number in time unit amount is not a double type or long type
* numeric, it returns a failing status: U_ILLEGAL_ARGUMENT_ERROR.
* @see Format#format(const Formattable&, UnicodeString&, FieldPosition&, UErrorCode&) const
* @stable ICU 4.2
*/
virtual UnicodeString& format(const Formattable& obj,
UnicodeString& toAppendTo,
FieldPosition& pos,
UErrorCode& status) const;
/**
* Parse a TimeUnitAmount.
* @see Format#parseObject(const UnicodeString&, Formattable&, ParsePosition&) const;
@ -213,13 +187,10 @@ public:
virtual UClassID getDynamicClassID(void) const;
private:
NumberFormat* fNumberFormat;
Locale fLocale;
Hashtable* fTimeUnitToCountToPatterns[TimeUnit::UTIMEUNIT_FIELD_COUNT];
PluralRules* fPluralRules;
UTimeUnitFormatStyle fStyle;
void create(const Locale& locale, UTimeUnitFormatStyle style, UErrorCode& status);
void create(UTimeUnitFormatStyle style, UErrorCode& status);
// it might actually be simpler to make them Decimal Formats later.
// initialize all private data members

View File

@ -56,7 +56,7 @@ uobjtest.o idnaref.o idnaconf.o nptrans.o punyref.o testidn.o testidna.o uts46te
incaltst.o calcasts.o v32test.o uvectest.o textfile.o tokiter.o utxttest.o \
windttst.o winnmtst.o winutil.o csdetest.o tzrulets.o tzoffloc.o tzfmttst.o ssearch.o dtifmtts.o \
tufmtts.o itspoof.o simplethread.o bidiconf.o locnmtst.o dcfmtest.o alphaindextst.o listformattertest.o genderinfotest.o compactdecimalformattest.o regiontst.o \
reldatefmttest.o lrucachetest.o simplepatternformattertest.o
reldatefmttest.o lrucachetest.o simplepatternformattertest.o measfmttest.o
DEPS = $(OBJECTS:.o=.d)

View File

@ -308,6 +308,7 @@
<ClCompile Include="lrucachetest.cpp">
<DisableLanguageExtensions>false</DisableLanguageExtensions>
</ClCompile>
<ClCompile Include="measfmttest.cpp" />
<ClCompile Include="miscdtfm.cpp" />
<ClCompile Include="msfmrgts.cpp" />
<ClCompile Include="nmfmapts.cpp" />

View File

@ -241,6 +241,9 @@
<ClCompile Include="locnmtst.cpp">
<Filter>formatting</Filter>
</ClCompile>
<ClCompile Include="measfmttest.cpp">
<Filter>formatting</Filter>
</ClCompile>
<ClCompile Include="miscdtfm.cpp">
<Filter>formatting</Filter>
</ClCompile>

View File

@ -1,6 +1,6 @@
/********************************************************************
* COPYRIGHT:
* Copyright (c) 1997-2013, International Business Machines
* Copyright (c) 1997-2014, International Business Machines
* Corporation and others. All Rights Reserved.
********************************************************************/
@ -62,6 +62,7 @@
extern IntlTest *createCompactDecimalFormatTest();
extern IntlTest *createGenderInfoTest();
extern IntlTest *createRelativeDateTimeFormatterTest();
extern IntlTest *createMeasureFormatTest();
#define TESTCLASS(id, TestClass) \
case id: \
@ -167,6 +168,15 @@ void IntlTestFormat::runIndexedTest( int32_t index, UBool exec, const char* &nam
callTest(*test, par);
}
break;
case 47:
name = "MeasureFormatTest";
if (exec) {
logln("MeasureFormatTest test---");
logln((UnicodeString)"");
LocalPointer<IntlTest> test(createMeasureFormatTest());
callTest(*test, par);
}
break;
default: name = ""; break; //needed to end loop
}
if (exec) {

View File

@ -0,0 +1,901 @@
/*
*******************************************************************************
* Copyright (C) 2014, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*
* File MEASFMTTEST.CPP
*
*******************************************************************************
*/
#include <stdio.h>
#include <stdlib.h>
#include "intltest.h"
#if !UCONFIG_NO_FORMATTING
#include "unicode/decimfmt.h"
#include "unicode/measfmt.h"
#include "unicode/measure.h"
#include "unicode/measunit.h"
#include "unicode/tmutamt.h"
#include "charstr.h"
#define LENGTHOF(array) (int32_t)(sizeof(array) / sizeof((array)[0]))
struct ExpectedResult {
const Measure *measures;
int32_t count;
const char *expected;
};
class MeasureFormatTest : public IntlTest {
public:
MeasureFormatTest() {
}
void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par=0);
private:
void TestBasic();
void TestGetAvailable();
void TestExamplesInDocs();
void TestFormatPeriodEn();
void Test10219FractionalPlurals();
void TestGreek();
void TestFormatSingleArg();
void TestFormatMeasuresZeroArg();
void TestMultiples();
void TestGram();
void TestCurrencies();
void TestFieldPosition();
void TestFieldPositionMultiple();
void TestBadArg();
void TestEquality();
void verifyFormat(
const char *description,
const MeasureFormat &fmt,
const Measure *measures,
int32_t measureCount,
const char *expected);
void verifyFormatWithPrefix(
const char *description,
const MeasureFormat &fmt,
const UnicodeString &prefix,
const Measure *measures,
int32_t measureCount,
const char *expected);
void verifyFormat(
const char *description,
const MeasureFormat &fmt,
const ExpectedResult *expectedResults,
int32_t count);
void helperTestMultiples(
const Locale &locale,
UMeasureFormatWidth width,
const char *expected);
void verifyFieldPosition(
const char *description,
const MeasureFormat &fmt,
const UnicodeString &prefix,
const Measure *measures,
int32_t measureCount,
NumberFormat::EAlignmentFields field,
int32_t start,
int32_t end);
};
void MeasureFormatTest::runIndexedTest(
int32_t index, UBool exec, const char *&name, char *) {
if (exec) {
logln("TestSuite MeasureFormatTest: ");
}
TESTCASE_AUTO_BEGIN;
TESTCASE_AUTO(TestBasic);
TESTCASE_AUTO(TestGetAvailable);
TESTCASE_AUTO(TestExamplesInDocs);
TESTCASE_AUTO(TestFormatPeriodEn);
TESTCASE_AUTO(Test10219FractionalPlurals);
TESTCASE_AUTO(TestGreek);
TESTCASE_AUTO(TestFormatSingleArg);
TESTCASE_AUTO(TestFormatMeasuresZeroArg);
TESTCASE_AUTO(TestMultiples);
TESTCASE_AUTO(TestGram);
TESTCASE_AUTO(TestCurrencies);
TESTCASE_AUTO(TestFieldPosition);
TESTCASE_AUTO(TestFieldPositionMultiple);
TESTCASE_AUTO(TestBadArg);
TESTCASE_AUTO(TestEquality);
TESTCASE_AUTO_END;
}
void MeasureFormatTest::TestBasic() {
UErrorCode status = U_ZERO_ERROR;
MeasureUnit *ptr1 = MeasureUnit::createArcMinute(status);
MeasureUnit *ptr2 = MeasureUnit::createArcMinute(status);
if (!(*ptr1 == *ptr2)) {
errln("Expect == to work.");
}
if (*ptr1 != *ptr2) {
errln("Expect != to work.");
}
MeasureUnit *ptr3 = MeasureUnit::createMeter(status);
if (*ptr1 == *ptr3) {
errln("Expect == to work.");
}
if (!(*ptr1 != *ptr3)) {
errln("Expect != to work.");
}
MeasureUnit *ptr4 = (MeasureUnit *) ptr1->clone();
if (*ptr1 != *ptr4) {
errln("Expect clone to work.");
}
MeasureUnit stack;
stack = *ptr1;
if (*ptr1 != stack) {
errln("Expect assignment to work.");
}
delete ptr1;
delete ptr2;
delete ptr3;
delete ptr4;
}
void MeasureFormatTest::TestGetAvailable() {
MeasureUnit *units = NULL;
UErrorCode status = U_ZERO_ERROR;
int32_t totalCount = MeasureUnit::getAvailable(units, 0, status);
while (status == U_BUFFER_OVERFLOW_ERROR) {
status = U_ZERO_ERROR;
delete [] units;
units = new MeasureUnit[totalCount];
totalCount = MeasureUnit::getAvailable(units, totalCount, status);
}
if (U_FAILURE(status)) {
dataerrln("Failure creating format object - %s", u_errorName(status));
delete [] units;
return;
}
if (totalCount < 200) {
errln("Expect at least 200 measure units including currencies.");
}
delete [] units;
StringEnumeration *types = MeasureUnit::getAvailableTypes(status);
if (U_FAILURE(status)) {
dataerrln("Failure getting types - %s", u_errorName(status));
delete types;
return;
}
if (types->count(status) < 10) {
errln("Expect at least 10 distinct unit types.");
}
units = NULL;
int32_t unitCapacity = 0;
int32_t unitCountSum = 0;
for (
const char* type = types->next(NULL, status);
type != NULL;
type = types->next(NULL, status)) {
int32_t unitCount = MeasureUnit::getAvailable(type, units, unitCapacity, status);
while (status == U_BUFFER_OVERFLOW_ERROR) {
status = U_ZERO_ERROR;
delete [] units;
units = new MeasureUnit[unitCount];
unitCapacity = unitCount;
unitCount = MeasureUnit::getAvailable(type, units, unitCapacity, status);
}
if (U_FAILURE(status)) {
dataerrln("Failure getting units - %s", u_errorName(status));
delete [] units;
delete types;
return;
}
if (unitCount < 1) {
errln("Expect at least one unit count per type.");
}
unitCountSum += unitCount;
}
if (unitCountSum != totalCount) {
errln("Expected total unit count to equal sum of unit counts by type.");
}
delete [] units;
delete types;
}
void MeasureFormatTest::TestExamplesInDocs() {
UErrorCode status = U_ZERO_ERROR;
MeasureFormat fmtFr(Locale::getFrench(), UMEASFMT_WIDTH_SHORT, status);
MeasureFormat fmtFrFull(
Locale::getFrench(), UMEASFMT_WIDTH_WIDE, status);
MeasureFormat fmtFrNarrow(
Locale::getFrench(), UMEASFMT_WIDTH_NARROW, status);
MeasureFormat fmtEn(Locale::getUS(), UMEASFMT_WIDTH_WIDE, status);
if (!assertSuccess("Error creating formatters", status)) {
return;
}
Measure measureC(23, MeasureUnit::createCelsius(status), status);
Measure measureF(70, MeasureUnit::createFahrenheit(status), status);
Measure feetAndInches[] = {
Measure(70, MeasureUnit::createFoot(status), status),
Measure(5.3, MeasureUnit::createInch(status), status)};
Measure footAndInch[] = {
Measure(1, MeasureUnit::createFoot(status), status),
Measure(1, MeasureUnit::createInch(status), status)};
Measure inchAndFeet[] = {
Measure(1, MeasureUnit::createInch(status), status),
Measure(2, MeasureUnit::createFoot(status), status)};
if (!assertSuccess("Error creating measurements.", status)) {
return;
}
verifyFormat(
"Celsius",
fmtFr,
&measureC,
1,
"23 \\u00B0C");
verifyFormatWithPrefix(
"Celsius",
fmtFr,
"Prefix: ",
&measureC,
1,
"Prefix: 23 \\u00B0C");
verifyFormat(
"Fahrenheit",
fmtFr,
&measureF,
1,
"70 \\u00B0F");
verifyFormat(
"Feet and inches",
fmtFrFull,
feetAndInches,
LENGTHOF(feetAndInches),
"70 pieds et 5,3 pouces");
verifyFormatWithPrefix(
"Feet and inches",
fmtFrFull,
"Prefix: ",
feetAndInches,
LENGTHOF(feetAndInches),
"Prefix: 70 pieds et 5,3 pouces");
verifyFormat(
"Foot and inch",
fmtFrFull,
footAndInch,
LENGTHOF(footAndInch),
"1 pied et 1 pouce");
verifyFormat(
"Foot and inch narrow",
fmtFrNarrow,
footAndInch,
LENGTHOF(footAndInch),
"1\\u2032 1\\u2033");
verifyFormat(
"Inch and feet",
fmtEn,
inchAndFeet,
LENGTHOF(inchAndFeet),
"1 inch, 2 feet");
}
void MeasureFormatTest::TestFormatPeriodEn() {
UErrorCode status = U_ZERO_ERROR;
Measure t_19m[] = {Measure(19, MeasureUnit::createMinute(status), status)};
Measure t_1h_23_5s[] = {
Measure(1.0, MeasureUnit::createHour(status), status),
Measure(23.5, MeasureUnit::createSecond(status), status)
};
Measure t_1h_23_5m[] = {
Measure(1.0, MeasureUnit::createHour(status), status),
Measure(23.5, MeasureUnit::createMinute(status), status)
};
Measure t_1h_0m_23s[] = {
Measure(1.0, MeasureUnit::createHour(status), status),
Measure(0.0, MeasureUnit::createMinute(status), status),
Measure(23, MeasureUnit::createSecond(status), status)
};
Measure t_2y_5M_3w_4d[] = {
Measure(2.0, MeasureUnit::createYear(status), status),
Measure(5.0, MeasureUnit::createMonth(status), status),
Measure(3.0, MeasureUnit::createWeek(status), status),
Measure(4.0, MeasureUnit::createDay(status), status)
};
Measure t_1m_59_9996s[] = {
Measure(1.0, MeasureUnit::createMinute(status), status),
Measure(59.9996, MeasureUnit::createSecond(status), status)
};
Measure t_5h_17m[] = {
Measure(5.0, MeasureUnit::createHour(status), status),
Measure(17.0, MeasureUnit::createMinute(status), status)
};
Measure t_19m_28s[] = {
Measure(19.0, MeasureUnit::createMinute(status), status),
Measure(28.0, MeasureUnit::createSecond(status), status)
};
Measure t_0h_0m_17s[] = {
Measure(0.0, MeasureUnit::createHour(status), status),
Measure(0.0, MeasureUnit::createMinute(status), status),
Measure(17.0, MeasureUnit::createSecond(status), status)
};
Measure t_6h_56_92m[] = {
Measure(6.0, MeasureUnit::createHour(status), status),
Measure(56.92, MeasureUnit::createMinute(status), status)
};
Measure t_3h_5h[] = {
Measure(3.0, MeasureUnit::createHour(status), status),
Measure(5.0, MeasureUnit::createHour(status), status)
};
if (!assertSuccess("Error creating Measure objects", status)) {
return;
}
ExpectedResult fullData[] = {
{t_1m_59_9996s, LENGTHOF(t_1m_59_9996s), "1 minute, 59.9996 seconds"},
{t_19m, LENGTHOF(t_19m), "19 minutes"},
{t_1h_23_5s, LENGTHOF(t_1h_23_5s), "1 hour, 23.5 seconds"},
{t_1h_23_5m, LENGTHOF(t_1h_23_5m), "1 hour, 23.5 minutes"},
{t_1h_0m_23s, LENGTHOF(t_1h_0m_23s), "1 hour, 0 minutes, 23 seconds"},
{t_2y_5M_3w_4d, LENGTHOF(t_2y_5M_3w_4d), "2 years, 5 months, 3 weeks, 4 days"}};
ExpectedResult abbrevData[] = {
{t_1m_59_9996s, LENGTHOF(t_1m_59_9996s), "1 min, 59.9996 secs"},
{t_19m, LENGTHOF(t_19m), "19 mins"},
{t_1h_23_5s, LENGTHOF(t_1h_23_5s), "1 hr, 23.5 secs"},
{t_1h_23_5m, LENGTHOF(t_1h_23_5m), "1 hr, 23.5 mins"},
{t_1h_0m_23s, LENGTHOF(t_1h_0m_23s), "1 hr, 0 mins, 23 secs"},
{t_2y_5M_3w_4d, LENGTHOF(t_2y_5M_3w_4d), "2 yrs, 5 mths, 3 wks, 4 days"}};
ExpectedResult narrowData[] = {
{t_1m_59_9996s, LENGTHOF(t_1m_59_9996s), "1m 59.9996s"},
{t_19m, LENGTHOF(t_19m), "19m"},
{t_1h_23_5s, LENGTHOF(t_1h_23_5s), "1h 23.5s"},
{t_1h_23_5m, LENGTHOF(t_1h_23_5m), "1h 23.5m"},
{t_1h_0m_23s, LENGTHOF(t_1h_0m_23s), "1h 0m 23s"},
{t_2y_5M_3w_4d, LENGTHOF(t_2y_5M_3w_4d), "2y 5m 3w 4d"}};
ExpectedResult numericData[] = {
{t_1m_59_9996s, LENGTHOF(t_1m_59_9996s), "1:59.9996"},
{t_19m, LENGTHOF(t_19m), "19m"},
{t_1h_23_5s, LENGTHOF(t_1h_23_5s), "1:00:23.5"},
{t_1h_23_5m, LENGTHOF(t_1h_23_5m), "1:23.5"},
{t_1h_0m_23s, LENGTHOF(t_1h_0m_23s), "1:00:23"},
{t_5h_17m, LENGTHOF(t_5h_17m), "5:17"},
{t_19m_28s, LENGTHOF(t_19m_28s), "19:28"},
{t_2y_5M_3w_4d, LENGTHOF(t_2y_5M_3w_4d), "2y 5m 3w 4d"},
{t_0h_0m_17s, LENGTHOF(t_0h_0m_17s), "0:00:17"},
{t_6h_56_92m, LENGTHOF(t_6h_56_92m), "6:56.92"},
{t_3h_5h, LENGTHOF(t_3h_5h), "3h 5h"}};
ExpectedResult fullDataDe[] = {
{t_1m_59_9996s, LENGTHOF(t_1m_59_9996s), "1 Minute und 59,9996 Sekunden"},
{t_19m, LENGTHOF(t_19m), "19 Minuten"},
{t_1h_23_5s, LENGTHOF(t_1h_23_5s), "1 Stunde und 23,5 Sekunden"},
{t_1h_23_5m, LENGTHOF(t_1h_23_5m), "1 Stunde und 23,5 Minuten"},
{t_1h_0m_23s, LENGTHOF(t_1h_0m_23s), "1 Stunde, 0 Minuten und 23 Sekunden"},
{t_2y_5M_3w_4d, LENGTHOF(t_2y_5M_3w_4d), "2 Jahre, 5 Monate, 3 Wochen und 4 Tage"}};
ExpectedResult numericDataDe[] = {
{t_1m_59_9996s, LENGTHOF(t_1m_59_9996s), "1:59,9996"},
{t_19m, LENGTHOF(t_19m), "19 Min."},
{t_1h_23_5s, LENGTHOF(t_1h_23_5s), "1:00:23,5"},
{t_1h_23_5m, LENGTHOF(t_1h_23_5m), "1:23,5"},
{t_1h_0m_23s, LENGTHOF(t_1h_0m_23s), "1:00:23"},
{t_5h_17m, LENGTHOF(t_5h_17m), "5:17"},
{t_19m_28s, LENGTHOF(t_19m_28s), "19:28"},
{t_2y_5M_3w_4d, LENGTHOF(t_2y_5M_3w_4d), "2 J, 5 M, 3 W und 4 T"},
{t_0h_0m_17s, LENGTHOF(t_0h_0m_17s), "0:00:17"},
{t_6h_56_92m, LENGTHOF(t_6h_56_92m), "6:56,92"},
{t_3h_5h, LENGTHOF(t_3h_5h), "3 Std., 5 Std."}};
Locale en(Locale::getEnglish());
LocalPointer<NumberFormat> nf(NumberFormat::createInstance(en, status));
if (!assertSuccess("Error creating number format en object", status)) {
return;
}
nf->setMaximumFractionDigits(4);
MeasureFormat mf(en, UMEASFMT_WIDTH_WIDE, (NumberFormat *) nf->clone(), status);
if (!assertSuccess("Error creating measure format en WIDE", status)) {
return;
}
verifyFormat("en WIDE", mf, fullData, LENGTHOF(fullData));
// exercise copy constructor
{
MeasureFormat mf2(mf);
verifyFormat("en WIDE copy", mf2, fullData, LENGTHOF(fullData));
}
// exercise clone
{
MeasureFormat *mf3 = (MeasureFormat *) mf.clone();
verifyFormat("en WIDE copy", *mf3, fullData, LENGTHOF(fullData));
delete mf3;
}
mf = MeasureFormat(en, UMEASFMT_WIDTH_SHORT, (NumberFormat *) nf->clone(), status);
if (!assertSuccess("Error creating measure format en SHORT", status)) {
return;
}
verifyFormat("en SHORT", mf, abbrevData, LENGTHOF(abbrevData));
mf = MeasureFormat(en, UMEASFMT_WIDTH_NARROW, (NumberFormat *) nf->clone(), status);
if (!assertSuccess("Error creating measure format en NARROW", status)) {
return;
}
verifyFormat("en NARROW", mf, narrowData, LENGTHOF(narrowData));
mf = MeasureFormat(en, UMEASFMT_WIDTH_NUMERIC, (NumberFormat *) nf->clone(), status);
if (!assertSuccess("Error creating measure format en NUMERIC", status)) {
return;
}
verifyFormat("en NUMERIC", mf, numericData, LENGTHOF(numericData));
Locale de(Locale::getGerman());
nf.adoptInstead(NumberFormat::createInstance(de, status));
if (!assertSuccess("Error creating number format de object", status)) {
return;
}
nf->setMaximumFractionDigits(4);
mf = MeasureFormat(de, UMEASFMT_WIDTH_WIDE, (NumberFormat *) nf->clone(), status);
if (!assertSuccess("Error creating measure format de WIDE", status)) {
return;
}
verifyFormat("de WIDE", mf, fullDataDe, LENGTHOF(fullDataDe));
mf = MeasureFormat(de, UMEASFMT_WIDTH_NUMERIC, (NumberFormat *) nf->clone(), status);
if (!assertSuccess("Error creating measure format de NUMERIC", status)) {
return;
}
verifyFormat("de NUMERIC", mf, numericDataDe, LENGTHOF(numericDataDe));
}
void MeasureFormatTest::Test10219FractionalPlurals() {
Locale en(Locale::getEnglish());
double values[] = {1.588, 1.011};
const char *expected[2][3] = {
{"1 minute", "1.5 minutes", "1.58 minutes"},
{"1 minute", "1.0 minutes", "1.01 minutes"}
};
UErrorCode status = U_ZERO_ERROR;
for (int j = 0; j < LENGTHOF(values); j++) {
for (int i = 0; i < LENGTHOF(expected[j]); i++) {
DecimalFormat *df =
(DecimalFormat *) NumberFormat::createInstance(en, status);
if (!assertSuccess("Error creating Number format", status)) {
return;
}
df->setRoundingMode(DecimalFormat::kRoundDown);
df->setMinimumFractionDigits(i);
df->setMaximumFractionDigits(i);
MeasureFormat mf(en, UMEASFMT_WIDTH_WIDE, df, status);
if (!assertSuccess("Error creating Measure format", status)) {
return;
}
Measure measure(values[j], MeasureUnit::createMinute(status), status);
if (!assertSuccess("Error creating Measure unit", status)) {
return;
}
verifyFormat("Test10219", mf, &measure, 1, expected[j][i]);
}
}
}
static MeasureUnit toMeasureUnit(MeasureUnit *adopted) {
MeasureUnit result(*adopted);
delete adopted;
return result;
}
void MeasureFormatTest::TestGreek() {
Locale locales[] = {Locale("el_GR"), Locale("el")};
UErrorCode status = U_ZERO_ERROR;
MeasureUnit units[] = {
toMeasureUnit(MeasureUnit::createSecond(status)),
toMeasureUnit(MeasureUnit::createMinute(status)),
toMeasureUnit(MeasureUnit::createHour(status)),
toMeasureUnit(MeasureUnit::createDay(status)),
toMeasureUnit(MeasureUnit::createWeek(status)),
toMeasureUnit(MeasureUnit::createMonth(status)),
toMeasureUnit(MeasureUnit::createYear(status))};
if (!assertSuccess("Error creating Measure units", status)) {
return;
}
UMeasureFormatWidth styles[] = {
UMEASFMT_WIDTH_WIDE,
UMEASFMT_WIDTH_SHORT};
int32_t numbers[] = {1, 7};
const char *expected[] = {
"1 \\u03B4\\u03B5\\u03C5\\u03C4\\u03B5\\u03C1\\u03CC\\u03BB\\u03B5\\u03C0\\u03C4\\u03BF",
"1 \\u03BB\\u03B5\\u03C0\\u03C4\\u03CC",
"1 \\u03CE\\u03C1\\u03B1",
"1 \\u03B7\\u03BC\\u03AD\\u03C1\\u03B1",
"1 \\u03B5\\u03B2\\u03B4\\u03BF\\u03BC\\u03AC\\u03B4\\u03B1",
"1 \\u03BC\\u03AE\\u03BD\\u03B1\\u03C2",
"1 \\u03AD\\u03C4\\u03BF\\u03C2",
"1 \\u03B4\\u03B5\\u03C5\\u03C4.",
"1 \\u03BB\\u03B5\\u03C0.",
"1 \\u03CE\\u03C1\\u03B1",
"1 \\u03B7\\u03BC\\u03AD\\u03C1\\u03B1",
"1 \\u03B5\\u03B2\\u03B4.",
"1 \\u03BC\\u03AE\\u03BD.",
"1 \\u03AD\\u03C4\\u03BF\\u03C2",
"7 \\u03B4\\u03B5\\u03C5\\u03C4\\u03B5\\u03C1\\u03CC\\u03BB\\u03B5\\u03C0\\u03C4\\u03B1",
"7 \\u03BB\\u03B5\\u03C0\\u03C4\\u03AC",
"7 \\u03CE\\u03C1\\u03B5\\u03C2",
"7 \\u03B7\\u03BC\\u03AD\\u03C1\\u03B5\\u03C2",
"7 \\u03B5\\u03B2\\u03B4\\u03BF\\u03BC\\u03AC\\u03B4\\u03B5\\u03C2",
"7 \\u03BC\\u03AE\\u03BD\\u03B5\\u03C2",
"7 \\u03AD\\u03C4\\u03B7",
"7 \\u03B4\\u03B5\\u03C5\\u03C4.",
"7 \\u03BB\\u03B5\\u03C0.",
"7 \\u03CE\\u03C1\\u03B5\\u03C2",
"7 \\u03B7\\u03BC\\u03AD\\u03C1\\u03B5\\u03C2",
"7 \\u03B5\\u03B2\\u03B4.",
"7 \\u03BC\\u03AE\\u03BD.",
"7 \\u03AD\\u03C4\\u03B7",
"1 \\u03B4\\u03B5\\u03C5\\u03C4\\u03B5\\u03C1\\u03CC\\u03BB\\u03B5\\u03C0\\u03C4\\u03BF",
"1 \\u03BB\\u03B5\\u03C0\\u03C4\\u03CC",
"1 \\u03CE\\u03C1\\u03B1",
"1 \\u03B7\\u03BC\\u03AD\\u03C1\\u03B1",
"1 \\u03B5\\u03B2\\u03B4\\u03BF\\u03BC\\u03AC\\u03B4\\u03B1",
"1 \\u03BC\\u03AE\\u03BD\\u03B1\\u03C2",
"1 \\u03AD\\u03C4\\u03BF\\u03C2",
"1 \\u03B4\\u03B5\\u03C5\\u03C4.",
"1 \\u03BB\\u03B5\\u03C0.",
"1 \\u03CE\\u03C1\\u03B1",
"1 \\u03B7\\u03BC\\u03AD\\u03C1\\u03B1",
"1 \\u03B5\\u03B2\\u03B4.",
"1 \\u03BC\\u03AE\\u03BD.",
"1 \\u03AD\\u03C4\\u03BF\\u03C2",
"7 \\u03B4\\u03B5\\u03C5\\u03C4\\u03B5\\u03C1\\u03CC\\u03BB\\u03B5\\u03C0\\u03C4\\u03B1",
"7 \\u03BB\\u03B5\\u03C0\\u03C4\\u03AC",
"7 \\u03CE\\u03C1\\u03B5\\u03C2",
"7 \\u03B7\\u03BC\\u03AD\\u03C1\\u03B5\\u03C2",
"7 \\u03B5\\u03B2\\u03B4\\u03BF\\u03BC\\u03AC\\u03B4\\u03B5\\u03C2",
"7 \\u03BC\\u03AE\\u03BD\\u03B5\\u03C2",
"7 \\u03AD\\u03C4\\u03B7",
"7 \\u03B4\\u03B5\\u03C5\\u03C4.",
"7 \\u03BB\\u03B5\\u03C0.",
"7 \\u03CE\\u03C1\\u03B5\\u03C2",
"7 \\u03B7\\u03BC\\u03AD\\u03C1\\u03B5\\u03C2",
"7 \\u03B5\\u03B2\\u03B4.",
"7 \\u03BC\\u03AE\\u03BD.",
"7 \\u03AD\\u03C4\\u03B7"};
int32_t counter = 0;
for (int32_t locIndex = 0; locIndex < LENGTHOF(locales); ++locIndex ) {
for( int32_t numIndex = 0; numIndex < LENGTHOF(numbers); ++numIndex ) {
for ( int32_t styleIndex = 0; styleIndex < LENGTHOF(styles); ++styleIndex ) {
for ( int32_t unitIndex = 0; unitIndex < LENGTHOF(units); ++unitIndex ) {
Measure measure(numbers[numIndex], new MeasureUnit(units[unitIndex]), status);
if (!assertSuccess("Error creating Measure", status)) {
return;
}
MeasureFormat fmt(locales[locIndex], styles[styleIndex], status);
if (!assertSuccess("Error creating Measure format", status)) {
return;
}
verifyFormat("TestGreek", fmt, &measure, 1, expected[counter]);
++counter;
}
}
}
}
}
void MeasureFormatTest::TestFormatSingleArg() {
UErrorCode status = U_ZERO_ERROR;
MeasureFormat fmt("en", UMEASFMT_WIDTH_WIDE, status);
if (!assertSuccess("Error creating formatter", status)) {
return;
}
UnicodeString buffer;
FieldPosition pos(0);
fmt.format(
new Measure(3.5, MeasureUnit::createFoot(status), status),
buffer,
pos,
status);
if (!assertSuccess("Error formatting", status)) {
return;
}
assertEquals(
"TestFormatSingleArg",
UnicodeString("3.5 feet"),
buffer);
}
void MeasureFormatTest::TestFormatMeasuresZeroArg() {
UErrorCode status = U_ZERO_ERROR;
MeasureFormat fmt("en", UMEASFMT_WIDTH_WIDE, status);
verifyFormat("TestFormatMeasuresZeroArg", fmt, NULL, 0, "");
}
void MeasureFormatTest::TestMultiples() {
Locale ru("ru");
Locale en("en");
helperTestMultiples(en, UMEASFMT_WIDTH_WIDE, "2 miles, 1 foot, 2.3 inches");
helperTestMultiples(en, UMEASFMT_WIDTH_SHORT, "2 mi, 1 ft, 2.3 in");
helperTestMultiples(en, UMEASFMT_WIDTH_NARROW, "2mi 1\\u2032 2.3\\u2033");
helperTestMultiples(ru, UMEASFMT_WIDTH_WIDE, "2 \\u043C\\u0438\\u043B\\u0438, 1 \\u0444\\u0443\\u0442 \\u0438 2,3 \\u0434\\u044E\\u0439\\u043C\\u0430");
helperTestMultiples(ru, UMEASFMT_WIDTH_SHORT, "2 \\u043C\\u0438\\u043B\\u0438 1 \\u0444\\u0443\\u0442 2,3 \\u0434\\u044E\\u0439\\u043C\\u0430");
helperTestMultiples(ru, UMEASFMT_WIDTH_NARROW, "2 \\u043C\\u0438\\u043B\\u0438, 1 \\u0444\\u0443\\u0442, 2,3 \\u0434\\u044E\\u0439\\u043C\\u0430");
}
void MeasureFormatTest::helperTestMultiples(
const Locale &locale,
UMeasureFormatWidth width,
const char *expected) {
UErrorCode status = U_ZERO_ERROR;
FieldPosition pos(0);
MeasureFormat fmt(locale, width, status);
if (!assertSuccess("Error creating format object", status)) {
return;
}
Measure measures[] = {
Measure(2, MeasureUnit::createMile(status), status),
Measure(1, MeasureUnit::createFoot(status), status),
Measure(2.3, MeasureUnit::createInch(status), status)};
if (!assertSuccess("Error creating measures", status)) {
return;
}
UnicodeString buffer;
fmt.formatMeasures(measures, LENGTHOF(measures), buffer, pos, status);
if (!assertSuccess("Error formatting measures", status)) {
return;
}
assertEquals("TestMultiples", UnicodeString(expected).unescape(), buffer);
}
void MeasureFormatTest::TestGram() {
UErrorCode status = U_ZERO_ERROR;
MeasureFormat fmt("en", UMEASFMT_WIDTH_SHORT, status);
if (!assertSuccess("Error creating format object", status)) {
return;
}
Measure gram(1, MeasureUnit::createGram(status), status);
Measure gforce(1, MeasureUnit::createGForce(status), status);
if (!assertSuccess("Error creating measures", status)) {
return;
}
verifyFormat("TestGram", fmt, &gram, 1, "1 g");
verifyFormat("TestGram", fmt, &gforce, 1, "1 G");
}
void MeasureFormatTest::TestCurrencies() {
UChar USD[] = {'U', 'S', 'D', 0};
UErrorCode status = U_ZERO_ERROR;
CurrencyAmount USD_1(1.0, USD, status);
CurrencyAmount USD_2(2.0, USD, status);
CurrencyAmount USD_NEG_1(-1.0, USD, status);
if (!assertSuccess("Error creating measures", status)) {
return;
}
Locale en("en");
MeasureFormat fmt(en, UMEASFMT_WIDTH_WIDE, status);
if (!assertSuccess("Error creating format object", status)) {
return;
}
verifyFormat("TestCurrenciesWide", fmt, &USD_NEG_1, 1, "-1.00 US dollars");
verifyFormat("TestCurrenciesWide", fmt, &USD_1, 1, "1.00 US dollars");
verifyFormat("TestCurrenciesWide", fmt, &USD_2, 1, "2.00 US dollars");
fmt = MeasureFormat(en, UMEASFMT_WIDTH_SHORT, status);
if (!assertSuccess("Error creating format object", status)) {
return;
}
verifyFormat("TestCurrenciesShort", fmt, &USD_NEG_1, 1, "-USD1.00");
verifyFormat("TestCurrenciesShort", fmt, &USD_1, 1, "USD1.00");
verifyFormat("TestCurrenciesShort", fmt, &USD_2, 1, "USD2.00");
fmt = MeasureFormat(en, UMEASFMT_WIDTH_NARROW, status);
if (!assertSuccess("Error creating format object", status)) {
return;
}
verifyFormat("TestCurrenciesNarrow", fmt, &USD_NEG_1, 1, "-$1.00");
verifyFormat("TestCurrenciesNarrow", fmt, &USD_1, 1, "$1.00");
verifyFormat("TestCurrenciesNarrow", fmt, &USD_2, 1, "$2.00");
fmt = MeasureFormat(en, UMEASFMT_WIDTH_NUMERIC, status);
if (!assertSuccess("Error creating format object", status)) {
return;
}
verifyFormat("TestCurrenciesNumeric", fmt, &USD_NEG_1, 1, "-$1.00");
verifyFormat("TestCurrenciesNumeric", fmt, &USD_1, 1, "$1.00");
verifyFormat("TestCurrenciesNumeric", fmt, &USD_2, 1, "$2.00");
}
void MeasureFormatTest::TestFieldPosition() {
UErrorCode status = U_ZERO_ERROR;
MeasureFormat fmt("en", UMEASFMT_WIDTH_SHORT, status);
if (!assertSuccess("Error creating format object", status)) {
return;
}
Measure measure(43.5, MeasureUnit::createFoot(status), status);
if (!assertSuccess("Error creating measure object 1", status)) {
return;
}
UnicodeString prefix("123456: ");
verifyFieldPosition(
"",
fmt,
prefix,
&measure,
1,
NumberFormat::kDecimalSeparatorField,
10,
11);
measure = Measure(43, MeasureUnit::createFoot(status), status);
if (!assertSuccess("Error creating measure object 2", status)) {
return;
}
verifyFieldPosition(
"",
fmt,
prefix,
&measure,
1,
NumberFormat::kDecimalSeparatorField,
0,
0);
}
void MeasureFormatTest::TestFieldPositionMultiple() {
UErrorCode status = U_ZERO_ERROR;
MeasureFormat fmt("en", UMEASFMT_WIDTH_SHORT, status);
if (!assertSuccess("Error creating format object", status)) {
return;
}
Measure first[] = {
Measure(354, MeasureUnit::createMeter(status), status),
Measure(23, MeasureUnit::createCentimeter(status), status)};
Measure second[] = {
Measure(354, MeasureUnit::createMeter(status), status),
Measure(23, MeasureUnit::createCentimeter(status), status),
Measure(5.4, MeasureUnit::createMillimeter(status), status)};
Measure third[] = {
Measure(3, MeasureUnit::createMeter(status), status),
Measure(23, MeasureUnit::createCentimeter(status), status),
Measure(5, MeasureUnit::createMillimeter(status), status)};
if (!assertSuccess("Error creating measure objects", status)) {
return;
}
UnicodeString prefix("123456: ");
verifyFieldPosition(
"Integer",
fmt,
prefix,
first,
LENGTHOF(first),
NumberFormat::kIntegerField,
8,
11);
verifyFieldPosition(
"Decimal separator",
fmt,
prefix,
second,
LENGTHOF(second),
NumberFormat::kDecimalSeparatorField,
23,
24);
verifyFieldPosition(
"no decimal separator",
fmt,
prefix,
third,
LENGTHOF(third),
NumberFormat::kDecimalSeparatorField,
0,
0);
}
void MeasureFormatTest::TestBadArg() {
UErrorCode status = U_ZERO_ERROR;
MeasureFormat fmt("en", UMEASFMT_WIDTH_SHORT, status);
if (!assertSuccess("Error creating format object", status)) {
return;
}
FieldPosition pos(0);
UnicodeString buffer;
fmt.format(
9.3,
buffer,
pos,
status);
if (status != U_ILLEGAL_ARGUMENT_ERROR) {
errln("Expected ILLEGAL_ARGUMENT_ERROR");
}
}
void MeasureFormatTest::TestEquality() {
UErrorCode status = U_ZERO_ERROR;
NumberFormat* nfeq = NumberFormat::createInstance("en", status);
NumberFormat* nfne = NumberFormat::createInstance("fr", status);
MeasureFormat fmt("en", UMEASFMT_WIDTH_SHORT, status);
MeasureFormat fmtEq(fmt);
MeasureFormat fmtEq2("en", UMEASFMT_WIDTH_SHORT, nfeq, status);
MeasureFormat fmtne1("en", UMEASFMT_WIDTH_WIDE, status);
MeasureFormat fmtne2("fr", UMEASFMT_WIDTH_SHORT, status);
MeasureFormat fmtne3("en", UMEASFMT_WIDTH_SHORT, nfne, status);
assertSuccess("Error creating MeasureFormats", status);
assertTrue("Equal", fmt == fmtEq);
assertTrue("Equal2", fmt == fmtEq2);
assertFalse("Equal Neg", fmt != fmtEq);
assertTrue("Not Equal 1", fmt != fmtne1);
assertFalse("Not Equal Neg 1", fmt == fmtne1);
assertTrue("Not Equal 2", fmt != fmtne2);
assertTrue("Not Equal 3", fmt != fmtne3);
}
void MeasureFormatTest::verifyFieldPosition(
const char *description,
const MeasureFormat &fmt,
const UnicodeString &prefix,
const Measure *measures,
int32_t measureCount,
NumberFormat::EAlignmentFields field,
int32_t start,
int32_t end) {
// 8 char lead
UnicodeString result(prefix);
FieldPosition pos(field);
UErrorCode status = U_ZERO_ERROR;
CharString ch;
const char *descPrefix = ch.append(description, status)
.append(": ", status).data();
CharString beginIndex;
beginIndex.append(descPrefix, status).append("beginIndex", status);
CharString endIndex;
endIndex.append(descPrefix, status).append("endIndex", status);
fmt.formatMeasures(measures, measureCount, result, pos, status);
if (!assertSuccess("Error formatting", status)) {
return;
}
assertEquals(beginIndex.data(), start, pos.getBeginIndex());
assertEquals(endIndex.data(), end, pos.getEndIndex());
}
void MeasureFormatTest::verifyFormat(
const char *description,
const MeasureFormat &fmt,
const Measure *measures,
int32_t measureCount,
const char *expected) {
verifyFormatWithPrefix(
description,
fmt,
"",
measures,
measureCount,
expected);
}
void MeasureFormatTest::verifyFormatWithPrefix(
const char *description,
const MeasureFormat &fmt,
const UnicodeString &prefix,
const Measure *measures,
int32_t measureCount,
const char *expected) {
UnicodeString result(prefix);
FieldPosition pos(0);
UErrorCode status = U_ZERO_ERROR;
fmt.formatMeasures(measures, measureCount, result, pos, status);
if (!assertSuccess("Error formatting", status)) {
return;
}
assertEquals(description, UnicodeString(expected).unescape(), result);
}
void MeasureFormatTest::verifyFormat(
const char *description,
const MeasureFormat &fmt,
const ExpectedResult *expectedResults,
int32_t count) {
for (int32_t i = 0; i < count; ++i) {
verifyFormat(description, fmt, expectedResults[i].measures, expectedResults[i].count, expectedResults[i].expected);
}
}
extern IntlTest *createMeasureFormatTest() {
return new MeasureFormatTest();
}
#endif

View File

@ -1896,6 +1896,8 @@ void NumberFormatTest::TestCurrencyNames(void) {
void NumberFormatTest::TestCurrencyUnit(void){
UErrorCode ec = U_ZERO_ERROR;
static const UChar USD[] = {85, 83, 68, 0}; /*USD*/
static const UChar BAD[] = {63, 63, 63, 0}; /*???*/
static const UChar BAD2[] = {63, 63, 65, 0}; /*???*/
CurrencyUnit cu(USD, ec);
assertSuccess("CurrencyUnit", ec);
@ -1911,6 +1913,23 @@ void NumberFormatTest::TestCurrencyUnit(void){
if (!(*cu3 == cu)){
errln("CurrencyUnit cloned object should be same");
}
CurrencyUnit bad(BAD, ec);
assertSuccess("CurrencyUnit", ec);
if (cu.getIndex() == bad.getIndex()) {
errln("Indexes of different currencies should differ.");
}
CurrencyUnit bad2(BAD2, ec);
assertSuccess("CurrencyUnit", ec);
if (bad2.getIndex() != bad.getIndex()) {
errln("Indexes of unrecognized currencies should be the same.");
}
if (bad == bad2) {
errln("Different unrecognized currencies should not be equal.");
}
bad = bad2;
if (bad != bad2) {
errln("Currency unit assignment should be the same.");
}
delete cu3;
}

View File

@ -138,10 +138,37 @@ void TimeUnitTest::testAPI() {
TimeUnit::UTimeUnitFields field = tmunit_m->getTimeUnitField();
assertTrue("field of month time unit is month", (field == TimeUnit::UTIMEUNIT_MONTH));
//===== Interropability with MeasureUnit ======
MeasureUnit **ptrs = new MeasureUnit *[TimeUnit::UTIMEUNIT_FIELD_COUNT];
ptrs[TimeUnit::UTIMEUNIT_YEAR] = MeasureUnit::createYear(status);
ptrs[TimeUnit::UTIMEUNIT_MONTH] = MeasureUnit::createMonth(status);
ptrs[TimeUnit::UTIMEUNIT_DAY] = MeasureUnit::createDay(status);
ptrs[TimeUnit::UTIMEUNIT_WEEK] = MeasureUnit::createWeek(status);
ptrs[TimeUnit::UTIMEUNIT_HOUR] = MeasureUnit::createHour(status);
ptrs[TimeUnit::UTIMEUNIT_MINUTE] = MeasureUnit::createMinute(status);
ptrs[TimeUnit::UTIMEUNIT_SECOND] = MeasureUnit::createSecond(status);
if (!assertSuccess("TimeUnit::createInstance", status)) return;
for (TimeUnit::UTimeUnitFields j = TimeUnit::UTIMEUNIT_YEAR;
j < TimeUnit::UTIMEUNIT_FIELD_COUNT;
j = (TimeUnit::UTimeUnitFields)(j+1)) {
MeasureUnit *ptr = TimeUnit::createInstance(j, status);
if (!assertSuccess("TimeUnit::createInstance", status)) return;
assertTrue(
"Time unit should be equal to corresponding MeasureUnit",
*ptr == *ptrs[j]);
delete ptr;
}
delete tmunit;
delete another;
delete tmunit_m;
for (int i = 0; i < TimeUnit::UTIMEUNIT_FIELD_COUNT; ++i) {
delete ptrs[i];
}
delete [] ptrs;
//
//================= TimeUnitAmount =================