]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/i18n/simpletz.cpp
ICU-64232.0.1.tar.gz
[apple/icu.git] / icuSources / i18n / simpletz.cpp
index f04f85f0dbbf9c8d15d6b32ed0dc87c753effb49..9321fda3447d1835e5d6e94cb1eaba18ef569210 100644 (file)
@@ -1,6 +1,8 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
 /*
  *******************************************************************************
- * Copyright (C) 1997-2011, International Business Machines Corporation and
+ * Copyright (C) 1997-2013, International Business Machines Corporation and
  * others. All Rights Reserved.
  *******************************************************************************
  *
@@ -21,7 +23,7 @@
  ********************************************************************************
  */
 
-#include <typeinfo>  // for 'typeid' to work
+#include "utypeinfo.h"  // for 'typeid' to work
 
 #include "unicode/utypes.h"
 
@@ -31,7 +33,9 @@
 #include "unicode/gregocal.h"
 #include "unicode/smpdtfmt.h"
 
+#include "cmemory.h"
 #include "gregoimp.h"
+#include "umutex.h"
 
 U_NAMESPACE_BEGIN
 
@@ -174,7 +178,7 @@ void SimpleTimeZone::construct(int32_t rawOffsetGMT,
 
     decodeRules(status);
 
-    if (savingsDST <= 0) {
+    if (savingsDST == 0) {
         status = U_ILLEGAL_ARGUMENT_ERROR;
     }
 }
@@ -506,7 +510,7 @@ SimpleTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
 
 void
 SimpleTimeZone::getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
-                                   int32_t& rawOffsetGMT, int32_t& savingsDST, UErrorCode& status) /*const*/ {
+                                   int32_t& rawOffsetGMT, int32_t& savingsDST, UErrorCode& status) const {
     if (U_FAILURE(status)) {
         return;
     }
@@ -683,7 +687,7 @@ SimpleTimeZone::setRawOffset(int32_t offsetMillis)
 void 
 SimpleTimeZone::setDSTSavings(int32_t millisSavedDuringDST, UErrorCode& status) 
 {
-    if (millisSavedDuringDST <= 0) {
+    if (millisSavedDuringDST == 0) {
         status = U_ILLEGAL_ARGUMENT_ERROR;
     }
     else {
@@ -967,13 +971,13 @@ SimpleTimeZone::decodeEndRule(UErrorCode& status)
 }
 
 UBool
-SimpleTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/ {
+SimpleTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const {
     if (!useDaylight) {
         return FALSE;
     }
 
     UErrorCode status = U_ZERO_ERROR;
-    initTransitionRules(status);
+    checkTransitionRules(status);
     if (U_FAILURE(status)) {
         return FALSE;
     }
@@ -1001,13 +1005,13 @@ SimpleTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransitio
 }
 
 UBool
-SimpleTimeZone::getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/ {
+SimpleTimeZone::getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const {
     if (!useDaylight) {
         return FALSE;
     }
 
     UErrorCode status = U_ZERO_ERROR;
-    initTransitionRules(status);
+    checkTransitionRules(status);
     if (U_FAILURE(status)) {
         return FALSE;
     }
@@ -1060,6 +1064,35 @@ SimpleTimeZone::deleteTransitionRules(void) {
     clearTransitionRules();
  }
 
+/*
+ * Lazy transition rules initializer
+ *
+ *    Note On the removal of UMTX_CHECK from checkTransitionRules():
+ *
+ *         It would be faster to have a UInitOnce as part of a SimpleTimeZone object,
+ *         which would avoid needing to lock a mutex to check the initialization state.
+ *         But we can't easily because simpletz.h is a public header, and including
+ *         a UInitOnce as a member of SimpleTimeZone would publicly expose internal ICU headers.
+ *
+ *         Alternatively we could have a pointer to a UInitOnce in the SimpleTimeZone object,
+ *         allocate it in the constructors. This would be a more intrusive change, but doable
+ *         if performance turns out to be an issue.
+ */
+
+void
+SimpleTimeZone::checkTransitionRules(UErrorCode& status) const {
+    if (U_FAILURE(status)) {
+        return;
+    }
+    static UMutex *gLock = STATIC_NEW(UMutex);
+    umtx_lock(gLock);
+    if (!transitionRulesInitialized) {
+        SimpleTimeZone *ncThis = const_cast<SimpleTimeZone*>(this);
+        ncThis->initTransitionRules(status);
+    }
+    umtx_unlock(gLock);
+}
+
 void
 SimpleTimeZone::initTransitionRules(UErrorCode& status) {
     if (U_FAILURE(status)) {
@@ -1099,8 +1132,8 @@ SimpleTimeZone::initTransitionRules(UErrorCode& status) {
         }
         // Check for Null pointer
         if (dtRule == NULL) {
-               status = U_MEMORY_ALLOCATION_ERROR;
-               return;
+            status = U_MEMORY_ALLOCATION_ERROR;
+            return;
         }
         // For now, use ID + "(DST)" as the name
         dstRule = new AnnualTimeZoneRule(tzid+UnicodeString(DST_STR), getRawOffset(), getDSTSavings(),
@@ -1108,9 +1141,9 @@ SimpleTimeZone::initTransitionRules(UErrorCode& status) {
         
         // Check for Null pointer
         if (dstRule == NULL) {
-               status = U_MEMORY_ALLOCATION_ERROR;
-               deleteTransitionRules();
-               return;
+            status = U_MEMORY_ALLOCATION_ERROR;
+            deleteTransitionRules();
+            return;
         }
  
         // Calculate the first DST start time
@@ -1136,9 +1169,9 @@ SimpleTimeZone::initTransitionRules(UErrorCode& status) {
         
         // Check for Null pointer
         if (dtRule == NULL) {
-               status = U_MEMORY_ALLOCATION_ERROR;
-               deleteTransitionRules();
-               return;
+            status = U_MEMORY_ALLOCATION_ERROR;
+            deleteTransitionRules();
+            return;
         }
         // For now, use ID + "(STD)" as the name
         stdRule = new AnnualTimeZoneRule(tzid+UnicodeString(STD_STR), getRawOffset(), 0,
@@ -1146,9 +1179,9 @@ SimpleTimeZone::initTransitionRules(UErrorCode& status) {
         
         //Check for Null pointer
         if (stdRule == NULL) {
-               status = U_MEMORY_ALLOCATION_ERROR;
-               deleteTransitionRules();
-               return;
+            status = U_MEMORY_ALLOCATION_ERROR;
+            deleteTransitionRules();
+            return;
         }
 
         // Calculate the first STD start time
@@ -1157,16 +1190,25 @@ SimpleTimeZone::initTransitionRules(UErrorCode& status) {
         // Create a TimeZoneRule for initial time
         if (firstStdStart < firstDstStart) {
             initialRule = new InitialTimeZoneRule(tzid+UnicodeString(DST_STR), getRawOffset(), dstRule->getDSTSavings());
+            if (initialRule == NULL) {
+                status = U_MEMORY_ALLOCATION_ERROR;
+                deleteTransitionRules();
+                return;
+            }
             firstTransition = new TimeZoneTransition(firstStdStart, *initialRule, *stdRule);
         } else {
             initialRule = new InitialTimeZoneRule(tzid+UnicodeString(STD_STR), getRawOffset(), 0);
+            if (initialRule == NULL) {
+                status = U_MEMORY_ALLOCATION_ERROR;
+                deleteTransitionRules();
+                return;
+            }
             firstTransition = new TimeZoneTransition(firstDstStart, *initialRule, *dstRule);
         }
-        // Check for null pointers.
-        if (initialRule == NULL || firstTransition == NULL) {
-               status = U_MEMORY_ALLOCATION_ERROR;
-               deleteTransitionRules();
-               return;
+        if (firstTransition == NULL) {
+            status = U_MEMORY_ALLOCATION_ERROR;
+            deleteTransitionRules();
+            return;
         }
         
     } else {
@@ -1174,17 +1216,17 @@ SimpleTimeZone::initTransitionRules(UErrorCode& status) {
         initialRule = new InitialTimeZoneRule(tzid, getRawOffset(), 0);
         // Check for null pointer.
         if (initialRule == NULL) {
-               status = U_MEMORY_ALLOCATION_ERROR;
-               deleteTransitionRules();
-               return;
+            status = U_MEMORY_ALLOCATION_ERROR;
+            deleteTransitionRules();
+            return;
         }
     }
 
-    transitionRulesInitialized = true;
+    transitionRulesInitialized = TRUE;
 }
 
 int32_t
-SimpleTimeZone::countTransitionRules(UErrorCode& /*status*/) /*const*/ {
+SimpleTimeZone::countTransitionRules(UErrorCode& /*status*/) const {
     return (useDaylight) ? 2 : 0;
 }
 
@@ -1192,11 +1234,11 @@ void
 SimpleTimeZone::getTimeZoneRules(const InitialTimeZoneRule*& initial,
                                  const TimeZoneRule* trsrules[],
                                  int32_t& trscount,
-                                 UErrorCode& status) /*const*/ {
+                                 UErrorCode& status) const {
     if (U_FAILURE(status)) {
         return;
     }
-    initTransitionRules(status);
+    checkTransitionRules(status);
     if (U_FAILURE(status)) {
         return;
     }