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
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
/**
* 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,
const UnicodeString& second,
UnicodeString &result,
UBool recordOffset,
- int32_t offset,
+ int32_t &offset,
UErrorCode& errorCode) {
if (U_FAILURE(errorCode)) {
return;
offset,
errorCode);
if (U_SUCCESS(errorCode)) {
- offset += appendTo.length();
+ if (offset >= 0) {
+ offset += appendTo.length();
+ }
appendTo += temp[npos];
}
return appendTo;
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
/*
**********************************************************************
-* Copyright (c) 2004-2012 International Business Machines
+* Copyright (c) 2004-2014 International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
* Author: Alan Liu
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);
}
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);
}
/*
**********************************************************************
-* Copyright (c) 2004-2010, International Business Machines
+* Copyright (c) 2004-2014, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
* Author: Alan Liu
*/
virtual ~CurrencyFormat();
- /**
- * Override Format API.
- */
- virtual UBool operator==(const Format& other) const;
-
/**
* Override Format API.
*/
/*
**********************************************************************
-* Copyright (c) 2004-2012, International Business Machines
+* Copyright (c) 2004-2014, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
* Author: Alan Liu
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;
}
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;
}
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
/*
**********************************************************************
-* Copyright (c) 2004-2011, International Business Machines
+* Copyright (c) 2004-2014, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
* Author: Alan Liu
#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);
+};
+
+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() {}
+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) {
--- /dev/null
+/*
+**********************************************************************
+* 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
+
+
/*
**********************************************************************
-* Copyright (c) 2004-2012, International Business Machines
+* Copyright (c) 2004-2014, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
* Author: Alan Liu
return *this;
}
+UObject *Measure::clone() const {
+ return new Measure(*this);
+}
+
Measure::~Measure() {
delete unit;
}
(unit != NULL && *unit == m->getUnit());
}
-//----------------------------------------------------------------------
-// MeasureUnit implementation
-
-MeasureUnit:: MeasureUnit() {}
-
-MeasureUnit::~MeasureUnit() {}
-
U_NAMESPACE_END
#endif // !UCONFIG_NO_FORMATTING
#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]))
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;
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
class PluralRules;
class NumberFormat;
class Formattable;
+class FieldPosition;
/**
* A plural aware formatter that is good for expressing a single quantity and
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
const NumberFormat &fmt,
const PluralRules &rules,
UnicodeString &appendTo,
+ FieldPosition &pos,
UErrorCode &status) const;
private:
#include "uresimp.h"
#include "unicode/ures.h"
#include "cstring.h"
-#include "plurrule_impl.h"
#include "ucln_in.h"
#include "mutex.h"
#include "charstr.h"
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);
}
/*
*******************************************************************************
- * Copyright (C) 2008-2012, Google, International Business Machines Corporation and
+ * Copyright (C) 2008-2014, Google, International Business Machines Corporation and
* others. All Rights Reserved.
*******************************************************************************
*/
#include "utypeinfo.h" // for 'typeid' to work
#include "unicode/tmunit.h"
+#include "uassert.h"
#if !UCONFIG_NO_FORMATTING
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() {
}
/*
*******************************************************************************
- * Copyright (C) 2008-2013, Google, International Business Machines Corporation
+ * Copyright (C) 2008-2014, Google, International Business Machines Corporation
* and others. All Rights Reserved.
*******************************************************************************
*/
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;
}
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)) {
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,
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;
}
}
void
-TimeUnitFormat::create(const Locale& locale, UTimeUnitFormatStyle style, UErrorCode& status) {
+TimeUnitFormat::create(UTimeUnitFormatStyle style, UErrorCode& status) {
if (U_FAILURE(status)) {
return;
}
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.
initDataMembers(err);
UVector pluralCounts(0, uhash_compareUnicodeString, 6, err);
- StringEnumeration* keywords = fPluralRules->getKeywords(err);
+ StringEnumeration* keywords = getPluralRules().getKeywords(err);
if (U_FAILURE(err)) {
return;
}
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)) {
// 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)) {
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) {
// 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) {
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,
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) {
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);
void
TimeUnitFormat::setLocale(const Locale& locale, UErrorCode& status) {
- if (U_SUCCESS(status) && fLocale != locale) {
- fLocale = locale;
+ if (setMeasureFormatLocale(locale, status)) {
setup(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);
}
/*
******************************************************************************
* *
-* Copyright (C) 2001-2013, International Business Machines *
+* Copyright (C) 2001-2014, International Business Machines *
* Corporation and others. All Rights Reserved. *
* *
******************************************************************************
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,
UCLN_I18N_CURRENCY,
UCLN_I18N_DECFMT,
UCLN_I18N_NUMFMT,
+ UCLN_I18N_RELDATEFMT,
+ UCLN_I18N_MEASFMT,
UCLN_I18N_SMPDTFMT,
UCLN_I18N_USEARCH,
UCLN_I18N_COLLATOR,
/*
**********************************************************************
-* Copyright (c) 2004-2006, International Business Machines
+* Copyright (c) 2004-2014, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
* Author: Alan Liu
*/
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.
/*
**********************************************************************
-* Copyright (c) 2004-2011, International Business Machines
+* Copyright (c) 2004-2014, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
* Author: Alan Liu
#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
*/
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.
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
/*
**********************************************************************
-* Copyright (c) 2004-2006, International Business Machines
+* Copyright (c) 2004-2014, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
* Author: Alan Liu
#define __MEASUREUNIT_H__
#include "unicode/utypes.h"
-
-#if !UCONFIG_NO_FORMATTING
-
-#include "unicode/fmtable.h"
+#include "unicode/unistr.h"
/**
* \file
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:
+
+ /**
+ * 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);
+
/**
- * Return a polymorphic clone of this object. The result will
+ * 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
+ */
+ void initTime(const char *timeId);
+
+ /**
+ * For ICU use only.
+ * @internal
*/
- MeasureUnit();
+ 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__
/*
**********************************************************************
-* Copyright (c) 2004-2006, International Business Machines
+* Copyright (c) 2004-2014, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
* Author: Alan Liu
* have the same class as returned by getDynamicClassID().
* @stable ICU 3.0
*/
- virtual UObject* clone() const = 0;
+ virtual UObject* clone() const;
/**
* Destructor
/*
*******************************************************************************
- * Copyright (C) 2009-2010, Google, International Business Machines Corporation and *
+ * Copyright (C) 2009-2014, Google, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
*/
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.
};
-inline UBool
-TimeUnit::operator!=(const UObject& other) const {
- return !operator==(other);
-}
-
-
U_NAMESPACE_END
#endif /* #if !UCONFIG_NO_FORMATTING */
/*
*******************************************************************************
- * Copyright (C) 2008-2013, Google, International Business Machines Corporation
+ * Copyright (C) 2008-2014, Google, International Business Machines Corporation
* and others. All Rights Reserved.
*******************************************************************************
*/
*/
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.
*/
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;
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
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)
<ClCompile Include="lrucachetest.cpp">\r
<DisableLanguageExtensions>false</DisableLanguageExtensions>\r
</ClCompile>\r
+ <ClCompile Include="measfmttest.cpp" />\r
<ClCompile Include="miscdtfm.cpp" />\r
<ClCompile Include="msfmrgts.cpp" />\r
<ClCompile Include="nmfmapts.cpp" />\r
<ClCompile Include="locnmtst.cpp">\r
<Filter>formatting</Filter>\r
</ClCompile>\r
+ <ClCompile Include="measfmttest.cpp">\r
+ <Filter>formatting</Filter>\r
+ </ClCompile>\r
<ClCompile Include="miscdtfm.cpp">\r
<Filter>formatting</Filter>\r
</ClCompile>\r
/********************************************************************
* COPYRIGHT:
- * Copyright (c) 1997-2013, International Business Machines
+ * Copyright (c) 1997-2014, International Business Machines
* Corporation and others. All Rights Reserved.
********************************************************************/
extern IntlTest *createCompactDecimalFormatTest();
extern IntlTest *createGenderInfoTest();
extern IntlTest *createRelativeDateTimeFormatterTest();
+extern IntlTest *createMeasureFormatTest();
#define TESTCLASS(id, TestClass) \
case id: \
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) {
--- /dev/null
+/*
+*******************************************************************************
+* 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
+
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);
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;
}
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 =================