mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-07 06:25:30 +00:00
ICU-10461 Make NumberFormat::createInstance() and PluralRules::forLocale() 10X faster than before for most common types. Provide internal createSharedInstance() for NumberFormat and SharedFormat for internal use that is 2 orders of magnitude faster than before.
X-SVN-Rev: 35114
This commit is contained in:
parent
eb26b21238
commit
53ababf5a7
16 changed files with 735 additions and 338 deletions
2
.gitattributes
vendored
2
.gitattributes
vendored
|
@ -80,6 +80,8 @@ 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/i18n/sharednumberformat.h -text
|
||||
icu4c/source/i18n/sharedpluralrules.h -text
|
||||
icu4c/source/io/io.vcxproj -text
|
||||
icu4c/source/io/io.vcxproj.filters -text
|
||||
icu4c/source/layout/layout.vcxproj -text
|
||||
|
|
|
@ -1115,6 +1115,8 @@
|
|||
</CustomBuild>
|
||||
<ClInclude Include="plurrule_impl.h" />
|
||||
<ClInclude Include="quantityformatter.h" />
|
||||
<ClInclude Include="sharednumberformat.h" />
|
||||
<ClInclude Include="sharedpluralrules.h" />
|
||||
<CustomBuild Include="unicode\rbnf.h">
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
|
||||
</Command>
|
||||
|
|
|
@ -644,6 +644,12 @@
|
|||
<ClInclude Include="reldtfmt.h">
|
||||
<Filter>formatting</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="sharednumberformat.h">
|
||||
<Filter>formatting</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="sharedpluralrules.h">
|
||||
<Filter>formatting</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="smpdtfst.h">
|
||||
<Filter>formatting</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
@ -30,10 +30,12 @@
|
|||
#include "unicode/putil.h"
|
||||
#include "unicode/smpdtfmt.h"
|
||||
|
||||
#include "sharedptr.h"
|
||||
#include "sharednumberformat.h"
|
||||
#include "sharedpluralrules.h"
|
||||
|
||||
#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
|
||||
#define MEAS_UNIT_COUNT 46
|
||||
#define WIDTH_INDEX_COUNT (UMEASFMT_WIDTH_NARROW + 1)
|
||||
|
||||
static icu::LRUCache *gCache = NULL;
|
||||
static UMutex gCacheMutex = U_MUTEX_INITIALIZER;
|
||||
|
@ -52,20 +54,20 @@ U_CDECL_END
|
|||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
// Used to format durations like 5:47 or 21:35:42.
|
||||
class NumericDateFormatters : public UMemory {
|
||||
public:
|
||||
// Formats like H:mm
|
||||
SimpleDateFormat hourMinute;
|
||||
|
||||
// formats like M:ss
|
||||
SimpleDateFormat minuteSecond;
|
||||
|
||||
// formats like H:mm:ss
|
||||
SimpleDateFormat hourMinuteSecond;
|
||||
|
||||
// Constructor that takes the actual patterns for hour-minute,
|
||||
// minute-second, and hour-minute-second respectively.
|
||||
NumericDateFormatters(
|
||||
const UnicodeString &hm,
|
||||
const UnicodeString &ms,
|
||||
|
@ -84,24 +86,51 @@ private:
|
|||
NumericDateFormatters &operator=(const NumericDateFormatters &other);
|
||||
};
|
||||
|
||||
class MeasureFormatData : public SharedObject {
|
||||
// Instances contain all MeasureFormat specific data for a particular locale.
|
||||
// This data is cached. It is never copied, but is shared via shared pointers.
|
||||
class MeasureFormatCacheData : public SharedObject {
|
||||
public:
|
||||
SharedPtr<UnitFormatters> unitFormatters;
|
||||
SharedPtr<PluralRules> pluralRules;
|
||||
SharedPtr<NumberFormat> numberFormat;
|
||||
SharedPtr<NumberFormat> currencyFormats[UMEASFMT_WIDTH_NARROW + 1];
|
||||
SharedPtr<NumericDateFormatters> numericDateFormatters;
|
||||
virtual ~MeasureFormatData();
|
||||
QuantityFormatter formatters[MEAS_UNIT_COUNT][WIDTH_INDEX_COUNT];
|
||||
MeasureFormatCacheData();
|
||||
void adoptCurrencyFormat(int32_t widthIndex, NumberFormat *nfToAdopt) {
|
||||
delete currencyFormats[widthIndex];
|
||||
currencyFormats[widthIndex] = nfToAdopt;
|
||||
}
|
||||
const NumberFormat *getCurrencyFormat(int32_t widthIndex) const {
|
||||
return currencyFormats[widthIndex];
|
||||
}
|
||||
void adoptNumericDateFormatters(NumericDateFormatters *formattersToAdopt) {
|
||||
delete numericDateFormatters;
|
||||
numericDateFormatters = formattersToAdopt;
|
||||
}
|
||||
const NumericDateFormatters *getNumericDateFormatters() const {
|
||||
return numericDateFormatters;
|
||||
}
|
||||
virtual ~MeasureFormatCacheData();
|
||||
private:
|
||||
MeasureFormatData &operator=(const MeasureFormatData& other);
|
||||
NumberFormat *currencyFormats[WIDTH_INDEX_COUNT];
|
||||
NumericDateFormatters *numericDateFormatters;
|
||||
MeasureFormatCacheData(const MeasureFormatCacheData &other);
|
||||
MeasureFormatCacheData &operator=(const MeasureFormatCacheData &other);
|
||||
};
|
||||
|
||||
MeasureFormatData::~MeasureFormatData() {
|
||||
MeasureFormatCacheData::MeasureFormatCacheData() {
|
||||
for (int32_t i = 0; i < LENGTHOF(currencyFormats); ++i) {
|
||||
currencyFormats[i] = NULL;
|
||||
}
|
||||
numericDateFormatters = NULL;
|
||||
}
|
||||
|
||||
MeasureFormatCacheData::~MeasureFormatCacheData() {
|
||||
for (int32_t i = 0; i < LENGTHOF(currencyFormats); ++i) {
|
||||
delete currencyFormats[i];
|
||||
}
|
||||
delete numericDateFormatters;
|
||||
}
|
||||
|
||||
static int32_t widthToIndex(UMeasureFormatWidth width) {
|
||||
if (width > UMEASFMT_WIDTH_NARROW) {
|
||||
return UMEASFMT_WIDTH_NARROW;
|
||||
if (width >= WIDTH_INDEX_COUNT) {
|
||||
return WIDTH_INDEX_COUNT - 1;
|
||||
}
|
||||
return width;
|
||||
}
|
||||
|
@ -124,9 +153,9 @@ static UBool getString(
|
|||
}
|
||||
|
||||
|
||||
static UBool load(
|
||||
static UBool loadMeasureUnitData(
|
||||
const UResourceBundle *resource,
|
||||
UnitFormatters &unitFormatters,
|
||||
MeasureFormatCacheData &cacheData,
|
||||
UErrorCode &status) {
|
||||
if (U_FAILURE(status)) {
|
||||
return FALSE;
|
||||
|
@ -144,7 +173,7 @@ static UBool load(
|
|||
}
|
||||
unitCount = MeasureUnit::getAvailable(units, unitCount, status);
|
||||
}
|
||||
for (int32_t currentWidth = 0; currentWidth <= UMEASFMT_WIDTH_NARROW; ++currentWidth) {
|
||||
for (int32_t currentWidth = 0; currentWidth < WIDTH_INDEX_COUNT; ++currentWidth) {
|
||||
// Be sure status is clear since next resource bundle lookup may fail.
|
||||
if (U_FAILURE(status)) {
|
||||
delete [] units;
|
||||
|
@ -198,7 +227,7 @@ static UBool load(
|
|||
}
|
||||
UnicodeString rawPattern;
|
||||
getString(pluralBundle.getAlias(), rawPattern, status);
|
||||
unitFormatters.formatters[units[currentUnit].getIndex()][currentWidth].add(
|
||||
cacheData.formatters[units[currentUnit].getIndex()][currentWidth].add(
|
||||
ures_getKey(pluralBundle.getAlias()),
|
||||
rawPattern,
|
||||
status);
|
||||
|
@ -260,6 +289,7 @@ static NumericDateFormatters *loadNumericDateFormatters(
|
|||
return result;
|
||||
}
|
||||
|
||||
// Creates the MeasureFormatCacheData for a particular locale
|
||||
static SharedObject *U_CALLCONV createData(
|
||||
const char *localeId, UErrorCode &status) {
|
||||
LocalUResourceBundlePointer topLevel(ures_open(NULL, localeId, &status));
|
||||
|
@ -268,66 +298,30 @@ static SharedObject *U_CALLCONV createData(
|
|||
if (U_FAILURE(status)) {
|
||||
return NULL;
|
||||
}
|
||||
LocalPointer<MeasureFormatData> result(new MeasureFormatData());
|
||||
LocalPointer<UnitFormatters> unitFormatters(new UnitFormatters());
|
||||
if (result.getAlias() == NULL
|
||||
|| unitFormatters.getAlias() == NULL) {
|
||||
LocalPointer<MeasureFormatCacheData> result(new MeasureFormatCacheData());
|
||||
if (result.getAlias() == NULL) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
if (!load(
|
||||
if (!loadMeasureUnitData(
|
||||
topLevel.getAlias(),
|
||||
*unitFormatters,
|
||||
*result,
|
||||
status)) {
|
||||
return NULL;
|
||||
}
|
||||
if (!result->unitFormatters.reset(unitFormatters.orphan())) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LocalPointer<NumericDateFormatters> ndf(
|
||||
loadNumericDateFormatters(topLevel.getAlias(), status));
|
||||
result->adoptNumericDateFormatters(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));
|
||||
for (int32_t i = 0; i < WIDTH_INDEX_COUNT; ++i) {
|
||||
result->adoptCurrencyFormat(i, 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();
|
||||
}
|
||||
|
||||
|
@ -342,16 +336,17 @@ static void U_CALLCONV cacheInit(UErrorCode &status) {
|
|||
}
|
||||
}
|
||||
|
||||
static void getFromCache(
|
||||
static UBool getFromCache(
|
||||
const char *locale,
|
||||
const MeasureFormatData *&ptr,
|
||||
const MeasureFormatCacheData *&ptr,
|
||||
UErrorCode &status) {
|
||||
umtx_initOnce(gCacheInitOnce, &cacheInit, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
return FALSE;
|
||||
}
|
||||
Mutex lock(&gCacheMutex);
|
||||
gCache->get(locale, ptr, status);
|
||||
return U_SUCCESS(status);
|
||||
}
|
||||
|
||||
static int32_t toHMS(
|
||||
|
@ -405,8 +400,12 @@ static int32_t toHMS(
|
|||
|
||||
MeasureFormat::MeasureFormat(
|
||||
const Locale &locale, UMeasureFormatWidth w, UErrorCode &status)
|
||||
: ptr(NULL), width(w) {
|
||||
initMeasureFormat(locale, w, status);
|
||||
: cache(NULL),
|
||||
numberFormat(NULL),
|
||||
pluralRules(NULL),
|
||||
width(w),
|
||||
listFormatter(NULL) {
|
||||
initMeasureFormat(locale, w, NULL, status);
|
||||
}
|
||||
|
||||
MeasureFormat::MeasureFormat(
|
||||
|
@ -414,14 +413,25 @@ MeasureFormat::MeasureFormat(
|
|||
UMeasureFormatWidth w,
|
||||
NumberFormat *nfToAdopt,
|
||||
UErrorCode &status)
|
||||
: ptr(NULL), width(w) {
|
||||
initMeasureFormat(locale, w, status);
|
||||
adoptNumberFormat(nfToAdopt, status);
|
||||
: cache(NULL),
|
||||
numberFormat(NULL),
|
||||
pluralRules(NULL),
|
||||
width(w),
|
||||
listFormatter(NULL) {
|
||||
initMeasureFormat(locale, w, nfToAdopt, status);
|
||||
}
|
||||
|
||||
MeasureFormat::MeasureFormat(const MeasureFormat &other)
|
||||
: Format(other), ptr(other.ptr), width(other.width) {
|
||||
ptr->addRef();
|
||||
MeasureFormat::MeasureFormat(const MeasureFormat &other) :
|
||||
Format(other),
|
||||
cache(other.cache),
|
||||
numberFormat(other.numberFormat),
|
||||
pluralRules(other.pluralRules),
|
||||
width(other.width),
|
||||
listFormatter(NULL) {
|
||||
cache->addRef();
|
||||
numberFormat->addRef();
|
||||
pluralRules->addRef();
|
||||
listFormatter = new ListFormatter(*other.listFormatter);
|
||||
}
|
||||
|
||||
MeasureFormat &MeasureFormat::operator=(const MeasureFormat &other) {
|
||||
|
@ -429,18 +439,34 @@ MeasureFormat &MeasureFormat::operator=(const MeasureFormat &other) {
|
|||
return *this;
|
||||
}
|
||||
Format::operator=(other);
|
||||
SharedObject::copyPtr(other.ptr, ptr);
|
||||
SharedObject::copyPtr(other.cache, cache);
|
||||
SharedObject::copyPtr(other.numberFormat, numberFormat);
|
||||
SharedObject::copyPtr(other.pluralRules, pluralRules);
|
||||
width = other.width;
|
||||
delete listFormatter;
|
||||
listFormatter = new ListFormatter(*other.listFormatter);
|
||||
return *this;
|
||||
}
|
||||
|
||||
MeasureFormat::MeasureFormat() : ptr(NULL), width(UMEASFMT_WIDTH_WIDE) {
|
||||
MeasureFormat::MeasureFormat() :
|
||||
cache(NULL),
|
||||
numberFormat(NULL),
|
||||
pluralRules(NULL),
|
||||
width(UMEASFMT_WIDTH_WIDE),
|
||||
listFormatter(NULL) {
|
||||
}
|
||||
|
||||
MeasureFormat::~MeasureFormat() {
|
||||
if (ptr != NULL) {
|
||||
ptr->removeRef();
|
||||
if (cache != NULL) {
|
||||
cache->removeRef();
|
||||
}
|
||||
if (numberFormat != NULL) {
|
||||
numberFormat->removeRef();
|
||||
}
|
||||
if (pluralRules != NULL) {
|
||||
pluralRules->removeRef();
|
||||
}
|
||||
delete listFormatter;
|
||||
}
|
||||
|
||||
UBool MeasureFormat::operator==(const Format &other) const {
|
||||
|
@ -448,6 +474,10 @@ UBool MeasureFormat::operator==(const Format &other) const {
|
|||
if (rhs == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Note: Since the ListFormatter depends only on Locale and width, we
|
||||
// don't have to check it here.
|
||||
|
||||
// Same objects are equivalent
|
||||
if (this == rhs) {
|
||||
return TRUE;
|
||||
|
@ -456,21 +486,24 @@ UBool MeasureFormat::operator==(const Format &other) const {
|
|||
if (width != rhs->width) {
|
||||
return FALSE;
|
||||
}
|
||||
// Width the same, same shared data -> equivlanet
|
||||
if (ptr == rhs->ptr) {
|
||||
return TRUE;
|
||||
// Width the same check locales.
|
||||
// We don't need to check locales if both objects have same cache.
|
||||
if (cache != rhs->cache) {
|
||||
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;
|
||||
}
|
||||
if (uprv_strcmp(localeId, rhsLocaleId) != 0) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
// 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);
|
||||
// Locales same, check NumberFormat if shared data differs.
|
||||
return (
|
||||
numberFormat == rhs->numberFormat ||
|
||||
**numberFormat == **rhs->numberFormat);
|
||||
}
|
||||
|
||||
Format *MeasureFormat::clone() const {
|
||||
|
@ -507,7 +540,6 @@ UnicodeString &MeasureFormat::formatMeasures(
|
|||
UnicodeString &appendTo,
|
||||
FieldPosition &pos,
|
||||
UErrorCode &status) const {
|
||||
static const char *listStyles[] = {"unit", "unit-short", "unit-narrow"};
|
||||
if (U_FAILURE(status)) {
|
||||
return appendTo;
|
||||
}
|
||||
|
@ -524,17 +556,9 @@ UnicodeString &MeasureFormat::formatMeasures(
|
|||
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);
|
||||
measures, measureCount, appendTo, pos, status);
|
||||
}
|
||||
UnicodeString *results = new UnicodeString[measureCount];
|
||||
if (results == NULL) {
|
||||
|
@ -544,51 +568,86 @@ UnicodeString &MeasureFormat::formatMeasures(
|
|||
for (int32_t i = 0; i < measureCount; ++i) {
|
||||
formatMeasure(measures[i], results[i], pos, status);
|
||||
}
|
||||
lf->format(results, measureCount, appendTo, status);
|
||||
listFormatter->format(results, measureCount, appendTo, status);
|
||||
delete [] results;
|
||||
return appendTo;
|
||||
}
|
||||
|
||||
void MeasureFormat::initMeasureFormat(
|
||||
const Locale &locale, UMeasureFormatWidth w, UErrorCode &status) {
|
||||
const Locale &locale,
|
||||
UMeasureFormatWidth w,
|
||||
NumberFormat *nfToAdopt,
|
||||
UErrorCode &status) {
|
||||
static const char *listStyles[] = {"unit", "unit-short", "unit-narrow"};
|
||||
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 (!getFromCache(name, cache, status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
SharedObject::copyPtr(
|
||||
PluralRules::createSharedInstance(
|
||||
locale, UPLURAL_TYPE_CARDINAL, status),
|
||||
pluralRules);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
MeasureFormatData* wptr = SharedObject::copyOnWrite(ptr);
|
||||
if (wptr == NULL) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
pluralRules->removeRef();
|
||||
if (nfToAdopt == NULL) {
|
||||
SharedObject::copyPtr(
|
||||
NumberFormat::createSharedInstance(
|
||||
locale, UNUM_DECIMAL, status),
|
||||
numberFormat);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
numberFormat->removeRef();
|
||||
} else {
|
||||
adoptNumberFormat(nfToAdopt, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
width = w;
|
||||
delete listFormatter;
|
||||
listFormatter = ListFormatter::createInstance(
|
||||
locale,
|
||||
listStyles[widthToIndex(width)],
|
||||
status);
|
||||
}
|
||||
|
||||
void MeasureFormat::adoptNumberFormat(
|
||||
NumberFormat *nfToAdopt, UErrorCode &status) {
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
if (!wptr->numberFormat.reset(nfToAdopt)) {
|
||||
SharedNumberFormat *shared = new SharedNumberFormat(nfToAdopt);
|
||||
if (shared == NULL) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
delete nfToAdopt;
|
||||
return;
|
||||
}
|
||||
SharedObject::copyPtr(shared, numberFormat);
|
||||
}
|
||||
|
||||
UBool MeasureFormat::setMeasureFormatLocale(const Locale &locale, UErrorCode &status) {
|
||||
if (U_FAILURE(status) || locale == getLocale(status)) {
|
||||
return FALSE;
|
||||
}
|
||||
initMeasureFormat(locale, width, status);
|
||||
initMeasureFormat(locale, width, NULL, status);
|
||||
return U_SUCCESS(status);
|
||||
}
|
||||
|
||||
const NumberFormat &MeasureFormat::getNumberFormat() const {
|
||||
return *ptr->numberFormat;
|
||||
return **numberFormat;
|
||||
}
|
||||
|
||||
const PluralRules &MeasureFormat::getPluralRules() const {
|
||||
return *ptr->pluralRules;
|
||||
return **pluralRules;
|
||||
}
|
||||
|
||||
Locale MeasureFormat::getLocale(UErrorCode &status) const {
|
||||
|
@ -612,7 +671,7 @@ UnicodeString &MeasureFormat::formatMeasure(
|
|||
if (isCurrency(amtUnit)) {
|
||||
UChar isoCode[4];
|
||||
u_charsToUChars(amtUnit.getSubtype(), isoCode, 4);
|
||||
return ptr->currencyFormats[widthToIndex(width)]->format(
|
||||
return cache->getCurrencyFormat(widthToIndex(width))->format(
|
||||
new CurrencyAmount(amtNumber, isoCode, status),
|
||||
appendTo,
|
||||
pos,
|
||||
|
@ -625,8 +684,9 @@ UnicodeString &MeasureFormat::formatMeasure(
|
|||
}
|
||||
return quantityFormatter->format(
|
||||
amtNumber,
|
||||
*ptr->numberFormat,
|
||||
*ptr->pluralRules, appendTo,
|
||||
**numberFormat,
|
||||
**pluralRules,
|
||||
appendTo,
|
||||
pos,
|
||||
status);
|
||||
}
|
||||
|
@ -648,7 +708,7 @@ UnicodeString &MeasureFormat::formatNumeric(
|
|||
case 7: // hms
|
||||
return formatNumeric(
|
||||
millis,
|
||||
ptr->numericDateFormatters->hourMinuteSecond,
|
||||
cache->getNumericDateFormatters()->hourMinuteSecond,
|
||||
UDAT_SECOND_FIELD,
|
||||
hms[2],
|
||||
appendTo,
|
||||
|
@ -657,7 +717,7 @@ UnicodeString &MeasureFormat::formatNumeric(
|
|||
case 6: // ms
|
||||
return formatNumeric(
|
||||
millis,
|
||||
ptr->numericDateFormatters->minuteSecond,
|
||||
cache->getNumericDateFormatters()->minuteSecond,
|
||||
UDAT_SECOND_FIELD,
|
||||
hms[2],
|
||||
appendTo,
|
||||
|
@ -666,7 +726,7 @@ UnicodeString &MeasureFormat::formatNumeric(
|
|||
case 3: // hm
|
||||
return formatNumeric(
|
||||
millis,
|
||||
ptr->numericDateFormatters->hourMinute,
|
||||
cache->getNumericDateFormatters()->hourMinute,
|
||||
UDAT_MINUTE_FIELD,
|
||||
hms[1],
|
||||
appendTo,
|
||||
|
@ -691,7 +751,7 @@ UnicodeString &MeasureFormat::formatNumeric(
|
|||
return appendTo;
|
||||
}
|
||||
UnicodeString smallestAmountFormatted;
|
||||
ptr->numberFormat->format(
|
||||
(*numberFormat)->format(
|
||||
smallestAmount, smallestAmountFormatted, status);
|
||||
FieldPosition smallestFieldPosition(smallestField);
|
||||
UnicodeString draft;
|
||||
|
@ -718,7 +778,7 @@ const QuantityFormatter *MeasureFormat::getQuantityFormatter(
|
|||
return NULL;
|
||||
}
|
||||
const QuantityFormatter *formatters =
|
||||
ptr->unitFormatters->formatters[index];
|
||||
cache->formatters[index];
|
||||
if (formatters[widthIndex].isValid()) {
|
||||
return &formatters[widthIndex];
|
||||
}
|
||||
|
@ -735,7 +795,6 @@ const QuantityFormatter *MeasureFormat::getQuantityFormatter(
|
|||
UnicodeString &MeasureFormat::formatMeasuresSlowTrack(
|
||||
const Measure *measures,
|
||||
int32_t measureCount,
|
||||
const ListFormatter& lf,
|
||||
UnicodeString& appendTo,
|
||||
FieldPosition& pos,
|
||||
UErrorCode& status) const {
|
||||
|
@ -761,7 +820,7 @@ UnicodeString &MeasureFormat::formatMeasuresSlowTrack(
|
|||
}
|
||||
}
|
||||
int32_t offset;
|
||||
lf.format(
|
||||
listFormatter->format(
|
||||
results,
|
||||
measureCount,
|
||||
appendTo,
|
||||
|
|
|
@ -51,6 +51,8 @@
|
|||
#include "mutex.h"
|
||||
#include "digitlst.h"
|
||||
#include <float.h>
|
||||
#include "sharednumberformat.h"
|
||||
#include "lrucache.h"
|
||||
|
||||
//#define FMT_DEBUG
|
||||
|
||||
|
@ -139,6 +141,10 @@ static const char *gFormatKeys[UNUM_FORMAT_STYLE_COUNT] = {
|
|||
"currencyFormat" // UNUM_CURRENCY_PLURAL
|
||||
};
|
||||
|
||||
static icu::LRUCache *gNumberFormatCache = NULL;
|
||||
static UMutex gNumberFormatCacheMutex = U_MUTEX_INITIALIZER;
|
||||
static icu::UInitOnce gNumberFormatCacheInitOnce = U_INITONCE_INITIALIZER;
|
||||
|
||||
// Static hashtable cache of NumberingSystem objects used by NumberFormat
|
||||
static UHashtable * NumberingSystem_cache = NULL;
|
||||
static UMutex nscacheMutex = U_MUTEX_INITIALIZER;
|
||||
|
@ -172,7 +178,11 @@ static UBool U_CALLCONV numfmt_cleanup(void) {
|
|||
uhash_close(NumberingSystem_cache);
|
||||
NumberingSystem_cache = NULL;
|
||||
}
|
||||
|
||||
gNumberFormatCacheInitOnce.reset();
|
||||
if (gNumberFormatCache) {
|
||||
delete gNumberFormatCache;
|
||||
gNumberFormatCache = NULL;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
U_CDECL_END
|
||||
|
@ -234,6 +244,10 @@ NumberFormat::~NumberFormat()
|
|||
{
|
||||
}
|
||||
|
||||
SharedNumberFormat::~SharedNumberFormat() {
|
||||
delete ptr;
|
||||
}
|
||||
|
||||
// -------------------------------------
|
||||
// copy constructor
|
||||
|
||||
|
@ -1008,8 +1022,8 @@ NumberFormat::getAvailableLocales(void)
|
|||
#endif /* UCONFIG_NO_SERVICE */
|
||||
// -------------------------------------
|
||||
|
||||
NumberFormat* U_EXPORT2
|
||||
NumberFormat::createInstance(const Locale& loc, UNumberFormatStyle kind, UErrorCode& status) {
|
||||
NumberFormat*
|
||||
NumberFormat::internalCreateInstance(const Locale& loc, UNumberFormatStyle kind, UErrorCode& status) {
|
||||
#if !UCONFIG_NO_SERVICE
|
||||
if (haveService()) {
|
||||
return (NumberFormat*)gService->get(loc, kind, status);
|
||||
|
@ -1018,6 +1032,23 @@ NumberFormat::createInstance(const Locale& loc, UNumberFormatStyle kind, UErrorC
|
|||
return makeInstance(loc, kind, status);
|
||||
}
|
||||
|
||||
NumberFormat* U_EXPORT2
|
||||
NumberFormat::createInstance(const Locale& loc, UNumberFormatStyle kind, UErrorCode& status) {
|
||||
if (kind != UNUM_DECIMAL) {
|
||||
return internalCreateInstance(loc, kind, status);
|
||||
}
|
||||
const SharedNumberFormat *shared = createSharedInstance(loc, kind, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return NULL;
|
||||
}
|
||||
NumberFormat *result = (NumberFormat *) (*shared)->clone();
|
||||
shared->removeRef();
|
||||
if (result == NULL) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------
|
||||
// Checks if the thousand/10 thousand grouping is used in the
|
||||
|
@ -1205,6 +1236,61 @@ static void U_CALLCONV nscacheInit() {
|
|||
uhash_setValueDeleter(NumberingSystem_cache, deleteNumberingSystem);
|
||||
}
|
||||
|
||||
static SharedObject *U_CALLCONV createSharedNumberFormat(
|
||||
const char *localeId, UErrorCode &status) {
|
||||
if (U_FAILURE(status)) {
|
||||
return NULL;
|
||||
}
|
||||
NumberFormat *nf = NumberFormat::internalCreateInstance(
|
||||
localeId, UNUM_DECIMAL, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return NULL;
|
||||
}
|
||||
SharedObject *result = new SharedNumberFormat(nf);
|
||||
if (result == NULL) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
delete nf;
|
||||
return NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void U_CALLCONV numberFormatCacheInit(UErrorCode &status) {
|
||||
U_ASSERT(gNumberFormatCache == NULL);
|
||||
ucln_i18n_registerCleanup(UCLN_I18N_NUMFMT, numfmt_cleanup);
|
||||
gNumberFormatCache = new SimpleLRUCache(100, &createSharedNumberFormat, status);
|
||||
if (U_FAILURE(status)) {
|
||||
delete gNumberFormatCache;
|
||||
gNumberFormatCache = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void getSharedNumberFormatFromCache(
|
||||
const char *locale,
|
||||
const SharedNumberFormat *&ptr,
|
||||
UErrorCode &status) {
|
||||
umtx_initOnce(gNumberFormatCacheInitOnce, &numberFormatCacheInit, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
Mutex lock(&gNumberFormatCacheMutex);
|
||||
gNumberFormatCache->get(locale, ptr, status);
|
||||
}
|
||||
|
||||
const SharedNumberFormat* U_EXPORT2
|
||||
NumberFormat::createSharedInstance(const Locale& loc, UNumberFormatStyle kind, UErrorCode& status) {
|
||||
if (U_FAILURE(status)) {
|
||||
return NULL;
|
||||
}
|
||||
if (kind != UNUM_DECIMAL) {
|
||||
status = U_UNSUPPORTED_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
const SharedNumberFormat *result = NULL;
|
||||
getSharedNumberFormatFromCache(loc.getName(), result, status);
|
||||
return result;
|
||||
}
|
||||
|
||||
UBool
|
||||
NumberFormat::isStyleSupported(UNumberFormatStyle style) {
|
||||
return gLastResortNumberPatterns[style] != NULL;
|
||||
|
|
|
@ -29,9 +29,26 @@
|
|||
#include "ustrfmt.h"
|
||||
#include "uassert.h"
|
||||
#include "uvectr32.h"
|
||||
#include "sharedpluralrules.h"
|
||||
#include "lrucache.h"
|
||||
|
||||
#if !UCONFIG_NO_FORMATTING
|
||||
|
||||
static icu::LRUCache *gPluralRulesCache = NULL;
|
||||
static UMutex gPluralRulesCacheMutex = U_MUTEX_INITIALIZER;
|
||||
static icu::UInitOnce gPluralRulesCacheInitOnce = U_INITONCE_INITIALIZER;
|
||||
|
||||
U_CDECL_BEGIN
|
||||
static UBool U_CALLCONV plurrules_cleanup(void) {
|
||||
gPluralRulesCacheInitOnce.reset();
|
||||
if (gPluralRulesCache) {
|
||||
delete gPluralRulesCache;
|
||||
gPluralRulesCache = NULL;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
U_CDECL_END
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
#define ARRAY_SIZE(array) (int32_t)(sizeof array / sizeof array[0])
|
||||
|
@ -73,6 +90,10 @@ PluralRules::~PluralRules() {
|
|||
delete mRules;
|
||||
}
|
||||
|
||||
SharedPluralRules::~SharedPluralRules() {
|
||||
delete ptr;
|
||||
}
|
||||
|
||||
PluralRules*
|
||||
PluralRules::clone() const {
|
||||
return new PluralRules(*this);
|
||||
|
@ -131,6 +152,71 @@ PluralRules::createDefaultRules(UErrorCode& status) {
|
|||
return createRules(UnicodeString(TRUE, PLURAL_DEFAULT_RULE, -1), status);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* Create PluralRules cache */
|
||||
|
||||
static SharedObject *U_CALLCONV createSharedPluralRules(
|
||||
const char *localeId, UErrorCode &status) {
|
||||
if (U_FAILURE(status)) {
|
||||
return NULL;
|
||||
}
|
||||
PluralRules *pr = PluralRules::internalForLocale(
|
||||
localeId, UPLURAL_TYPE_CARDINAL, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return NULL;
|
||||
}
|
||||
SharedObject *result = new SharedPluralRules(pr);
|
||||
if (result == NULL) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
delete pr;
|
||||
return NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void U_CALLCONV pluralRulesCacheInit(UErrorCode &status) {
|
||||
U_ASSERT(gPluralRulesCache == NULL);
|
||||
ucln_i18n_registerCleanup(UCLN_I18N_PLURAL_RULE, plurrules_cleanup);
|
||||
gPluralRulesCache = new SimpleLRUCache(100, &createSharedPluralRules, status);
|
||||
if (U_FAILURE(status)) {
|
||||
delete gPluralRulesCache;
|
||||
gPluralRulesCache = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void getSharedPluralRulesFromCache(
|
||||
const char *locale,
|
||||
const SharedPluralRules *&ptr,
|
||||
UErrorCode &status) {
|
||||
umtx_initOnce(gPluralRulesCacheInitOnce, &pluralRulesCacheInit, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
Mutex lock(&gPluralRulesCacheMutex);
|
||||
gPluralRulesCache->get(locale, ptr, status);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* end plural rules cache */
|
||||
/******************************************************************************/
|
||||
|
||||
const SharedPluralRules* U_EXPORT2
|
||||
PluralRules::createSharedInstance(
|
||||
const Locale& locale, UPluralType type, UErrorCode& status) {
|
||||
if (U_FAILURE(status)) {
|
||||
return NULL;
|
||||
}
|
||||
if (type != UPLURAL_TYPE_CARDINAL) {
|
||||
status = U_UNSUPPORTED_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
const SharedPluralRules *result = NULL;
|
||||
getSharedPluralRulesFromCache(locale.getName(), result, status);
|
||||
return result;
|
||||
}
|
||||
|
||||
PluralRules* U_EXPORT2
|
||||
PluralRules::forLocale(const Locale& locale, UErrorCode& status) {
|
||||
return forLocale(locale, UPLURAL_TYPE_CARDINAL, status);
|
||||
|
@ -138,6 +224,24 @@ PluralRules::forLocale(const Locale& locale, UErrorCode& status) {
|
|||
|
||||
PluralRules* U_EXPORT2
|
||||
PluralRules::forLocale(const Locale& locale, UPluralType type, UErrorCode& status) {
|
||||
if (type != UPLURAL_TYPE_CARDINAL) {
|
||||
return internalForLocale(locale, type, status);
|
||||
}
|
||||
const SharedPluralRules *shared = createSharedInstance(
|
||||
locale, type, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return NULL;
|
||||
}
|
||||
PluralRules *result = (*shared)->clone();
|
||||
shared->removeRef();
|
||||
if (result == NULL) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
PluralRules* U_EXPORT2
|
||||
PluralRules::internalForLocale(const Locale& locale, UPluralType type, UErrorCode& status) {
|
||||
if (U_FAILURE(status)) {
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
#include "charstr.h"
|
||||
|
||||
#include "sharedptr.h"
|
||||
#include "sharedpluralrules.h"
|
||||
#include "sharednumberformat.h"
|
||||
|
||||
// Copied from uscript_props.cpp
|
||||
#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
|
||||
|
@ -48,37 +50,35 @@ U_CDECL_END
|
|||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
class QualitativeUnits : public UMemory {
|
||||
// RelativeDateTimeFormatter specific data for a single locale
|
||||
class RelativeDateTimeCacheData: public SharedObject {
|
||||
public:
|
||||
QualitativeUnits() { }
|
||||
UnicodeString data[UDAT_ABSOLUTE_UNIT_COUNT][UDAT_DIRECTION_COUNT];
|
||||
RelativeDateTimeCacheData() : combinedDateAndTime(NULL) { }
|
||||
virtual ~RelativeDateTimeCacheData();
|
||||
|
||||
// no numbers: e.g Next Tuesday; Yesterday; etc.
|
||||
UnicodeString absoluteUnits[UDAT_ABSOLUTE_UNIT_COUNT][UDAT_DIRECTION_COUNT];
|
||||
|
||||
// has numbers: e.g Next Tuesday; Yesterday; etc. For second index, 0
|
||||
// means past e.g 5 days ago; 1 means future e.g in 5 days.
|
||||
QuantityFormatter relativeUnits[UDAT_RELATIVE_UNIT_COUNT][2];
|
||||
|
||||
void adoptCombinedDateAndTime(MessageFormat *mfToAdopt) {
|
||||
delete combinedDateAndTime;
|
||||
combinedDateAndTime = mfToAdopt;
|
||||
}
|
||||
const MessageFormat *getCombinedDateAndTime() const {
|
||||
return combinedDateAndTime;
|
||||
}
|
||||
private:
|
||||
QualitativeUnits(const QualitativeUnits &other);
|
||||
QualitativeUnits &operator=(const QualitativeUnits& other);
|
||||
MessageFormat *combinedDateAndTime;
|
||||
RelativeDateTimeCacheData(const RelativeDateTimeCacheData &other);
|
||||
RelativeDateTimeCacheData& operator=(
|
||||
const RelativeDateTimeCacheData &other);
|
||||
};
|
||||
|
||||
class QuantitativeUnits : public UMemory {
|
||||
public:
|
||||
QuantitativeUnits() { }
|
||||
QuantityFormatter data[UDAT_RELATIVE_UNIT_COUNT][2];
|
||||
private:
|
||||
QuantitativeUnits(const QuantitativeUnits &other);
|
||||
QuantitativeUnits &operator=(const QuantitativeUnits& other);
|
||||
};
|
||||
|
||||
class RelativeDateTimeData : public SharedObject {
|
||||
public:
|
||||
SharedPtr<QualitativeUnits> qualitativeUnits;
|
||||
SharedPtr<QuantitativeUnits> quantitativeUnits;
|
||||
SharedPtr<MessageFormat> combinedDateAndTime;
|
||||
SharedPtr<PluralRules> pluralRules;
|
||||
SharedPtr<NumberFormat> numberFormat;
|
||||
virtual ~RelativeDateTimeData();
|
||||
private:
|
||||
RelativeDateTimeData &operator=(const RelativeDateTimeData& other);
|
||||
};
|
||||
|
||||
RelativeDateTimeData::~RelativeDateTimeData() {
|
||||
RelativeDateTimeCacheData::~RelativeDateTimeCacheData() {
|
||||
delete combinedDateAndTime;
|
||||
}
|
||||
|
||||
static UBool getStringWithFallback(
|
||||
|
@ -147,45 +147,42 @@ static UBool getStringByIndex(
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static void addQualitativeUnit(
|
||||
static void initAbsoluteUnit(
|
||||
const UResourceBundle *resource,
|
||||
UDateAbsoluteUnit absoluteUnit,
|
||||
const UnicodeString &unitName,
|
||||
QualitativeUnits &qualitativeUnits,
|
||||
UnicodeString *absoluteUnit,
|
||||
UErrorCode &status) {
|
||||
getStringWithFallback(
|
||||
resource,
|
||||
"-1",
|
||||
qualitativeUnits.data[absoluteUnit][UDAT_DIRECTION_LAST],
|
||||
absoluteUnit[UDAT_DIRECTION_LAST],
|
||||
status);
|
||||
getStringWithFallback(
|
||||
resource,
|
||||
"0",
|
||||
qualitativeUnits.data[absoluteUnit][UDAT_DIRECTION_THIS],
|
||||
absoluteUnit[UDAT_DIRECTION_THIS],
|
||||
status);
|
||||
getStringWithFallback(
|
||||
resource,
|
||||
"1",
|
||||
qualitativeUnits.data[absoluteUnit][UDAT_DIRECTION_NEXT],
|
||||
absoluteUnit[UDAT_DIRECTION_NEXT],
|
||||
status);
|
||||
getOptionalStringWithFallback(
|
||||
resource,
|
||||
"-2",
|
||||
qualitativeUnits.data[absoluteUnit][UDAT_DIRECTION_LAST_2],
|
||||
absoluteUnit[UDAT_DIRECTION_LAST_2],
|
||||
status);
|
||||
getOptionalStringWithFallback(
|
||||
resource,
|
||||
"2",
|
||||
qualitativeUnits.data[absoluteUnit][UDAT_DIRECTION_NEXT_2],
|
||||
absoluteUnit[UDAT_DIRECTION_NEXT_2],
|
||||
status);
|
||||
qualitativeUnits.data[absoluteUnit][UDAT_DIRECTION_PLAIN] = unitName;
|
||||
absoluteUnit[UDAT_DIRECTION_PLAIN] = unitName;
|
||||
}
|
||||
|
||||
static void addTimeUnit(
|
||||
static void initQuantityFormatter(
|
||||
const UResourceBundle *resource,
|
||||
UDateRelativeUnit relativeUnit,
|
||||
int32_t pastOrFuture,
|
||||
QuantitativeUnits &quantitativeUnits,
|
||||
QuantityFormatter &formatter,
|
||||
UErrorCode &status) {
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
|
@ -201,20 +198,18 @@ static void addTimeUnit(
|
|||
if (!getString(pluralBundle.getAlias(), rawPattern, status)) {
|
||||
return;
|
||||
}
|
||||
if (!quantitativeUnits.data[relativeUnit][pastOrFuture]
|
||||
.add(
|
||||
ures_getKey(pluralBundle.getAlias()),
|
||||
rawPattern,
|
||||
status)) {
|
||||
if (!formatter.add(
|
||||
ures_getKey(pluralBundle.getAlias()),
|
||||
rawPattern,
|
||||
status)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void addTimeUnit(
|
||||
static void initRelativeUnit(
|
||||
const UResourceBundle *resource,
|
||||
UDateRelativeUnit relativeUnit,
|
||||
QuantitativeUnits &quantitativeUnits,
|
||||
QuantityFormatter *relativeUnit,
|
||||
UErrorCode &status) {
|
||||
LocalUResourceBundlePointer topLevel(
|
||||
ures_getByKeyWithFallback(
|
||||
|
@ -227,53 +222,46 @@ static void addTimeUnit(
|
|||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
addTimeUnit(
|
||||
initQuantityFormatter(
|
||||
futureBundle.getAlias(),
|
||||
relativeUnit,
|
||||
1,
|
||||
quantitativeUnits,
|
||||
relativeUnit[1],
|
||||
status);
|
||||
LocalUResourceBundlePointer pastBundle(ures_getByKeyWithFallback(
|
||||
topLevel.getAlias(), "past", NULL, &status));
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
addTimeUnit(
|
||||
initQuantityFormatter(
|
||||
pastBundle.getAlias(),
|
||||
relativeUnit,
|
||||
0,
|
||||
quantitativeUnits,
|
||||
relativeUnit[0],
|
||||
status);
|
||||
}
|
||||
|
||||
static void addTimeUnit(
|
||||
static void initRelativeUnit(
|
||||
const UResourceBundle *resource,
|
||||
const char *path,
|
||||
UDateRelativeUnit relativeUnit,
|
||||
QuantitativeUnits &quantitativeUnits,
|
||||
QuantityFormatter *relativeUnit,
|
||||
UErrorCode &status) {
|
||||
LocalUResourceBundlePointer topLevel(
|
||||
ures_getByKeyWithFallback(resource, path, NULL, &status));
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
addTimeUnit(topLevel.getAlias(), relativeUnit, quantitativeUnits, status);
|
||||
initRelativeUnit(topLevel.getAlias(), relativeUnit, status);
|
||||
}
|
||||
|
||||
static void addTimeUnit(
|
||||
const UResourceBundle *resource,
|
||||
const char *path,
|
||||
UDateRelativeUnit relativeUnit,
|
||||
UDateAbsoluteUnit absoluteUnit,
|
||||
QuantitativeUnits &quantitativeUnits,
|
||||
QualitativeUnits &qualitativeUnits,
|
||||
QuantityFormatter *relativeUnit,
|
||||
UnicodeString *absoluteUnit,
|
||||
UErrorCode &status) {
|
||||
LocalUResourceBundlePointer topLevel(
|
||||
ures_getByKeyWithFallback(resource, path, NULL, &status));
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
addTimeUnit(topLevel.getAlias(), relativeUnit, quantitativeUnits, status);
|
||||
initRelativeUnit(topLevel.getAlias(), relativeUnit, status);
|
||||
UnicodeString unitName;
|
||||
if (!getStringWithFallback(topLevel.getAlias(), "dn", unitName, status)) {
|
||||
return;
|
||||
|
@ -294,11 +282,10 @@ static void addTimeUnit(
|
|||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
addQualitativeUnit(
|
||||
initAbsoluteUnit(
|
||||
topLevel.getAlias(),
|
||||
absoluteUnit,
|
||||
unitName,
|
||||
qualitativeUnits,
|
||||
absoluteUnit,
|
||||
status);
|
||||
}
|
||||
|
||||
|
@ -329,80 +316,67 @@ static void addWeekDay(
|
|||
const char *path,
|
||||
const UnicodeString *daysOfWeek,
|
||||
UDateAbsoluteUnit absoluteUnit,
|
||||
QualitativeUnits &qualitativeUnits,
|
||||
UnicodeString absoluteUnits[][UDAT_DIRECTION_COUNT],
|
||||
UErrorCode &status) {
|
||||
LocalUResourceBundlePointer topLevel(
|
||||
ures_getByKeyWithFallback(resource, path, NULL, &status));
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
addQualitativeUnit(
|
||||
initAbsoluteUnit(
|
||||
topLevel.getAlias(),
|
||||
absoluteUnit,
|
||||
daysOfWeek[absoluteUnit - UDAT_ABSOLUTE_SUNDAY],
|
||||
qualitativeUnits,
|
||||
absoluteUnits[absoluteUnit],
|
||||
status);
|
||||
}
|
||||
|
||||
static UBool load(
|
||||
static UBool loadUnitData(
|
||||
const UResourceBundle *resource,
|
||||
QualitativeUnits &qualitativeUnits,
|
||||
QuantitativeUnits &quantitativeUnits,
|
||||
RelativeDateTimeCacheData &cacheData,
|
||||
UErrorCode &status) {
|
||||
addTimeUnit(
|
||||
resource,
|
||||
"fields/day",
|
||||
UDAT_RELATIVE_DAYS,
|
||||
UDAT_ABSOLUTE_DAY,
|
||||
quantitativeUnits,
|
||||
qualitativeUnits,
|
||||
cacheData.relativeUnits[UDAT_RELATIVE_DAYS],
|
||||
cacheData.absoluteUnits[UDAT_ABSOLUTE_DAY],
|
||||
status);
|
||||
addTimeUnit(
|
||||
resource,
|
||||
"fields/week",
|
||||
UDAT_RELATIVE_WEEKS,
|
||||
UDAT_ABSOLUTE_WEEK,
|
||||
quantitativeUnits,
|
||||
qualitativeUnits,
|
||||
cacheData.relativeUnits[UDAT_RELATIVE_WEEKS],
|
||||
cacheData.absoluteUnits[UDAT_ABSOLUTE_WEEK],
|
||||
status);
|
||||
addTimeUnit(
|
||||
resource,
|
||||
"fields/month",
|
||||
UDAT_RELATIVE_MONTHS,
|
||||
UDAT_ABSOLUTE_MONTH,
|
||||
quantitativeUnits,
|
||||
qualitativeUnits,
|
||||
cacheData.relativeUnits[UDAT_RELATIVE_MONTHS],
|
||||
cacheData.absoluteUnits[UDAT_ABSOLUTE_MONTH],
|
||||
status);
|
||||
addTimeUnit(
|
||||
resource,
|
||||
"fields/year",
|
||||
UDAT_RELATIVE_YEARS,
|
||||
UDAT_ABSOLUTE_YEAR,
|
||||
quantitativeUnits,
|
||||
qualitativeUnits,
|
||||
cacheData.relativeUnits[UDAT_RELATIVE_YEARS],
|
||||
cacheData.absoluteUnits[UDAT_ABSOLUTE_YEAR],
|
||||
status);
|
||||
addTimeUnit(
|
||||
initRelativeUnit(
|
||||
resource,
|
||||
"fields/second",
|
||||
UDAT_RELATIVE_SECONDS,
|
||||
quantitativeUnits,
|
||||
cacheData.relativeUnits[UDAT_RELATIVE_SECONDS],
|
||||
status);
|
||||
addTimeUnit(
|
||||
initRelativeUnit(
|
||||
resource,
|
||||
"fields/minute",
|
||||
UDAT_RELATIVE_MINUTES,
|
||||
quantitativeUnits,
|
||||
cacheData.relativeUnits[UDAT_RELATIVE_MINUTES],
|
||||
status);
|
||||
addTimeUnit(
|
||||
initRelativeUnit(
|
||||
resource,
|
||||
"fields/hour",
|
||||
UDAT_RELATIVE_HOURS,
|
||||
quantitativeUnits,
|
||||
cacheData.relativeUnits[UDAT_RELATIVE_HOURS],
|
||||
status);
|
||||
getStringWithFallback(
|
||||
resource,
|
||||
"fields/second/relative/0",
|
||||
qualitativeUnits.data[UDAT_ABSOLUTE_NOW][UDAT_DIRECTION_PLAIN],
|
||||
cacheData.absoluteUnits[UDAT_ABSOLUTE_NOW][UDAT_DIRECTION_PLAIN],
|
||||
status);
|
||||
UnicodeString daysOfWeek[7];
|
||||
readDaysOfWeek(
|
||||
|
@ -415,49 +389,49 @@ static UBool load(
|
|||
"fields/mon/relative",
|
||||
daysOfWeek,
|
||||
UDAT_ABSOLUTE_MONDAY,
|
||||
qualitativeUnits,
|
||||
cacheData.absoluteUnits,
|
||||
status);
|
||||
addWeekDay(
|
||||
resource,
|
||||
"fields/tue/relative",
|
||||
daysOfWeek,
|
||||
UDAT_ABSOLUTE_TUESDAY,
|
||||
qualitativeUnits,
|
||||
cacheData.absoluteUnits,
|
||||
status);
|
||||
addWeekDay(
|
||||
resource,
|
||||
"fields/wed/relative",
|
||||
daysOfWeek,
|
||||
UDAT_ABSOLUTE_WEDNESDAY,
|
||||
qualitativeUnits,
|
||||
cacheData.absoluteUnits,
|
||||
status);
|
||||
addWeekDay(
|
||||
resource,
|
||||
"fields/thu/relative",
|
||||
daysOfWeek,
|
||||
UDAT_ABSOLUTE_THURSDAY,
|
||||
qualitativeUnits,
|
||||
cacheData.absoluteUnits,
|
||||
status);
|
||||
addWeekDay(
|
||||
resource,
|
||||
"fields/fri/relative",
|
||||
daysOfWeek,
|
||||
UDAT_ABSOLUTE_FRIDAY,
|
||||
qualitativeUnits,
|
||||
cacheData.absoluteUnits,
|
||||
status);
|
||||
addWeekDay(
|
||||
resource,
|
||||
"fields/sat/relative",
|
||||
daysOfWeek,
|
||||
UDAT_ABSOLUTE_SATURDAY,
|
||||
qualitativeUnits,
|
||||
cacheData.absoluteUnits,
|
||||
status);
|
||||
addWeekDay(
|
||||
resource,
|
||||
"fields/sun/relative",
|
||||
daysOfWeek,
|
||||
UDAT_ABSOLUTE_SUNDAY,
|
||||
qualitativeUnits,
|
||||
cacheData.absoluteUnits,
|
||||
status);
|
||||
return U_SUCCESS(status);
|
||||
}
|
||||
|
@ -494,72 +468,34 @@ static UBool getDateTimePattern(
|
|||
return getStringByIndex(topLevel.getAlias(), 8, result, status);
|
||||
}
|
||||
|
||||
// Creates RelativeDateTimeFormatter specific data for a given locale
|
||||
static SharedObject *U_CALLCONV createData(
|
||||
const char *localeId, UErrorCode &status) {
|
||||
LocalUResourceBundlePointer topLevel(ures_open(NULL, localeId, &status));
|
||||
if (U_FAILURE(status)) {
|
||||
return NULL;
|
||||
}
|
||||
LocalPointer<RelativeDateTimeData> result(new RelativeDateTimeData());
|
||||
LocalPointer<QualitativeUnits> qualitativeUnits(new QualitativeUnits());
|
||||
LocalPointer<QuantitativeUnits> quantitativeUnits(new QuantitativeUnits());
|
||||
if (result.getAlias() == NULL
|
||||
|| qualitativeUnits.getAlias() == NULL
|
||||
|| quantitativeUnits.getAlias() == NULL) {
|
||||
LocalPointer<RelativeDateTimeCacheData> result(
|
||||
new RelativeDateTimeCacheData());
|
||||
if (result.getAlias() == NULL) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
if (!load(
|
||||
if (!loadUnitData(
|
||||
topLevel.getAlias(),
|
||||
*qualitativeUnits,
|
||||
*quantitativeUnits,
|
||||
*result,
|
||||
status)) {
|
||||
return NULL;
|
||||
}
|
||||
if (!result->qualitativeUnits.reset(qualitativeUnits.orphan())) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
if (!result->quantitativeUnits.reset(quantitativeUnits.orphan())) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
UnicodeString dateTimePattern;
|
||||
if (!getDateTimePattern(topLevel.getAlias(), dateTimePattern, status)) {
|
||||
return NULL;
|
||||
}
|
||||
LocalPointer<MessageFormat> mf(
|
||||
result->adoptCombinedDateAndTime(
|
||||
new MessageFormat(dateTimePattern, localeId, status));
|
||||
if (U_FAILURE(status)) {
|
||||
return NULL;
|
||||
}
|
||||
if (mf.getAlias() == NULL) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
if (!result->combinedDateAndTime.reset(mf.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;
|
||||
}
|
||||
return result.orphan();
|
||||
}
|
||||
|
||||
|
@ -573,67 +509,70 @@ static void U_CALLCONV cacheInit(UErrorCode &status) {
|
|||
}
|
||||
}
|
||||
|
||||
static void getFromCache(
|
||||
static UBool getFromCache(
|
||||
const char *locale,
|
||||
const RelativeDateTimeData *&ptr,
|
||||
const RelativeDateTimeCacheData *&ptr,
|
||||
UErrorCode &status) {
|
||||
umtx_initOnce(gCacheInitOnce, &cacheInit, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
return FALSE;
|
||||
}
|
||||
Mutex lock(&gCacheMutex);
|
||||
gCache->get(locale, ptr, status);
|
||||
return U_SUCCESS(status);
|
||||
}
|
||||
|
||||
RelativeDateTimeFormatter::RelativeDateTimeFormatter(UErrorCode& status)
|
||||
: ptr(NULL) {
|
||||
getFromCache(Locale::getDefault().getName(), ptr, status);
|
||||
: cache(NULL), numberFormat(NULL), pluralRules(NULL) {
|
||||
init(Locale::getDefault(), NULL, status);
|
||||
}
|
||||
|
||||
RelativeDateTimeFormatter::RelativeDateTimeFormatter(
|
||||
const Locale& locale, UErrorCode& status) : ptr(NULL) {
|
||||
getFromCache(locale.getName(), ptr, status);
|
||||
const Locale& locale, UErrorCode& status)
|
||||
: cache(NULL), numberFormat(NULL), pluralRules(NULL) {
|
||||
init(locale, NULL, status);
|
||||
}
|
||||
|
||||
RelativeDateTimeFormatter::RelativeDateTimeFormatter(
|
||||
const Locale& locale, NumberFormat *nfToAdopt, UErrorCode& status)
|
||||
: ptr(NULL) {
|
||||
getFromCache(locale.getName(), ptr, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
RelativeDateTimeData* wptr = SharedObject::copyOnWrite(ptr);
|
||||
if (wptr == NULL) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
return;
|
||||
}
|
||||
if (!wptr->numberFormat.reset(nfToAdopt)) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
return;
|
||||
}
|
||||
: cache(NULL), numberFormat(NULL), pluralRules(NULL) {
|
||||
init(locale, nfToAdopt, status);
|
||||
}
|
||||
|
||||
RelativeDateTimeFormatter::RelativeDateTimeFormatter(
|
||||
const RelativeDateTimeFormatter& other) : ptr(other.ptr) {
|
||||
ptr->addRef();
|
||||
const RelativeDateTimeFormatter& other)
|
||||
: cache(other.cache),
|
||||
numberFormat(other.numberFormat),
|
||||
pluralRules(other.pluralRules) {
|
||||
cache->addRef();
|
||||
numberFormat->addRef();
|
||||
pluralRules->addRef();
|
||||
}
|
||||
|
||||
RelativeDateTimeFormatter& RelativeDateTimeFormatter::operator=(
|
||||
const RelativeDateTimeFormatter& other) {
|
||||
if (this != &other) {
|
||||
SharedObject::copyPtr(other.ptr, ptr);
|
||||
SharedObject::copyPtr(other.cache, cache);
|
||||
SharedObject::copyPtr(other.numberFormat, numberFormat);
|
||||
SharedObject::copyPtr(other.pluralRules, pluralRules);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
RelativeDateTimeFormatter::~RelativeDateTimeFormatter() {
|
||||
if (ptr != NULL) {
|
||||
ptr->removeRef();
|
||||
if (cache != NULL) {
|
||||
cache->removeRef();
|
||||
}
|
||||
if (numberFormat != NULL) {
|
||||
numberFormat->removeRef();
|
||||
}
|
||||
if (pluralRules != NULL) {
|
||||
pluralRules->removeRef();
|
||||
}
|
||||
}
|
||||
|
||||
const NumberFormat& RelativeDateTimeFormatter::getNumberFormat() const {
|
||||
return *ptr->numberFormat;
|
||||
return **numberFormat;
|
||||
}
|
||||
|
||||
UnicodeString& RelativeDateTimeFormatter::format(
|
||||
|
@ -648,10 +587,10 @@ UnicodeString& RelativeDateTimeFormatter::format(
|
|||
}
|
||||
int32_t bFuture = direction == UDAT_DIRECTION_NEXT ? 1 : 0;
|
||||
FieldPosition pos(FieldPosition::DONT_CARE);
|
||||
return ptr->quantitativeUnits->data[unit][bFuture].format(
|
||||
return cache->relativeUnits[unit][bFuture].format(
|
||||
quantity,
|
||||
*ptr->numberFormat,
|
||||
*ptr->pluralRules,
|
||||
**numberFormat,
|
||||
**pluralRules,
|
||||
appendTo,
|
||||
pos,
|
||||
status);
|
||||
|
@ -667,7 +606,7 @@ UnicodeString& RelativeDateTimeFormatter::format(
|
|||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return appendTo;
|
||||
}
|
||||
return appendTo.append(ptr->qualitativeUnits->data[unit][direction]);
|
||||
return appendTo.append(cache->absoluteUnits[unit][direction]);
|
||||
}
|
||||
|
||||
UnicodeString& RelativeDateTimeFormatter::combineDateAndTime(
|
||||
|
@ -675,9 +614,44 @@ UnicodeString& RelativeDateTimeFormatter::combineDateAndTime(
|
|||
UnicodeString& appendTo, UErrorCode& status) const {
|
||||
Formattable args[2] = {timeString, relativeDateString};
|
||||
FieldPosition fpos(0);
|
||||
return ptr->combinedDateAndTime->format(args, 2, appendTo, fpos, status);
|
||||
return cache->getCombinedDateAndTime()->format(
|
||||
args, 2, appendTo, fpos, status);
|
||||
}
|
||||
|
||||
void RelativeDateTimeFormatter::init(
|
||||
const Locale &locale, NumberFormat *nfToAdopt, UErrorCode &status) {
|
||||
if (!getFromCache(locale.getName(), cache, status)) {
|
||||
return;
|
||||
}
|
||||
SharedObject::copyPtr(
|
||||
PluralRules::createSharedInstance(
|
||||
locale, UPLURAL_TYPE_CARDINAL, status),
|
||||
pluralRules);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
pluralRules->removeRef();
|
||||
if (nfToAdopt == NULL) {
|
||||
SharedObject::copyPtr(
|
||||
NumberFormat::createSharedInstance(
|
||||
locale, UNUM_DECIMAL, status),
|
||||
numberFormat);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
numberFormat->removeRef();
|
||||
} else {
|
||||
SharedNumberFormat *shared = new SharedNumberFormat(nfToAdopt);
|
||||
if (shared == NULL) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
delete nfToAdopt;
|
||||
return;
|
||||
}
|
||||
SharedObject::copyPtr(shared, numberFormat);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
||||
#endif /* !UCONFIG_NO_FORMATTING */
|
||||
|
|
34
icu4c/source/i18n/sharednumberformat.h
Normal file
34
icu4c/source/i18n/sharednumberformat.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
******************************************************************************
|
||||
* Copyright (C) 2014, International Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
******************************************************************************
|
||||
* sharednumberformat.h
|
||||
*/
|
||||
|
||||
#ifndef __SHARED_NUMBERFORMAT_H__
|
||||
#define __SHARED_NUMBERFORMAT_H__
|
||||
|
||||
#include "unicode/utypes.h"
|
||||
#include "sharedobject.h"
|
||||
#include "sharedptr.h"
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
class NumberFormat;
|
||||
|
||||
class U_I18N_API SharedNumberFormat : public SharedObject {
|
||||
public:
|
||||
SharedNumberFormat(NumberFormat *nfToAdopt) : ptr(nfToAdopt) { }
|
||||
virtual ~SharedNumberFormat();
|
||||
const NumberFormat *operator->() const { return ptr; }
|
||||
const NumberFormat &operator*() const { return *ptr; }
|
||||
private:
|
||||
NumberFormat *ptr;
|
||||
SharedNumberFormat(const SharedNumberFormat &);
|
||||
SharedNumberFormat &operator=(const SharedNumberFormat &);
|
||||
};
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
||||
#endif
|
34
icu4c/source/i18n/sharedpluralrules.h
Normal file
34
icu4c/source/i18n/sharedpluralrules.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
******************************************************************************
|
||||
* Copyright (C) 2014, International Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
******************************************************************************
|
||||
* sharedpluralrules.h
|
||||
*/
|
||||
|
||||
#ifndef __SHARED_PLURALRULES_H__
|
||||
#define __SHARED_PLURALRULES_H__
|
||||
|
||||
#include "unicode/utypes.h"
|
||||
#include "sharedobject.h"
|
||||
#include "sharedptr.h"
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
class PluralRules;
|
||||
|
||||
class U_I18N_API SharedPluralRules : public SharedObject {
|
||||
public:
|
||||
SharedPluralRules(PluralRules *prToAdopt) : ptr(prToAdopt) { }
|
||||
virtual ~SharedPluralRules();
|
||||
const PluralRules *operator->() const { return ptr; }
|
||||
const PluralRules &operator*() const { return *ptr; }
|
||||
private:
|
||||
PluralRules *ptr;
|
||||
SharedPluralRules(const SharedPluralRules &);
|
||||
SharedPluralRules &operator=(const SharedPluralRules &);
|
||||
};
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
||||
#endif
|
|
@ -79,13 +79,13 @@ 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) {
|
||||
initMeasureFormat(Locale::getDefault(), UMEASFMT_WIDTH_WIDE, status);
|
||||
initMeasureFormat(Locale::getDefault(), UMEASFMT_WIDTH_WIDE, NULL, status);
|
||||
create(UTMUTFMT_FULL_STYLE, status);
|
||||
}
|
||||
|
||||
|
||||
TimeUnitFormat::TimeUnitFormat(const Locale& locale, UErrorCode& status) {
|
||||
initMeasureFormat(locale, UMEASFMT_WIDTH_WIDE, status);
|
||||
initMeasureFormat(locale, UMEASFMT_WIDTH_WIDE, NULL, status);
|
||||
create(UTMUTFMT_FULL_STYLE, status);
|
||||
}
|
||||
|
||||
|
@ -93,13 +93,13 @@ TimeUnitFormat::TimeUnitFormat(const Locale& locale, UErrorCode& status) {
|
|||
TimeUnitFormat::TimeUnitFormat(const Locale& locale, UTimeUnitFormatStyle style, UErrorCode& status) {
|
||||
switch (style) {
|
||||
case UTMUTFMT_FULL_STYLE:
|
||||
initMeasureFormat(locale, UMEASFMT_WIDTH_WIDE, status);
|
||||
initMeasureFormat(locale, UMEASFMT_WIDTH_WIDE, NULL, status);
|
||||
break;
|
||||
case UTMUTFMT_ABBREVIATED_STYLE:
|
||||
initMeasureFormat(locale, UMEASFMT_WIDTH_SHORT, status);
|
||||
initMeasureFormat(locale, UMEASFMT_WIDTH_SHORT, NULL, status);
|
||||
break;
|
||||
default:
|
||||
initMeasureFormat(locale, UMEASFMT_WIDTH_WIDE, status);
|
||||
initMeasureFormat(locale, UMEASFMT_WIDTH_WIDE, NULL, status);
|
||||
break;
|
||||
}
|
||||
create(style, status);
|
||||
|
|
|
@ -72,7 +72,9 @@ U_NAMESPACE_BEGIN
|
|||
|
||||
class NumberFormat;
|
||||
class PluralRules;
|
||||
class MeasureFormatData;
|
||||
class MeasureFormatCacheData;
|
||||
class SharedNumberFormat;
|
||||
class SharedPluralRules;
|
||||
class QuantityFormatter;
|
||||
class ListFormatter;
|
||||
class DateFormat;
|
||||
|
@ -208,10 +210,14 @@ class U_I18N_API MeasureFormat : public Format {
|
|||
|
||||
/**
|
||||
* ICU use only.
|
||||
* Initialize MeasureFormat class from base class.
|
||||
* Initialize or change MeasureFormat class from subclass.
|
||||
* @internal.
|
||||
*/
|
||||
void initMeasureFormat(const Locale &locale, UMeasureFormatWidth width, UErrorCode &status);
|
||||
void initMeasureFormat(
|
||||
const Locale &locale,
|
||||
UMeasureFormatWidth width,
|
||||
NumberFormat *nfToAdopt,
|
||||
UErrorCode &status);
|
||||
|
||||
/**
|
||||
* ICU use only.
|
||||
|
@ -256,9 +262,16 @@ class U_I18N_API MeasureFormat : public Format {
|
|||
#endif /* U_HIDE_INTERNAL_API */
|
||||
|
||||
private:
|
||||
const MeasureFormatData *ptr;
|
||||
const MeasureFormatCacheData *cache;
|
||||
const SharedNumberFormat *numberFormat;
|
||||
const SharedPluralRules *pluralRules;
|
||||
UMeasureFormatWidth width;
|
||||
|
||||
// Declared outside of MeasureFormatSharedData because ListFormatter
|
||||
// objects are relatively cheap to copy; therefore, they don't need to be
|
||||
// shared across instances.
|
||||
ListFormatter *listFormatter;
|
||||
|
||||
const QuantityFormatter *getQuantityFormatter(
|
||||
int32_t index,
|
||||
int32_t widthIndex,
|
||||
|
@ -273,14 +286,14 @@ class U_I18N_API MeasureFormat : public Format {
|
|||
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
|
||||
const Formattable *hms, // always length 3: [0] is hour; [1] is
|
||||
// minute; [2] is second.
|
||||
int32_t bitMap, // 1=hour set, 2=minute set, 4=second set
|
||||
UnicodeString &appendTo,
|
||||
UErrorCode &status) const;
|
||||
|
||||
|
|
|
@ -43,6 +43,8 @@ class NumberFormatTest;
|
|||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
class SharedNumberFormat;
|
||||
|
||||
#if !UCONFIG_NO_SERVICE
|
||||
class NumberFormatFactory;
|
||||
class StringEnumeration;
|
||||
|
@ -706,6 +708,30 @@ public:
|
|||
UNumberFormatStyle style,
|
||||
UErrorCode& errorCode);
|
||||
|
||||
#ifndef U_HIDE_INTERNAL_API
|
||||
|
||||
/**
|
||||
* ICU use only.
|
||||
* Creates NumberFormat instance without using the cache.
|
||||
* @internal
|
||||
*/
|
||||
static NumberFormat* internalCreateInstance(
|
||||
const Locale& desiredLocale,
|
||||
UNumberFormatStyle style,
|
||||
UErrorCode& errorCode);
|
||||
|
||||
/**
|
||||
* ICU use only.
|
||||
* Returns handle to the shared, cached NumberFormat instance for given
|
||||
* locale. On success, caller must call removeRef() on returned value
|
||||
* once it is done with the shared instance.
|
||||
* @internal
|
||||
*/
|
||||
static const SharedNumberFormat* U_EXPORT2 createSharedInstance(
|
||||
const Locale& inLocale, UNumberFormatStyle style, UErrorCode& status);
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Returns a currency format for the current default locale.
|
||||
* @stable ICU 2.0
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2008-2013, International Business Machines Corporation and
|
||||
* Copyright (C) 2008-2014, International Business Machines Corporation and
|
||||
* others. All Rights Reserved.
|
||||
*******************************************************************************
|
||||
*
|
||||
|
@ -43,6 +43,7 @@ class RuleChain;
|
|||
class PluralRuleParser;
|
||||
class PluralKeywordEnumeration;
|
||||
class AndConstraint;
|
||||
class SharedPluralRules;
|
||||
|
||||
/**
|
||||
* Defines rules for mapping non-negative numeric values onto a small set of
|
||||
|
@ -297,6 +298,25 @@ public:
|
|||
* @internal
|
||||
*/
|
||||
static UBool hasOverride(const Locale &locale);
|
||||
|
||||
/**
|
||||
* For ICU use only.
|
||||
* creates a SharedPluralRules object
|
||||
* @internal
|
||||
*/
|
||||
static PluralRules* U_EXPORT2 internalForLocale(const Locale& locale, UPluralType type, UErrorCode& status);
|
||||
|
||||
/**
|
||||
* For ICU use only.
|
||||
* Returns handle to the shared, cached PluralRules isntance.
|
||||
* Caller must call removeRef() on returned value once it is done with
|
||||
* the shared instance.
|
||||
* @internal
|
||||
*/
|
||||
static const SharedPluralRules* U_EXPORT2 createSharedInstance(
|
||||
const Locale& locale, UPluralType type, UErrorCode& status);
|
||||
|
||||
|
||||
#endif /* U_HIDE_INTERNAL_API */
|
||||
|
||||
/**
|
||||
|
|
|
@ -221,7 +221,9 @@ typedef enum UDateDirection {
|
|||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
class RelativeDateTimeData;
|
||||
class RelativeDateTimeCacheData;
|
||||
class SharedNumberFormat;
|
||||
class SharedPluralRules;
|
||||
class NumberFormat;
|
||||
|
||||
/**
|
||||
|
@ -407,8 +409,10 @@ public:
|
|||
const NumberFormat& getNumberFormat() const;
|
||||
|
||||
private:
|
||||
RelativeDateTimeFormatter();
|
||||
const RelativeDateTimeData* ptr;
|
||||
const RelativeDateTimeCacheData* cache;
|
||||
const SharedNumberFormat *numberFormat;
|
||||
const SharedPluralRules *pluralRules;
|
||||
void init(const Locale &, NumberFormat *nfToAdopt, UErrorCode &status);
|
||||
};
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
|
|
@ -52,6 +52,7 @@ private:
|
|||
void TestFieldPositionMultiple();
|
||||
void TestBadArg();
|
||||
void TestEquality();
|
||||
void TestBenchmark();
|
||||
void verifyFormat(
|
||||
const char *description,
|
||||
const MeasureFormat &fmt,
|
||||
|
@ -106,6 +107,7 @@ void MeasureFormatTest::runIndexedTest(
|
|||
TESTCASE_AUTO(TestFieldPositionMultiple);
|
||||
TESTCASE_AUTO(TestBadArg);
|
||||
TESTCASE_AUTO(TestEquality);
|
||||
TESTCASE_AUTO(TestBenchmark);
|
||||
TESTCASE_AUTO_END;
|
||||
}
|
||||
|
||||
|
@ -823,6 +825,29 @@ void MeasureFormatTest::TestEquality() {
|
|||
assertTrue("Not Equal 3", fmt != fmtne3);
|
||||
}
|
||||
|
||||
void MeasureFormatTest::TestBenchmark() {
|
||||
/*
|
||||
clock_t t;
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
Locale en("en");
|
||||
MeasureFormat fmt(en, UMEASFMT_WIDTH_SHORT, status);
|
||||
MeasureFormat fmt2 = fmt;
|
||||
Measure ms[] = {
|
||||
Measure(70, MeasureUnit::createYear(status), status),
|
||||
Measure(5, MeasureUnit::createMonth(status), status),
|
||||
Measure(23, MeasureUnit::createDay(status), status),
|
||||
Measure(15, MeasureUnit::createHour(status), status),
|
||||
Measure(58, MeasureUnit::createMinute(status), status)};
|
||||
FieldPosition pos(FieldPosition::DONT_CARE);
|
||||
t = clock();
|
||||
for (int32_t i = 0; i < 1000000; ++i) {
|
||||
fmt2 = fmt;
|
||||
}
|
||||
t = clock() - t;
|
||||
errln("It took %f seconds.", ((float)t)/CLOCKS_PER_SEC);
|
||||
*/
|
||||
}
|
||||
|
||||
void MeasureFormatTest::verifyFieldPosition(
|
||||
const char *description,
|
||||
const MeasureFormat &fmt,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2013, International Business Machines Corporation and *
|
||||
* Copyright (C) 2013-2014, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*
|
||||
|
@ -294,7 +294,15 @@ void RelativeDateTimeFormatterTest::TestCustomNumberFormat() {
|
|||
nf->setMinimumFractionDigits(1);
|
||||
nf->setMaximumFractionDigits(1);
|
||||
RelativeDateTimeFormatter fmt("en", nf, status);
|
||||
RunTest(fmt, kEnglishDecimal, LENGTHOF(kEnglishDecimal), "en decimal digits");
|
||||
|
||||
// Test copy constructor.
|
||||
RelativeDateTimeFormatter fmt2(fmt);
|
||||
RunTest(fmt2, kEnglishDecimal, LENGTHOF(kEnglishDecimal), "en decimal digits");
|
||||
|
||||
// Test assignment
|
||||
fmt = RelativeDateTimeFormatter("es", status);
|
||||
RunTest(fmt, kSpanishNoQuantity, LENGTHOF(kSpanishNoQuantity), "assignment operator");
|
||||
|
||||
}
|
||||
|
||||
void RelativeDateTimeFormatterTest::TestCombineDateAndTime() {
|
||||
|
|
Loading…
Add table
Reference in a new issue