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
</CustomBuild>\r
<ClInclude Include="plurrule_impl.h" />\r
<ClInclude Include="quantityformatter.h" />\r
+ <ClInclude Include="sharednumberformat.h" />\r
+ <ClInclude Include="sharedpluralrules.h" />\r
<CustomBuild Include="unicode\rbnf.h">\r
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode\r
</Command>\r
<ClInclude Include="reldtfmt.h">\r
<Filter>formatting</Filter>\r
</ClInclude>\r
+ <ClInclude Include="sharednumberformat.h">\r
+ <Filter>formatting</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="sharedpluralrules.h">\r
+ <Filter>formatting</Filter>\r
+ </ClInclude>\r
<ClInclude Include="smpdtfst.h">\r
<Filter>formatting</Filter>\r
</ClInclude>\r
#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;
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,
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;
}
}
-static UBool load(
+static UBool loadMeasureUnitData(
const UResourceBundle *resource,
- UnitFormatters &unitFormatters,
+ MeasureFormatCacheData &cacheData,
UErrorCode &status) {
if (U_FAILURE(status)) {
return FALSE;
}
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;
}
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);
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));
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();
}
}
}
-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(
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(
UMeasureFormatWidth w,
NumberFormat *nfToAdopt,
UErrorCode &status)
- : ptr(NULL), width(w) {
- initMeasureFormat(locale, w, status);
- adoptNumberFormat(nfToAdopt, status);
-}
-
-MeasureFormat::MeasureFormat(const MeasureFormat &other)
- : Format(other), ptr(other.ptr), width(other.width) {
- ptr->addRef();
+ : cache(NULL),
+ numberFormat(NULL),
+ pluralRules(NULL),
+ width(w),
+ listFormatter(NULL) {
+ initMeasureFormat(locale, w, nfToAdopt, status);
+}
+
+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) {
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 {
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;
if (width != rhs->width) {
return FALSE;
}
- // Width the same, same shared data -> equivlanet
- if (ptr == rhs->ptr) {
- return TRUE;
- }
- // Width same, but differing shred data. Depends on locale
- // and number format objects being the same.
- UErrorCode status = U_ZERO_ERROR;
- const char *localeId = getLocaleID(status);
- const char *rhsLocaleId = rhs->getLocaleID(status);
- if (U_FAILURE(status)) {
- // On failure, assume not equal
- return FALSE;
+ // 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;
+ }
}
- 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 {
UnicodeString &appendTo,
FieldPosition &pos,
UErrorCode &status) const {
- static const char *listStyles[] = {"unit", "unit-short", "unit-narrow"};
if (U_FAILURE(status)) {
return appendTo;
}
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) {
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 {
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,
}
return quantityFormatter->format(
amtNumber,
- *ptr->numberFormat,
- *ptr->pluralRules, appendTo,
+ **numberFormat,
+ **pluralRules,
+ appendTo,
pos,
status);
}
case 7: // hms
return formatNumeric(
millis,
- ptr->numericDateFormatters->hourMinuteSecond,
+ cache->getNumericDateFormatters()->hourMinuteSecond,
UDAT_SECOND_FIELD,
hms[2],
appendTo,
case 6: // ms
return formatNumeric(
millis,
- ptr->numericDateFormatters->minuteSecond,
+ cache->getNumericDateFormatters()->minuteSecond,
UDAT_SECOND_FIELD,
hms[2],
appendTo,
case 3: // hm
return formatNumeric(
millis,
- ptr->numericDateFormatters->hourMinute,
+ cache->getNumericDateFormatters()->hourMinute,
UDAT_MINUTE_FIELD,
hms[1],
appendTo,
return appendTo;
}
UnicodeString smallestAmountFormatted;
- ptr->numberFormat->format(
+ (*numberFormat)->format(
smallestAmount, smallestAmountFormatted, status);
FieldPosition smallestFieldPosition(smallestField);
UnicodeString draft;
return NULL;
}
const QuantityFormatter *formatters =
- ptr->unitFormatters->formatters[index];
+ cache->formatters[index];
if (formatters[widthIndex].isValid()) {
return &formatters[widthIndex];
}
UnicodeString &MeasureFormat::formatMeasuresSlowTrack(
const Measure *measures,
int32_t measureCount,
- const ListFormatter& lf,
UnicodeString& appendTo,
FieldPosition& pos,
UErrorCode& status) const {
}
}
int32_t offset;
- lf.format(
+ listFormatter->format(
results,
measureCount,
appendTo,
#include "mutex.h"
#include "digitlst.h"
#include <float.h>
+#include "sharednumberformat.h"
+#include "lrucache.h"
//#define FMT_DEBUG
"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;
uhash_close(NumberingSystem_cache);
NumberingSystem_cache = NULL;
}
-
+ gNumberFormatCacheInitOnce.reset();
+ if (gNumberFormatCache) {
+ delete gNumberFormatCache;
+ gNumberFormatCache = NULL;
+ }
return TRUE;
}
U_CDECL_END
{
}
+SharedNumberFormat::~SharedNumberFormat() {
+ delete ptr;
+}
+
// -------------------------------------
// copy constructor
#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);
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
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;
#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])
delete mRules;
}
+SharedPluralRules::~SharedPluralRules() {
+ delete ptr;
+}
+
PluralRules*
PluralRules::clone() const {
return new PluralRules(*this);
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);
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;
}
#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]))
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];
-private:
- QualitativeUnits(const QualitativeUnits &other);
- QualitativeUnits &operator=(const QualitativeUnits& other);
-};
+ RelativeDateTimeCacheData() : combinedDateAndTime(NULL) { }
+ virtual ~RelativeDateTimeCacheData();
-class QuantitativeUnits : public UMemory {
-public:
- QuantitativeUnits() { }
- QuantityFormatter data[UDAT_RELATIVE_UNIT_COUNT][2];
-private:
- QuantitativeUnits(const QuantitativeUnits &other);
- QuantitativeUnits &operator=(const QuantitativeUnits& other);
-};
+ // no numbers: e.g Next Tuesday; Yesterday; etc.
+ UnicodeString absoluteUnits[UDAT_ABSOLUTE_UNIT_COUNT][UDAT_DIRECTION_COUNT];
-class RelativeDateTimeData : public SharedObject {
-public:
- SharedPtr<QualitativeUnits> qualitativeUnits;
- SharedPtr<QuantitativeUnits> quantitativeUnits;
- SharedPtr<MessageFormat> combinedDateAndTime;
- SharedPtr<PluralRules> pluralRules;
- SharedPtr<NumberFormat> numberFormat;
- virtual ~RelativeDateTimeData();
+ // 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:
- RelativeDateTimeData &operator=(const RelativeDateTimeData& other);
+ MessageFormat *combinedDateAndTime;
+ RelativeDateTimeCacheData(const RelativeDateTimeCacheData &other);
+ RelativeDateTimeCacheData& operator=(
+ const RelativeDateTimeCacheData &other);
};
-RelativeDateTimeData::~RelativeDateTimeData() {
+RelativeDateTimeCacheData::~RelativeDateTimeCacheData() {
+ delete combinedDateAndTime;
}
static UBool getStringWithFallback(
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;
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(
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;
if (U_FAILURE(status)) {
return;
}
- addQualitativeUnit(
+ initAbsoluteUnit(
topLevel.getAlias(),
- absoluteUnit,
unitName,
- qualitativeUnits,
+ absoluteUnit,
status);
}
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(
"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);
}
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();
}
}
}
-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(
}
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);
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(
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 */
--- /dev/null
+/*
+******************************************************************************
+* 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
--- /dev/null
+/*
+******************************************************************************
+* 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
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);
}
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);
class NumberFormat;
class PluralRules;
-class MeasureFormatData;
+class MeasureFormatCacheData;
+class SharedNumberFormat;
+class SharedPluralRules;
class QuantityFormatter;
class ListFormatter;
class DateFormat;
/**
* 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.
#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,
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;
U_NAMESPACE_BEGIN
+class SharedNumberFormat;
+
#if !UCONFIG_NO_SERVICE
class NumberFormatFactory;
class StringEnumeration;
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
/*
*******************************************************************************
-* Copyright (C) 2008-2013, International Business Machines Corporation and
+* Copyright (C) 2008-2014, International Business Machines Corporation and
* others. All Rights Reserved.
*******************************************************************************
*
class PluralRuleParser;
class PluralKeywordEnumeration;
class AndConstraint;
+class SharedPluralRules;
/**
* Defines rules for mapping non-negative numeric values onto a small set of
* @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 */
/**
U_NAMESPACE_BEGIN
-class RelativeDateTimeData;
+class RelativeDateTimeCacheData;
+class SharedNumberFormat;
+class SharedPluralRules;
class NumberFormat;
/**
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
void TestFieldPositionMultiple();
void TestBadArg();
void TestEquality();
+ void TestBenchmark();
void verifyFormat(
const char *description,
const MeasureFormat &fmt,
TESTCASE_AUTO(TestFieldPositionMultiple);
TESTCASE_AUTO(TestBadArg);
TESTCASE_AUTO(TestEquality);
+ TESTCASE_AUTO(TestBenchmark);
TESTCASE_AUTO_END;
}
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,
/*
*******************************************************************************
-* Copyright (C) 2013, International Business Machines Corporation and *
+* Copyright (C) 2013-2014, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*
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() {