ICU-6311 full and abbreviated simple duration format support, release to trunk
X-SVN-Rev: 24609
This commit is contained in:
parent
08e67ed3a7
commit
fe4e67b5a6
8
.gitattributes
vendored
8
.gitattributes
vendored
@ -95,8 +95,14 @@ icu4c/source/data/xml/main/zu.xml -text
|
||||
icu4c/source/i18n/dtitv_impl.h -text
|
||||
icu4c/source/i18n/dtitvfmt.cpp -text
|
||||
icu4c/source/i18n/dtitvinf.cpp -text
|
||||
icu4c/source/i18n/tmunit.cpp -text
|
||||
icu4c/source/i18n/tmutamt.cpp -text
|
||||
icu4c/source/i18n/tmutfmt.cpp -text
|
||||
icu4c/source/i18n/unicode/dtitvfmt.h -text
|
||||
icu4c/source/i18n/unicode/dtitvinf.h -text
|
||||
icu4c/source/i18n/unicode/tmunit.h -text
|
||||
icu4c/source/i18n/unicode/tmutamt.h -text
|
||||
icu4c/source/i18n/unicode/tmutfmt.h -text
|
||||
icu4c/source/i18n/wintzimpl.cpp -text
|
||||
icu4c/source/i18n/wintzimpl.h -text
|
||||
icu4c/source/samples/layout/cgnomelayout.c -text
|
||||
@ -104,6 +110,8 @@ icu4c/source/samples/ucnv/data02.bin -text
|
||||
icu4c/source/test/compat/tzone.pl -text
|
||||
icu4c/source/test/intltest/dtifmtts.cpp -text
|
||||
icu4c/source/test/intltest/dtifmtts.h -text
|
||||
icu4c/source/test/intltest/tufmtts.cpp -text
|
||||
icu4c/source/test/intltest/tufmtts.h -text
|
||||
icu4c/source/test/perf/Makefile.in -text
|
||||
icu4c/source/test/perf/README -text
|
||||
icu4c/source/test/perf/strsrchperf/Makefile.in -text
|
||||
|
@ -80,7 +80,8 @@ regexcmp.o rematch.o repattrn.o regexst.o udatpg.o uregex.o uregexc.o \
|
||||
ulocdata.o measfmt.o currfmt.o curramt.o currunit.o measure.o utmscale.o \
|
||||
csdetect.o csmatch.o csr2022.o csrecog.o csrmbcs.o csrsbcs.o csrucode.o csrutf8.o inputext.o \
|
||||
wintzimpl.o windtfmt.o winnmfmt.o basictz.o dtrule.o rbtz.o tzrule.o tztrans.o vtzone.o \
|
||||
zonemeta.o zstrfmt.o plurrule.o plurfmt.o dtitvfmt.o dtitvinf.o
|
||||
zonemeta.o zstrfmt.o plurrule.o plurfmt.o dtitvfmt.o dtitvinf.o \
|
||||
tmunit.o tmutamt.o tmutfmt.o
|
||||
|
||||
## Header files to install
|
||||
HEADERS = $(srcdir)/unicode/*.h
|
||||
|
@ -2253,6 +2253,30 @@
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\tmunit.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\unicode\tmunit.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\tmutamt.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\unicode\tmutamt.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\tmutfmt.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\unicode\tmutfmt.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\tzrule.cpp"
|
||||
>
|
||||
|
@ -1787,6 +1787,12 @@ MessageFormat::isLegalArgName(const UnicodeString& argName) const {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int32_t
|
||||
MessageFormat::getArgTypeCount() const {
|
||||
return argTypeCount;
|
||||
}
|
||||
|
||||
|
||||
FormatNameEnumeration::FormatNameEnumeration(UVector *fNameList, UErrorCode& /*status*/) {
|
||||
pos=0;
|
||||
fFormatNames = fNameList;
|
||||
@ -1819,6 +1825,8 @@ FormatNameEnumeration::~FormatNameEnumeration() {
|
||||
}
|
||||
delete fFormatNames;
|
||||
}
|
||||
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||
|
115
icu4c/source/i18n/tmunit.cpp
Normal file
115
icu4c/source/i18n/tmunit.cpp
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2008, Google, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
||||
#include "unicode/tmunit.h"
|
||||
|
||||
#if !UCONFIG_NO_FORMATTING
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TimeUnit)
|
||||
|
||||
|
||||
/*
|
||||
* There are only 7 time units.
|
||||
* So, TimeUnit could be made as singleton
|
||||
* (similar to uniset_props.cpp, or unorm.cpp,
|
||||
* in which a static TimeUnit* array is created, and
|
||||
* the creatInstance() returns a const TimeUnit*).
|
||||
* But the constraint is TimeUnit is a data member of Measure.
|
||||
* But Measure (which is an existing API) does not expect it's "unit" member
|
||||
* as singleton. Meaure takes ownership of the "unit" member.
|
||||
* In its constructor, it does not take a const "unit" pointer.
|
||||
* Also, Measure can clone and destruct the "unit" pointer.
|
||||
* In order to preserve the old behavior and let Measure handle singleton "unit",
|
||||
* 1. a flag need to be added in Measure;
|
||||
* 2. a new constructor which takes const "unit" as parameter need to be added,
|
||||
* and this new constructor will set the flag on.
|
||||
* 3. clone and destructor need to check upon this flag to distinguish on how
|
||||
* to handle the "unit".
|
||||
*
|
||||
* Since TimeUnit is such a light weight object, comparing with the heavy weight
|
||||
* format operation, we decided to avoid the above complication.
|
||||
*
|
||||
* So, both TimeUnit and CurrencyUnit (the 2 subclasses of MeasureUnit) are
|
||||
* immutable and non-singleton.
|
||||
*
|
||||
* Currently, TimeUnitAmount and CurrencyAmount are immutable.
|
||||
* If an application needs to create a long list of TimeUnitAmount on the same
|
||||
* time unit but different number, for example,
|
||||
* 1 hour, 2 hour, 3 hour, ................. 10,000 hour,
|
||||
* there might be performance hit because 10,000 TimeUnit object,
|
||||
* although all are the same time unit, will be created in heap and deleted.
|
||||
*
|
||||
* To address this performance issue, if there is any in the future,
|
||||
* we should and need to change TimeUnitAmount and CurrencyAmount to be
|
||||
* immutable by allowing a setter on the number.
|
||||
* Or we need to add 2 parallel mutable classes in order to
|
||||
* preserve the existing API.
|
||||
* Or we can use freezable.
|
||||
*/
|
||||
TimeUnit* U_EXPORT2
|
||||
TimeUnit::createInstance(TimeUnit::UTimeUnitFields timeUnitField,
|
||||
UErrorCode& status) {
|
||||
if (U_FAILURE(status)) {
|
||||
return NULL;
|
||||
}
|
||||
if (timeUnitField < 0 || timeUnitField >= UTIMEUNIT_FIELD_COUNT) {
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
return new TimeUnit(timeUnitField);
|
||||
}
|
||||
|
||||
|
||||
TimeUnit::TimeUnit(TimeUnit::UTimeUnitFields timeUnitField) {
|
||||
fTimeUnitField = timeUnitField;
|
||||
}
|
||||
|
||||
|
||||
TimeUnit::TimeUnit(const TimeUnit& other)
|
||||
: MeasureUnit(other) {
|
||||
*this = other;
|
||||
}
|
||||
|
||||
|
||||
UObject*
|
||||
TimeUnit::clone() const {
|
||||
return new TimeUnit(*this);
|
||||
}
|
||||
|
||||
|
||||
TimeUnit&
|
||||
TimeUnit::operator=(const TimeUnit& other) {
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
fTimeUnitField = other.fTimeUnitField;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
UBool
|
||||
TimeUnit::operator==(const UObject& other) const {
|
||||
return (other.getDynamicClassID() == TimeUnit::getStaticClassID()
|
||||
&& fTimeUnitField == ((TimeUnit*)&other)->fTimeUnitField);
|
||||
}
|
||||
|
||||
|
||||
TimeUnit::UTimeUnitFields
|
||||
TimeUnit::getTimeUnitField() const {
|
||||
return fTimeUnitField;
|
||||
}
|
||||
|
||||
|
||||
TimeUnit::~TimeUnit() {
|
||||
}
|
||||
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
||||
#endif
|
76
icu4c/source/i18n/tmutamt.cpp
Normal file
76
icu4c/source/i18n/tmutamt.cpp
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2008, Google, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
||||
#include "unicode/tmutamt.h"
|
||||
|
||||
#if !UCONFIG_NO_FORMATTING
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TimeUnitAmount)
|
||||
|
||||
|
||||
TimeUnitAmount::TimeUnitAmount(const Formattable& number,
|
||||
TimeUnit::UTimeUnitFields timeUnitField,
|
||||
UErrorCode& status)
|
||||
: Measure(number, TimeUnit::createInstance(timeUnitField, status), status) {
|
||||
}
|
||||
|
||||
|
||||
TimeUnitAmount::TimeUnitAmount(double amount,
|
||||
TimeUnit::UTimeUnitFields timeUnitField,
|
||||
UErrorCode& status)
|
||||
: Measure(Formattable(amount),
|
||||
TimeUnit::createInstance(timeUnitField, status),
|
||||
status) {
|
||||
}
|
||||
|
||||
|
||||
TimeUnitAmount::TimeUnitAmount(const TimeUnitAmount& other)
|
||||
: Measure(other)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
TimeUnitAmount&
|
||||
TimeUnitAmount::operator=(const TimeUnitAmount& other) {
|
||||
Measure::operator=(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
UBool
|
||||
TimeUnitAmount::operator==(const UObject& other) const {
|
||||
return Measure::operator==(other);
|
||||
}
|
||||
|
||||
UObject*
|
||||
TimeUnitAmount::clone() const {
|
||||
return new TimeUnitAmount(*this);
|
||||
}
|
||||
|
||||
|
||||
TimeUnitAmount::~TimeUnitAmount() {
|
||||
}
|
||||
|
||||
|
||||
|
||||
const TimeUnit&
|
||||
TimeUnitAmount::getTimeUnit() const {
|
||||
return (const TimeUnit&) getUnit();
|
||||
}
|
||||
|
||||
|
||||
TimeUnit::UTimeUnitFields
|
||||
TimeUnitAmount::getTimeUnitField() const {
|
||||
return getTimeUnit().getTimeUnitField();
|
||||
}
|
||||
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
||||
#endif
|
859
icu4c/source/i18n/tmutfmt.cpp
Normal file
859
icu4c/source/i18n/tmutfmt.cpp
Normal file
@ -0,0 +1,859 @@
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2008, Google, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
||||
|
||||
#include "unicode/tmutfmt.h"
|
||||
|
||||
#if !UCONFIG_NO_FORMATTING
|
||||
|
||||
#include "cmemory.h"
|
||||
#include "cstring.h"
|
||||
#include "hash.h"
|
||||
#include "uresimp.h"
|
||||
#include "unicode/msgfmt.h"
|
||||
|
||||
#define LEFT_CURLY_BRACKET ((UChar)0x007B)
|
||||
#define RIGHT_CURLY_BRACKET ((UChar)0x007D)
|
||||
#define SPACE ((UChar)0x0020)
|
||||
#define DIGIT_ZERO ((UChar)0x0030)
|
||||
#define LOW_S ((UChar)0x0073)
|
||||
#define LOW_M ((UChar)0x006D)
|
||||
#define LOW_I ((UChar)0x0069)
|
||||
#define LOW_N ((UChar)0x006E)
|
||||
#define LOW_H ((UChar)0x0068)
|
||||
#define LOW_W ((UChar)0x0077)
|
||||
#define LOW_D ((UChar)0x0064)
|
||||
#define LOW_Y ((UChar)0x0079)
|
||||
#define LOW_Z ((UChar)0x007A)
|
||||
#define LOW_E ((UChar)0x0065)
|
||||
#define LOW_R ((UChar)0x0072)
|
||||
#define LOW_O ((UChar)0x006F)
|
||||
#define LOW_N ((UChar)0x006E)
|
||||
#define LOW_T ((UChar)0x0074)
|
||||
|
||||
|
||||
//FIXME
|
||||
//#define TMUTFMT_DEBUG 1
|
||||
|
||||
#ifdef TMUTFMT_DEBUG
|
||||
#include <iostream>
|
||||
#endif
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
|
||||
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TimeUnitFormat)
|
||||
|
||||
static const char gUnitsTag[] = "units";
|
||||
static const char gShortUnitsTag[] = "short_units";
|
||||
static const char gTimeUnitYear[] = "year";
|
||||
static const char gTimeUnitMonth[] = "month";
|
||||
static const char gTimeUnitDay[] = "day";
|
||||
static const char gTimeUnitWeek[] = "week";
|
||||
static const char gTimeUnitHour[] = "hour";
|
||||
static const char gTimeUnitMinute[] = "minute";
|
||||
static const char gTimeUnitSecond[] = "second";
|
||||
static const char gPluralCountOther[] = "other";
|
||||
|
||||
static const UChar DEFAULT_PATTERN_FOR_SECOND[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_S, 0};
|
||||
static const UChar DEFAULT_PATTERN_FOR_MINUTE[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_M, LOW_I, LOW_N, 0};
|
||||
static const UChar DEFAULT_PATTERN_FOR_HOUR[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_H, 0};
|
||||
static const UChar DEFAULT_PATTERN_FOR_WEEK[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_W, 0};
|
||||
static const UChar DEFAULT_PATTERN_FOR_DAY[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_D, 0};
|
||||
static const UChar DEFAULT_PATTERN_FOR_MONTH[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_M, 0};
|
||||
static const UChar DEFAULT_PATTERN_FOR_YEAR[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_Y, 0};
|
||||
|
||||
static const UChar PLURAL_COUNT_ZERO[] = {LOW_Z, LOW_E, LOW_R, LOW_O, 0};
|
||||
static const UChar PLURAL_COUNT_ONE[] = {LOW_O, LOW_N, LOW_E, 0};
|
||||
static const UChar PLURAL_COUNT_TWO[] = {LOW_T, LOW_W, LOW_O, 0};
|
||||
|
||||
|
||||
TimeUnitFormat::TimeUnitFormat(UErrorCode& status)
|
||||
: fNumberFormat(NULL),
|
||||
fPluralRules(NULL) {
|
||||
create(Locale::getDefault(), kFull, status);
|
||||
}
|
||||
|
||||
|
||||
TimeUnitFormat::TimeUnitFormat(const Locale& locale, UErrorCode& status)
|
||||
: fNumberFormat(NULL),
|
||||
fPluralRules(NULL) {
|
||||
create(locale, kFull, status);
|
||||
}
|
||||
|
||||
|
||||
TimeUnitFormat::TimeUnitFormat(const Locale& locale, EStyle style, UErrorCode& status)
|
||||
: fNumberFormat(NULL),
|
||||
fPluralRules(NULL) {
|
||||
create(locale, style, status);
|
||||
}
|
||||
|
||||
|
||||
TimeUnitFormat::TimeUnitFormat(const TimeUnitFormat& other)
|
||||
: MeasureFormat(other),
|
||||
fNumberFormat(NULL),
|
||||
fPluralRules(NULL),
|
||||
fStyle(kFull)
|
||||
{
|
||||
for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
|
||||
i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
|
||||
i = (TimeUnit::UTimeUnitFields)(i+1)) {
|
||||
fTimeUnitToCountToPatterns[i] = NULL;
|
||||
}
|
||||
*this = other;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
Format*
|
||||
TimeUnitFormat::clone(void) const {
|
||||
return new TimeUnitFormat(*this);
|
||||
}
|
||||
|
||||
|
||||
TimeUnitFormat&
|
||||
TimeUnitFormat::operator=(const TimeUnitFormat& other) {
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
delete fNumberFormat;
|
||||
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)) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (other.fPluralRules) {
|
||||
fPluralRules = (PluralRules*)other.fPluralRules->clone();
|
||||
} else {
|
||||
fPluralRules = NULL;
|
||||
}
|
||||
fStyle = other.fStyle;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
UBool
|
||||
TimeUnitFormat::operator==(const Format& other) const {
|
||||
if (other.getDynamicClassID() == TimeUnitFormat::getStaticClassID()) {
|
||||
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();
|
||||
if (formatObj->getDynamicClassID() == TimeUnitAmount::getStaticClassID()){
|
||||
TimeUnitAmount* amount = (TimeUnitAmount*)formatObj;
|
||||
Hashtable* countToPattern = fTimeUnitToCountToPatterns[amount->getTimeUnitField()];
|
||||
double number;
|
||||
const Formattable& amtNumber = amount->getNumber();
|
||||
if (amtNumber.getType() == Formattable::kDouble) {
|
||||
number = amtNumber.getDouble();
|
||||
} else if (amtNumber.getType() == Formattable::kLong) {
|
||||
number = amtNumber.getLong();
|
||||
} else {
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return toAppendTo;
|
||||
}
|
||||
UnicodeString count = fPluralRules->select(number);
|
||||
#ifdef TMUTFMT_DEBUG
|
||||
char result[1000];
|
||||
count.extract(0, count.length(), result, "UTF-8");
|
||||
std::cout << "number: " << number << "; format plural count: " << result << "\n";
|
||||
#endif
|
||||
MessageFormat* pattern = ((MessageFormat**)countToPattern->get(count))[fStyle];
|
||||
Formattable formattable[1];
|
||||
formattable[0].setDouble(number);
|
||||
return pattern->format(formattable, 1, toAppendTo, pos, status);
|
||||
}
|
||||
}
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return toAppendTo;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TimeUnitFormat::parseObject(const UnicodeString& source,
|
||||
Formattable& result,
|
||||
ParsePosition& pos) const {
|
||||
double resultNumber = -1;
|
||||
UBool withNumberFormat = false;
|
||||
TimeUnit::UTimeUnitFields resultTimeUnit = TimeUnit::UTIMEUNIT_FIELD_COUNT;
|
||||
int32_t oldPos = pos.getIndex();
|
||||
int32_t newPos = -1;
|
||||
int32_t longestParseDistance = 0;
|
||||
UnicodeString* countOfLongestMatch = NULL;
|
||||
#ifdef TMUTFMT_DEBUG
|
||||
char res[1000];
|
||||
source.extract(0, source.length(), res, "UTF-8");
|
||||
std::cout << "parse source: " << res << "\n";
|
||||
#endif
|
||||
// parse by iterating through all available patterns
|
||||
// and looking for the longest match.
|
||||
for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
|
||||
i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
|
||||
i = (TimeUnit::UTimeUnitFields)(i+1)) {
|
||||
Hashtable* countToPatterns = fTimeUnitToCountToPatterns[i];
|
||||
int32_t elemPos = -1;
|
||||
const UHashElement* elem = NULL;
|
||||
while ((elem = countToPatterns->nextElement(elemPos)) != NULL){
|
||||
const UHashTok keyTok = elem->key;
|
||||
UnicodeString* count = (UnicodeString*)keyTok.pointer;
|
||||
#ifdef TMUTFMT_DEBUG
|
||||
count->extract(0, count->length(), res, "UTF-8");
|
||||
std::cout << "parse plural count: " << res << "\n";
|
||||
#endif
|
||||
const UHashTok valueTok = elem->value;
|
||||
// the value is a pair of MessageFormat*
|
||||
MessageFormat** patterns = (MessageFormat**)valueTok.pointer;
|
||||
for (EStyle style = kFull; style < kTotal; style = (EStyle)(style + 1)) {
|
||||
MessageFormat* pattern = patterns[style];
|
||||
pos.setErrorIndex(-1);
|
||||
pos.setIndex(oldPos);
|
||||
// see if we can parse
|
||||
Formattable parsed;
|
||||
pattern->parseObject(source, parsed, pos);
|
||||
if (pos.getErrorIndex() != -1 || pos.getIndex() == oldPos) {
|
||||
continue;
|
||||
}
|
||||
#ifdef TMUTFMT_DEBUG
|
||||
std::cout << "parsed.getType: " << parsed.getType() << "\n";
|
||||
#endif
|
||||
double tmpNumber = 0;
|
||||
if (pattern->getArgTypeCount() != 0) {
|
||||
// pattern with Number as beginning, such as "{0} d".
|
||||
// check to make sure that the timeUnit is consistent
|
||||
Formattable& temp = parsed[0];
|
||||
if (temp.getType() == Formattable::kDouble) {
|
||||
tmpNumber = temp.getDouble();
|
||||
} else if (temp.getType() == Formattable::kLong) {
|
||||
tmpNumber = temp.getLong();
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
UnicodeString select = fPluralRules->select(tmpNumber);
|
||||
#ifdef TMUTFMT_DEBUG
|
||||
select.extract(0, select.length(), res, "UTF-8");
|
||||
std::cout << "parse plural select count: " << res << "\n";
|
||||
#endif
|
||||
if (*count != select) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
int32_t parseDistance = pos.getIndex() - oldPos;
|
||||
if (parseDistance > longestParseDistance) {
|
||||
if (pattern->getArgTypeCount() != 0) {
|
||||
resultNumber = tmpNumber;
|
||||
withNumberFormat = true;
|
||||
} else {
|
||||
withNumberFormat = false;
|
||||
}
|
||||
resultTimeUnit = i;
|
||||
newPos = pos.getIndex();
|
||||
longestParseDistance = parseDistance;
|
||||
countOfLongestMatch = count;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* After find the longest match, parse the number.
|
||||
* Result number could be null for the pattern without number pattern.
|
||||
* such as unit pattern in Arabic.
|
||||
* When result number is null, use plural rule to set the number.
|
||||
*/
|
||||
if (withNumberFormat == false && longestParseDistance != 0) {
|
||||
// set the number using plurrual count
|
||||
if ( *countOfLongestMatch == PLURAL_COUNT_ZERO ) {
|
||||
resultNumber = 0;
|
||||
} else if ( *countOfLongestMatch == PLURAL_COUNT_ONE ) {
|
||||
resultNumber = 1;
|
||||
} else if ( *countOfLongestMatch == PLURAL_COUNT_TWO ) {
|
||||
resultNumber = 2;
|
||||
} else {
|
||||
// should not happen.
|
||||
// TODO: how to handle?
|
||||
resultNumber = 3;
|
||||
}
|
||||
}
|
||||
if (longestParseDistance == 0) {
|
||||
pos.setIndex(oldPos);
|
||||
pos.setErrorIndex(0);
|
||||
} else {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
TimeUnitAmount* tmutamt = new TimeUnitAmount(resultNumber, resultTimeUnit, status);
|
||||
if (U_SUCCESS(status)) {
|
||||
result.adoptObject(tmutamt);
|
||||
pos.setIndex(newPos);
|
||||
pos.setErrorIndex(-1);
|
||||
} else {
|
||||
pos.setIndex(oldPos);
|
||||
pos.setErrorIndex(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TimeUnitFormat::create(const Locale& locale, EStyle style, UErrorCode& status) {
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
if (style < kFull || style > kAbbreviate) {
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
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.
|
||||
//and here, the behavior is not consistent with Java.
|
||||
//In Java, create an empty instance does not setup locale as
|
||||
//default locale. If it followed by setNumberFormat(),
|
||||
//in format(), the locale will set up as the locale in fNumberFormat.
|
||||
//But in C++, this sets the locale as the default locale.
|
||||
setup(status);
|
||||
}
|
||||
|
||||
void
|
||||
TimeUnitFormat::setup(UErrorCode& err) {
|
||||
initDataMembers(err);
|
||||
readFromCurrentLocale(kFull, gUnitsTag, err);
|
||||
checkConsistency(kFull, gUnitsTag, err);
|
||||
readFromCurrentLocale(kAbbreviate, gShortUnitsTag, err);
|
||||
checkConsistency(kAbbreviate, gShortUnitsTag, err);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TimeUnitFormat::initDataMembers(UErrorCode& err){
|
||||
if (U_FAILURE(err)) {
|
||||
return;
|
||||
}
|
||||
if (fNumberFormat == NULL) {
|
||||
fNumberFormat = NumberFormat::createInstance(fLocale, err);
|
||||
}
|
||||
delete fPluralRules;
|
||||
fPluralRules = PluralRules::forLocale(fLocale, err);
|
||||
for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
|
||||
i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
|
||||
i = (TimeUnit::UTimeUnitFields)(i+1)) {
|
||||
deleteHash(fTimeUnitToCountToPatterns[i]);
|
||||
fTimeUnitToCountToPatterns[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void
|
||||
TimeUnitFormat::readFromCurrentLocale(EStyle style, const char* key, UErrorCode& err) {
|
||||
if (U_FAILURE(err)) {
|
||||
return;
|
||||
}
|
||||
// fill timeUnitToCountToPatterns from resource file
|
||||
// err is used to indicate wrong status except missing resource.
|
||||
// status is an error code used in resource lookup.
|
||||
// status does not affect "err".
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
UResourceBundle *rb, *unitsRes;
|
||||
rb = ures_open(NULL, fLocale.getName(), &status);
|
||||
unitsRes = ures_getByKey(rb, key, NULL, &status);
|
||||
if (U_FAILURE(status)) {
|
||||
ures_close(unitsRes);
|
||||
ures_close(rb);
|
||||
return;
|
||||
}
|
||||
int32_t size = ures_getSize(unitsRes);
|
||||
for ( int32_t index = 0; index < size; ++index) {
|
||||
// resource of one time unit
|
||||
UResourceBundle* oneTimeUnit = ures_getByIndex(unitsRes, index,
|
||||
NULL, &status);
|
||||
if (U_SUCCESS(status)) {
|
||||
const char* timeUnitName = ures_getKey(oneTimeUnit);
|
||||
if (timeUnitName == NULL) {
|
||||
ures_close(oneTimeUnit);
|
||||
continue;
|
||||
}
|
||||
UResourceBundle* countsToPatternRB = ures_getByKey(unitsRes,
|
||||
timeUnitName,
|
||||
NULL, &status);
|
||||
if (countsToPatternRB == NULL || U_FAILURE(status)) {
|
||||
ures_close(countsToPatternRB);
|
||||
ures_close(oneTimeUnit);
|
||||
continue;
|
||||
}
|
||||
TimeUnit::UTimeUnitFields timeUnitField = TimeUnit::UTIMEUNIT_FIELD_COUNT;
|
||||
if ( uprv_strcmp(timeUnitName, gTimeUnitYear) == 0 ) {
|
||||
timeUnitField = TimeUnit::UTIMEUNIT_YEAR;
|
||||
} else if ( uprv_strcmp(timeUnitName, gTimeUnitMonth) == 0 ) {
|
||||
timeUnitField = TimeUnit::UTIMEUNIT_MONTH;
|
||||
} else if ( uprv_strcmp(timeUnitName, gTimeUnitDay) == 0 ) {
|
||||
timeUnitField = TimeUnit::UTIMEUNIT_DAY;
|
||||
} else if ( uprv_strcmp(timeUnitName, gTimeUnitHour) == 0 ) {
|
||||
timeUnitField = TimeUnit::UTIMEUNIT_HOUR;
|
||||
} else if ( uprv_strcmp(timeUnitName, gTimeUnitMinute) == 0 ) {
|
||||
timeUnitField = TimeUnit::UTIMEUNIT_MINUTE;
|
||||
} else if ( uprv_strcmp(timeUnitName, gTimeUnitSecond) == 0 ) {
|
||||
timeUnitField = TimeUnit::UTIMEUNIT_SECOND;
|
||||
} else if ( uprv_strcmp(timeUnitName, gTimeUnitWeek) == 0 ) {
|
||||
timeUnitField = TimeUnit::UTIMEUNIT_WEEK;
|
||||
} else {
|
||||
ures_close(countsToPatternRB);
|
||||
ures_close(oneTimeUnit);
|
||||
continue;
|
||||
}
|
||||
Hashtable* countToPatterns = fTimeUnitToCountToPatterns[timeUnitField];
|
||||
if (countToPatterns == NULL) {
|
||||
countToPatterns = initHash(err);
|
||||
if (U_FAILURE(err)) {
|
||||
ures_close(countsToPatternRB);
|
||||
ures_close(oneTimeUnit);
|
||||
delete countToPatterns;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int32_t count = ures_getSize(countsToPatternRB);
|
||||
const UChar* pattern;
|
||||
const char* pluralCount;
|
||||
int32_t ptLength;
|
||||
for ( int32_t pluralIndex = 0; pluralIndex < count; ++pluralIndex) {
|
||||
// resource of count to pattern
|
||||
pattern = ures_getNextString(countsToPatternRB, &ptLength,
|
||||
&pluralCount, &status);
|
||||
if (U_FAILURE(status)) {
|
||||
continue;
|
||||
}
|
||||
MessageFormat* messageFormat = new MessageFormat(pattern, fLocale, err);
|
||||
if ( U_SUCCESS(err) ) {
|
||||
if (fNumberFormat != NULL) {
|
||||
messageFormat->setFormat(0, *fNumberFormat);
|
||||
}
|
||||
MessageFormat** formatters = (MessageFormat**)countToPatterns->get(pluralCount);
|
||||
if (formatters == NULL) {
|
||||
// formatters = new MessageFormat*[kTotal];
|
||||
formatters = (MessageFormat**)uprv_malloc(2*sizeof(MessageFormat*));
|
||||
formatters[kFull] = NULL;
|
||||
formatters[kAbbreviate] = NULL;
|
||||
countToPatterns->put(pluralCount, formatters, err);
|
||||
if (U_FAILURE(err)) {
|
||||
delete [] formatters;
|
||||
}
|
||||
}
|
||||
if (U_SUCCESS(err)) {
|
||||
//delete formatters[style];
|
||||
formatters[style] = messageFormat;
|
||||
}
|
||||
}
|
||||
if (U_FAILURE(err)) {
|
||||
ures_close(countsToPatternRB);
|
||||
ures_close(oneTimeUnit);
|
||||
ures_close(unitsRes);
|
||||
ures_close(rb);
|
||||
delete messageFormat;
|
||||
delete countToPatterns;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (fTimeUnitToCountToPatterns[timeUnitField] == NULL) {
|
||||
fTimeUnitToCountToPatterns[timeUnitField] = countToPatterns;
|
||||
}
|
||||
ures_close(countsToPatternRB);
|
||||
}
|
||||
ures_close(oneTimeUnit);
|
||||
}
|
||||
ures_close(unitsRes);
|
||||
ures_close(rb);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TimeUnitFormat::checkConsistency(EStyle style, const char* key, UErrorCode& err) {
|
||||
if (U_FAILURE(err)) {
|
||||
return;
|
||||
}
|
||||
// there should be patterns for each plural rule in each time unit.
|
||||
// For each time unit,
|
||||
// for each plural rule, following is unit pattern fall-back rule:
|
||||
// ( for example: "one" hour )
|
||||
// look for its unit pattern in its locale tree.
|
||||
// if pattern is not found in its own locale, such as de_DE,
|
||||
// look for the pattern in its parent, such as de,
|
||||
// keep looking till found or till root.
|
||||
// if the pattern is not found in root either,
|
||||
// fallback to plural count "other",
|
||||
// look for the pattern of "other" in the locale tree:
|
||||
// "de_DE" to "de" to "root".
|
||||
// If not found, fall back to value of
|
||||
// static variable DEFAULT_PATTERN_FOR_xxx, such as "{0} h".
|
||||
//
|
||||
// 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);
|
||||
if (U_SUCCESS(err)) {
|
||||
const char* pluralCount;
|
||||
while ((pluralCount = keywords->next(NULL, err)) != NULL) {
|
||||
if ( U_SUCCESS(err) ) {
|
||||
for (int32_t i = 0; i < TimeUnit::UTIMEUNIT_FIELD_COUNT; ++i) {
|
||||
// for each time unit,
|
||||
// get all the patterns for each plural rule in this locale.
|
||||
Hashtable* countToPatterns = fTimeUnitToCountToPatterns[i];
|
||||
if ( countToPatterns == NULL ) {
|
||||
countToPatterns = initHash(err);
|
||||
if (U_FAILURE(err)) {
|
||||
delete countToPatterns;
|
||||
return;
|
||||
}
|
||||
fTimeUnitToCountToPatterns[i] = countToPatterns;
|
||||
}
|
||||
MessageFormat** formatters = (MessageFormat**)countToPatterns->get(pluralCount);
|
||||
if( formatters == NULL || formatters[style] == NULL ) {
|
||||
// look through parents
|
||||
searchInLocaleChain(style, key,
|
||||
(TimeUnit::UTimeUnitFields)i,
|
||||
pluralCount, pluralCount,
|
||||
countToPatterns, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
delete keywords;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// srcPluralCount is the original plural count on which the pattern is
|
||||
// searched for.
|
||||
// searchPluralCount is the fallback plural count.
|
||||
// For example, to search for pattern for ""one" hour",
|
||||
// "one" is the srcPluralCount,
|
||||
// if the pattern is not found even in root, fallback to
|
||||
// using patterns of plural count "other",
|
||||
// then, "other" is the searchPluralCount.
|
||||
void
|
||||
TimeUnitFormat::searchInLocaleChain(EStyle style, const char* key,
|
||||
TimeUnit::UTimeUnitFields srcTimeUnitField,
|
||||
const char* srcPluralCount,
|
||||
const char* searchPluralCount,
|
||||
Hashtable* countToPatterns,
|
||||
UErrorCode& err) {
|
||||
if (U_FAILURE(err)) {
|
||||
return;
|
||||
}
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
const char *locName = fLocale.getName();
|
||||
char parentLocale[ULOC_FULLNAME_CAPACITY];
|
||||
uprv_strcpy(parentLocale, locName);
|
||||
int32_t locNameLen;
|
||||
while ((locNameLen = uloc_getParent(parentLocale, parentLocale,
|
||||
ULOC_FULLNAME_CAPACITY, &status)) >= 0){
|
||||
// look for pattern for srcPluralCount in locale tree
|
||||
UResourceBundle *rb, *unitsRes, *countsToPatternRB;
|
||||
rb = ures_open(NULL, parentLocale, &status);
|
||||
unitsRes = ures_getByKey(rb, key, NULL, &status);
|
||||
const char* timeUnitName = getTimeUnitName(srcTimeUnitField, status);
|
||||
countsToPatternRB = ures_getByKey(unitsRes, timeUnitName, NULL, &status);
|
||||
const UChar* pattern;
|
||||
int32_t ptLength;
|
||||
pattern = ures_getStringByKeyWithFallback(countsToPatternRB, searchPluralCount, &ptLength, &status);
|
||||
if (U_SUCCESS(status)) {
|
||||
//found
|
||||
MessageFormat* messageFormat = new MessageFormat(pattern, fLocale, err);
|
||||
if (U_SUCCESS(err)) {
|
||||
if (fNumberFormat != NULL) {
|
||||
messageFormat->setFormat(0, *fNumberFormat);
|
||||
}
|
||||
MessageFormat** formatters = (MessageFormat**)countToPatterns->get(srcPluralCount);
|
||||
if (formatters == NULL) {
|
||||
//formatters = new MessageFormat*[kTotal];
|
||||
formatters = (MessageFormat**)uprv_malloc(2*sizeof(MessageFormat*));
|
||||
formatters[kFull] = NULL;
|
||||
formatters[kAbbreviate] = NULL;
|
||||
countToPatterns->put(srcPluralCount, formatters, err);
|
||||
if (U_FAILURE(err)) {
|
||||
delete [] formatters;
|
||||
delete messageFormat;
|
||||
}
|
||||
}
|
||||
if (U_SUCCESS(err)) {
|
||||
//delete formatters[style];
|
||||
formatters[style] = messageFormat;
|
||||
}
|
||||
} else {
|
||||
delete messageFormat;
|
||||
}
|
||||
ures_close(countsToPatternRB);
|
||||
ures_close(unitsRes);
|
||||
ures_close(rb);
|
||||
return;
|
||||
}
|
||||
ures_close(countsToPatternRB);
|
||||
ures_close(unitsRes);
|
||||
ures_close(rb);
|
||||
if ( locNameLen ==0 ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if not found the pattern for this plural count at all,
|
||||
// fall-back to plural count "other"
|
||||
if ( uprv_strcmp(searchPluralCount, gPluralCountOther) == 0 ) {
|
||||
// set default fall back the same as the resource in root
|
||||
MessageFormat* messageFormat = NULL;
|
||||
if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_SECOND ) {
|
||||
messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_SECOND, fLocale, err);
|
||||
} else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_MINUTE ) {
|
||||
messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_MINUTE, fLocale, err);
|
||||
} else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_HOUR ) {
|
||||
messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_HOUR, fLocale, err);
|
||||
} else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_WEEK ) {
|
||||
messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_WEEK, fLocale, err);
|
||||
} else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_DAY ) {
|
||||
messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_DAY, fLocale, err);
|
||||
} else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_MONTH ) {
|
||||
messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_MONTH, fLocale, err);
|
||||
} else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_YEAR ) {
|
||||
messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_YEAR, fLocale, err);
|
||||
}
|
||||
if (U_SUCCESS(err)) {
|
||||
if (fNumberFormat != NULL && messageFormat != NULL) {
|
||||
messageFormat->setFormat(0, *fNumberFormat);
|
||||
}
|
||||
MessageFormat** formatters = (MessageFormat**)countToPatterns->get(srcPluralCount);
|
||||
if (formatters == NULL) {
|
||||
//formatters = new MessageFormat*[kTotal];
|
||||
formatters = (MessageFormat**)uprv_malloc(2*sizeof(MessageFormat*));
|
||||
formatters[kFull] = NULL;
|
||||
formatters[kAbbreviate] = NULL;
|
||||
countToPatterns->put(srcPluralCount, formatters, err);
|
||||
if (U_FAILURE(err)) {
|
||||
delete [] formatters;
|
||||
delete messageFormat;
|
||||
}
|
||||
}
|
||||
if (U_SUCCESS(err)) {
|
||||
//delete formatters[style];
|
||||
formatters[style] = messageFormat;
|
||||
}
|
||||
} else {
|
||||
delete messageFormat;
|
||||
}
|
||||
} else {
|
||||
// fall back to rule "other", and search in parents
|
||||
searchInLocaleChain(style, key, srcTimeUnitField, srcPluralCount,
|
||||
gPluralCountOther, countToPatterns, err);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TimeUnitFormat::setLocale(const Locale& locale, UErrorCode& status) {
|
||||
if (U_SUCCESS(status) && fLocale != locale) {
|
||||
fLocale = locale;
|
||||
setup(status);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TimeUnitFormat::setNumberFormat(const NumberFormat& format, UErrorCode& status){
|
||||
if (U_FAILURE(status) || fNumberFormat && format == *fNumberFormat) {
|
||||
return;
|
||||
}
|
||||
delete fNumberFormat;
|
||||
fNumberFormat = (NumberFormat*)format.clone();
|
||||
// reset the number formatter in the fTimeUnitToCountToPatterns map
|
||||
for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
|
||||
i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
|
||||
i = (TimeUnit::UTimeUnitFields)(i+1)) {
|
||||
int32_t pos = -1;
|
||||
const UHashElement* elem = NULL;
|
||||
while ((elem = fTimeUnitToCountToPatterns[i]->nextElement(pos)) != NULL){
|
||||
const UHashTok keyTok = elem->value;
|
||||
MessageFormat** pattern = (MessageFormat**)keyTok.pointer;
|
||||
pattern[kFull]->setFormat(0, format);
|
||||
pattern[kAbbreviate]->setFormat(0, format);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TimeUnitFormat::deleteHash(Hashtable* htable) {
|
||||
int32_t pos = -1;
|
||||
const UHashElement* element = NULL;
|
||||
if ( htable ) {
|
||||
while ( (element = htable->nextElement(pos)) != NULL ) {
|
||||
const UHashTok valueTok = element->value;
|
||||
const MessageFormat** value = (const MessageFormat**)valueTok.pointer;
|
||||
delete value[kFull];
|
||||
delete value[kAbbreviate];
|
||||
//delete[] value;
|
||||
uprv_free(value);
|
||||
}
|
||||
}
|
||||
delete htable;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TimeUnitFormat::copyHash(const Hashtable* source, Hashtable* target, UErrorCode& status) {
|
||||
if ( U_FAILURE(status) ) {
|
||||
return;
|
||||
}
|
||||
int32_t pos = -1;
|
||||
const UHashElement* element = NULL;
|
||||
if ( source ) {
|
||||
while ( (element = source->nextElement(pos)) != NULL ) {
|
||||
const UHashTok keyTok = element->key;
|
||||
const UnicodeString* key = (UnicodeString*)keyTok.pointer;
|
||||
const UHashTok valueTok = element->value;
|
||||
const MessageFormat** value = (const MessageFormat**)valueTok.pointer;
|
||||
//MessageFormat** newVal = new MessageFormat*[kTotal];
|
||||
MessageFormat** newVal = (MessageFormat**)uprv_malloc(2*sizeof(MessageFormat*));
|
||||
newVal[0] = (MessageFormat*)value[0]->clone();
|
||||
newVal[1] = (MessageFormat*)value[1]->clone();
|
||||
target->put(UnicodeString(*key), newVal, status);
|
||||
if ( U_FAILURE(status) ) {
|
||||
delete newVal[0];
|
||||
delete newVal[1];
|
||||
delete [] newVal;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
U_CDECL_BEGIN
|
||||
|
||||
/**
|
||||
* set hash table value comparator
|
||||
*
|
||||
* @param val1 one value in comparison
|
||||
* @param val2 the other value in comparison
|
||||
* @return TRUE if 2 values are the same, FALSE otherwise
|
||||
*/
|
||||
static UBool U_CALLCONV hashTableValueComparator(UHashTok val1, UHashTok val2);
|
||||
|
||||
U_CDECL_END
|
||||
|
||||
UBool
|
||||
U_CALLCONV hashTableValueComparator(UHashTok val1, UHashTok val2) {
|
||||
const MessageFormat** pattern1 = (const MessageFormat**)val1.pointer;
|
||||
const MessageFormat** pattern2 = (const MessageFormat**)val2.pointer;
|
||||
return *pattern1[0] == *pattern2[0] && *pattern1[1] == *pattern2[1];
|
||||
}
|
||||
|
||||
|
||||
Hashtable*
|
||||
TimeUnitFormat::initHash(UErrorCode& status) {
|
||||
if ( U_FAILURE(status) ) {
|
||||
return NULL;
|
||||
}
|
||||
Hashtable* hTable;
|
||||
if ( (hTable = new Hashtable(TRUE, status)) == NULL ) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
hTable->setValueCompartor(hashTableValueComparator);
|
||||
return hTable;
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
TimeUnitFormat::getTimeUnitName(TimeUnit::UTimeUnitFields unitField,
|
||||
UErrorCode& status) {
|
||||
if (U_FAILURE(status)) {
|
||||
return NULL;
|
||||
}
|
||||
switch (unitField) {
|
||||
case TimeUnit::UTIMEUNIT_YEAR:
|
||||
return gTimeUnitYear;
|
||||
case TimeUnit::UTIMEUNIT_MONTH:
|
||||
return gTimeUnitMonth;
|
||||
case TimeUnit::UTIMEUNIT_DAY:
|
||||
return gTimeUnitDay;
|
||||
case TimeUnit::UTIMEUNIT_WEEK:
|
||||
return gTimeUnitWeek;
|
||||
case TimeUnit::UTIMEUNIT_HOUR:
|
||||
return gTimeUnitHour;
|
||||
case TimeUnit::UTIMEUNIT_MINUTE:
|
||||
return gTimeUnitMinute;
|
||||
case TimeUnit::UTIMEUNIT_SECOND:
|
||||
return gTimeUnitSecond;
|
||||
default:
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
||||
#endif
|
@ -748,6 +748,19 @@ public:
|
||||
*/
|
||||
UBool usesNamedArguments() const;
|
||||
|
||||
|
||||
/**
|
||||
* This API is for ICU internal use only.
|
||||
* Please do not use it.
|
||||
*
|
||||
* Returns argument types count in the parsed pattern.
|
||||
* Used to distinguish pattern "{0} d" and "d".
|
||||
*
|
||||
* @return The number of formattable types in the pattern
|
||||
* @internal
|
||||
*/
|
||||
int32_t getArgTypeCount() const;
|
||||
|
||||
/**
|
||||
* Returns a unique class ID POLYMORPHICALLY. Pure virtual override.
|
||||
* This method is to implement a simple version of RTTI, since not all
|
||||
|
149
icu4c/source/i18n/unicode/tmunit.h
Normal file
149
icu4c/source/i18n/unicode/tmunit.h
Normal file
@ -0,0 +1,149 @@
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2008, Google, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef __TMUNIT_H__
|
||||
#define __TMUNIT_H__
|
||||
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \brief C++ API: time unit object
|
||||
*/
|
||||
|
||||
|
||||
#if !UCONFIG_NO_FORMATTING
|
||||
|
||||
#include "unicode/measunit.h"
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
/**
|
||||
* Measurement unit for time units.
|
||||
* @see TimeUnitAmount
|
||||
* @see TimeUnit
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
class U_I18N_API TimeUnit: public MeasureUnit {
|
||||
public:
|
||||
/**
|
||||
* Constants for all the time units we supported.
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
enum UTimeUnitFields {
|
||||
UTIMEUNIT_YEAR,
|
||||
UTIMEUNIT_MONTH,
|
||||
UTIMEUNIT_DAY,
|
||||
UTIMEUNIT_WEEK,
|
||||
UTIMEUNIT_HOUR,
|
||||
UTIMEUNIT_MINUTE,
|
||||
UTIMEUNIT_SECOND,
|
||||
UTIMEUNIT_FIELD_COUNT
|
||||
};
|
||||
|
||||
/**
|
||||
* Create Instance.
|
||||
* @param timeUnitField time unit field based on which the instance
|
||||
* is created.
|
||||
* @param status input-output error code.
|
||||
* If the timeUnitField is invalid,
|
||||
* then this will be set to U_ILLEGAL_ARGUMENT_ERROR.
|
||||
* @return a TimeUnit instance
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
static TimeUnit* U_EXPORT2 createInstance(UTimeUnitFields timeUnitField,
|
||||
UErrorCode& status);
|
||||
|
||||
|
||||
/**
|
||||
* Override clone.
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
virtual UObject* clone() const;
|
||||
|
||||
/**
|
||||
* Copy operator.
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
TimeUnit(const TimeUnit& other);
|
||||
|
||||
/**
|
||||
* Assignment operator.
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
TimeUnit& operator=(const TimeUnit& other);
|
||||
|
||||
/**
|
||||
* Equality operator.
|
||||
* @return true if 2 objects are the same.
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
virtual UBool operator==(const UObject& other) const;
|
||||
|
||||
/**
|
||||
* Non-Equality operator.
|
||||
* @return true if 2 objects are not the same.
|
||||
* @draft 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.
|
||||
* @return The class ID for this object. All objects of a given
|
||||
* class have the same class ID. Objects of other classes have
|
||||
* different class IDs.
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
virtual UClassID getDynamicClassID() const;
|
||||
|
||||
/**
|
||||
* Returns the class ID for this class. This is used to compare to
|
||||
* the return value of getDynamicClassID().
|
||||
* @return The class ID for all objects of this class.
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
static UClassID U_EXPORT2 getStaticClassID();
|
||||
|
||||
|
||||
/**
|
||||
* Get time unit field.
|
||||
* @return time unit field.
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
UTimeUnitFields getTimeUnitField() const;
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
virtual ~TimeUnit();
|
||||
|
||||
private:
|
||||
UTimeUnitFields fTimeUnitField;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @internal ICU 4.2
|
||||
*/
|
||||
TimeUnit(UTimeUnitFields timeUnitField);
|
||||
|
||||
};
|
||||
|
||||
|
||||
inline UBool
|
||||
TimeUnit::operator!=(const UObject& other) const {
|
||||
return !operator==(other);
|
||||
}
|
||||
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||
|
||||
#endif // __TMUNIT_H__
|
||||
//eof
|
||||
//
|
168
icu4c/source/i18n/unicode/tmutamt.h
Normal file
168
icu4c/source/i18n/unicode/tmutamt.h
Normal file
@ -0,0 +1,168 @@
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2008, Google, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef __TMUTAMT_H__
|
||||
#define __TMUTAMT_H__
|
||||
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \brief C++ API: time unit amount object.
|
||||
*/
|
||||
|
||||
#if !UCONFIG_NO_FORMATTING
|
||||
|
||||
#include "unicode/measure.h"
|
||||
#include "unicode/tmunit.h"
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
/**
|
||||
* Express a duration as a time unit and number. Patterned after Currency.
|
||||
* @see TimeUnitAmount
|
||||
* @see TimeUnitFormat
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
class U_I18N_API TimeUnitAmount: public Measure {
|
||||
public:
|
||||
/**
|
||||
* Construct TimeUnitAmount object with the given number and the
|
||||
* given time unit.
|
||||
* @param number a numeric object; number.isNumeric() must be TRUE
|
||||
* @param timeUnitField the time unit field of a time unit
|
||||
* @param status the input-output error code.
|
||||
* If the number is not numeric or the timeUnitField
|
||||
* is not valid,
|
||||
* then this will be set to a failing value:
|
||||
* U_ILLEGAL_ARGUMENT_ERROR.
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
TimeUnitAmount(const Formattable& number,
|
||||
TimeUnit::UTimeUnitFields timeUnitField,
|
||||
UErrorCode& status);
|
||||
|
||||
/**
|
||||
* Construct TimeUnitAmount object with the given numeric amount and the
|
||||
* given time unit.
|
||||
* @param amount a numeric amount.
|
||||
* @param timeUnitField the time unit field on which a time unit amount
|
||||
* object will be created.
|
||||
* @param status the input-output error code.
|
||||
* If the timeUnitField is not valid,
|
||||
* then this will be set to a failing value:
|
||||
* U_ILLEGAL_ARGUMENT_ERROR.
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
TimeUnitAmount(double amount, TimeUnit::UTimeUnitFields timeUnitField,
|
||||
UErrorCode& status);
|
||||
|
||||
|
||||
/**
|
||||
* Copy constructor
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
TimeUnitAmount(const TimeUnitAmount& other);
|
||||
|
||||
|
||||
/**
|
||||
* Assignment operator
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
TimeUnitAmount& operator=(const TimeUnitAmount& other);
|
||||
|
||||
|
||||
/**
|
||||
* Clone.
|
||||
* @return a polymorphic clone of this object. The result will have the same class as returned by getDynamicClassID().
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
virtual UObject* clone() const;
|
||||
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
virtual ~TimeUnitAmount();
|
||||
|
||||
|
||||
/**
|
||||
* Equality operator.
|
||||
* @param other the object to compare to.
|
||||
* @return true if this object is equal to the given object.
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
virtual UBool operator==(const UObject& other) const;
|
||||
|
||||
|
||||
/**
|
||||
* Not-equality operator.
|
||||
* @param other the object to compare to.
|
||||
* @return true if this object is not equal to the given object.
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
UBool operator!=(const UObject& other) const;
|
||||
|
||||
|
||||
/**
|
||||
* Return the class ID for this class. This is useful only for comparing to
|
||||
* a return value from getDynamicClassID(). For example:
|
||||
* <pre>
|
||||
* . Base* polymorphic_pointer = createPolymorphicObject();
|
||||
* . if (polymorphic_pointer->getDynamicClassID() ==
|
||||
* . erived::getStaticClassID()) ...
|
||||
* </pre>
|
||||
* @return The class ID for all objects of this class.
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
static UClassID U_EXPORT2 getStaticClassID(void);
|
||||
|
||||
|
||||
/**
|
||||
* Returns a unique class ID POLYMORPHICALLY. Pure virtual override. This
|
||||
* method is to implement a simple version of RTTI, since not all C++
|
||||
* compilers support genuine RTTI. Polymorphic operator==() and clone()
|
||||
* methods call this method.
|
||||
*
|
||||
* @return The class ID for this object. All objects of a
|
||||
* given class have the same class ID. Objects of
|
||||
* other classes have different class IDs.
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
virtual UClassID getDynamicClassID(void) const;
|
||||
|
||||
|
||||
/**
|
||||
* Get the time unit.
|
||||
* @return time unit object.
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
const TimeUnit& getTimeUnit() const;
|
||||
|
||||
/**
|
||||
* Get the time unit field value.
|
||||
* @return time unit field value.
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
TimeUnit::UTimeUnitFields getTimeUnitField() const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
inline UBool
|
||||
TimeUnitAmount::operator!=(const UObject& other) const {
|
||||
return !operator==(other);
|
||||
}
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||
|
||||
#endif // __TMUTAMT_H__
|
||||
//eof
|
||||
//
|
281
icu4c/source/i18n/unicode/tmutfmt.h
Normal file
281
icu4c/source/i18n/unicode/tmutfmt.h
Normal file
@ -0,0 +1,281 @@
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2008, Google, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef __TMUTFMT_H__
|
||||
#define __TMUTFMT_H__
|
||||
|
||||
#include "unicode/utypes.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \brief C++ API: Format and parse duration in single time unit
|
||||
*/
|
||||
|
||||
|
||||
#if !UCONFIG_NO_FORMATTING
|
||||
|
||||
#include "unicode/unistr.h"
|
||||
#include "unicode/tmunit.h"
|
||||
#include "unicode/tmutamt.h"
|
||||
#include "unicode/measfmt.h"
|
||||
#include "unicode/numfmt.h"
|
||||
#include "unicode/plurrule.h"
|
||||
|
||||
/**
|
||||
* @internal ICU 4.2
|
||||
*/
|
||||
|
||||
union UHashTok;
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
U_CDECL_BEGIN
|
||||
|
||||
/**
|
||||
* @internal ICU 4.2
|
||||
*/
|
||||
static UBool U_CALLCONV hashTableValueComparator(UHashTok val1, UHashTok val2) ;
|
||||
|
||||
U_CDECL_END
|
||||
|
||||
|
||||
class Hashtable;
|
||||
|
||||
|
||||
/**
|
||||
* Format or parse a TimeUnitAmount, using plural rules for the units where available.
|
||||
*
|
||||
* <P>
|
||||
* Code Sample:
|
||||
* <pre>
|
||||
* // create time unit amount instance - a combination of Number and time unit
|
||||
* UErrorCode status = U_ZERO_ERROR;
|
||||
* TimeUnitAmount* source = new TimeUnitAmount(2, TimeUnit::UTIMEUNIT_YEAR, status);
|
||||
* // create time unit format instance
|
||||
* TimeUnitFormat* format = new TimeUnitFormat(Locale("en"), status);
|
||||
* // format a time unit amount
|
||||
* UnicodeString formatted;
|
||||
* Formattable formattable;
|
||||
* if (U_SUCCESS(status)) {
|
||||
* formattable.adoptObject(source);
|
||||
* formatted = ((Format*)format)->format(formattable, formatted, status);
|
||||
* Formattable result;
|
||||
* ((Format*)format)->parseObject(formatted, result, status);
|
||||
* if (U_SUCCESS(status)) {
|
||||
* assert (result == formattable);
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <P>
|
||||
* @see TimeUnitAmount
|
||||
* @see TimeUnitFormat
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
class U_I18N_API TimeUnitFormat: public MeasureFormat {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constants for various styles.
|
||||
* There are 2 styles: full name and abbreviated name.
|
||||
* For example, for English, the full name for hour duration is "3 hours",
|
||||
* and the abbreviated name is "3 hrs".
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
enum EStyle {
|
||||
kFull = 0,
|
||||
kAbbreviate = 1,
|
||||
kTotal = kAbbreviate + 1
|
||||
};
|
||||
|
||||
/**
|
||||
* Create TimeUnitFormat with default locale, and full name style.
|
||||
* Use setLocale and/or setFormat to modify.
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
TimeUnitFormat(UErrorCode& status);
|
||||
|
||||
/**
|
||||
* Create TimeUnitFormat given locale, and full name style.
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
TimeUnitFormat(const Locale& locale, UErrorCode& status);
|
||||
|
||||
/**
|
||||
* Create TimeUnitFormat given locale and style.
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
TimeUnitFormat(const Locale& locale, EStyle style, UErrorCode& status);
|
||||
|
||||
/**
|
||||
* Copy constructor.
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
TimeUnitFormat(const TimeUnitFormat&);
|
||||
|
||||
/**
|
||||
* deconstructor
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
virtual ~TimeUnitFormat();
|
||||
|
||||
/**
|
||||
* Clone this Format object polymorphically. The caller owns the result and
|
||||
* should delete it when done.
|
||||
* @return A copy of the object.
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
virtual Format* clone(void) const;
|
||||
|
||||
/**
|
||||
* Assignment operator
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
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.
|
||||
* @draft 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.
|
||||
* @param other the object to be compared with.
|
||||
* @return true if the given Format objects are not semantically equal.
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
UBool operator!=(const Format& other) const;
|
||||
|
||||
/**
|
||||
* Set the locale used for formatting or parsing.
|
||||
* @param locale the locale to be set
|
||||
* @param status output param set to success/failure code on exit
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
void setLocale(const Locale& locale, UErrorCode& status);
|
||||
|
||||
|
||||
/**
|
||||
* Set the number format used for formatting or parsing.
|
||||
* @param format the number formatter to be set
|
||||
* @param status output param set to success/failure code on exit
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
void setNumberFormat(const NumberFormat& format, UErrorCode& status);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @draft 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;
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
virtual void parseObject(const UnicodeString& source,
|
||||
Formattable& result,
|
||||
ParsePosition& pos) const;
|
||||
|
||||
/**
|
||||
* Return the class ID for this class. This is useful only for comparing to
|
||||
* a return value from getDynamicClassID(). For example:
|
||||
* <pre>
|
||||
* . Base* polymorphic_pointer = createPolymorphicObject();
|
||||
* . if (polymorphic_pointer->getDynamicClassID() ==
|
||||
* . erived::getStaticClassID()) ...
|
||||
* </pre>
|
||||
* @return The class ID for all objects of this class.
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
static UClassID U_EXPORT2 getStaticClassID(void);
|
||||
|
||||
/**
|
||||
* Returns a unique class ID POLYMORPHICALLY. Pure virtual override. This
|
||||
* method is to implement a simple version of RTTI, since not all C++
|
||||
* compilers support genuine RTTI. Polymorphic operator==() and clone()
|
||||
* methods call this method.
|
||||
*
|
||||
* @return The class ID for this object. All objects of a
|
||||
* given class have the same class ID. Objects of
|
||||
* other classes have different class IDs.
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
virtual UClassID getDynamicClassID(void) const;
|
||||
|
||||
private:
|
||||
NumberFormat* fNumberFormat;
|
||||
Locale fLocale;
|
||||
Hashtable* fTimeUnitToCountToPatterns[TimeUnit::UTIMEUNIT_FIELD_COUNT];
|
||||
PluralRules* fPluralRules;
|
||||
EStyle fStyle;
|
||||
|
||||
friend UBool U_CALLCONV hashTableValueComparator(UHashTok val1, UHashTok val2);
|
||||
|
||||
void create(const Locale& locale, EStyle style, UErrorCode& status);
|
||||
|
||||
// it might actually be simpler to make them Decimal Formats later.
|
||||
// initialize all private data members
|
||||
void setup(UErrorCode& status);
|
||||
|
||||
// initialize data member without fill in data for fTimeUnitToCountToPattern
|
||||
void initDataMembers(UErrorCode& status);
|
||||
|
||||
// initialize fTimeUnitToCountToPatterns from current locale's resource.
|
||||
void readFromCurrentLocale(EStyle style, const char* key, UErrorCode& status);
|
||||
|
||||
// check completeness of fTimeUnitToCountToPatterns against all time units,
|
||||
// and all plural rules, fill in fallback as necessary.
|
||||
void checkConsistency(EStyle style, const char* key, UErrorCode& status);
|
||||
|
||||
// fill in fTimeUnitToCountToPatterns from locale fall-back chain
|
||||
void searchInLocaleChain(EStyle style, const char* key,
|
||||
TimeUnit::UTimeUnitFields field, const char*,
|
||||
const char*, Hashtable*, UErrorCode&);
|
||||
|
||||
// initialize hash table
|
||||
Hashtable* initHash(UErrorCode& status);
|
||||
|
||||
// delete hash table
|
||||
void deleteHash(Hashtable* htable);
|
||||
|
||||
// copy hash table
|
||||
void copyHash(const Hashtable* source, Hashtable* target, UErrorCode& status);
|
||||
// get time unit name, such as "year", from time unit field enum, such as
|
||||
// UTIMEUNIT_YEAR.
|
||||
static const char* getTimeUnitName(TimeUnit::UTimeUnitFields field, UErrorCode& status);
|
||||
};
|
||||
|
||||
|
||||
|
||||
inline UBool
|
||||
TimeUnitFormat::operator!=(const Format& other) const {
|
||||
return !operator==(other);
|
||||
}
|
||||
|
||||
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||
|
||||
#endif // __TMUTFMT_H__
|
||||
//eof
|
@ -56,7 +56,8 @@ jamotest.o srchtest.o reptest.o regextst.o \
|
||||
itrbnf.o itrbnfrt.o itrbnfp.o ucaconf.o icusvtst.o \
|
||||
uobjtest.o idnaref.o idnaconf.o nptrans.o punyref.o testidn.o testidna.o 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
|
||||
windttst.o winnmtst.o winutil.o csdetest.o tzrulets.o tzoffloc.o tzfmttst.o ssearch.o dtifmtts.o \
|
||||
tufmtts.o
|
||||
|
||||
DEPS = $(OBJECTS:.o=.d)
|
||||
|
||||
|
@ -1032,6 +1032,14 @@
|
||||
RelativePath=".\tsnmfmt.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\tufmtts.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\tufmtts.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\tzbdtest.cpp"
|
||||
>
|
||||
|
@ -51,6 +51,7 @@
|
||||
#include "plurults.h" // PluralRulesTest
|
||||
#include "plurfmts.h" // PluralFormatTest
|
||||
#include "dtifmtts.h" // DateIntervalFormatTest
|
||||
#include "tufmtts.h" // TimeUnitTest
|
||||
|
||||
#define TESTCLASS(id, TestClass) \
|
||||
case id: \
|
||||
@ -119,6 +120,7 @@ void IntlTestFormat::runIndexedTest( int32_t index, UBool exec, const char* &nam
|
||||
TESTCLASS(35,PluralRulesTest);
|
||||
TESTCLASS(36,PluralFormatTest);
|
||||
TESTCLASS(37,DateIntervalFormatTest);
|
||||
TESTCLASS(38,TimeUnitTest);
|
||||
|
||||
default: name = ""; break; //needed to end loop
|
||||
}
|
||||
|
205
icu4c/source/test/intltest/tufmtts.cpp
Normal file
205
icu4c/source/test/intltest/tufmtts.cpp
Normal file
@ -0,0 +1,205 @@
|
||||
/********************************************************************
|
||||
* Copyright (c) 2008, International Business Machines Corporation and
|
||||
* others. All Rights Reserved.
|
||||
********************************************************************/
|
||||
|
||||
#include "unicode/utypes.h"
|
||||
|
||||
#if !UCONFIG_NO_FORMATTING
|
||||
|
||||
#include "unicode/tmunit.h"
|
||||
#include "unicode/tmutamt.h"
|
||||
#include "unicode/tmutfmt.h"
|
||||
#include "tufmtts.h"
|
||||
|
||||
|
||||
//FIXME
|
||||
//#define TUFMTTS_DEBUG 1
|
||||
|
||||
#ifdef TUFMTTS_DEBUG
|
||||
#include <iostream>
|
||||
#endif
|
||||
|
||||
void TimeUnitTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ ) {
|
||||
if (exec) logln("TestSuite TimeUnitTest");
|
||||
switch (index) {
|
||||
TESTCASE(0, testBasic);
|
||||
TESTCASE(1, testAPI);
|
||||
default: name = ""; break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test basic
|
||||
*/
|
||||
void TimeUnitTest::testBasic() {
|
||||
const char* locales[] = {"en", "sl", "fr", "zh", "ar", "ru", "zh_Hant"};
|
||||
for ( unsigned int locIndex = 0;
|
||||
locIndex < sizeof(locales)/sizeof(locales[0]);
|
||||
++locIndex ) {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
Locale loc(locales[locIndex]);
|
||||
TimeUnitFormat** formats = new TimeUnitFormat*[2];
|
||||
formats[TimeUnitFormat::kFull] = new TimeUnitFormat(loc, status);
|
||||
if (!assertSuccess("TimeUnitFormat(full)", status)) return;
|
||||
formats[TimeUnitFormat::kAbbreviate] = new TimeUnitFormat(loc, TimeUnitFormat::kAbbreviate, status);
|
||||
if (!assertSuccess("TimeUnitFormat(short)", status)) return;
|
||||
#ifdef TUFMTTS_DEBUG
|
||||
std::cout << "locale: " << locales[locIndex] << "\n";
|
||||
#endif
|
||||
for (int style = TimeUnitFormat::kFull;
|
||||
style <= TimeUnitFormat::kAbbreviate;
|
||||
++style) {
|
||||
for (TimeUnit::UTimeUnitFields j = TimeUnit::UTIMEUNIT_YEAR;
|
||||
j < TimeUnit::UTIMEUNIT_FIELD_COUNT;
|
||||
j = (TimeUnit::UTimeUnitFields)(j+1)) {
|
||||
#ifdef TUFMTTS_DEBUG
|
||||
std::cout << "time unit: " << j << "\n";
|
||||
#endif
|
||||
double tests[] = {0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 5, 10, 100, 101.35};
|
||||
for (unsigned int i = 0; i < sizeof(tests)/sizeof(tests[0]); ++i) {
|
||||
#ifdef TUFMTTS_DEBUG
|
||||
std::cout << "number: " << tests[i] << "\n";
|
||||
#endif
|
||||
TimeUnitAmount* source = new TimeUnitAmount(tests[i], j, status);
|
||||
if (!assertSuccess("TimeUnitAmount()", status)) return;
|
||||
UnicodeString formatted;
|
||||
Formattable formattable;
|
||||
formattable.adoptObject(source);
|
||||
formatted = ((Format*)formats[style])->format(formattable, formatted, status);
|
||||
if (!assertSuccess("format()", status)) return;
|
||||
#ifdef TUFMTTS_DEBUG
|
||||
char formatResult[1000];
|
||||
formatted.extract(0, formatted.length(), formatResult, "UTF-8");
|
||||
std::cout << "format result: " << formatResult << "\n";
|
||||
#endif
|
||||
Formattable result;
|
||||
((Format*)formats[style])->parseObject(formatted, result, status);
|
||||
if (!assertSuccess("parseObject()", status)) return;
|
||||
if (result != formattable) {
|
||||
dataerrln("No round trip: ");
|
||||
}
|
||||
// other style parsing
|
||||
Formattable result_1;
|
||||
((Format*)formats[1-style])->parseObject(formatted, result_1, status);
|
||||
if (!assertSuccess("parseObject()", status)) return;
|
||||
if (result_1 != formattable) {
|
||||
dataerrln("No round trip: ");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
delete formats[TimeUnitFormat::kFull];
|
||||
delete formats[TimeUnitFormat::kAbbreviate];
|
||||
delete[] formats;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TimeUnitTest::testAPI() {
|
||||
//================= TimeUnit =================
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
|
||||
TimeUnit* tmunit = TimeUnit::createInstance(TimeUnit::UTIMEUNIT_YEAR, status);
|
||||
if (!assertSuccess("TimeUnit::createInstance", status)) return;
|
||||
|
||||
TimeUnit* another = (TimeUnit*)tmunit->clone();
|
||||
TimeUnit third(*tmunit);
|
||||
TimeUnit fourth = third;
|
||||
|
||||
assertTrue("orig and clone are equal", (*tmunit == *another));
|
||||
assertTrue("copied and assigned are equal", (third == fourth));
|
||||
|
||||
TimeUnit* tmunit_m = TimeUnit::createInstance(TimeUnit::UTIMEUNIT_MONTH, status);
|
||||
assertTrue("year != month", (*tmunit != *tmunit_m));
|
||||
|
||||
TimeUnit::UTimeUnitFields field = tmunit_m->getTimeUnitField();
|
||||
assertTrue("field of month time unit is month", (field == TimeUnit::UTIMEUNIT_MONTH));
|
||||
|
||||
delete tmunit;
|
||||
delete another;
|
||||
delete tmunit_m;
|
||||
//
|
||||
//================= TimeUnitAmount =================
|
||||
|
||||
Formattable formattable(2);
|
||||
TimeUnitAmount tma_long(formattable, TimeUnit::UTIMEUNIT_DAY, status);
|
||||
if (!assertSuccess("TimeUnitAmount(formattable...)", status)) return;
|
||||
|
||||
formattable.setDouble(2);
|
||||
TimeUnitAmount tma_double(formattable, TimeUnit::UTIMEUNIT_DAY, status);
|
||||
if (!assertSuccess("TimeUnitAmount(formattable...)", status)) return;
|
||||
|
||||
formattable.setDouble(3);
|
||||
TimeUnitAmount tma_double_3(formattable, TimeUnit::UTIMEUNIT_DAY, status);
|
||||
if (!assertSuccess("TimeUnitAmount(formattable...)", status)) return;
|
||||
|
||||
TimeUnitAmount tma(2, TimeUnit::UTIMEUNIT_DAY, status);
|
||||
if (!assertSuccess("TimeUnitAmount(number...)", status)) return;
|
||||
|
||||
TimeUnitAmount tma_h(2, TimeUnit::UTIMEUNIT_HOUR, status);
|
||||
if (!assertSuccess("TimeUnitAmount(number...)", status)) return;
|
||||
|
||||
TimeUnitAmount second(tma);
|
||||
TimeUnitAmount third_tma = tma;
|
||||
TimeUnitAmount* fourth_tma = (TimeUnitAmount*)tma.clone();
|
||||
|
||||
assertTrue("orig and copy are equal", (second == tma));
|
||||
assertTrue("clone and assigned are equal", (third_tma == *fourth_tma));
|
||||
assertTrue("different if number diff", (tma_double != tma_double_3));
|
||||
assertTrue("different if number type diff", (tma_double != tma_long));
|
||||
assertTrue("different if time unit diff", (tma != tma_h));
|
||||
assertTrue("same even different constructor", (tma_double == tma));
|
||||
|
||||
assertTrue("getTimeUnitField", (tma.getTimeUnitField() == TimeUnit::UTIMEUNIT_DAY));
|
||||
delete fourth_tma;
|
||||
//
|
||||
//================= TimeUnitFormat =================
|
||||
//
|
||||
TimeUnitFormat* tmf_en = new TimeUnitFormat(Locale("en"), status);
|
||||
if (!assertSuccess("TimeUnitFormat(en...)", status)) return;
|
||||
TimeUnitFormat tmf_fr(Locale("fr"), status);
|
||||
if (!assertSuccess("TimeUnitFormat(fr...)", status)) return;
|
||||
|
||||
assertTrue("TimeUnitFormat: en and fr diff", (*tmf_en != tmf_fr));
|
||||
|
||||
TimeUnitFormat tmf_assign = *tmf_en;
|
||||
assertTrue("TimeUnitFormat: orig and assign are equal", (*tmf_en == tmf_assign));
|
||||
|
||||
TimeUnitFormat tmf_copy(tmf_fr);
|
||||
assertTrue("TimeUnitFormat: orig and copy are equal", (tmf_fr == tmf_copy));
|
||||
|
||||
TimeUnitFormat* tmf_clone = (TimeUnitFormat*)tmf_en->clone();
|
||||
assertTrue("TimeUnitFormat: orig and clone are equal", (*tmf_en == *tmf_clone));
|
||||
delete tmf_clone;
|
||||
|
||||
tmf_en->setLocale(Locale("fr"), status);
|
||||
if (!assertSuccess("setLocale(fr...)", status)) return;
|
||||
|
||||
NumberFormat* numberFmt = NumberFormat::createInstance(
|
||||
Locale("fr"), status);
|
||||
if (!assertSuccess("NumberFormat::createInstance()", status)) return;
|
||||
tmf_en->setNumberFormat(*numberFmt, status);
|
||||
if (!assertSuccess("setNumberFormat(en...)", status)) return;
|
||||
assertTrue("TimeUnitFormat: setLocale", (*tmf_en == tmf_fr));
|
||||
|
||||
delete tmf_en;
|
||||
|
||||
TimeUnitFormat* en_long = new TimeUnitFormat(Locale("en"), TimeUnitFormat::kFull, status);
|
||||
if (!assertSuccess("TimeUnitFormat(en...)", status)) return;
|
||||
delete en_long;
|
||||
|
||||
TimeUnitFormat* en_short = new TimeUnitFormat(Locale("en"), TimeUnitFormat::kAbbreviate, status);
|
||||
if (!assertSuccess("TimeUnitFormat(en...)", status)) return;
|
||||
delete en_short;
|
||||
|
||||
TimeUnitFormat* format = new TimeUnitFormat(status);
|
||||
format->setLocale(Locale("zh"), status);
|
||||
format->setNumberFormat(*numberFmt, status);
|
||||
if (!assertSuccess("TimeUnitFormat(en...)", status)) return;
|
||||
delete numberFmt;
|
||||
delete format;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
37
icu4c/source/test/intltest/tufmtts.h
Normal file
37
icu4c/source/test/intltest/tufmtts.h
Normal file
@ -0,0 +1,37 @@
|
||||
/********************************************************************
|
||||
* COPYRIGHT:
|
||||
* Copyright (c) 2008, International Business Machines Corporation and
|
||||
* others. All Rights Reserved.
|
||||
********************************************************************/
|
||||
|
||||
#ifndef __INTLTESTTIMEUNITTEST__
|
||||
#define __INTLTESTTIMEUNITTEST__
|
||||
|
||||
|
||||
#if !UCONFIG_NO_FORMATTING
|
||||
|
||||
#include "unicode/utypes.h"
|
||||
#include "unicode/locid.h"
|
||||
#include "intltest.h"
|
||||
|
||||
/**
|
||||
* Test basic functionality of various API functions
|
||||
**/
|
||||
class TimeUnitTest: public IntlTest {
|
||||
void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
|
||||
|
||||
public:
|
||||
/**
|
||||
* Performs basic tests
|
||||
**/
|
||||
void testBasic();
|
||||
|
||||
/**
|
||||
* Performs API tests
|
||||
**/
|
||||
void testAPI();
|
||||
};
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user