]> granicus.if.org Git - icu/commitdiff
ICU-11401 Reduce cache keyspace by caching only the components of DateFormat by local...
authorTravis Keep <keep94@gmail.com>
Fri, 5 Dec 2014 18:15:35 +0000 (18:15 +0000)
committerTravis Keep <keep94@gmail.com>
Fri, 5 Dec 2014 18:15:35 +0000 (18:15 +0000)
X-SVN-Rev: 36811

15 files changed:
.gitattributes
icu4c/source/i18n/calendar.cpp
icu4c/source/i18n/datefmt.cpp
icu4c/source/i18n/dtfmtsym.cpp
icu4c/source/i18n/i18n.vcxproj
icu4c/source/i18n/i18n.vcxproj.filters
icu4c/source/i18n/sharedcalendar.h [new file with mode: 0644]
icu4c/source/i18n/shareddatefmt.h [deleted file]
icu4c/source/i18n/shareddateformatsymbols.h [new file with mode: 0644]
icu4c/source/i18n/smpdtfmt.cpp
icu4c/source/i18n/unicode/calendar.h
icu4c/source/i18n/unicode/dtfmtsym.h
icu4c/source/i18n/unicode/smpdtfmt.h
icu4c/source/test/intltest/dtfmttst.cpp
icu4c/source/test/intltest/dtfmttst.h

index 3bcf7a3b731a883baf94cc67b5609544c5cbeb85..ec2a08dd84d0642889ce69bb2f0d0afb58182749 100644 (file)
@@ -77,7 +77,8 @@ icu4c/source/extra/uconv/uconv.vcxproj.filters -text
 icu4c/source/i18n/i18n.vcxproj -text
 icu4c/source/i18n/i18n.vcxproj.filters -text
 icu4c/source/i18n/scientificnumberformatter.cpp -text
-icu4c/source/i18n/shareddatefmt.h -text
+icu4c/source/i18n/sharedcalendar.h -text
+icu4c/source/i18n/shareddateformatsymbols.h -text
 icu4c/source/i18n/shareddatetimepatterngenerator.h -text
 icu4c/source/i18n/unicode/scientificnumberformatter.h -text
 icu4c/source/io/io.vcxproj -text
index 062a9e9c30ae0af4dffe7d7629b2002001e872f6..adee2d66dfb01e7b64b83fd4a44776fed27981ce 100644 (file)
@@ -57,6 +57,8 @@
 #include "ustrenum.h"
 #include "uassert.h"
 #include "olsontz.h"
+#include "sharedcalendar.h"
+#include "unifiedcache.h"
 
 #if !UCONFIG_NO_SERVICE
 static icu::ICULocaleService* gService = NULL;
@@ -199,6 +201,27 @@ typedef enum ECalType {
 
 U_NAMESPACE_BEGIN
 
+SharedCalendar::~SharedCalendar() {
+    delete ptr;
+}
+
+template<> U_I18N_API
+const SharedCalendar *LocaleCacheKey<SharedCalendar>::createObject(
+        const void * /*unusedCreationContext*/, UErrorCode &status) const {
+    Calendar *calendar = Calendar::makeInstance(fLoc, status);
+    if (U_FAILURE(status)) {
+        return NULL; 
+    }
+    SharedCalendar *shared = new SharedCalendar(calendar);
+    if (shared == NULL) {
+        delete calendar;
+        status = U_MEMORY_ALLOCATION_ERROR;
+        return NULL;
+    }
+    shared->addRef();
+    return shared;
+}
+
 static ECalType getCalendarType(const char *s) {
     for (int i = 0; gCalTypes[i] != NULL; i++) {
         if (uprv_stricmp(s, gCalTypes[i]) == 0) {
@@ -833,9 +856,8 @@ Calendar::createInstance(const Locale& aLocale, UErrorCode& success)
 
 // Note: this is the bottleneck that actually calls the service routines.
 
-Calendar* U_EXPORT2
-Calendar::createInstance(TimeZone* zone, const Locale& aLocale, UErrorCode& success)
-{
+Calendar * U_EXPORT2
+Calendar::makeInstance(const Locale& aLocale, UErrorCode& success) {
     if (U_FAILURE(success)) {
         return NULL;
     }
@@ -855,7 +877,6 @@ Calendar::createInstance(TimeZone* zone, const Locale& aLocale, UErrorCode& succ
     Calendar* c = NULL;
 
     if(U_FAILURE(success) || !u) {
-        delete zone;
         if(U_SUCCESS(success)) { // Propagate some kind of err
             success = U_INTERNAL_PROGRAM_ERROR;
         }
@@ -884,7 +905,6 @@ Calendar::createInstance(TimeZone* zone, const Locale& aLocale, UErrorCode& succ
         c = (Calendar*)getCalendarService(success)->get(l, LocaleKey::KIND_ANY, &actualLoc2, success);
 
         if(U_FAILURE(success) || !c) {
-            delete zone;
             if(U_SUCCESS(success)) { 
                 success = U_INTERNAL_PROGRAM_ERROR; // Propagate some err
             }
@@ -910,7 +930,6 @@ Calendar::createInstance(TimeZone* zone, const Locale& aLocale, UErrorCode& succ
 #endif
             success = U_MISSING_RESOURCE_ERROR;  // requested a calendar type which could NOT be found.
             delete c;
-            delete zone;
             return NULL;
         }
 #ifdef U_DEBUG_CALSVC
@@ -933,8 +952,27 @@ Calendar::createInstance(TimeZone* zone, const Locale& aLocale, UErrorCode& succ
         c = (Calendar*)u;
     }
 
+    return c;
+}
+
+Calendar* U_EXPORT2
+Calendar::createInstance(TimeZone* zone, const Locale& aLocale, UErrorCode& success)
+{
+    LocalPointer<TimeZone> zonePtr(zone);
+    const SharedCalendar *shared = NULL;
+    UnifiedCache::getByLocale(aLocale, shared, success);
+    if (U_FAILURE(success)) {
+        return NULL;
+    }
+    Calendar *c = (*shared)->clone();
+    shared->removeRef();
+    if (c == NULL) {
+        success = U_MEMORY_ALLOCATION_ERROR;
+        return NULL;
+    }
+
     // Now, reset calendar to default state:
-    c->adoptTimeZone(zone); //  Set the correct time zone
+    c->adoptTimeZone(zonePtr.orphan()); //  Set the correct time zone
     c->setTimeInMillis(getNow(), success); // let the new calendar have the current time.
 
     return c;
@@ -954,6 +992,24 @@ Calendar::createInstance(const TimeZone& zone, const Locale& aLocale, UErrorCode
 
 // -------------------------------------
 
+void U_EXPORT2
+Calendar::getCalendarTypeFromLocale(
+        const Locale &aLocale,
+        char *typeBuffer,
+        int32_t typeBufferSize,
+        UErrorCode &success) {
+    const SharedCalendar *shared = NULL;
+    UnifiedCache::getByLocale(aLocale, shared, success);
+    if (U_FAILURE(success)) {
+        return;
+    }
+    uprv_strncpy(typeBuffer, (*shared)->getType(), typeBufferSize);
+    shared->removeRef();
+    if (typeBuffer[typeBufferSize - 1]) {
+        success = U_BUFFER_OVERFLOW_ERROR;
+    }
+}
+
 UBool
 Calendar::operator==(const Calendar& that) const
 {
index e9efbea7565d10933832fdbaf1c056d241c7ecfc..7006e10317a8cc95cee09019b939040baf2c586a 100644 (file)
@@ -27,9 +27,6 @@
 #include "unicode/dtptngen.h"
 #include "unicode/udisplaycontext.h"
 #include "reldtfmt.h"
-#include "shareddatefmt.h"
-#include "shareddatetimepatterngenerator.h"
-#include "unifiedcache.h"
 
 #include "cstring.h"
 #include "windtfmt.h"
 
 U_NAMESPACE_BEGIN
 
-SharedDateFormat::~SharedDateFormat() {
-    delete ptr;
-}
-
-// We must fully define LocaleCacheKey<SharedDateFormat>
-template<> U_I18N_API
-const SharedDateFormat *LocaleCacheKey<SharedDateFormat>::createObject(
-        const void * /*creationContext*/, UErrorCode &status) const {
-    status = U_UNSUPPORTED_ERROR;
-    return NULL;
-}
-
-class U_I18N_API DateFmtKeyByStyle : public LocaleCacheKey<SharedDateFormat> {
- private:
-   DateFormat::EStyle fDateStyle;
-   DateFormat::EStyle fTimeStyle;
- public:
-   DateFmtKeyByStyle(
-           const Locale &loc,
-           DateFormat::EStyle dateStyle,
-           DateFormat::EStyle timeStyle)
-           : LocaleCacheKey<SharedDateFormat>(loc),
-           fDateStyle(dateStyle),
-           fTimeStyle(timeStyle) { }
-   DateFmtKeyByStyle(const DateFmtKeyByStyle &other) :
-           LocaleCacheKey<SharedDateFormat>(other),
-           fDateStyle(other.fDateStyle),
-           fTimeStyle(other.fTimeStyle) { }
-   virtual ~DateFmtKeyByStyle();
-   virtual int32_t hashCode() const {
-       int32_t hash = 37 * LocaleCacheKey<SharedDateFormat>::hashCode() + fDateStyle;
-       hash = 37 * hash + fTimeStyle;
-       return hash;
-   }
-   virtual UBool operator==(const CacheKeyBase &other) const {
-       // reflexive
-       if (this == &other) {
-           return TRUE;
-       }
-       if (!LocaleCacheKey<SharedDateFormat>::operator==(other)) {
-           return FALSE;
-       }
-       // We know that this an other are of same class if we get this far.
-       const DateFmtKeyByStyle *realOther =
-               static_cast<const DateFmtKeyByStyle *>(&other);
-       return (realOther->fDateStyle == fDateStyle &&
-               realOther->fTimeStyle == fTimeStyle);
-   }
-   virtual CacheKeyBase *clone() const {
-       return new DateFmtKeyByStyle(*this);
-   }
-   virtual const SharedDateFormat *createObject(
-           const void * /*creationContext*/, UErrorCode &status) const {
-       DateFormat::EStyle dateStyle = fDateStyle;
-       if(dateStyle != DateFormat::kNone)
-       {
-           dateStyle = (DateFormat::EStyle) (dateStyle + DateFormat::kDateOffset);
-       }
-       DateFormat *fmt = DateFormat::create(fTimeStyle, dateStyle, fLoc);
-       if (fmt == NULL) {
-           status = U_MEMORY_ALLOCATION_ERROR;
-           return NULL;
-       }
-       SharedDateFormat *result = new SharedDateFormat(fmt);
-       if (result == NULL) {
-           delete fmt;
-           status = U_MEMORY_ALLOCATION_ERROR;
-           return NULL;
-       }
-       result->addRef();
-       return result;
-   }
-};
-
-DateFmtKeyByStyle::~DateFmtKeyByStyle() {
-}
-
-class U_I18N_API DateFmtKeyBySkeleton : public LocaleCacheKey<SharedDateFormat> {
- private:
-    UnicodeString fSkeleton;
- public:
-   DateFmtKeyBySkeleton(const Locale &loc, const UnicodeString &skeleton) :
-           LocaleCacheKey<SharedDateFormat>(loc),
-           fSkeleton(skeleton) { }
-   DateFmtKeyBySkeleton(const DateFmtKeyBySkeleton &other) :
-           LocaleCacheKey<SharedDateFormat>(other),
-           fSkeleton(other.fSkeleton) { }
-   virtual ~DateFmtKeyBySkeleton();
-   virtual int32_t hashCode() const {
-       return 37 * LocaleCacheKey<SharedDateFormat>::hashCode() + fSkeleton.hashCode();
-   }
-   virtual UBool operator==(const CacheKeyBase &other) const {
-       // reflexive
-       if (this == &other) {
-           return TRUE;
-       }
-       if (!LocaleCacheKey<SharedDateFormat>::operator==(other)) {
-           return FALSE;
-       }
-       // We know that this an other are of same class if we get this far.
-       const DateFmtKeyBySkeleton *realOther =
-               static_cast<const DateFmtKeyBySkeleton *>(&other);
-       return (realOther->fSkeleton == fSkeleton);
-   }
-   virtual CacheKeyBase *clone() const {
-       return new DateFmtKeyBySkeleton(*this);
-   }
-   virtual const SharedDateFormat *createObject(
-           const void *creationContext, UErrorCode &status) const {
-       void *mutableCreationContext = const_cast<void *>(creationContext);
-       DateTimePatternGenerator *ownedDtpg = NULL;
-       DateTimePatternGenerator *dtpg =
-               static_cast<DateTimePatternGenerator *>(mutableCreationContext);
-       if (dtpg == NULL) {
-           ownedDtpg = DateTimePatternGenerator::createInstance(fLoc, status);
-           if (U_FAILURE(status)) {
-               return NULL;
-           }
-           dtpg = ownedDtpg;
-       } 
-       DateFormat *fmt = new SimpleDateFormat(
-               dtpg->getBestPattern(fSkeleton, status),
-               fLoc,
-               status);
-       delete ownedDtpg;
-       if (fmt == NULL) {
-           status = U_MEMORY_ALLOCATION_ERROR;
-           return NULL;
-       }
-       if (U_FAILURE(status)) {
-           delete fmt;
-           return NULL;
-       }
-       SharedDateFormat *result = new SharedDateFormat(fmt);
-       if (result == NULL) {
-           delete fmt;
-           status = U_MEMORY_ALLOCATION_ERROR;
-           return NULL;
-       }
-       result->addRef();
-       return result;
-   }
-};
-
-DateFmtKeyBySkeleton::~DateFmtKeyBySkeleton() {
-}
-
-static DateFormat *createFromCache(
-        const CacheKey<SharedDateFormat> &key,
-        const void *context,
-        UErrorCode &status) {
-    const UnifiedCache *cache = UnifiedCache::getInstance(status);
-    if (U_FAILURE(status)) {
-        return NULL;
-    }
-    const SharedDateFormat *ptr = NULL;
-    cache->get(key, context, ptr, status);
-    if (U_FAILURE(status)) {
-        return NULL;
-    }
-    DateFormat *result = static_cast<DateFormat *>((*ptr)->clone());
-    ptr->removeRef();
-    if (result == NULL) {
-        status = U_MEMORY_ALLOCATION_ERROR;
-    } else {
-        // Set the currently active default TimeZone,
-        // because the cached instance might be created
-        // with another TimeZone.
-        // Note: We could do some optimization in SharedDateFormat
-        // to pick up the current default without cloning old default.
-        result->adoptTimeZone(TimeZone::createDefault());
-    }
-    return result;
-}
-
 DateFormat::DateFormat()
 :   fCalendar(0),
     fNumberFormat(0),
@@ -487,9 +309,7 @@ DateFormat* U_EXPORT2
 DateFormat::createTimeInstance(DateFormat::EStyle style,
                                const Locale& aLocale)
 {
-    DateFmtKeyByStyle key(aLocale, kNone, style);
-    UErrorCode status = U_ZERO_ERROR;
-    return createFromCache(key, NULL, status);
+    return createDateTimeInstance(kNone, style, aLocale);
 }
 
 //----------------------------------------------------------------------
@@ -498,9 +318,7 @@ DateFormat* U_EXPORT2
 DateFormat::createDateInstance(DateFormat::EStyle style,
                                const Locale& aLocale)
 {
-    DateFmtKeyByStyle key(aLocale, style, kNone);
-    UErrorCode status = U_ZERO_ERROR;
-    return createFromCache(key, NULL, status);
+    return createDateTimeInstance(style, kNone, aLocale);
 }
 
 //----------------------------------------------------------------------
@@ -510,9 +328,11 @@ DateFormat::createDateTimeInstance(EStyle dateStyle,
                                    EStyle timeStyle,
                                    const Locale& aLocale)
 {
-    DateFmtKeyByStyle key(aLocale, dateStyle, timeStyle);
-    UErrorCode status = U_ZERO_ERROR;
-    return createFromCache(key, NULL, status);
+   if(dateStyle != kNone)
+   {
+       dateStyle = (EStyle) (dateStyle + kDateOffset);
+   }
+   return create(timeStyle, dateStyle, aLocale);
 }
 
 //----------------------------------------------------------------------
@@ -520,9 +340,7 @@ DateFormat::createDateTimeInstance(EStyle dateStyle,
 DateFormat* U_EXPORT2
 DateFormat::createInstance()
 {
-    DateFmtKeyByStyle key(Locale::getDefault(), kShort, kShort);
-    UErrorCode status = U_ZERO_ERROR;
-    return createFromCache(key, NULL, status);
+    return createDateTimeInstance(kShort, kShort, Locale::getDefault());
 }
 
 //----------------------------------------------------------------------
@@ -541,8 +359,7 @@ DateFormat::createInstanceForSkeleton(
         status = U_ILLEGAL_ARGUMENT_ERROR;
         return NULL;
     }
-    DateFmtKeyBySkeleton key(locale, skeleton);
-    DateFormat *result = createFromCache(key, NULL, status);
+    DateFormat *result = createInstanceForSkeleton(skeleton, locale, status);
     if (U_FAILURE(status)) {
         return NULL;
     }
@@ -555,22 +372,21 @@ DateFormat::createInstanceForSkeleton(
         const UnicodeString& skeleton,
         const Locale &locale,
         UErrorCode &status) {
+    LocalPointer<DateTimePatternGenerator> gen(
+            DateTimePatternGenerator::createInstance(locale, status));
     if (U_FAILURE(status)) {
         return NULL;
     }
-    DateFmtKeyBySkeleton key(locale, skeleton);
-    return createFromCache(key, NULL, status);
+    return internalCreateInstanceForSkeleton(
+            skeleton, locale, *gen, status);
 }
 
 DateFormat* U_EXPORT2
 DateFormat::createInstanceForSkeleton(
         const UnicodeString& skeleton,
         UErrorCode &status) {
-    if (U_FAILURE(status)) {
-        return NULL;
-    }
-    DateFmtKeyBySkeleton key(Locale::getDefault(), skeleton);
-    return createFromCache(key, NULL, status);
+    return createInstanceForSkeleton(
+            skeleton, Locale::getDefault(), status);
 }
 
 DateFormat* U_EXPORT2
@@ -582,8 +398,19 @@ DateFormat::internalCreateInstanceForSkeleton(
     if (U_FAILURE(status)) {
         return NULL;
     }
-    DateFmtKeyBySkeleton key(locale, skeleton);
-    return createFromCache(key, &gen, status);
+    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;
 }
 
 //----------------------------------------------------------------------
index a08811b75a35ada73c134442e694a60c17f4a5bb..f2ac6f75c22e0261fbc2cee77175a2d285e3fe07 100644 (file)
@@ -36,6 +36,9 @@
 #include "hash.h"
 #include "uresimp.h"
 #include "ureslocs.h"
+#include "shareddateformatsymbols.h"
+#include "unicode/calendar.h"
+#include "unifiedcache.h"
 
 // *****************************************************************************
 // class DateFormatSymbols
@@ -146,6 +149,32 @@ typedef enum LastResortSize {
 
 U_NAMESPACE_BEGIN
 
+SharedDateFormatSymbols::~SharedDateFormatSymbols() {
+}
+
+template<> U_I18N_API
+const SharedDateFormatSymbols *
+        LocaleCacheKey<SharedDateFormatSymbols>::createObject(
+                const void */*unusedContext*/, UErrorCode &status) const {
+    char type[256];
+    Calendar::getCalendarTypeFromLocale(fLoc, type, UPRV_LENGTHOF(type), status);
+    if (U_FAILURE(status)) {
+        return NULL;
+    }
+    SharedDateFormatSymbols *shared
+            = new SharedDateFormatSymbols(fLoc, type, status);
+    if (shared == NULL) {
+        status = U_MEMORY_ALLOCATION_ERROR;
+        return NULL;
+    }
+    if (U_FAILURE(status)) {
+        delete shared;
+        return NULL;
+    }
+    shared->addRef();
+    return shared;
+}
+
 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateFormatSymbols)
 
 #define kSUPPLEMENTAL "supplementalData"
@@ -191,6 +220,23 @@ static inline UnicodeString* newUnicodeStringArray(size_t count) {
 
 //------------------------------------------------------
 
+DateFormatSymbols * U_EXPORT2
+DateFormatSymbols::createForLocale(
+        const Locale& locale, UErrorCode &status) {
+    const SharedDateFormatSymbols *shared = NULL;
+    UnifiedCache::getByLocale(locale, shared, status);
+    if (U_FAILURE(status)) {
+        return NULL;
+    }
+    DateFormatSymbols *result = new DateFormatSymbols(shared->get());
+    shared->removeRef();
+    if (result == NULL) {
+        status = U_MEMORY_ALLOCATION_ERROR;
+        return NULL;
+    }
+    return result;
+}
+
 DateFormatSymbols::DateFormatSymbols(const Locale& locale,
                                      UErrorCode& status)
     : UObject()
index bb06144bf83ffc101771932a5319d5bebd490c32..a339aa9f2c3fba2bfada2e4cef2d13ec56ed6706 100644 (file)
     <ClInclude Include="plurrule_impl.h" />\r
     <ClInclude Include="quantityformatter.h" />\r
     <ClInclude Include="sharedbreakiterator.h" />\r
-    <ClInclude Include="shareddatefmt.h" />\r
+    <ClInclude Include="sharedcalendar.h" />\r
+    <ClInclude Include="shareddateformatsymbols.h" />\r
     <ClInclude Include="shareddatetimepatterngenerator.h" />\r
     <ClInclude Include="sharednumberformat.h" />\r
     <ClInclude Include="sharedpluralrules.h" />\r
index f960acc2f2621fda1511143de78306e9cbfb40a9..f1252f7d325153d431cf149f12d13de430362c74 100644 (file)
     <ClInclude Include="sharedbreakiterator.h">\r
       <Filter>formatting</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="shareddatefmt.h">\r
+    <ClInclude Include="sharedcalendar.h">\r
+      <Filter>formatting</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="shareddateformatsymbols.h">\r
       <Filter>formatting</Filter>\r
     </ClInclude>\r
     <ClInclude Include="shareddatetimepatterngenerator.h">\r
diff --git a/icu4c/source/i18n/sharedcalendar.h b/icu4c/source/i18n/sharedcalendar.h
new file mode 100644 (file)
index 0000000..2a10c88
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+******************************************************************************
+* Copyright (C) 2014, International Business Machines
+* Corporation and others.  All Rights Reserved.
+******************************************************************************
+* sharedcalendar.h
+*/
+
+#ifndef __SHARED_CALENDAR_H__
+#define __SHARED_CALENDAR_H__
+
+#include "unicode/utypes.h"
+#include "sharedobject.h"
+
+U_NAMESPACE_BEGIN
+
+class Calendar;
+
+class U_I18N_API SharedCalendar : public SharedObject {
+public:
+    SharedCalendar(Calendar *calToAdopt) : ptr(calToAdopt) { }
+    virtual ~SharedCalendar();
+    const Calendar *get() const { return ptr; }
+    const Calendar *operator->() const { return ptr; }
+    const Calendar &operator*() const { return *ptr; }
+private:
+    Calendar *ptr;
+    SharedCalendar(const SharedCalendar &);
+    SharedCalendar &operator=(const SharedCalendar &);
+};
+
+U_NAMESPACE_END
+
+#endif
diff --git a/icu4c/source/i18n/shareddatefmt.h b/icu4c/source/i18n/shareddatefmt.h
deleted file mode 100644 (file)
index 010b6e2..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
-******************************************************************************
-* Copyright (C) 2014, International Business Machines
-* Corporation and others.  All Rights Reserved.
-******************************************************************************
-* shareddateformat.h
-*/
-
-#ifndef __SHARED_DATEFORMAT_H__
-#define __SHARED_DATEFORMAT_H__
-
-#include "unicode/utypes.h"
-#include "sharedobject.h"
-
-U_NAMESPACE_BEGIN
-
-class DateFormat;
-
-class U_I18N_API SharedDateFormat : public SharedObject {
-public:
-    SharedDateFormat(DateFormat *dfToAdopt) : ptr(dfToAdopt) { }
-    virtual ~SharedDateFormat();
-    const DateFormat *get() const { return ptr; }
-    const DateFormat *operator->() const { return ptr; }
-    const DateFormat &operator*() const { return *ptr; }
-private:
-    DateFormat *ptr;
-    SharedDateFormat(const SharedDateFormat &);
-    SharedDateFormat &operator=(const SharedDateFormat &);
-};
-
-U_NAMESPACE_END
-
-#endif
diff --git a/icu4c/source/i18n/shareddateformatsymbols.h b/icu4c/source/i18n/shareddateformatsymbols.h
new file mode 100644 (file)
index 0000000..8451183
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+******************************************************************************
+* Copyright (C) 2014, International Business Machines
+* Corporation and others.  All Rights Reserved.
+******************************************************************************
+* shareddateformatsymbols.h
+*/
+
+#ifndef __SHARED_DATEFORMATSYMBOLS_H__
+#define __SHARED_DATEFORMATSYMBOLS_H__
+
+#include "unicode/utypes.h"
+#include "sharedobject.h"
+#include "unicode/dtfmtsym.h"
+
+U_NAMESPACE_BEGIN
+
+
+class U_I18N_API SharedDateFormatSymbols : public SharedObject {
+public:
+    SharedDateFormatSymbols(
+            const Locale &loc, const char *type, UErrorCode &status)
+            : dfs(loc, type, status) { }
+    virtual ~SharedDateFormatSymbols();
+    const DateFormatSymbols &get() const { return dfs; }
+private:
+    DateFormatSymbols dfs;
+    SharedDateFormatSymbols(const SharedDateFormatSymbols &);
+    SharedDateFormatSymbols &operator=(const SharedDateFormatSymbols &);
+};
+
+U_NAMESPACE_END
+
+#endif
index 749484e71be0a3b293a5258af3f1f90b9e887efb..4ba8d27a7609d8c299a77160d30addfb2c26202a 100644 (file)
@@ -394,7 +394,8 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
     fDateOverride.setToBogus();
     fTimeOverride.setToBogus();
     initializeBooleanAttributes();
-    initializeSymbols(fLocale, initializeCalendar(NULL,fLocale,status), status);
+    initializeCalendar(NULL,fLocale,status);
+    fSymbols = DateFormatSymbols::createForLocale(fLocale, status);
     initialize(fLocale, status);
     initializeDefaultCentury();
 
@@ -414,7 +415,8 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
     fDateOverride.setTo(override);
     fTimeOverride.setToBogus();
     initializeBooleanAttributes();
-    initializeSymbols(fLocale, initializeCalendar(NULL,fLocale,status), status);
+    initializeCalendar(NULL,fLocale,status);
+    fSymbols = DateFormatSymbols::createForLocale(fLocale, status);
     initialize(fLocale, status);
     initializeDefaultCentury();
 
@@ -438,7 +440,8 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
     fTimeOverride.setToBogus();
     initializeBooleanAttributes();
 
-    initializeSymbols(fLocale, initializeCalendar(NULL,fLocale,status), status);
+    initializeCalendar(NULL,fLocale,status);
+    fSymbols = DateFormatSymbols::createForLocale(fLocale, status);
     initialize(fLocale, status);
     initializeDefaultCentury();
 }
@@ -460,7 +463,8 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
     fTimeOverride.setToBogus();
     initializeBooleanAttributes();
 
-    initializeSymbols(fLocale, initializeCalendar(NULL,fLocale,status), status);
+    initializeCalendar(NULL,fLocale,status);
+    fSymbols = DateFormatSymbols::createForLocale(fLocale, status);
     initialize(fLocale, status);
     initializeDefaultCentury();
 
@@ -550,7 +554,8 @@ SimpleDateFormat::SimpleDateFormat(const Locale& locale,
 {
     if (U_FAILURE(status)) return;
     initializeBooleanAttributes();
-    initializeSymbols(fLocale, initializeCalendar(NULL, fLocale, status),status);
+    initializeCalendar(NULL, fLocale, status);
+    fSymbols = DateFormatSymbols::createForLocale(fLocale, status);
     if (U_FAILURE(status))
     {
         status = U_ZERO_ERROR;
@@ -699,7 +704,7 @@ void SimpleDateFormat::construct(EStyle timeStyle,
                  ures_getLocaleByType(dateTimePatterns, ULOC_ACTUAL_LOCALE, &status));
 
     // create a symbols object from the locale
-    initializeSymbols(locale,fCalendar, status);
+    fSymbols = DateFormatSymbols::createForLocale(locale, status);
     if (U_FAILURE(status)) return;
     /* test for NULL */
     if (fSymbols == 0) {
@@ -870,28 +875,9 @@ SimpleDateFormat::initializeCalendar(TimeZone* adoptZone, const Locale& locale,
     if(!U_FAILURE(status)) {
         fCalendar = Calendar::createInstance(adoptZone?adoptZone:TimeZone::createDefault(), locale, status);
     }
-    if (U_SUCCESS(status) && fCalendar == NULL) {
-        status = U_MEMORY_ALLOCATION_ERROR;
-    }
     return fCalendar;
 }
 
-void
-SimpleDateFormat::initializeSymbols(const Locale& locale, Calendar* calendar, UErrorCode& status)
-{
-  if(U_FAILURE(status)) {
-    fSymbols = NULL;
-  } else {
-    // pass in calendar type - use NULL (default) if no calendar set (or err).
-    fSymbols = new DateFormatSymbols(locale, calendar?calendar->getType() :NULL , status);
-    // Null pointer check
-    if (fSymbols == NULL) {
-        status = U_MEMORY_ALLOCATION_ERROR;
-        return;
-    }
-  }
-}
-
 void
 SimpleDateFormat::initialize(const Locale& locale,
                              UErrorCode& status)
@@ -3517,10 +3503,16 @@ SimpleDateFormat::setTimeZoneFormat(const TimeZoneFormat& newTimeZoneFormat)
 void SimpleDateFormat::adoptCalendar(Calendar* calendarToAdopt)
 {
   UErrorCode status = U_ZERO_ERROR;
+  Locale calLocale(fLocale);
+  calLocale.setKeywordValue("calendar", calendarToAdopt->getType(), status);
+  DateFormatSymbols *newSymbols =
+          DateFormatSymbols::createForLocale(calLocale, status);
+  if (U_FAILURE(status)) {
+      return;
+  }
   DateFormat::adoptCalendar(calendarToAdopt);
   delete fSymbols;
-  fSymbols=NULL;
-  initializeSymbols(fLocale, fCalendar, status);  // we need new symbols
+  fSymbols = newSymbols;
   initializeDefaultCentury();  // we need a new century (possibly)
 }
 
index b3f0fd8302ae8a70acad39d643b3c0744bacf855..66b3ef98990b731c23e57f7769732d87fbf73955 100644 (file)
@@ -2461,6 +2461,34 @@ private:
      * @return TRUE if a transition is found.
      */
     UBool getImmediatePreviousZoneTransition(UDate base, UDate *transitionTime, UErrorCode& status) const;
+
+public:
+    /**
+     * Creates a new Calendar from a Locale for the cache.
+     * This method does not set the time or timezone in returned calendar.
+     * @param locale the locale.
+     * @param status any error returned here.
+     * @return the new Calendar object with no time or timezone set.
+     * @internal For ICU use only.
+     */
+    static Calendar U_EXPORT2 *makeInstance(
+            const Locale &locale, UErrorCode &status);
+
+    /**
+     * Get the calendar type for given locale.
+     * @param locale the locale
+     * @param typeBuffer calendar type returned here
+     * @param typeBufferSize The size of typeBuffer in bytes. If the type
+     *   can't fit in the buffer, this method sets status to
+     *   U_BUFFER_OVERFLOW_ERROR
+     * @param status error, if any, returned here.
+     * @internal For ICU use only.
+     */
+    static void U_EXPORT2 getCalendarTypeFromLocale(
+            const Locale &locale,
+            char *typeBuffer,
+            int32_t typeBufferSize,
+            UErrorCode &status);
 };
 
 // -------------------------------------
index 8010914685f4088fafc45d53f3b69468a38ec62a..37b0a6d4d9bca91fbc53ff2a08cfc8881012afd0 100644 (file)
@@ -902,6 +902,20 @@ private:
      * Returns TRUE if c (repeated count times) is the pattern character for a numeric field.
      */
     static UBool U_EXPORT2 isNumericPatternChar(UChar c, int32_t count);
+public:
+    /**
+     * Gets a DateFormatSymbols by locale.
+     * Unlike the constructors which always use gregorian calendar, this
+     * method uses the calendar in the locale. If the locale contains no
+     * explicit calendar, this method uses the default calendar for that
+     * locale.
+     * @param locale the locale.
+     * @param status error returned here.
+     * @return the new DateFormatSymbols which the caller owns.
+     * @internal For ICU use only.
+     */
+    static DateFormatSymbols * U_EXPORT2 createForLocale(
+            const Locale &locale, UErrorCode &status);
 };
 
 U_NAMESPACE_END
index 585ea10a1716ee445e311827de963ea6222abdd2..3f1e7d796441b43bf85e31c655b732e26beecc8d 100644 (file)
@@ -1310,14 +1310,6 @@ private:
      */
     Calendar *initializeCalendar(TimeZone* adoptZone, const Locale& locale, UErrorCode& status);
 
-    /**
-     * initializes fSymbols from parameters.
-     * @param locale Locale of the symbols
-     * @param calendar Alias to Calendar that will be used.
-     * @param status Error code
-     */
-    void initializeSymbols(const Locale& locale, Calendar* calendar, UErrorCode& status);
-
     /**
      * Called by several of the constructors to load pattern data and formatting symbols
      * out of a resource bundle and initialize the locale based on it.
index 2a602ecb34b3a8500bbf230b140d0a4a1f29bf81..e15fa9e8e3e586464cb960ba5ed84e3fa2306fdf 100644 (file)
@@ -108,6 +108,9 @@ void DateFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &nam
     TESTCASE_AUTO(TestCreateInstanceForSkeleton);
     TESTCASE_AUTO(TestCreateInstanceForSkeletonDefault);
     TESTCASE_AUTO(TestCreateInstanceForSkeletonWithCalendar);
+    TESTCASE_AUTO(TestDFSCreateForLocaleNonGregorianLocale);
+    TESTCASE_AUTO(TestDFSCreateForLocaleWithCalendarInLocale);
+    TESTCASE_AUTO(TestChangeCalendar);
 
     TESTCASE_AUTO_END;
 }
@@ -4686,6 +4689,63 @@ void DateFormatTest::TestCreateInstanceForSkeletonWithCalendar() {
     assertSuccess("", status);
 }
 
+void DateFormatTest::TestDFSCreateForLocaleNonGregorianLocale() {
+    UErrorCode status = U_ZERO_ERROR;
+    Locale fa("fa");
+    LocalPointer<DateFormatSymbols> sym(
+            DateFormatSymbols::createForLocale(fa, status));
+    if (!assertSuccess("", status)) {
+        return;
+    }
+
+    // Farsi should default to the persian calendar, not gregorian
+    int32_t count;
+    const UnicodeString *months = sym->getShortMonths(count);
+
+    // First persian month.
+    UnicodeString expected("\\u0641\\u0631\\u0648\\u0631\\u062f\\u06cc\\u0646");
+    assertEquals("", expected.unescape(), months[0]);
+}
+
+void DateFormatTest::TestDFSCreateForLocaleWithCalendarInLocale() {
+    UErrorCode status = U_ZERO_ERROR;
+    Locale en_heb("en@calendar=hebrew");
+    LocalPointer<DateFormatSymbols> sym(
+            DateFormatSymbols::createForLocale(en_heb, status));
+    if (!assertSuccess("", status)) {
+        return;
+    }
+
+    // We should get the months of the hebrew calendar, not the gregorian
+    // calendar.
+    int32_t count;
+    const UnicodeString *months = sym->getShortMonths(count);
+
+    // First hebrew month.
+    UnicodeString expected("Tishri");
+    assertEquals("", expected, months[0]);
+}
+
+void DateFormatTest::TestChangeCalendar() {
+    UErrorCode status = U_ZERO_ERROR;
+    Locale en("en");
+    Locale en_heb("en@calendar=hebrew");
+    LocalPointer<DateFormat> fmt(
+            DateFormat::createInstanceForSkeleton("yMMMd", en, status));
+    if (!assertSuccess("", status)) {
+        return;
+    }
+    fmt->adoptCalendar(Calendar::createInstance(en_heb, status));
+    if (!assertSuccess("", status)) {
+        return;
+    }
+    UnicodeString result;
+    FieldPosition pos(0);
+    fmt->format(date(98, 5-1, 25), result, pos);
+    assertEquals("format yMMMd", "Iyar 29, 5758", result);
+}
+
+
 #endif /* #if !UCONFIG_NO_FORMATTING */
 
 //eof
index ae165d5fee8c954e36ece052e48e09837f3553b3..2c3ef5c995066509d02fa94306dc1972b3282e9b 100644 (file)
@@ -244,6 +244,9 @@ public:
     void TestCreateInstanceForSkeleton();
     void TestCreateInstanceForSkeletonDefault();
     void TestCreateInstanceForSkeletonWithCalendar();
+    void TestDFSCreateForLocaleNonGregorianLocale();
+    void TestDFSCreateForLocaleWithCalendarInLocale();
+    void TestChangeCalendar();
 
 private:
     UBool showParse(DateFormat &format, const UnicodeString &formattedString);