ICU-11780 Reduce heap size for caching date formatters.

X-SVN-Rev: 37860
This commit is contained in:
Travis Keep 2015-09-01 20:13:27 +00:00
parent 71ee34ed74
commit b7d18e518c
8 changed files with 150 additions and 212 deletions

View file

@ -1,6 +1,6 @@
/*
*******************************************************************************
* Copyright (C) 1997-2014, International Business Machines Corporation and *
* Copyright (C) 1997-2015, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*
@ -27,6 +27,9 @@
#include "unicode/dtptngen.h"
#include "unicode/udisplaycontext.h"
#include "reldtfmt.h"
#include "sharedobject.h"
#include "unifiedcache.h"
#include "uarrsort.h"
#include "cstring.h"
#include "windtfmt.h"
@ -41,6 +44,82 @@
U_NAMESPACE_BEGIN
class U_I18N_API DateFmtBestPattern : public SharedObject {
public:
UnicodeString fPattern;
DateFmtBestPattern(const UnicodeString &pattern)
: fPattern(pattern) { }
~DateFmtBestPattern();
};
DateFmtBestPattern::~DateFmtBestPattern() {
}
template<> U_I18N_API
const DateFmtBestPattern *LocaleCacheKey<DateFmtBestPattern>::createObject(
const void * /*creationContext*/, UErrorCode &status) const {
status = U_UNSUPPORTED_ERROR;
return NULL;
}
class U_I18N_API DateFmtBestPatternKey : public LocaleCacheKey<DateFmtBestPattern> {
private:
UnicodeString fSkeleton;
public:
DateFmtBestPatternKey(
const Locale &loc,
const UnicodeString &skeleton,
UErrorCode &status)
: LocaleCacheKey<DateFmtBestPattern>(loc),
fSkeleton(DateTimePatternGenerator::staticGetSkeleton(skeleton, status)) { }
DateFmtBestPatternKey(const DateFmtBestPatternKey &other) :
LocaleCacheKey<DateFmtBestPattern>(other),
fSkeleton(other.fSkeleton) { }
virtual ~DateFmtBestPatternKey();
virtual int32_t hashCode() const {
return 37 * LocaleCacheKey<DateFmtBestPattern>::hashCode() + fSkeleton.hashCode();
}
virtual UBool operator==(const CacheKeyBase &other) const {
// reflexive
if (this == &other) {
return TRUE;
}
if (!LocaleCacheKey<DateFmtBestPattern>::operator==(other)) {
return FALSE;
}
// We know that this and other are of same class if we get this far.
const DateFmtBestPatternKey &realOther =
static_cast<const DateFmtBestPatternKey &>(other);
return (realOther.fSkeleton == fSkeleton);
}
virtual CacheKeyBase *clone() const {
return new DateFmtBestPatternKey(*this);
}
virtual const DateFmtBestPattern *createObject(
const void * /*unused*/, UErrorCode &status) const {
LocalPointer<DateTimePatternGenerator> dtpg(
DateTimePatternGenerator::createInstance(fLoc, status));
if (U_FAILURE(status)) {
return NULL;
}
LocalPointer<DateFmtBestPattern> pattern(
new DateFmtBestPattern(
dtpg->getBestPattern(fSkeleton, status)),
status);
if (U_FAILURE(status)) {
return NULL;
}
DateFmtBestPattern *result = pattern.orphan();
result->addRef();
return result;
}
};
DateFmtBestPatternKey::~DateFmtBestPatternKey() { }
DateFormat::DateFormat()
: fCalendar(0),
fNumberFormat(0),
@ -345,6 +424,26 @@ DateFormat::createInstance()
//----------------------------------------------------------------------
UnicodeString U_EXPORT2
DateFormat::getBestPattern(
const Locale &locale,
const UnicodeString &skeleton,
UErrorCode &status) {
UnifiedCache *cache = UnifiedCache::getInstance(status);
if (U_FAILURE(status)) {
return UnicodeString();
}
DateFmtBestPatternKey key(locale, skeleton, status);
const DateFmtBestPattern *patternPtr = NULL;
cache->get(key, patternPtr, status);
if (U_FAILURE(status)) {
return UnicodeString();
}
UnicodeString result(patternPtr->fPattern);
patternPtr->removeRef();
return result;
}
DateFormat* U_EXPORT2
DateFormat::createInstanceForSkeleton(
Calendar *calendarToAdopt,
@ -372,13 +471,15 @@ DateFormat::createInstanceForSkeleton(
const UnicodeString& skeleton,
const Locale &locale,
UErrorCode &status) {
LocalPointer<DateTimePatternGenerator> gen(
DateTimePatternGenerator::createInstance(locale, status));
if (U_FAILURE(status)) {
return NULL;
}
return internalCreateInstanceForSkeleton(
skeleton, locale, *gen, status);
LocalPointer<DateFormat> df(
new SimpleDateFormat(
getBestPattern(locale, skeleton, status),
locale, status),
status);
return U_SUCCESS(status) ? df.orphan() : NULL;
}
DateFormat* U_EXPORT2
@ -389,30 +490,6 @@ DateFormat::createInstanceForSkeleton(
skeleton, Locale::getDefault(), status);
}
DateFormat* U_EXPORT2
DateFormat::internalCreateInstanceForSkeleton(
const UnicodeString& skeleton,
const Locale &locale,
DateTimePatternGenerator &gen,
UErrorCode &status) {
if (U_FAILURE(status)) {
return NULL;
}
DateFormat *fmt = new SimpleDateFormat(
gen.getBestPattern(skeleton, status),
locale,
status);
if (fmt == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
return NULL;
}
if (U_FAILURE(status)) {
delete fmt;
return NULL;
}
return fmt;
}
//----------------------------------------------------------------------
DateFormat* U_EXPORT2

View file

@ -117,7 +117,7 @@ DateIntervalFormat::DateIntervalFormat()
fDateFormat(NULL),
fFromCalendar(NULL),
fToCalendar(NULL),
fDtpng(NULL),
fLocale(Locale::getRoot()),
fDatePattern(NULL),
fTimePattern(NULL),
fDateTimeFormat(NULL)
@ -130,7 +130,7 @@ DateIntervalFormat::DateIntervalFormat(const DateIntervalFormat& itvfmt)
fDateFormat(NULL),
fFromCalendar(NULL),
fToCalendar(NULL),
fDtpng(NULL),
fLocale(itvfmt.fLocale),
fDatePattern(NULL),
fTimePattern(NULL),
fDateTimeFormat(NULL) {
@ -145,7 +145,6 @@ DateIntervalFormat::operator=(const DateIntervalFormat& itvfmt) {
delete fInfo;
delete fFromCalendar;
delete fToCalendar;
delete fDtpng;
delete fDatePattern;
delete fTimePattern;
delete fDateTimeFormat;
@ -174,11 +173,7 @@ DateIntervalFormat::operator=(const DateIntervalFormat& itvfmt) {
for ( i = 0; i< DateIntervalInfo::kIPI_MAX_INDEX; ++i ) {
fIntervalPatterns[i] = itvfmt.fIntervalPatterns[i];
}
if (itvfmt.fDtpng) {
fDtpng = itvfmt.fDtpng->clone();
} else {
fDtpng = NULL;
}
fLocale = itvfmt.fLocale;
fDatePattern = (itvfmt.fDatePattern)? (UnicodeString*)itvfmt.fDatePattern->clone(): NULL;
fTimePattern = (itvfmt.fTimePattern)? (UnicodeString*)itvfmt.fTimePattern->clone(): NULL;
fDateTimeFormat = (itvfmt.fDateTimeFormat)? (UnicodeString*)itvfmt.fDateTimeFormat->clone(): NULL;
@ -192,7 +187,6 @@ DateIntervalFormat::~DateIntervalFormat() {
delete fDateFormat;
delete fFromCalendar;
delete fToCalendar;
delete fDtpng;
delete fDatePattern;
delete fTimePattern;
delete fDateTimeFormat;
@ -236,9 +230,7 @@ DateIntervalFormat::operator==(const Format& other) const {
fSkeleton == fmt->fSkeleton &&
((fDatePattern == NULL && fmt->fDatePattern == NULL) || (fDatePattern && fmt->fDatePattern && *fDatePattern == *fmt->fDatePattern)) &&
((fTimePattern == NULL && fmt->fTimePattern == NULL) || (fTimePattern && fmt->fTimePattern && *fTimePattern == *fmt->fTimePattern)) &&
((fDateTimeFormat == NULL && fmt->fDateTimeFormat == NULL) || (fDateTimeFormat && fmt->fDateTimeFormat && *fDateTimeFormat == *fmt->fDateTimeFormat)) &&
fDtpng &&
(*fDtpng == *fmt->fDtpng) );
((fDateTimeFormat == NULL && fmt->fDateTimeFormat == NULL) || (fDateTimeFormat && fmt->fDateTimeFormat && *fDateTimeFormat == *fmt->fDateTimeFormat)) && fLocale == fmt->fLocale);
int8_t i;
for (i = 0; i< DateIntervalInfo::kIPI_MAX_INDEX && res == TRUE; ++i ) {
res = ( fIntervalPatterns[i].firstPart ==
@ -509,7 +501,7 @@ DateIntervalFormat::DateIntervalFormat(const Locale& locale,
fDateFormat(NULL),
fFromCalendar(NULL),
fToCalendar(NULL),
fDtpng(NULL),
fLocale(locale),
fDatePattern(NULL),
fTimePattern(NULL),
fDateTimeFormat(NULL)
@ -518,21 +510,20 @@ DateIntervalFormat::DateIntervalFormat(const Locale& locale,
delete dtItvInfo;
return;
}
fDtpng = DateTimePatternGenerator::createInstance(locale, status);
SimpleDateFormat* dtfmt = createSDFPatternInstance(*skeleton, locale,
fDtpng, status);
SimpleDateFormat* dtfmt =
static_cast<SimpleDateFormat *>(
DateFormat::createInstanceForSkeleton(
*skeleton, locale, status));
if ( U_FAILURE(status) ) {
delete dtItvInfo;
delete fDtpng;
delete dtfmt;
return;
}
if ( dtfmt == NULL || dtItvInfo == NULL || fDtpng == NULL ) {
if ( dtfmt == NULL || dtItvInfo == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
// safe to delete NULL
delete dtfmt;
delete dtItvInfo;
delete fDtpng;
return;
}
if ( skeleton ) {
@ -550,19 +541,6 @@ DateIntervalFormat::DateIntervalFormat(const Locale& locale,
initializePattern(status);
}
SimpleDateFormat* U_EXPORT2
DateIntervalFormat::createSDFPatternInstance(const UnicodeString& skeleton,
const Locale& locale,
DateTimePatternGenerator* dtpng,
UErrorCode& status)
{
DateFormat *df = DateFormat::internalCreateInstanceForSkeleton(
skeleton, locale, *dtpng, status);
return static_cast<SimpleDateFormat *>(df);
}
DateIntervalFormat* U_EXPORT2
DateIntervalFormat::create(const Locale& locale,
DateIntervalInfo* dtitvinf,
@ -721,7 +699,8 @@ DateIntervalFormat::initializePattern(UErrorCode& status) {
if ( dateSkeleton.length() == 0 ) {
// prefix with yMd
timeSkeleton.insert(0, gDateFormatSkeleton[DateFormat::kShort], -1);
UnicodeString pattern = fDtpng->getBestPattern(timeSkeleton, status);
UnicodeString pattern = DateFormat::getBestPattern(
locale, timeSkeleton, status);
if ( U_FAILURE(status) ) {
return;
}
@ -746,7 +725,8 @@ DateIntervalFormat::initializePattern(UErrorCode& status) {
} else if ( dateSkeleton.length() == 0 ) {
// prefix with yMd
timeSkeleton.insert(0, gDateFormatSkeleton[DateFormat::kShort], -1);
UnicodeString pattern = fDtpng->getBestPattern(timeSkeleton, status);
UnicodeString pattern = DateFormat::getBestPattern(
locale, timeSkeleton, status);
if ( U_FAILURE(status) ) {
return;
}
@ -796,7 +776,8 @@ DateIntervalFormat::initializePattern(UErrorCode& status) {
return;
}
UnicodeString datePattern = fDtpng->getBestPattern(dateSkeleton, status);
UnicodeString datePattern = DateFormat::getBestPattern(
locale, dateSkeleton, status);
concatSingleDate2TimeInterval(*fDateTimeFormat, datePattern, UCAL_AM_PM, status);
concatSingleDate2TimeInterval(*fDateTimeFormat, datePattern, UCAL_HOUR, status);
@ -1018,13 +999,15 @@ DateIntervalFormat::setSeparateDateTimePtn(
// Set patterns for fallback use, need to do this
// before returning if differenceInfo == -1
UErrorCode status;
if ( dateSkeleton.length() != 0 && fDtpng != NULL ) {
if ( dateSkeleton.length() != 0) {
status = U_ZERO_ERROR;
fDatePattern = new UnicodeString(fDtpng->getBestPattern(dateSkeleton, status));
fDatePattern = new UnicodeString(DateFormat::getBestPattern(
fLocale, dateSkeleton, status));
}
if ( timeSkeleton.length() != 0 && fDtpng != NULL ) {
if ( timeSkeleton.length() != 0) {
status = U_ZERO_ERROR;
fTimePattern = new UnicodeString(fDtpng->getBestPattern(timeSkeleton, status));
fTimePattern = new UnicodeString(DateFormat::getBestPattern(
fLocale, timeSkeleton, status));
}
// difference:
@ -1073,7 +1056,8 @@ DateIntervalFormat::setFallbackPattern(UCalendarDateFields field,
if ( U_FAILURE(status) ) {
return;
}
UnicodeString pattern = fDtpng->getBestPattern(skeleton, status);
UnicodeString pattern = DateFormat::getBestPattern(
fLocale, skeleton, status);
if ( U_FAILURE(status) ) {
return;
}

View file

@ -34,8 +34,6 @@
#include "hash.h"
#include "uresimp.h"
#include "dtptngen_impl.h"
#include "shareddatetimepatterngenerator.h"
#include "unifiedcache.h"
#if U_CHARSET_FAMILY==U_EBCDIC_FAMILY
/**
@ -126,28 +124,6 @@ static const UChar *ures_a_getNextString(UResourceBundleAIterator *aiter, int32_
U_NAMESPACE_BEGIN
SharedDateTimePatternGenerator::~SharedDateTimePatternGenerator() {
delete ptr;
}
template<> U_I18N_API
const SharedDateTimePatternGenerator *LocaleCacheKey<SharedDateTimePatternGenerator>::createObject(
const void * /*creationContext*/, UErrorCode &status) const {
DateTimePatternGenerator *fmt = DateTimePatternGenerator::internalMakeInstance(fLoc, status);
if (U_FAILURE(status)) {
return NULL;
}
SharedDateTimePatternGenerator *result = new SharedDateTimePatternGenerator(fmt);
if (result == NULL) {
delete fmt;
status = U_MEMORY_ALLOCATION_ERROR;
return NULL;
}
result->addRef();
return result;
}
// *****************************************************************************
// class DateTimePatternGenerator
// *****************************************************************************
@ -268,32 +244,12 @@ DateTimePatternGenerator::createInstance(UErrorCode& status) {
DateTimePatternGenerator* U_EXPORT2
DateTimePatternGenerator::createInstance(const Locale& locale, UErrorCode& status) {
const SharedDateTimePatternGenerator *shared = NULL;
UnifiedCache::getByLocale(locale, shared, status);
if (U_FAILURE(status)) {
return NULL;
}
DateTimePatternGenerator *result = new DateTimePatternGenerator(**shared);
shared->removeRef();
if (result == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
}
return result;
}
DateTimePatternGenerator* U_EXPORT2
DateTimePatternGenerator::internalMakeInstance(const Locale& locale, UErrorCode& status) {
DateTimePatternGenerator *result = new DateTimePatternGenerator(locale, status);
if (result == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
return NULL;
}
if (U_FAILURE(status)) {
delete result;
return NULL;
}
return result;
LocalPointer<DateTimePatternGenerator> result(
new DateTimePatternGenerator(locale, status), status);
return U_SUCCESS(status) ? result.orphan() : NULL;
}
DateTimePatternGenerator* U_EXPORT2

View file

@ -1176,7 +1176,6 @@
<ClInclude Include="sharedbreakiterator.h" />
<ClInclude Include="sharedcalendar.h" />
<ClInclude Include="shareddateformatsymbols.h" />
<ClInclude Include="shareddatetimepatterngenerator.h" />
<ClInclude Include="sharednumberformat.h" />
<ClInclude Include="sharedpluralrules.h" />
<CustomBuild Include="unicode\rbnf.h">

View file

@ -778,9 +778,6 @@
<ClInclude Include="shareddateformatsymbols.h">
<Filter>formatting</Filter>
</ClInclude>
<ClInclude Include="shareddatetimepatterngenerator.h">
<Filter>formatting</Filter>
</ClInclude>
<ClInclude Include="sharednumberformat.h">
<Filter>formatting</Filter>
</ClInclude>

View file

@ -1,34 +0,0 @@
/*
******************************************************************************
* Copyright (C) 2014, International Business Machines
* Corporation and others. All Rights Reserved.
******************************************************************************
* shareddateformat.h
*/
#ifndef __SHARED_DATETIMEPATTERNGENERATOR_H__
#define __SHARED_DATETIMEPATTERNGENERATOR_H__
#include "unicode/utypes.h"
#include "sharedobject.h"
U_NAMESPACE_BEGIN
class DateTimePatternGenerator;
class U_I18N_API SharedDateTimePatternGenerator : public SharedObject {
public:
SharedDateTimePatternGenerator(DateTimePatternGenerator *dtpgToAdopt) : ptr(dtpgToAdopt) { }
virtual ~SharedDateTimePatternGenerator();
const DateTimePatternGenerator *get() const { return ptr; }
const DateTimePatternGenerator *operator->() const { return ptr; }
const DateTimePatternGenerator &operator*() const { return *ptr; }
private:
DateTimePatternGenerator *ptr;
SharedDateTimePatternGenerator(const SharedDateTimePatternGenerator &);
SharedDateTimePatternGenerator &operator=(const SharedDateTimePatternGenerator &);
};
U_NAMESPACE_END
#endif

View file

@ -573,6 +573,21 @@ public:
#ifndef U_HIDE_DRAFT_API
#ifndef U_HIDE_INTERNAL_API
/**
* Returns the best pattern given a skeleton and locale.
* @param locale the locale
* @param skeleton the skeleton
* @param status ICU error returned here
* @return the best pattern.
* @internal For ICU use only.
*/
static UnicodeString getBestPattern(
const Locale &locale,
const UnicodeString &skeleton,
UErrorCode &status);
#endif
/**
* Creates a date/time formatter for the given skeleton and
* default locale.
@ -630,41 +645,6 @@ public:
#endif /* U_HIDE_DRAFT_API */
#ifndef U_HIDE_INTERNAL_API
/**
* Creates a date/time formatter for the given skeleton and locale and
* uses the given DateTimePatternGenerator to convert the skeleton to
* a format pattern. As creating a DateTimePatternGenerator is
* expensive, callers can supply it here (if they already have it) to save
* this method from creating its own.
*
* @param skeleton The skeleton e.g "yMMMMd." Fields in the skeleton can
* be in any order, and this method uses the provided
* DateTimePatternGenerator to map the skeleton to a
* pattern that includes appropriate separators with
* the fields in the appropriate order.
* @param locale The given locale.
* @param dpng The user supplied DateTimePatternGenerator. dpng
* must be created for the same locale as locale.
* Moreover, the caller must not modify dpng between
* creating it by locale and calling this method.
* Although dpng is a non-const reference, the caller
* must not regard it as an out or in-out parameter.
* The only reason dpng is a non-const reference is
* because its method, getBestPattern, which converts
* a skeleton to a date format pattern is non-const.
* @return A date/time formatter which the caller owns.
* @internal For ICU use only
*/
static DateFormat* U_EXPORT2 internalCreateInstanceForSkeleton(
const UnicodeString& skeleton,
const Locale &locale,
DateTimePatternGenerator &dpng,
UErrorCode &status);
#endif /* U_HIDE_INTERNAL_API */
/**
* Gets the set of locales for which DateFormats are installed.
* @param count Filled in with the number of locales in the list that is returned.
@ -887,6 +867,7 @@ protected:
private:
/**
* Gets the date/time formatter with the given formatting styles for the
* given locale.

View file

@ -652,25 +652,6 @@ private:
const UnicodeString* skeleton,
UErrorCode& status);
/**
* Create a simple date/time formatter from skeleton, given locale,
* and date time pattern generator.
*
* @param skeleton the skeleton on which date format based.
* @param locale the given locale.
* @param dtpng the date time pattern generator.
* @param status Output param to be set to success/failure code.
* If it is failure, the returned date formatter will
* be NULL.
* @return a simple date formatter which the caller owns.
*/
static SimpleDateFormat* U_EXPORT2 createSDFPatternInstance(
const UnicodeString& skeleton,
const Locale& locale,
DateTimePatternGenerator* dtpng,
UErrorCode& status);
/**
* Below are for generating interval patterns local to the formatter
*/
@ -994,10 +975,7 @@ private:
Calendar* fFromCalendar;
Calendar* fToCalendar;
/**
* Date time pattern generator
*/
DateTimePatternGenerator* fDtpng;
Locale fLocale;
/**
* Following are interval information relevant (locale) to this formatter.