/*
*******************************************************************************
-* Copyright (C) 2003-2012, International Business Machines Corporation and *
+* Copyright (C) 2003-2013, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*
}
#endif
-// default century
-const UDate BuddhistCalendar::fgSystemDefaultCentury = DBL_MIN;
-const int32_t BuddhistCalendar::fgSystemDefaultCenturyYear = -1;
-
-UDate BuddhistCalendar::fgSystemDefaultCenturyStart = DBL_MIN;
-int32_t BuddhistCalendar::fgSystemDefaultCenturyStartYear = -1;
+/**
+ * The system maintains a static default century start date. This is initialized
+ * the first time it is used. Once the system default century date and year
+ * are set, they do not change.
+ */
+static UDate gSystemDefaultCenturyStart = DBL_MIN;
+static int32_t gSystemDefaultCenturyStartYear = -1;
+static UInitOnce gBCInitOnce;
UBool BuddhistCalendar::haveDefaultCentury() const
return TRUE;
}
-UDate BuddhistCalendar::defaultCenturyStart() const
-{
- return internalGetDefaultCenturyStart();
-}
-
-int32_t BuddhistCalendar::defaultCenturyStartYear() const
-{
- return internalGetDefaultCenturyStartYear();
-}
-
-UDate
-BuddhistCalendar::internalGetDefaultCenturyStart() const
-{
- // lazy-evaluate systemDefaultCenturyStart
- UBool needsUpdate;
- UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate);
-
- if (needsUpdate) {
- initializeSystemDefaultCentury();
- }
-
- // use defaultCenturyStart unless it's the flag value;
- // then use systemDefaultCenturyStart
-
- return fgSystemDefaultCenturyStart;
-}
-
-int32_t
-BuddhistCalendar::internalGetDefaultCenturyStartYear() const
-{
- // lazy-evaluate systemDefaultCenturyStartYear
- UBool needsUpdate;
- UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate);
-
- if (needsUpdate) {
- initializeSystemDefaultCentury();
- }
-
- // use defaultCenturyStart unless it's the flag value;
- // then use systemDefaultCenturyStartYear
-
- return fgSystemDefaultCenturyStartYear;
-}
-
-void
-BuddhistCalendar::initializeSystemDefaultCentury()
+static void U_CALLCONV
+initializeSystemDefaultCentury()
{
// initialize systemDefaultCentury and systemDefaultCenturyYear based
// on the current time. They'll be set to 80 years before
// the current time.
UErrorCode status = U_ZERO_ERROR;
BuddhistCalendar calendar(Locale("@calendar=buddhist"),status);
- if (U_SUCCESS(status))
- {
+ if (U_SUCCESS(status)) {
calendar.setTime(Calendar::getNow(), status);
calendar.add(UCAL_YEAR, -80, status);
UDate newStart = calendar.getTime(status);
int32_t newYear = calendar.get(UCAL_YEAR, status);
- umtx_lock(NULL);
- if (fgSystemDefaultCenturyStart == fgSystemDefaultCentury) {
- fgSystemDefaultCenturyStartYear = newYear;
- fgSystemDefaultCenturyStart = newStart;
- }
- umtx_unlock(NULL);
+ gSystemDefaultCenturyStartYear = newYear;
+ gSystemDefaultCenturyStart = newStart;
}
// We have no recourse upon failure unless we want to propagate the failure
// out.
}
+UDate BuddhistCalendar::defaultCenturyStart() const
+{
+ // lazy-evaluate systemDefaultCenturyStart and systemDefaultCenturyStartYear
+ umtx_initOnce(gBCInitOnce, &initializeSystemDefaultCentury);
+ return gSystemDefaultCenturyStart;
+}
+
+int32_t BuddhistCalendar::defaultCenturyStartYear() const
+{
+ // lazy-evaluate systemDefaultCenturyStartYear and systemDefaultCenturyStart
+ umtx_initOnce(gBCInitOnce, &initializeSystemDefaultCentury);
+ return gSystemDefaultCenturyStartYear;
+}
+
U_NAMESPACE_END
/*
********************************************************************************
- * Copyright (C) 2003-2007, International Business Machines Corporation
+ * Copyright (C) 2003-2013, International Business Machines Corporation
* and others. All Rights Reserved.
********************************************************************************
*
* @internal
*/
virtual int32_t defaultCenturyStartYear() const;
-
- private: // default century stuff.
- /**
- * The system maintains a static default century start date. This is initialized
- * the first time it is used. Before then, it is set to SYSTEM_DEFAULT_CENTURY to
- * indicate an uninitialized state. Once the system default century date and year
- * are set, they do not change.
- */
- static UDate fgSystemDefaultCenturyStart;
-
- /**
- * See documentation for systemDefaultCenturyStart.
- */
- static int32_t fgSystemDefaultCenturyStartYear;
-
- /**
- * Default value that indicates the defaultCenturyStartYear is unitialized
- */
- static const int32_t fgSystemDefaultCenturyYear;
-
- /**
- * start of default century, as a date
- */
- static const UDate fgSystemDefaultCentury;
-
- /**
- * Returns the beginning date of the 100-year window that dates
- * with 2-digit years are considered to fall within.
- */
- UDate internalGetDefaultCenturyStart(void) const;
-
- /**
- * Returns the first year of the 100-year window that dates with
- * 2-digit years are considered to fall within.
- */
- int32_t internalGetDefaultCenturyStartYear(void) const;
-
- /**
- * Initializes the 100-year window that dates with 2-digit years
- * are considered to fall within so that its start date is 80 years
- * before the current time.
- */
- static void initializeSystemDefaultCentury(void);
};
U_NAMESPACE_END
#if !UCONFIG_NO_SERVICE
static icu::ICULocaleService* gService = NULL;
+static UInitOnce gServiceInitOnce = U_INITONCE_INITIALIZER;
#endif
// INTERNAL - for cleanup
delete gService;
gService = NULL;
}
+ gServiceInitOnce.reset();
#endif
return TRUE;
}
static inline UBool
isCalendarServiceUsed() {
- UBool retVal;
- UMTX_CHECK(NULL, gService != NULL, retVal);
- return retVal;
+ return !gServiceInitOnce.isReset();
}
// -------------------------------------
-static ICULocaleService*
-getCalendarService(UErrorCode &status)
+static void U_CALLCONV
+initCalendarService(UErrorCode &status)
{
- UBool needInit;
- UMTX_CHECK(NULL, (UBool)(gService == NULL), needInit);
- if (needInit) {
#ifdef U_DEBUG_CALSVC
- fprintf(stderr, "Spinning up Calendar Service\n");
+ fprintf(stderr, "Spinning up Calendar Service\n");
#endif
- ICULocaleService * newservice = new CalendarService();
- if (newservice == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return newservice;
- }
+ ucln_i18n_registerCleanup(UCLN_I18N_CALENDAR, calendar_cleanup);
+ gService = new CalendarService();
+ if (gService == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
#ifdef U_DEBUG_CALSVC
- fprintf(stderr, "Registering classes..\n");
+ fprintf(stderr, "Registering classes..\n");
#endif
- // Register all basic instances.
- newservice->registerFactory(new BasicCalendarFactory(),status);
+ // Register all basic instances.
+ gService->registerFactory(new BasicCalendarFactory(),status);
#ifdef U_DEBUG_CALSVC
- fprintf(stderr, "Done..\n");
+ fprintf(stderr, "Done..\n");
#endif
- if(U_FAILURE(status)) {
+ if(U_FAILURE(status)) {
#ifdef U_DEBUG_CALSVC
- fprintf(stderr, "err (%s) registering classes, deleting service.....\n", u_errorName(status));
+ fprintf(stderr, "err (%s) registering classes, deleting service.....\n", u_errorName(status));
#endif
- delete newservice;
- newservice = NULL;
- }
-
- if (newservice) {
- umtx_lock(NULL);
- if (gService == NULL) {
- gService = newservice;
- newservice = NULL;
- }
- umtx_unlock(NULL);
- }
- if (newservice) {
- delete newservice;
- } else {
- // we won the contention - we can register the cleanup.
- ucln_i18n_registerCleanup(UCLN_I18N_CALENDAR, calendar_cleanup);
- }
+ delete gService;
+ gService = NULL;
}
+}
+
+static ICULocaleService*
+getCalendarService(UErrorCode &status)
+{
+ umtx_initOnce(gServiceInitOnce, &initCalendarService, status);
return gService;
}
+
URegistryKey Calendar::registerFactory(ICUServiceFactory* toAdopt, UErrorCode& status)
{
return getCalendarService(status)->registerFactory(toAdopt, status);
static icu::CalendarCache *gChineseCalendarWinterSolsticeCache = NULL;
static icu::CalendarCache *gChineseCalendarNewYearCache = NULL;
static icu::TimeZone *gChineseCalendarZoneAstroCalc = NULL;
-static UBool gChineseCalendarZoneAstroCalcInitialized = FALSE;
+static UInitOnce gChineseCalendarZoneAstroCalcInitOnce = U_INITONCE_INITIALIZER;
/**
* The start year of the Chinese calendar, the 61st year of the reign
delete gChineseCalendarZoneAstroCalc;
gChineseCalendarZoneAstroCalc = NULL;
}
- gChineseCalendarZoneAstroCalcInitialized = FALSE;
+ gChineseCalendarZoneAstroCalcInitOnce.reset();
return TRUE;
}
U_CDECL_END
return "chinese";
}
+static void U_CALLCONV initChineseCalZoneAstroCalc() {
+ gChineseCalendarZoneAstroCalc = new SimpleTimeZone(CHINA_OFFSET, UNICODE_STRING_SIMPLE("CHINA_ZONE") );
+ ucln_i18n_registerCleanup(UCLN_I18N_CHINESE_CALENDAR, calendar_chinese_cleanup);
+}
+
const TimeZone* ChineseCalendar::getChineseCalZoneAstroCalc(void) const {
- UBool initialized;
- UMTX_CHECK(&astroLock, gChineseCalendarZoneAstroCalcInitialized, initialized);
- if (!initialized) {
- umtx_lock(&astroLock);
- {
- if (!gChineseCalendarZoneAstroCalcInitialized) {
- gChineseCalendarZoneAstroCalc = new SimpleTimeZone(CHINA_OFFSET, UNICODE_STRING_SIMPLE("CHINA_ZONE") );
- gChineseCalendarZoneAstroCalcInitialized = TRUE;
- ucln_i18n_registerCleanup(UCLN_I18N_CHINESE_CALENDAR, calendar_chinese_cleanup);
- }
- }
- umtx_unlock(&astroLock);
- }
+ umtx_initOnce(gChineseCalendarZoneAstroCalcInitOnce, &initChineseCalZoneAstroCalc);
return gChineseCalendarZoneAstroCalc;
}
}
// default century
-const UDate ChineseCalendar::fgSystemDefaultCentury = DBL_MIN;
-const int32_t ChineseCalendar::fgSystemDefaultCenturyYear = -1;
-UDate ChineseCalendar::fgSystemDefaultCenturyStart = DBL_MIN;
-int32_t ChineseCalendar::fgSystemDefaultCenturyStartYear = -1;
+static UDate gSystemDefaultCenturyStart = DBL_MIN;
+static int32_t gSystemDefaultCenturyStartYear = -1;
+static UInitOnce gSystemDefaultCenturyInitOnce = U_INITONCE_INITIALIZER;
UBool ChineseCalendar::haveDefaultCentury() const
return internalGetDefaultCenturyStartYear();
}
-UDate
-ChineseCalendar::internalGetDefaultCenturyStart() const
-{
- // lazy-evaluate systemDefaultCenturyStart
- UBool needsUpdate;
- UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate);
-
- if (needsUpdate) {
- initializeSystemDefaultCentury();
- }
-
- // use defaultCenturyStart unless it's the flag value;
- // then use systemDefaultCenturyStart
-
- return fgSystemDefaultCenturyStart;
-}
-
-int32_t
-ChineseCalendar::internalGetDefaultCenturyStartYear() const
-{
- // lazy-evaluate systemDefaultCenturyStartYear
- UBool needsUpdate;
- UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate);
-
- if (needsUpdate) {
- initializeSystemDefaultCentury();
- }
-
- // use defaultCenturyStart unless it's the flag value;
- // then use systemDefaultCenturyStartYear
-
- return fgSystemDefaultCenturyStartYear;
-}
-
-void
-ChineseCalendar::initializeSystemDefaultCentury()
+static void U_CALLCONV initializeSystemDefaultCentury()
{
// initialize systemDefaultCentury and systemDefaultCenturyYear based
// on the current time. They'll be set to 80 years before
// the current time.
UErrorCode status = U_ZERO_ERROR;
ChineseCalendar calendar(Locale("@calendar=chinese"),status);
- if (U_SUCCESS(status))
- {
+ if (U_SUCCESS(status)) {
calendar.setTime(Calendar::getNow(), status);
calendar.add(UCAL_YEAR, -80, status);
- UDate newStart = calendar.getTime(status);
- int32_t newYear = calendar.get(UCAL_YEAR, status);
- umtx_lock(NULL);
- if (fgSystemDefaultCenturyStart == fgSystemDefaultCentury)
- {
- fgSystemDefaultCenturyStartYear = newYear;
- fgSystemDefaultCenturyStart = newStart;
- }
- umtx_unlock(NULL);
+ gSystemDefaultCenturyStart = calendar.getTime(status);
+ gSystemDefaultCenturyStartYear = calendar.get(UCAL_YEAR, status);
}
// We have no recourse upon failure unless we want to propagate the failure
// out.
}
+UDate
+ChineseCalendar::internalGetDefaultCenturyStart() const
+{
+ // lazy-evaluate systemDefaultCenturyStart
+ umtx_initOnce(gSystemDefaultCenturyInitOnce, &initializeSystemDefaultCentury);
+ return gSystemDefaultCenturyStart;
+}
+
+int32_t
+ChineseCalendar::internalGetDefaultCenturyStartYear() const
+{
+ // lazy-evaluate systemDefaultCenturyStartYear
+ umtx_initOnce(gSystemDefaultCenturyInitOnce, &initializeSystemDefaultCentury);
+ return gSystemDefaultCenturyStartYear;
+}
+
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ChineseCalendar)
U_NAMESPACE_END
virtual int32_t defaultCenturyStartYear() const;
private: // default century stuff.
- /**
- * The system maintains a static default century start date. This is initialized
- * the first time it is used. Before then, it is set to SYSTEM_DEFAULT_CENTURY to
- * indicate an uninitialized state. Once the system default century date and year
- * are set, they do not change.
- */
- static UDate fgSystemDefaultCenturyStart;
-
- /**
- * See documentation for systemDefaultCenturyStart.
- */
- static int32_t fgSystemDefaultCenturyStartYear;
-
- /**
- * Default value that indicates the defaultCenturyStartYear is unitialized
- */
- static const int32_t fgSystemDefaultCenturyYear;
-
- /**
- * start of default century, as a date
- */
- static const UDate fgSystemDefaultCentury;
/**
* Returns the beginning date of the 100-year window that dates
*/
int32_t internalGetDefaultCenturyStartYear(void) const;
- /**
- * Initializes the 100-year window that dates with 2-digit years
- * are considered to fall within so that its start date is 80 years
- * before the current time.
- */
- static void initializeSystemDefaultCentury(void);
-
ChineseCalendar(); // default constructor not implemented
};
/*
******************************************************************************
- * Copyright (C) 1996-2012, International Business Machines Corporation and
+ * Copyright (C) 1996-2013, International Business Machines Corporation and
* others. All Rights Reserved.
******************************************************************************
*/
#include "cmemory.h"
#include "umutex.h"
#include "servloc.h"
+#include "uassert.h"
#include "ustrenum.h"
#include "uresimp.h"
#include "ucln_in.h"
static icu::Locale* availableLocaleList = NULL;
static int32_t availableLocaleListCount;
static icu::ICULocaleService* gService = NULL;
+static UInitOnce gServiceInitOnce = U_INITONCE_INITIALIZER;
+static UInitOnce gAvailableLocaleListInitOnce;
/**
* Release all static memory held by collator.
delete gService;
gService = NULL;
}
+ gServiceInitOnce.reset();
#endif
if (availableLocaleList) {
delete []availableLocaleList;
availableLocaleList = NULL;
}
availableLocaleListCount = 0;
-
+ gAvailableLocaleListInitOnce.reset();
return TRUE;
}
// -------------------------------------
+static void U_CALLCONV initService() {
+ gService = new ICUCollatorService();
+ ucln_i18n_registerCleanup(UCLN_I18N_COLLATOR, collator_cleanup);
+}
+
+
static ICULocaleService*
getService(void)
{
- UBool needInit;
- UMTX_CHECK(NULL, (UBool)(gService == NULL), needInit);
- if(needInit) {
- ICULocaleService *newservice = new ICUCollatorService();
- if(newservice) {
- umtx_lock(NULL);
- if(gService == NULL) {
- gService = newservice;
- newservice = NULL;
- }
- umtx_unlock(NULL);
- }
- if(newservice) {
- delete newservice;
- }
- else {
- ucln_i18n_registerCleanup(UCLN_I18N_COLLATOR, collator_cleanup);
- }
- }
+ umtx_initOnce(gServiceInitOnce, &initService);
return gService;
}
static inline UBool
hasService(void)
{
- UBool retVal;
- UMTX_CHECK(NULL, gService != NULL, retVal);
+ UBool retVal = !gServiceInitOnce.isReset() && (getService() != NULL);
return retVal;
}
}
#endif /* UCONFIG_NO_SERVICE */
-static UBool isAvailableLocaleListInitialized(UErrorCode &status) {
+static void U_CALLCONV
+initAvailableLocaleList(UErrorCode &status) {
+ U_ASSERT(availableLocaleListCount == 0);
+ U_ASSERT(availableLocaleList == NULL);
// for now, there is a hardcoded list, so just walk through that list and set it up.
- UBool needInit;
- UMTX_CHECK(NULL, availableLocaleList == NULL, needInit);
-
- if (needInit) {
- UResourceBundle *index = NULL;
- UResourceBundle installed;
- Locale * temp;
- int32_t i = 0;
- int32_t localeCount;
-
- ures_initStackObject(&installed);
- index = ures_openDirect(U_ICUDATA_COLL, "res_index", &status);
- ures_getByKey(index, "InstalledLocales", &installed, &status);
+ UResourceBundle *index = NULL;
+ UResourceBundle installed;
+ int32_t i = 0;
+
+ ures_initStackObject(&installed);
+ index = ures_openDirect(U_ICUDATA_COLL, "res_index", &status);
+ ures_getByKey(index, "InstalledLocales", &installed, &status);
+
+ if(U_SUCCESS(status)) {
+ availableLocaleListCount = ures_getSize(&installed);
+ availableLocaleList = new Locale[availableLocaleListCount];
- if(U_SUCCESS(status)) {
- localeCount = ures_getSize(&installed);
- temp = new Locale[localeCount];
-
- if (temp != NULL) {
- ures_resetIterator(&installed);
- while(ures_hasNext(&installed)) {
- const char *tempKey = NULL;
- ures_getNextString(&installed, NULL, &tempKey, &status);
- temp[i++] = Locale(tempKey);
- }
-
- umtx_lock(NULL);
- if (availableLocaleList == NULL)
- {
- availableLocaleListCount = localeCount;
- availableLocaleList = temp;
- temp = NULL;
- ucln_i18n_registerCleanup(UCLN_I18N_COLLATOR, collator_cleanup);
- }
- umtx_unlock(NULL);
-
- needInit = FALSE;
- if (temp) {
- delete []temp;
- }
+ if (availableLocaleList != NULL) {
+ ures_resetIterator(&installed);
+ while(ures_hasNext(&installed)) {
+ const char *tempKey = NULL;
+ ures_getNextString(&installed, NULL, &tempKey, &status);
+ availableLocaleList[i++] = Locale(tempKey);
}
-
- ures_close(&installed);
}
- ures_close(index);
+ U_ASSERT(availableLocaleListCount == i);
+ ures_close(&installed);
}
- return !needInit;
+ ures_close(index);
+ ucln_i18n_registerCleanup(UCLN_I18N_COLLATOR, collator_cleanup);
}
+static UBool isAvailableLocaleListInitialized(UErrorCode &status) {
+ umtx_initOnce(gAvailableLocaleListInitOnce, &initAvailableLocaleList, status);
+ return U_SUCCESS(status);
+}
+
+
// Collator public methods -----------------------------------------------
Collator* U_EXPORT2 Collator::createInstance(UErrorCode& success)
/*
*******************************************************************************
-* Copyright (C) 2003 - 2009, International Business Machines Corporation and *
+* Copyright (C) 2003 - 2013, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
internalSet(UCAL_DAY_OF_YEAR, (30 * month) + day);
}
-const UDate CopticCalendar::fgSystemDefaultCentury = DBL_MIN;
-const int32_t CopticCalendar::fgSystemDefaultCenturyYear = -1;
+/**
+ * The system maintains a static default century start date and Year. They are
+ * initialized the first time they are used. Once the system default century date
+ * and year are set, they do not change.
+ */
+static UDate gSystemDefaultCenturyStart = DBL_MIN;
+static int32_t gSystemDefaultCenturyStartYear = -1;
+static UInitOnce gSystemDefaultCenturyInit = U_INITONCE_INITIALIZER;
-UDate CopticCalendar::fgSystemDefaultCenturyStart = DBL_MIN;
-int32_t CopticCalendar::fgSystemDefaultCenturyStartYear = -1;
+
+static void U_CALLCONV initializeSystemDefaultCentury() {
+ UErrorCode status = U_ZERO_ERROR;
+ CopticCalendar calendar(Locale("@calendar=coptic"), status);
+ if (U_SUCCESS(status)) {
+ calendar.setTime(Calendar::getNow(), status);
+ calendar.add(UCAL_YEAR, -80, status);
+ gSystemDefaultCenturyStart = calendar.getTime(status);
+ gSystemDefaultCenturyStartYear = calendar.get(UCAL_YEAR, status);
+ }
+ // We have no recourse upon failure unless we want to propagate the failure
+ // out.
+}
UDate
CopticCalendar::defaultCenturyStart() const
{
- initializeSystemDefaultCentury();
-
- // use defaultCenturyStart unless it's the flag value;
- // then use systemDefaultCenturyStart
- return fgSystemDefaultCenturyStart;
+ // lazy-evaluate systemDefaultCenturyStart
+ umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury);
+ return gSystemDefaultCenturyStart;
}
int32_t
CopticCalendar::defaultCenturyStartYear() const
-{
- initializeSystemDefaultCentury();
-
- // use defaultCenturyStart unless it's the flag value;
- // then use systemDefaultCenturyStart
- return fgSystemDefaultCenturyStartYear;
-}
-
-void
-CopticCalendar::initializeSystemDefaultCentury()
{
// lazy-evaluate systemDefaultCenturyStart
- UBool needsUpdate;
- UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate);
-
- if (!needsUpdate) {
- return;
- }
-
- UErrorCode status = U_ZERO_ERROR;
-
- CopticCalendar calendar(Locale("@calendar=coptic"), status);
- if (U_SUCCESS(status)) {
- calendar.setTime(Calendar::getNow(), status);
- calendar.add(UCAL_YEAR, -80, status);
- UDate newStart = calendar.getTime(status);
- int32_t newYear = calendar.get(UCAL_YEAR, status);
- {
- umtx_lock(NULL);
- fgSystemDefaultCenturyStartYear = newYear;
- fgSystemDefaultCenturyStart = newStart;
- umtx_unlock(NULL);
- }
- }
- // We have no recourse upon failure unless we want to propagate the failure
- // out.
+ umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury);
+ return gSystemDefaultCenturyStartYear;
}
+
int32_t
CopticCalendar::getJDEpochOffset() const
{
/*
*******************************************************************************
-* Copyright (C) 2003 - 2008, International Business Machines Corporation and *
+* Copyright (C) 2003 - 2013, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
*/
virtual int32_t getJDEpochOffset() const;
-private:
- /**
- * The system maintains a static default century start date. This is initialized
- * the first time it is used. Before then, it is set to SYSTEM_DEFAULT_CENTURY to
- * indicate an uninitialized state. Once the system default century date and year
- * are set, they do not change.
- */
- static UDate fgSystemDefaultCenturyStart;
-
- /**
- * See documentation for systemDefaultCenturyStart.
- */
- static int32_t fgSystemDefaultCenturyStartYear;
-
- /**
- * Default value that indicates the defaultCenturyStartYear is unitialized
- */
- static const int32_t fgSystemDefaultCenturyYear;
-
- /**
- * start of default century, as a date
- */
- static const UDate fgSystemDefaultCentury;
-
- /**
- * Initializes the 100-year window that dates with 2-digit years
- * are considered to fall within so that its start date is 80 years
- * before the current time.
- */
- static void initializeSystemDefaultCentury(void);
public:
/**
/*
**********************************************************************
- * Copyright (C) 2005-2012, International Business Machines
+ * Copyright (C) 2005-2013, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
*/
#define NEW_ARRAY(type,count) (type *) uprv_malloc((count) * sizeof(type))
#define DELETE_ARRAY(array) uprv_free((void *) (array))
-U_CDECL_BEGIN
static icu::CharsetRecognizer **fCSRecognizers = NULL;
-
+static UInitOnce gCSRecognizersInitOnce;
static int32_t fCSRecognizers_size = 0;
+U_CDECL_BEGIN
static UBool U_CALLCONV csdet_cleanup(void)
{
+ U_NAMESPACE_USE
if (fCSRecognizers != NULL) {
for(int32_t r = 0; r < fCSRecognizers_size; r += 1) {
delete fCSRecognizers[r];
fCSRecognizers = NULL;
fCSRecognizers_size = 0;
}
+ gCSRecognizersInitOnce.reset();
return TRUE;
}
return (*csm_r)->getConfidence() - (*csm_l)->getConfidence();
}
+static void U_CALLCONV initRecognizers(UErrorCode &status) {
+ U_NAMESPACE_USE
+ ucln_i18n_registerCleanup(UCLN_I18N_CSDET, csdet_cleanup);
+ CharsetRecognizer *tempArray[] = {
+ new CharsetRecog_UTF8(),
+
+ new CharsetRecog_UTF_16_BE(),
+ new CharsetRecog_UTF_16_LE(),
+ new CharsetRecog_UTF_32_BE(),
+ new CharsetRecog_UTF_32_LE(),
+
+ new CharsetRecog_8859_1(),
+ new CharsetRecog_8859_2(),
+ new CharsetRecog_8859_5_ru(),
+ new CharsetRecog_8859_6_ar(),
+ new CharsetRecog_8859_7_el(),
+ new CharsetRecog_8859_8_I_he(),
+ new CharsetRecog_8859_8_he(),
+ new CharsetRecog_windows_1251(),
+ new CharsetRecog_windows_1256(),
+ new CharsetRecog_KOI8_R(),
+ new CharsetRecog_8859_9_tr(),
+ new CharsetRecog_sjis(),
+ new CharsetRecog_gb_18030(),
+ new CharsetRecog_euc_jp(),
+ new CharsetRecog_euc_kr(),
+ new CharsetRecog_big5(),
+
+ new CharsetRecog_2022JP(),
+ new CharsetRecog_2022KR(),
+ new CharsetRecog_2022CN(),
+
+ new CharsetRecog_IBM424_he_rtl(),
+ new CharsetRecog_IBM424_he_ltr(),
+ new CharsetRecog_IBM420_ar_rtl(),
+ new CharsetRecog_IBM420_ar_ltr()
+ };
+ int32_t rCount = ARRAY_SIZE(tempArray);
+
+ fCSRecognizers = NEW_ARRAY(CharsetRecognizer *, rCount);
+
+ if (fCSRecognizers == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ } else {
+ fCSRecognizers_size = rCount;
+ for (int32_t r = 0; r < rCount; r += 1) {
+ fCSRecognizers[r] = tempArray[r];
+ if (fCSRecognizers[r] == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ }
+ }
+}
+
U_CDECL_END
U_NAMESPACE_BEGIN
void CharsetDetector::setRecognizers(UErrorCode &status)
{
- UBool needsInit;
- CharsetRecognizer **recognizers;
-
- if (U_FAILURE(status)) {
- return;
- }
-
- UMTX_CHECK(NULL, (UBool) (fCSRecognizers == NULL), needsInit);
-
- if (needsInit) {
- CharsetRecognizer *tempArray[] = {
- new CharsetRecog_UTF8(),
-
- new CharsetRecog_UTF_16_BE(),
- new CharsetRecog_UTF_16_LE(),
- new CharsetRecog_UTF_32_BE(),
- new CharsetRecog_UTF_32_LE(),
-
- new CharsetRecog_8859_1(),
- new CharsetRecog_8859_2(),
- new CharsetRecog_8859_5_ru(),
- new CharsetRecog_8859_6_ar(),
- new CharsetRecog_8859_7_el(),
- new CharsetRecog_8859_8_I_he(),
- new CharsetRecog_8859_8_he(),
- new CharsetRecog_windows_1251(),
- new CharsetRecog_windows_1256(),
- new CharsetRecog_KOI8_R(),
- new CharsetRecog_8859_9_tr(),
- new CharsetRecog_sjis(),
- new CharsetRecog_gb_18030(),
- new CharsetRecog_euc_jp(),
- new CharsetRecog_euc_kr(),
- new CharsetRecog_big5(),
-
- new CharsetRecog_2022JP(),
- new CharsetRecog_2022KR(),
- new CharsetRecog_2022CN(),
-
- new CharsetRecog_IBM424_he_rtl(),
- new CharsetRecog_IBM424_he_ltr(),
- new CharsetRecog_IBM420_ar_rtl(),
- new CharsetRecog_IBM420_ar_ltr()
- };
- int32_t rCount = ARRAY_SIZE(tempArray);
- int32_t r;
-
- recognizers = NEW_ARRAY(CharsetRecognizer *, rCount);
-
- if (recognizers == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
- } else {
- for (r = 0; r < rCount; r += 1) {
- recognizers[r] = tempArray[r];
-
- if (recognizers[r] == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- break;
- }
- }
- }
-
- if (U_SUCCESS(status)) {
- umtx_lock(NULL);
- if (fCSRecognizers == NULL) {
- fCSRecognizers_size = rCount;
- fCSRecognizers = recognizers;
- }
- umtx_unlock(NULL);
- }
-
- if (fCSRecognizers != recognizers) {
- for (r = 0; r < rCount; r += 1) {
- delete recognizers[r];
- recognizers[r] = NULL;
- }
-
- DELETE_ARRAY(recognizers);
- }
-
- recognizers = NULL;
- ucln_i18n_registerCleanup(UCLN_I18N_CSDET, csdet_cleanup);
- }
+ umtx_initOnce(gCSRecognizersInitOnce, &initRecognizers, status);
}
CharsetDetector::CharsetDetector(UErrorCode &status)
#if !UCONFIG_NO_FORMATTING
-#include "umutex.h"
#include "gregoimp.h" // Math
+#include "uassert.h"
+#include "ucln_in.h"
+#include "umutex.h"
#include "unicode/rbtz.h"
#include "unicode/tzrule.h"
-#include "ucln_in.h"
// --- The cache --
-static UMutex dangiLock = U_MUTEX_INITIALIZER;
static icu::TimeZone *gDangiCalendarZoneAstroCalc = NULL;
-static UBool gDangiCalendarZoneAstroCalcInitialized = FALSE;
+static UInitOnce gDangiCalendarInitOnce = U_INITONCE_INITIALIZER;
/**
* The start year of the Korean traditional calendar (Dan-gi) is the inaugural
delete gDangiCalendarZoneAstroCalc;
gDangiCalendarZoneAstroCalc = NULL;
}
- gDangiCalendarZoneAstroCalcInitialized = FALSE;
+ gDangiCalendarInitOnce.reset();
return TRUE;
}
U_CDECL_END
* 1898-1911: GMT+8
* 1912- : GMT+9
*/
-const TimeZone* DangiCalendar::getDangiCalZoneAstroCalc(void) const {
- UBool initialized;
- UMTX_CHECK(&dangiLock, gDangiCalendarZoneAstroCalcInitialized, initialized);
- if (!initialized) {
- umtx_lock(&dangiLock);
- {
- if (!gDangiCalendarZoneAstroCalcInitialized) {
- const UDate millis1897[] = { (UDate)((1897 - 1970) * 365 * kOneDay) }; // some days of error is not a problem here
- const UDate millis1898[] = { (UDate)((1898 - 1970) * 365 * kOneDay) }; // some days of error is not a problem here
- const UDate millis1912[] = { (UDate)((1912 - 1970) * 365 * kOneDay) }; // this doesn't create an issue for 1911/12/20
- InitialTimeZoneRule* initialTimeZone = new InitialTimeZoneRule(UNICODE_STRING_SIMPLE("GMT+8"), 8*kOneHour, 0);
- TimeZoneRule* rule1897 = new TimeArrayTimeZoneRule(UNICODE_STRING_SIMPLE("Korean 1897"), 7*kOneHour, 0, millis1897, 1, DateTimeRule::STANDARD_TIME);
- TimeZoneRule* rule1898to1911 = new TimeArrayTimeZoneRule(UNICODE_STRING_SIMPLE("Korean 1898-1911"), 8*kOneHour, 0, millis1898, 1, DateTimeRule::STANDARD_TIME);
- TimeZoneRule* ruleFrom1912 = new TimeArrayTimeZoneRule(UNICODE_STRING_SIMPLE("Korean 1912-"), 9*kOneHour, 0, millis1912, 1, DateTimeRule::STANDARD_TIME);
- UErrorCode status = U_ZERO_ERROR;
- RuleBasedTimeZone* dangiCalZoneAstroCalc = new RuleBasedTimeZone(UNICODE_STRING_SIMPLE("KOREA_ZONE"), initialTimeZone); // adopts initialTimeZone
- dangiCalZoneAstroCalc->addTransitionRule(rule1897, status); // adopts rule1897
- dangiCalZoneAstroCalc->addTransitionRule(rule1898to1911, status);
- dangiCalZoneAstroCalc->addTransitionRule(ruleFrom1912, status);
- dangiCalZoneAstroCalc->complete(status);
- if (U_SUCCESS(status)) {
- gDangiCalendarZoneAstroCalc = dangiCalZoneAstroCalc;
- } else {
- delete dangiCalZoneAstroCalc;
- gDangiCalendarZoneAstroCalc = NULL;
- }
- gDangiCalendarZoneAstroCalcInitialized = TRUE;
- ucln_i18n_registerCleanup(UCLN_I18N_DANGI_CALENDAR, calendar_dangi_cleanup);
- }
- }
- umtx_unlock(&dangiLock);
+static void U_CALLCONV initDangiCalZoneAstroCalc(void) {
+ U_ASSERT(gDangiCalendarZoneAstroCalc == NULL);
+ const UDate millis1897[] = { (UDate)((1897 - 1970) * 365 * kOneDay) }; // some days of error is not a problem here
+ const UDate millis1898[] = { (UDate)((1898 - 1970) * 365 * kOneDay) }; // some days of error is not a problem here
+ const UDate millis1912[] = { (UDate)((1912 - 1970) * 365 * kOneDay) }; // this doesn't create an issue for 1911/12/20
+ InitialTimeZoneRule* initialTimeZone = new InitialTimeZoneRule(UNICODE_STRING_SIMPLE("GMT+8"), 8*kOneHour, 0);
+ TimeZoneRule* rule1897 = new TimeArrayTimeZoneRule(UNICODE_STRING_SIMPLE("Korean 1897"), 7*kOneHour, 0, millis1897, 1, DateTimeRule::STANDARD_TIME);
+ TimeZoneRule* rule1898to1911 = new TimeArrayTimeZoneRule(UNICODE_STRING_SIMPLE("Korean 1898-1911"), 8*kOneHour, 0, millis1898, 1, DateTimeRule::STANDARD_TIME);
+ TimeZoneRule* ruleFrom1912 = new TimeArrayTimeZoneRule(UNICODE_STRING_SIMPLE("Korean 1912-"), 9*kOneHour, 0, millis1912, 1, DateTimeRule::STANDARD_TIME);
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedTimeZone* dangiCalZoneAstroCalc = new RuleBasedTimeZone(UNICODE_STRING_SIMPLE("KOREA_ZONE"), initialTimeZone); // adopts initialTimeZone
+ dangiCalZoneAstroCalc->addTransitionRule(rule1897, status); // adopts rule1897
+ dangiCalZoneAstroCalc->addTransitionRule(rule1898to1911, status);
+ dangiCalZoneAstroCalc->addTransitionRule(ruleFrom1912, status);
+ dangiCalZoneAstroCalc->complete(status);
+ if (U_SUCCESS(status)) {
+ gDangiCalendarZoneAstroCalc = dangiCalZoneAstroCalc;
+ } else {
+ delete dangiCalZoneAstroCalc;
+ gDangiCalendarZoneAstroCalc = NULL;
}
+ ucln_i18n_registerCleanup(UCLN_I18N_DANGI_CALENDAR, calendar_dangi_cleanup);
+}
+
+const TimeZone* DangiCalendar::getDangiCalZoneAstroCalc(void) const {
+ umtx_initOnce(gDangiCalendarInitOnce, &initDangiCalZoneAstroCalc);
return gDangiCalendarZoneAstroCalc;
}
+
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DangiCalendar)
U_NAMESPACE_END
/*
*******************************************************************************
-* Copyright (C) 2009-2011, International Business Machines Corporation and *
+* Copyright (C) 2009-2013, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*
0x005B, 0x005C, 0x002D, 0x2212, 0x005D, 0x0000};
-DecimalFormatStaticSets *DecimalFormatStaticSets::gStaticSets = NULL;
-
-DecimalFormatStaticSets::DecimalFormatStaticSets(UErrorCode *status)
+DecimalFormatStaticSets::DecimalFormatStaticSets(UErrorCode &status)
: fDotEquivalents(NULL),
fCommaEquivalents(NULL),
fOtherGroupingSeparators(NULL),
fDefaultGroupingSeparators(NULL),
fStrictDefaultGroupingSeparators(NULL)
{
- fDotEquivalents = new UnicodeSet(UnicodeString(TRUE, gDotEquivalentsPattern, -1), *status);
- fCommaEquivalents = new UnicodeSet(UnicodeString(TRUE, gCommaEquivalentsPattern, -1), *status);
- fOtherGroupingSeparators = new UnicodeSet(UnicodeString(TRUE, gOtherGroupingSeparatorsPattern, -1), *status);
- fDashEquivalents = new UnicodeSet(UnicodeString(TRUE, gDashEquivalentsPattern, -1), *status);
+ fDotEquivalents = new UnicodeSet(UnicodeString(TRUE, gDotEquivalentsPattern, -1), status);
+ fCommaEquivalents = new UnicodeSet(UnicodeString(TRUE, gCommaEquivalentsPattern, -1), status);
+ fOtherGroupingSeparators = new UnicodeSet(UnicodeString(TRUE, gOtherGroupingSeparatorsPattern, -1), status);
+ fDashEquivalents = new UnicodeSet(UnicodeString(TRUE, gDashEquivalentsPattern, -1), status);
- fStrictDotEquivalents = new UnicodeSet(UnicodeString(TRUE, gStrictDotEquivalentsPattern, -1), *status);
- fStrictCommaEquivalents = new UnicodeSet(UnicodeString(TRUE, gStrictCommaEquivalentsPattern, -1), *status);
- fStrictOtherGroupingSeparators = new UnicodeSet(UnicodeString(TRUE, gStrictOtherGroupingSeparatorsPattern, -1), *status);
- fStrictDashEquivalents = new UnicodeSet(UnicodeString(TRUE, gStrictDashEquivalentsPattern, -1), *status);
+ fStrictDotEquivalents = new UnicodeSet(UnicodeString(TRUE, gStrictDotEquivalentsPattern, -1), status);
+ fStrictCommaEquivalents = new UnicodeSet(UnicodeString(TRUE, gStrictCommaEquivalentsPattern, -1), status);
+ fStrictOtherGroupingSeparators = new UnicodeSet(UnicodeString(TRUE, gStrictOtherGroupingSeparatorsPattern, -1), status);
+ fStrictDashEquivalents = new UnicodeSet(UnicodeString(TRUE, gStrictDashEquivalentsPattern, -1), status);
fDefaultGroupingSeparators = new UnicodeSet(*fDotEquivalents);
delete fStrictDefaultGroupingSeparators; fStrictDefaultGroupingSeparators = NULL;
delete fStrictOtherGroupingSeparators; fStrictOtherGroupingSeparators = NULL;
- *status = U_MEMORY_ALLOCATION_ERROR;
+ status = U_MEMORY_ALLOCATION_ERROR;
}
}
+static DecimalFormatStaticSets *gStaticSets;
+static UInitOnce gStaticSetsInitOnce = U_INITONCE_INITIALIZER;
+
+
//------------------------------------------------------------------------------
//
// decfmt_cleanup Memory cleanup function, free/delete all
// cached memory. Called by ICU's u_cleanup() function.
//
//------------------------------------------------------------------------------
-UBool
-DecimalFormatStaticSets::cleanup(void)
-{
- delete DecimalFormatStaticSets::gStaticSets;
- DecimalFormatStaticSets::gStaticSets = NULL;
-
- return TRUE;
-}
-
U_CDECL_BEGIN
static UBool U_CALLCONV
decimfmt_cleanup(void)
{
- return DecimalFormatStaticSets::cleanup();
+ delete gStaticSets;
+ gStaticSets = NULL;
+ gStaticSetsInitOnce.reset();
+ return TRUE;
}
-U_CDECL_END
-void DecimalFormatStaticSets::initSets(UErrorCode *status)
-{
- DecimalFormatStaticSets *p;
-
- UMTX_CHECK(NULL, gStaticSets, p);
- if (p == NULL) {
- p = new DecimalFormatStaticSets(status);
-
- if (p == NULL) {
- *status = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
-
- if (U_FAILURE(*status)) {
- delete p;
- return;
- }
-
- umtx_lock(NULL);
- if (gStaticSets == NULL) {
- gStaticSets = p;
- p = NULL;
- }
-
- umtx_unlock(NULL);
- if (p != NULL) {
- delete p;
- }
-
- ucln_i18n_registerCleanup(UCLN_I18N_DECFMT, decimfmt_cleanup);
+static void U_CALLCONV initSets(UErrorCode &status) {
+ ucln_i18n_registerCleanup(UCLN_I18N_DECFMT, decimfmt_cleanup);
+ gStaticSets = new DecimalFormatStaticSets(status);
+ if (U_FAILURE(status)) {
+ delete gStaticSets;
+ gStaticSets = NULL;
+ return;
+ }
+ if (gStaticSets == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
}
}
+U_CDECL_END
+
+const DecimalFormatStaticSets *DecimalFormatStaticSets::getStaticSets(UErrorCode &status) {
+ umtx_initOnce(gStaticSetsInitOnce, initSets, status);
+ return gStaticSets;
+}
+
const UnicodeSet *DecimalFormatStaticSets::getSimilarDecimals(UChar32 decimal, UBool strictParse)
{
UErrorCode status = U_ZERO_ERROR;
-
- initSets(&status);
-
+ umtx_initOnce(gStaticSetsInitOnce, initSets, status);
if (U_FAILURE(status)) {
return NULL;
}
/*
*******************************************************************************
-* Copyright (C) 2009-2011, International Business Machines Corporation and *
+* Copyright (C) 2009-2013, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*
class DecimalFormatStaticSets : public UMemory
{
public:
- static DecimalFormatStaticSets *gStaticSets; // Ptr to all lazily initialized constant
- // shared sets.
-
- DecimalFormatStaticSets(UErrorCode *status);
+ // Constructor and Destructor not for general use.
+ // Public to permit access from plain C implementation functions.
+ DecimalFormatStaticSets(UErrorCode &status);
~DecimalFormatStaticSets();
- static void initSets(UErrorCode *status);
- static UBool cleanup();
+ /**
+ * Return a pointer to a lazy-initialized singleton instance of this class.
+ */
+ static const DecimalFormatStaticSets *getStaticSets(UErrorCode &status);
static const UnicodeSet *getSimilarDecimals(UChar32 decimal, UBool strictParse);
// Constructs a DecimalFormat instance in the default locale.
DecimalFormat::DecimalFormat(UErrorCode& status) {
- init(status);
+ init();
UParseError parseError;
construct(status, parseError);
}
DecimalFormat::DecimalFormat(const UnicodeString& pattern,
UErrorCode& status) {
- init(status);
+ init();
UParseError parseError;
construct(status, parseError, &pattern);
}
DecimalFormat::DecimalFormat(const UnicodeString& pattern,
DecimalFormatSymbols* symbolsToAdopt,
UErrorCode& status) {
- init(status);
+ init();
UParseError parseError;
if (symbolsToAdopt == NULL)
status = U_ILLEGAL_ARGUMENT_ERROR;
DecimalFormatSymbols* symbolsToAdopt,
UParseError& parseErr,
UErrorCode& status) {
- init(status);
+ init();
if (symbolsToAdopt == NULL)
status = U_ILLEGAL_ARGUMENT_ERROR;
construct(status,parseErr, &pattern, symbolsToAdopt);
DecimalFormat::DecimalFormat(const UnicodeString& pattern,
const DecimalFormatSymbols& symbols,
UErrorCode& status) {
- init(status);
+ init();
UParseError parseError;
construct(status, parseError, &pattern, new DecimalFormatSymbols(symbols));
}
DecimalFormatSymbols* symbolsToAdopt,
UNumberFormatStyle style,
UErrorCode& status) {
- init(status);
+ init();
fStyle = style;
UParseError parseError;
construct(status, parseError, &pattern, symbolsToAdopt);
// Common DecimalFormat initialization.
// Put all fields of an uninitialized object into a known state.
// Common code, shared by all constructors.
+// Can not fail. Leave the object in good enough shape that the destructor
+// or assignment operator can run successfully.
void
-DecimalFormat::init(UErrorCode &status) {
+DecimalFormat::init() {
fPosPrefixPattern = 0;
fPosSuffixPattern = 0;
fNegPrefixPattern = 0;
data.fFastFormatStatus=kFastpathUNKNOWN; // don't try to calculate the fastpath until later.
data.fFastParseStatus=kFastpathUNKNOWN; // don't try to calculate the fastpath until later.
#endif
- // only do this once per obj.
- DecimalFormatStaticSets::initSets(&status);
+ fStaticSets = NULL;
}
//------------------------------------------------------------------------------
// created instance owns the symbols.
void
-DecimalFormat::construct(UErrorCode& status,
+DecimalFormat::construct(UErrorCode& status,
UParseError& parseErr,
const UnicodeString* pattern,
DecimalFormatSymbols* symbolsToAdopt)
if (fSymbols == NULL)
{
fSymbols = new DecimalFormatSymbols(Locale::getDefault(), status);
- /* test for NULL */
if (fSymbols == 0) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
}
+ fStaticSets = DecimalFormatStaticSets::getStaticSets(status);
+ if (U_FAILURE(status)) {
+ return;
+ }
UErrorCode nsStatus = U_ZERO_ERROR;
NumberingSystem *ns = NumberingSystem::createInstance(nsStatus);
if (U_FAILURE(nsStatus)) {
DecimalFormat::DecimalFormat(const DecimalFormat &source) :
NumberFormat(source) {
- UErrorCode status = U_ZERO_ERROR;
- init(status); // if this fails, 'source' isn't initialized properly either.
+ init();
*this = source;
}
DecimalFormat::operator=(const DecimalFormat& rhs)
{
if(this != &rhs) {
+ UErrorCode status = U_ZERO_ERROR;
NumberFormat::operator=(rhs);
+ fStaticSets = DecimalFormatStaticSets::getStaticSets(status);
fPositivePrefix = rhs.fPositivePrefix;
fPositiveSuffix = rhs.fPositiveSuffix;
fNegativePrefix = rhs.fNegativePrefix;
if (groupingCharLength == groupingStringLength) {
if (strictParse) {
- groupingSet = DecimalFormatStaticSets::gStaticSets->fStrictDefaultGroupingSeparators;
+ groupingSet = fStaticSets->fStrictDefaultGroupingSeparators;
} else {
- groupingSet = DecimalFormatStaticSets::gStaticSets->fDefaultGroupingSeparators;
+ groupingSet = fStaticSets->fDefaultGroupingSeparators;
}
}
int32_t inputLength = input.length();
int32_t affixCharLength = U16_LENGTH(affixChar);
UnicodeSet *affixSet;
+ UErrorCode status = U_ZERO_ERROR;
+ const DecimalFormatStaticSets *staticSets = DecimalFormatStaticSets::getStaticSets(status);
+ if (U_FAILURE(status)) {
+ return -1;
+ }
if (!lenient) {
- affixSet = DecimalFormatStaticSets::gStaticSets->fStrictDashEquivalents;
+ affixSet = staticSets->fStrictDashEquivalents;
// If the affix is exactly one character long and that character
// is in the dash set and the very next input character is also
} else {
UBool match = FALSE;
- affixSet = DecimalFormatStaticSets::gStaticSets->fDashEquivalents;
+ affixSet = staticSets->fDashEquivalents;
if (affixCharLength == affixLength && affixSet->contains(affixChar)) {
pos = skipUWhiteSpace(input, pos);
/*
*******************************************************************************
-* Copyright (C) 2003 - 2009, International Business Machines Corporation and *
+* Copyright (C) 2003 - 2013, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
return CECalendar::handleGetLimit(field, limitType);
}
-const UDate EthiopicCalendar::fgSystemDefaultCentury = DBL_MIN;
-const int32_t EthiopicCalendar::fgSystemDefaultCenturyYear = -1;
+/**
+ * The system maintains a static default century start date and Year. They are
+ * initialized the first time they are used. Once the system default century date
+ * and year are set, they do not change.
+ */
+static UDate gSystemDefaultCenturyStart = DBL_MIN;
+static int32_t gSystemDefaultCenturyStartYear = -1;
+static UInitOnce gSystemDefaultCenturyInit = U_INITONCE_INITIALIZER;
-UDate EthiopicCalendar::fgSystemDefaultCenturyStart = DBL_MIN;
-int32_t EthiopicCalendar::fgSystemDefaultCenturyStartYear = -1;
+static void U_CALLCONV initializeSystemDefaultCentury()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ EthiopicCalendar calendar(Locale("@calendar=ethiopic"), status);
+ if (U_SUCCESS(status)) {
+ calendar.setTime(Calendar::getNow(), status);
+ calendar.add(UCAL_YEAR, -80, status);
+
+ gSystemDefaultCenturyStart = calendar.getTime(status);
+ gSystemDefaultCenturyStartYear = calendar.get(UCAL_YEAR, status);
+ }
+ // We have no recourse upon failure unless we want to propagate the failure
+ // out.
+}
UDate
EthiopicCalendar::defaultCenturyStart() const
{
- initializeSystemDefaultCentury();
- return fgSystemDefaultCenturyStart;
+ // lazy-evaluate systemDefaultCenturyStart
+ umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury);
+ return gSystemDefaultCenturyStart;
}
int32_t
EthiopicCalendar::defaultCenturyStartYear() const
{
- initializeSystemDefaultCentury();
+ // lazy-evaluate systemDefaultCenturyStartYear
+ umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury);
if (isAmeteAlemEra()) {
- return fgSystemDefaultCenturyStartYear + AMETE_MIHRET_DELTA;
+ return gSystemDefaultCenturyStartYear + AMETE_MIHRET_DELTA;
}
- return fgSystemDefaultCenturyStartYear;
+ return gSystemDefaultCenturyStartYear;
}
-void
-EthiopicCalendar::initializeSystemDefaultCentury()
-{
- // lazy-evaluate systemDefaultCenturyStart
- UBool needsUpdate;
- UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate);
-
- if (!needsUpdate) {
- return;
- }
-
- UErrorCode status = U_ZERO_ERROR;
-
- EthiopicCalendar calendar(Locale("@calendar=ethiopic"), status);
- if (U_SUCCESS(status)) {
- calendar.setTime(Calendar::getNow(), status);
- calendar.add(UCAL_YEAR, -80, status);
- UDate newStart = calendar.getTime(status);
- int32_t newYear = calendar.get(UCAL_YEAR, status);
- {
- umtx_lock(NULL);
- fgSystemDefaultCenturyStartYear = newYear;
- fgSystemDefaultCenturyStart = newStart;
- umtx_unlock(NULL);
- }
- }
- // We have no recourse upon failure unless we want to propagate the failure
- // out.
-}
int32_t
EthiopicCalendar::getJDEpochOffset() const
/*
*******************************************************************************
-* Copyright (C) 2003 - 2008, International Business Machines Corporation and *
+* Copyright (C) 2003 - 2013, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
virtual int32_t getJDEpochOffset() const;
private:
- /**
- * The system maintains a static default century start date. This is initialized
- * the first time it is used. Before then, it is set to SYSTEM_DEFAULT_CENTURY to
- * indicate an uninitialized state. Once the system default century date and year
- * are set, they do not change.
- */
- static UDate fgSystemDefaultCenturyStart;
-
- /**
- * See documentation for systemDefaultCenturyStart.
- */
- static int32_t fgSystemDefaultCenturyStartYear;
-
- /**
- * Default value that indicates the defaultCenturyStartYear is unitialized
- */
- static const int32_t fgSystemDefaultCenturyYear;
-
- /**
- * start of default century, as a date
- */
- static const UDate fgSystemDefaultCentury;
-
- /**
- * Initializes the 100-year window that dates with 2-digit years
- * are considered to fall within so that its start date is 80 years
- * before the current time.
- */
- static void initializeSystemDefaultCentury(void);
-
/**
* When eraType is AMETE_ALEM_ERA, then this calendar use only AMETE_ALEM
* for the era. Otherwise (default), this calendar uses both AMETE_ALEM
/*
*******************************************************************************
-* Copyright (C) 2008-2012, International Business Machines Corporation and
+* Copyright (C) 2008-2013, International Business Machines Corporation and
* others. All Rights Reserved.
*******************************************************************************
*
#include "cmemory.h"
#include "cstring.h"
#include "mutex.h"
+#include "uassert.h"
#include "ucln_in.h"
#include "umutex.h"
#include "uhash.h"
static const char* gMailTaintsStr = "maleTaints";
static const char* gMixedNeutralStr = "mixedNeutral";
static icu::GenderInfo* gObjs = NULL;
+static UInitOnce gGenderInitOnce = U_INITONCE_INITIALIZER;
enum GenderStyle {
NEUTRAL,
gGenderInfoCache = NULL;
delete [] gObjs;
}
+ gGenderInitOnce.reset();
return TRUE;
}
U_NAMESPACE_BEGIN
+void U_CALLCONV GenderInfo_initCache(UErrorCode &status) {
+ ucln_i18n_registerCleanup(UCLN_I18N_GENDERINFO, gender_cleanup);
+ U_ASSERT(gGenderInfoCache == NULL);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ gObjs = new GenderInfo[GENDER_STYLE_LENGTH];
+ if (gObjs == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ for (int i = 0; i < GENDER_STYLE_LENGTH; i++) {
+ gObjs[i]._style = i;
+ }
+ gGenderInfoCache = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
+ if (U_FAILURE(status)) {
+ delete [] gObjs;
+ return;
+ }
+ uhash_setKeyDeleter(gGenderInfoCache, uprv_free);
+}
+
+
GenderInfo::GenderInfo() {
}
}
const GenderInfo* GenderInfo::getInstance(const Locale& locale, UErrorCode& status) {
+ // Make sure our cache exists.
+ umtx_initOnce(gGenderInitOnce, &GenderInfo_initCache, status);
if (U_FAILURE(status)) {
return NULL;
}
- // Make sure our cache exists.
- UBool needed;
- UMTX_CHECK(&gGenderMetaLock, (gGenderInfoCache == NULL), needed);
- if (needed) {
- Mutex lock(&gGenderMetaLock);
- if (gGenderInfoCache == NULL) {
- gObjs = new GenderInfo[GENDER_STYLE_LENGTH];
- if (gObjs == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return NULL;
- }
- for (int i = 0; i < GENDER_STYLE_LENGTH; i++) {
- gObjs[i]._style = i;
- }
- gGenderInfoCache = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
- if (U_FAILURE(status)) {
- delete [] gObjs;
- return NULL;
- }
- uhash_setKeyDeleter(gGenderInfoCache, uprv_free);
- ucln_i18n_registerCleanup(UCLN_I18N_GENDERINFO, gender_cleanup);
- }
- }
-
const GenderInfo* result = NULL;
const char* key = locale.getName();
{
/*
*******************************************************************************
-* Copyright (C) 1997-2012, International Business Machines Corporation and *
+* Copyright (C) 1997-2013, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*
return "gregorian";
}
-const UDate GregorianCalendar::fgSystemDefaultCentury = DBL_MIN;
-const int32_t GregorianCalendar::fgSystemDefaultCenturyYear = -1;
-
-UDate GregorianCalendar::fgSystemDefaultCenturyStart = DBL_MIN;
-int32_t GregorianCalendar::fgSystemDefaultCenturyStartYear = -1;
+/**
+ * The system maintains a static default century start date and Year. They are
+ * initialized the first time they are used. Once the system default century date
+ * and year are set, they do not change.
+ */
+static UDate gSystemDefaultCenturyStart = DBL_MIN;
+static int32_t gSystemDefaultCenturyStartYear = -1;
+static UInitOnce gSystemDefaultCenturyInit = U_INITONCE_INITIALIZER;
UBool GregorianCalendar::haveDefaultCentury() const
return TRUE;
}
-UDate GregorianCalendar::defaultCenturyStart() const
-{
- return internalGetDefaultCenturyStart();
-}
-
-int32_t GregorianCalendar::defaultCenturyStartYear() const
-{
- return internalGetDefaultCenturyStartYear();
-}
-
-UDate
-GregorianCalendar::internalGetDefaultCenturyStart() const
-{
- // lazy-evaluate systemDefaultCenturyStart
- UBool needsUpdate;
- UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate);
-
- if (needsUpdate) {
- initializeSystemDefaultCentury();
- }
-
- // use defaultCenturyStart unless it's the flag value;
- // then use systemDefaultCenturyStart
-
- return fgSystemDefaultCenturyStart;
-}
-
-int32_t
-GregorianCalendar::internalGetDefaultCenturyStartYear() const
-{
- // lazy-evaluate systemDefaultCenturyStartYear
- UBool needsUpdate;
- UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate);
-
- if (needsUpdate) {
- initializeSystemDefaultCentury();
- }
-
- // use defaultCenturyStart unless it's the flag value;
- // then use systemDefaultCenturyStartYear
-
- return fgSystemDefaultCenturyStartYear;
-}
-
-void
-GregorianCalendar::initializeSystemDefaultCentury()
+static void U_CALLCONV
+initializeSystemDefaultCentury()
{
// initialize systemDefaultCentury and systemDefaultCenturyYear based
// on the current time. They'll be set to 80 years before
// the current time.
UErrorCode status = U_ZERO_ERROR;
- Calendar *calendar = new GregorianCalendar(status);
- if (calendar != NULL && U_SUCCESS(status))
- {
- calendar->setTime(Calendar::getNow(), status);
- calendar->add(UCAL_YEAR, -80, status);
+ GregorianCalendar calendar(status);
+ if (U_SUCCESS(status)) {
+ calendar.setTime(Calendar::getNow(), status);
+ calendar.add(UCAL_YEAR, -80, status);
- UDate newStart = calendar->getTime(status);
- int32_t newYear = calendar->get(UCAL_YEAR, status);
- umtx_lock(NULL);
- if (fgSystemDefaultCenturyStart == fgSystemDefaultCentury)
- {
- fgSystemDefaultCenturyStartYear = newYear;
- fgSystemDefaultCenturyStart = newStart;
- }
- umtx_unlock(NULL);
- delete calendar;
+ gSystemDefaultCenturyStart = calendar.getTime(status);
+ gSystemDefaultCenturyStartYear = calendar.get(UCAL_YEAR, status);
}
// We have no recourse upon failure unless we want to propagate the failure
// out.
}
+UDate GregorianCalendar::defaultCenturyStart() const {
+ // lazy-evaluate systemDefaultCenturyStart
+ umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury);
+ return gSystemDefaultCenturyStart;
+}
+
+int32_t GregorianCalendar::defaultCenturyStartYear() const {
+ // lazy-evaluate systemDefaultCenturyStartYear
+ umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury);
+ return gSystemDefaultCenturyStartYear;
+}
U_NAMESPACE_END
/*
******************************************************************************
-* Copyright (C) 2003-2011, International Business Machines Corporation
+* Copyright (C) 2003-2013, International Business Machines Corporation
* and others. All Rights Reserved.
******************************************************************************
*
return (UBool)(U_SUCCESS(status) ? (internalGet(UCAL_DST_OFFSET) != 0) : FALSE);
}
-// default century
-const UDate HebrewCalendar::fgSystemDefaultCentury = DBL_MIN;
-const int32_t HebrewCalendar::fgSystemDefaultCenturyYear = -1;
-
-UDate HebrewCalendar::fgSystemDefaultCenturyStart = DBL_MIN;
-int32_t HebrewCalendar::fgSystemDefaultCenturyStartYear = -1;
-
+/**
+ * The system maintains a static default century start date and Year. They are
+ * initialized the first time they are used. Once the system default century date
+ * and year are set, they do not change.
+ */
+static UDate gSystemDefaultCenturyStart = DBL_MIN;
+static int32_t gSystemDefaultCenturyStartYear = -1;
+static UInitOnce gSystemDefaultCenturyInit = U_INITONCE_INITIALIZER;
UBool HebrewCalendar::haveDefaultCentury() const
{
return TRUE;
}
-UDate HebrewCalendar::defaultCenturyStart() const
-{
- return internalGetDefaultCenturyStart();
-}
-
-int32_t HebrewCalendar::defaultCenturyStartYear() const
-{
- return internalGetDefaultCenturyStartYear();
-}
-
-UDate
-HebrewCalendar::internalGetDefaultCenturyStart() const
-{
- // lazy-evaluate systemDefaultCenturyStart
- UBool needsUpdate;
- UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate);
-
- if (needsUpdate) {
- initializeSystemDefaultCentury();
- }
-
- // use defaultCenturyStart unless it's the flag value;
- // then use systemDefaultCenturyStart
-
- return fgSystemDefaultCenturyStart;
-}
-
-int32_t
-HebrewCalendar::internalGetDefaultCenturyStartYear() const
-{
- // lazy-evaluate systemDefaultCenturyStartYear
- UBool needsUpdate;
- UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate);
-
- if (needsUpdate) {
- initializeSystemDefaultCentury();
- }
-
- // use defaultCenturyStart unless it's the flag value;
- // then use systemDefaultCenturyStartYear
-
- return fgSystemDefaultCenturyStartYear;
-}
-
-void
-HebrewCalendar::initializeSystemDefaultCentury()
+static void U_CALLCONV initializeSystemDefaultCentury()
{
// initialize systemDefaultCentury and systemDefaultCenturyYear based
// on the current time. They'll be set to 80 years before
// the current time.
UErrorCode status = U_ZERO_ERROR;
HebrewCalendar calendar(Locale("@calendar=hebrew"),status);
- if (U_SUCCESS(status))
- {
+ if (U_SUCCESS(status)) {
calendar.setTime(Calendar::getNow(), status);
calendar.add(UCAL_YEAR, -80, status);
- UDate newStart = calendar.getTime(status);
- int32_t newYear = calendar.get(UCAL_YEAR, status);
- umtx_lock(NULL);
- if (fgSystemDefaultCenturyStart == fgSystemDefaultCentury) {
- fgSystemDefaultCenturyStartYear = newYear;
- fgSystemDefaultCenturyStart = newStart;
- }
- umtx_unlock(NULL);
+
+ gSystemDefaultCenturyStart = calendar.getTime(status);
+ gSystemDefaultCenturyStartYear = calendar.get(UCAL_YEAR, status);
}
// We have no recourse upon failure unless we want to propagate the failure
// out.
}
+
+UDate HebrewCalendar::defaultCenturyStart() const {
+ // lazy-evaluate systemDefaultCenturyStart
+ umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury);
+ return gSystemDefaultCenturyStart;
+}
+
+int32_t HebrewCalendar::defaultCenturyStartYear() const {
+ // lazy-evaluate systemDefaultCenturyStartYear
+ umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury);
+ return gSystemDefaultCenturyStartYear;
+}
+
+
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(HebrewCalendar)
U_NAMESPACE_END
/*
******************************************************************************
-* Copyright (C) 2003-2009, International Business Machines Corporation
+* Copyright (C) 2003-2013, International Business Machines Corporation
* and others. All Rights Reserved.
******************************************************************************
*
*/
virtual int32_t defaultCenturyStartYear() const;
- private: // default century stuff.
- /**
- * The system maintains a static default century start date. This is initialized
- * the first time it is used. Before then, it is set to SYSTEM_DEFAULT_CENTURY to
- * indicate an uninitialized state. Once the system default century date and year
- * are set, they do not change.
- */
- static UDate fgSystemDefaultCenturyStart;
-
- /**
- * See documentation for systemDefaultCenturyStart.
- */
- static int32_t fgSystemDefaultCenturyStartYear;
-
- /**
- * Default value that indicates the defaultCenturyStartYear is unitialized
- */
- static const int32_t fgSystemDefaultCenturyYear;
-
- /**
- * start of default century, as a date
- */
- static const UDate fgSystemDefaultCentury;
-
- /**
- * Returns the beginning date of the 100-year window that dates
- * with 2-digit years are considered to fall within.
- */
- UDate internalGetDefaultCenturyStart(void) const;
-
- /**
- * Returns the first year of the 100-year window that dates with
- * 2-digit years are considered to fall within.
- */
- int32_t internalGetDefaultCenturyStartYear(void) const;
-
- /**
- * Initializes the 100-year window that dates with 2-digit years
- * are considered to fall within so that its start date is 80 years
- * before the current time.
- */
- static void initializeSystemDefaultCentury(void);
-
private: // Calendar-specific implementation
/**
* Finds the day # of the first day in the given Hebrew year.
<StringPooling>true</StringPooling>\r
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\r
<FunctionLevelLinking>true</FunctionLevelLinking>\r
- <DisableLanguageExtensions>true</DisableLanguageExtensions>\r
+ <DisableLanguageExtensions>false</DisableLanguageExtensions>\r
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>\r
<PrecompiledHeaderOutputFile>.\x86\Release/i18n.pch</PrecompiledHeaderOutputFile>\r
<AssemblerListingLocation>.\x86\Release/</AssemblerListingLocation>\r
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\r
<BufferSecurityCheck>true</BufferSecurityCheck>\r
- <DisableLanguageExtensions>true</DisableLanguageExtensions>\r
+ <DisableLanguageExtensions>false</DisableLanguageExtensions>\r
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>\r
<PrecompiledHeaderOutputFile>.\x86\Debug/i18n.pch</PrecompiledHeaderOutputFile>\r
<AssemblerListingLocation>.\x86\Debug/</AssemblerListingLocation>\r
<StringPooling>true</StringPooling>\r
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\r
<FunctionLevelLinking>true</FunctionLevelLinking>\r
- <DisableLanguageExtensions>true</DisableLanguageExtensions>\r
+ <DisableLanguageExtensions>false</DisableLanguageExtensions>\r
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>\r
<PrecompiledHeaderOutputFile>.\x64\Release/i18n.pch</PrecompiledHeaderOutputFile>\r
<AssemblerListingLocation>.\x64\Release/</AssemblerListingLocation>\r
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\r
<BufferSecurityCheck>true</BufferSecurityCheck>\r
- <DisableLanguageExtensions>true</DisableLanguageExtensions>\r
+ <DisableLanguageExtensions>false</DisableLanguageExtensions>\r
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>\r
<PrecompiledHeaderOutputFile>.\x64\Debug/i18n.pch</PrecompiledHeaderOutputFile>\r
<AssemblerListingLocation>.\x64\Debug/</AssemblerListingLocation>\r
/*
******************************************************************************
-* Copyright (C) 2003-2012, International Business Machines Corporation
+* Copyright (C) 2003-2013, International Business Machines Corporation
* and others. All Rights Reserved.
******************************************************************************
*
return (UBool)(U_SUCCESS(status) ? (internalGet(UCAL_DST_OFFSET) != 0) : FALSE);
}
-// default century
-const UDate IslamicCalendar::fgSystemDefaultCentury = DBL_MIN;
-const int32_t IslamicCalendar::fgSystemDefaultCenturyYear = -1;
-
-UDate IslamicCalendar::fgSystemDefaultCenturyStart = DBL_MIN;
-int32_t IslamicCalendar::fgSystemDefaultCenturyStartYear = -1;
-
+/**
+ * The system maintains a static default century start date and Year. They are
+ * initialized the first time they are used. Once the system default century date
+ * and year are set, they do not change.
+ */
+static UDate gSystemDefaultCenturyStart = DBL_MIN;
+static int32_t gSystemDefaultCenturyStartYear = -1;
+static UInitOnce gSystemDefaultCenturyInit = U_INITONCE_INITIALIZER;
UBool IslamicCalendar::haveDefaultCentury() const
{
return TRUE;
}
-UDate IslamicCalendar::defaultCenturyStart() const
-{
- return internalGetDefaultCenturyStart();
-}
-
-int32_t IslamicCalendar::defaultCenturyStartYear() const
-{
- return internalGetDefaultCenturyStartYear();
-}
-
-UDate
-IslamicCalendar::internalGetDefaultCenturyStart() const
-{
- // lazy-evaluate systemDefaultCenturyStart
- UBool needsUpdate;
- UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate);
-
- if (needsUpdate) {
- initializeSystemDefaultCentury();
- }
-
- // use defaultCenturyStart unless it's the flag value;
- // then use systemDefaultCenturyStart
-
- return fgSystemDefaultCenturyStart;
-}
-
-int32_t
-IslamicCalendar::internalGetDefaultCenturyStartYear() const
-{
- // lazy-evaluate systemDefaultCenturyStartYear
- UBool needsUpdate;
- UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate);
-
- if (needsUpdate) {
- initializeSystemDefaultCentury();
- }
-
- // use defaultCenturyStart unless it's the flag value;
- // then use systemDefaultCenturyStartYear
-
- return fgSystemDefaultCenturyStartYear;
-}
-
-void
-IslamicCalendar::initializeSystemDefaultCentury()
+static void U_CALLCONV initializeSystemDefaultCentury()
{
// initialize systemDefaultCentury and systemDefaultCenturyYear based
// on the current time. They'll be set to 80 years before
// the current time.
UErrorCode status = U_ZERO_ERROR;
IslamicCalendar calendar(Locale("@calendar=islamic-civil"),status);
- if (U_SUCCESS(status))
- {
+ if (U_SUCCESS(status)) {
calendar.setTime(Calendar::getNow(), status);
calendar.add(UCAL_YEAR, -80, status);
- UDate newStart = calendar.getTime(status);
- int32_t newYear = calendar.get(UCAL_YEAR, status);
- umtx_lock(NULL);
- if (fgSystemDefaultCenturyStart == fgSystemDefaultCentury)
- {
- fgSystemDefaultCenturyStartYear = newYear;
- fgSystemDefaultCenturyStart = newStart;
- }
- umtx_unlock(NULL);
+
+ gSystemDefaultCenturyStart = calendar.getTime(status);
+ gSystemDefaultCenturyStartYear = calendar.get(UCAL_YEAR, status);
}
// We have no recourse upon failure unless we want to propagate the failure
// out.
}
+UDate IslamicCalendar::defaultCenturyStart() const {
+ // lazy-evaluate systemDefaultCenturyStart
+ umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury);
+ return gSystemDefaultCenturyStart;
+}
+
+int32_t IslamicCalendar::defaultCenturyStartYear() const {
+ // lazy-evaluate systemDefaultCenturyStartYear
+ umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury);
+ return gSystemDefaultCenturyStartYear;
+}
+
+
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IslamicCalendar)
U_NAMESPACE_END
/*
********************************************************************************
- * Copyright (C) 2003-2009, International Business Machines Corporation
+ * Copyright (C) 2003-2013, International Business Machines Corporation
* and others. All Rights Reserved.
******************************************************************************
*
* @internal
*/
virtual int32_t defaultCenturyStartYear() const;
-
- private: // default century stuff.
- /**
- * The system maintains a static default century start date. This is initialized
- * the first time it is used. Before then, it is set to SYSTEM_DEFAULT_CENTURY to
- * indicate an uninitialized state. Once the system default century date and year
- * are set, they do not change.
- */
- static UDate fgSystemDefaultCenturyStart;
-
- /**
- * See documentation for systemDefaultCenturyStart.
- */
- static int32_t fgSystemDefaultCenturyStartYear;
-
- /**
- * Default value that indicates the defaultCenturyStartYear is unitialized
- */
- static const int32_t fgSystemDefaultCenturyYear;
-
- /**
- * start of default century, as a date
- */
- static const UDate fgSystemDefaultCentury;
-
- /**
- * Returns the beginning date of the 100-year window that dates
- * with 2-digit years are considered to fall within.
- */
- UDate internalGetDefaultCenturyStart(void) const;
-
- /**
- * Returns the first year of the 100-year window that dates with
- * 2-digit years are considered to fall within.
- */
- int32_t internalGetDefaultCenturyStartYear(void) const;
-
- /**
- * Initializes the 100-year window that dates with 2-digit years
- * are considered to fall within so that its start date is 80 years
- * before the current time.
- */
- static void initializeSystemDefaultCentury(void);
};
U_NAMESPACE_END
/*
*******************************************************************************
-* Copyright (C) 1997-2012, International Business Machines Corporation and *
+* Copyright (C) 1997-2013, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*
#include "ucln_in.h"
#include "cstring.h"
#include "putilimp.h"
+#include "uassert.h"
#include "umutex.h"
#include "mutex.h"
#include "digitlst.h"
// Static hashtable cache of NumberingSystem objects used by NumberFormat
static UHashtable * NumberingSystem_cache = NULL;
-
static UMutex nscacheMutex = U_MUTEX_INITIALIZER;
+static UInitOnce gNSCacheInitOnce = U_INITONCE_INITIALIZER;
#if !UCONFIG_NO_SERVICE
static icu::ICULocaleService* gService = NULL;
+static UInitOnce gServiceInitOnce = U_INITONCE_INITIALIZER;
#endif
/**
static UBool U_CALLCONV numfmt_cleanup(void) {
#if !UCONFIG_NO_SERVICE
+ gServiceInitOnce.reset();
if (gService) {
delete gService;
gService = NULL;
}
#endif
+ gNSCacheInitOnce.reset();
if (NumberingSystem_cache) {
// delete NumberingSystem_cache;
uhash_close(NumberingSystem_cache);
// -------------------------------------
+static void U_CALLCONV initNumberFormatService() {
+ U_ASSERT(gService == NULL);
+ ucln_i18n_registerCleanup(UCLN_I18N_NUMFMT, numfmt_cleanup);
+ gService = new ICUNumberFormatService();
+}
+
static ICULocaleService*
getNumberFormatService(void)
{
- UBool needInit;
- UMTX_CHECK(NULL, (UBool)(gService == NULL), needInit);
- if (needInit) {
- ICULocaleService * newservice = new ICUNumberFormatService();
- if (newservice) {
- umtx_lock(NULL);
- if (gService == NULL) {
- gService = newservice;
- newservice = NULL;
- }
- umtx_unlock(NULL);
- }
- if (newservice) {
- delete newservice;
- } else {
- // we won the contention, this thread can register cleanup.
- ucln_i18n_registerCleanup(UCLN_I18N_NUMFMT, numfmt_cleanup);
- }
- }
+ umtx_initOnce(gServiceInitOnce, &initNumberFormatService);
return gService;
}
+static UBool haveService() {
+ return !gServiceInitOnce.isReset() && (getNumberFormatService() != NULL);
+}
+
// -------------------------------------
URegistryKey U_EXPORT2
UBool U_EXPORT2
NumberFormat::unregister(URegistryKey key, UErrorCode& status)
{
- if (U_SUCCESS(status)) {
- UBool haveService;
- UMTX_CHECK(NULL, gService != NULL, haveService);
- if (haveService) {
- return gService->unregister(key, status);
- }
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+ if (haveService()) {
+ return gService->unregister(key, status);
+ } else {
status = U_ILLEGAL_ARGUMENT_ERROR;
+ return FALSE;
}
- return FALSE;
}
// -------------------------------------
{
ICULocaleService *service = getNumberFormatService();
if (service) {
- return service->getAvailableLocales();
+ return service->getAvailableLocales();
}
return NULL; // no way to return error condition
}
// -------------------------------------
NumberFormat* U_EXPORT2
-NumberFormat::createInstance(const Locale& loc, UNumberFormatStyle kind, UErrorCode& status)
-{
+NumberFormat::createInstance(const Locale& loc, UNumberFormatStyle kind, UErrorCode& status) {
#if !UCONFIG_NO_SERVICE
- UBool haveService;
- UMTX_CHECK(NULL, gService != NULL, haveService);
- if (haveService) {
+ if (haveService()) {
return (NumberFormat*)gService->get(loc, kind, status);
}
- else
#endif
- {
- return makeInstance(loc, kind, status);
- }
+ return makeInstance(loc, kind, status);
}
// Creates the NumberFormat instance of the specified style (number, currency,
// or percent) for the desired locale.
+static void U_CALLCONV nscacheInit() {
+ U_ASSERT(NumberingSystem_cache == NULL);
+ ucln_i18n_registerCleanup(UCLN_I18N_NUMFMT, numfmt_cleanup);
+ UErrorCode status = U_ZERO_ERROR;
+ NumberingSystem_cache = uhash_open(uhash_hashLong,
+ uhash_compareLong,
+ NULL,
+ &status);
+ if (U_FAILURE(status)) {
+ // Number Format code will run with no cache if creation fails.
+ NumberingSystem_cache = NULL;
+ return;
+ }
+ uhash_setValueDeleter(NumberingSystem_cache, deleteNumberingSystem);
+}
+
UBool
NumberFormat::isStyleSupported(UNumberFormatStyle style) {
return gLastResortNumberPatterns[style] != NULL;
}
#endif
// Use numbering system cache hashtable
- UHashtable *cache;
- UMTX_CHECK(&nscacheMutex, NumberingSystem_cache, cache);
-
- // Check cache we got, create if non-existant
- if (cache == NULL) {
- cache = uhash_open(uhash_hashLong,
- uhash_compareLong,
- NULL,
- &status);
-
- if (U_FAILURE(status)) {
- // cache not created - out of memory
- status = U_ZERO_ERROR; // work without the cache
- cache = NULL;
- } else {
- // cache created
- uhash_setValueDeleter(cache, deleteNumberingSystem);
-
- // set final NumberingSystem_cache value
- Mutex lock(&nscacheMutex);
- if (NumberingSystem_cache == NULL) {
- NumberingSystem_cache = cache;
- ucln_i18n_registerCleanup(UCLN_I18N_NUMFMT, numfmt_cleanup);
- } else {
- uhash_close(cache);
- cache = NumberingSystem_cache;
- }
- }
- }
+ umtx_initOnce(gNSCacheInitOnce, &nscacheInit);
// Get cached numbering system
LocalPointer<NumberingSystem> ownedNs;
NumberingSystem *ns = NULL;
- if (cache != NULL) {
+ if (NumberingSystem_cache != NULL) {
// TODO: Bad hash key usage, see ticket #8504.
int32_t hashKey = desiredLocale.hashCode();
Mutex lock(&nscacheMutex);
- ns = (NumberingSystem *)uhash_iget(cache, hashKey);
+ ns = (NumberingSystem *)uhash_iget(NumberingSystem_cache, hashKey);
if (ns == NULL) {
ns = NumberingSystem::createInstance(desiredLocale,status);
- uhash_iput(cache, hashKey, (void*)ns, &status);
+ uhash_iput(NumberingSystem_cache, hashKey, (void*)ns, &status);
}
} else {
ownedNs.adoptInstead(NumberingSystem::createInstance(desiredLocale,status));
const UResourceBundle* res,
const UnicodeString& tzid,
UErrorCode& ec) :
- BasicTimeZone(tzid), finalZone(NULL), transitionRulesInitialized(FALSE)
+ BasicTimeZone(tzid), finalZone(NULL)
{
clearTransitionRules();
U_DEBUG_TZ_MSG(("OlsonTimeZone(%s)\n", ures_getKey((UResourceBundle*)res)));
historicRuleCount = 0;
finalZoneWithStartYear = NULL;
firstTZTransitionIdx = 0;
- transitionRulesInitialized = FALSE;
+ transitionRulesInitOnce.reset();
}
void
/*
* Lazy transition rules initializer
*/
-static UMutex gLock = U_MUTEX_INITIALIZER;
+static void U_CALLCONV initRules(OlsonTimeZone *This, UErrorCode &status) {
+ This->initTransitionRules(status);
+}
+
void
OlsonTimeZone::checkTransitionRules(UErrorCode& status) const {
- if (U_FAILURE(status)) {
- return;
- }
- UBool initialized;
- UMTX_CHECK(&gLock, transitionRulesInitialized, initialized);
- if (!initialized) {
- umtx_lock(&gLock);
- if (!transitionRulesInitialized) {
- OlsonTimeZone *ncThis = const_cast<OlsonTimeZone*>(this);
- ncThis->initTransitionRules(status);
- }
- umtx_unlock(&gLock);
- }
+ OlsonTimeZone *ncThis = const_cast<OlsonTimeZone *>(this);
+ umtx_initOnce(ncThis->transitionRulesInitOnce, &initRules, ncThis, status);
}
void
if(U_FAILURE(status)) {
return;
}
- if (transitionRulesInitialized) {
- return;
- }
deleteTransitionRules();
UnicodeString tzid;
getID(tzid);
firstFinalTZTransition->adoptFrom(prevRule->clone());
firstFinalTZTransition->adoptTo(firstFinalRule);
}
- transitionRulesInitialized = TRUE;
}
UBool
#if !UCONFIG_NO_FORMATTING
#include "unicode/basictz.h"
+#include "umutex.h"
struct UResourceBundle;
void clearTransitionRules(void);
void deleteTransitionRules(void);
void checkTransitionRules(UErrorCode& status) const;
+
+ public: // Internal, for access from plain C code
void initTransitionRules(UErrorCode& status);
+ private:
InitialTimeZoneRule *initialRule;
TimeZoneTransition *firstTZTransition;
TimeArrayTimeZoneRule **historicRules;
int16_t historicRuleCount;
SimpleTimeZone *finalZoneWithStartYear; // hack
- UBool transitionRulesInitialized;
+ UInitOnce transitionRulesInitOnce;
};
inline int16_t
/*
******************************************************************************
- * Copyright (C) 2003-2012, International Business Machines Corporation
+ * Copyright (C) 2003-2013, International Business Machines Corporation
* and others. All Rights Reserved.
******************************************************************************
*
}
// default century
-const UDate PersianCalendar::fgSystemDefaultCentury = DBL_MIN;
-const int32_t PersianCalendar::fgSystemDefaultCenturyYear = -1;
-UDate PersianCalendar::fgSystemDefaultCenturyStart = DBL_MIN;
-int32_t PersianCalendar::fgSystemDefaultCenturyStartYear = -1;
+static UDate gSystemDefaultCenturyStart = DBL_MIN;
+static int32_t gSystemDefaultCenturyStartYear = -1;
+static UInitOnce gSystemDefaultCenturyInit = U_INITONCE_INITIALIZER;
UBool PersianCalendar::haveDefaultCentury() const
{
return TRUE;
}
-UDate PersianCalendar::defaultCenturyStart() const
-{
- return internalGetDefaultCenturyStart();
-}
-
-int32_t PersianCalendar::defaultCenturyStartYear() const
-{
- return internalGetDefaultCenturyStartYear();
-}
-
-UDate
-PersianCalendar::internalGetDefaultCenturyStart() const
-{
- // lazy-evaluate systemDefaultCenturyStart
- UBool needsUpdate;
- UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate);
-
- if (needsUpdate) {
- initializeSystemDefaultCentury();
- }
-
- // use defaultCenturyStart unless it's the flag value;
- // then use systemDefaultCenturyStart
-
- return fgSystemDefaultCenturyStart;
-}
-
-int32_t
-PersianCalendar::internalGetDefaultCenturyStartYear() const
-{
- // lazy-evaluate systemDefaultCenturyStartYear
- UBool needsUpdate;
- UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate);
-
- if (needsUpdate) {
- initializeSystemDefaultCentury();
- }
-
- // use defaultCenturyStart unless it's the flag value;
- // then use systemDefaultCenturyStartYear
-
- return fgSystemDefaultCenturyStartYear;
-}
-
-void
-PersianCalendar::initializeSystemDefaultCentury()
-{
+static void U_CALLCONV initializeSystemDefaultCentury() {
// initialize systemDefaultCentury and systemDefaultCenturyYear based
// on the current time. They'll be set to 80 years before
// the current time.
{
calendar.setTime(Calendar::getNow(), status);
calendar.add(UCAL_YEAR, -80, status);
- UDate newStart = calendar.getTime(status);
- int32_t newYear = calendar.get(UCAL_YEAR, status);
- umtx_lock(NULL);
- if (fgSystemDefaultCenturyStart == fgSystemDefaultCentury)
- {
- fgSystemDefaultCenturyStartYear = newYear;
- fgSystemDefaultCenturyStart = newStart;
- }
- umtx_unlock(NULL);
+
+ gSystemDefaultCenturyStart = calendar.getTime(status);
+ gSystemDefaultCenturyStartYear = calendar.get(UCAL_YEAR, status);
}
// We have no recourse upon failure unless we want to propagate the failure
// out.
}
+UDate PersianCalendar::defaultCenturyStart() const {
+ // lazy-evaluate systemDefaultCenturyStart
+ umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury);
+ return gSystemDefaultCenturyStart;
+}
+
+int32_t PersianCalendar::defaultCenturyStartYear() const {
+ // lazy-evaluate systemDefaultCenturyStartYear
+ umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury);
+ return gSystemDefaultCenturyStartYear;
+}
+
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(PersianCalendar)
U_NAMESPACE_END
/*
******************************************************************************
- * Copyright (C) 2003-2008, International Business Machines Corporation
+ * Copyright (C) 2003-2013, International Business Machines Corporation
* and others. All Rights Reserved.
******************************************************************************
*
* @internal
*/
virtual int32_t defaultCenturyStartYear() const;
-
- private: // default century stuff.
- /**
- * The system maintains a static default century start date. This is initialized
- * the first time it is used. Before then, it is set to SYSTEM_DEFAULT_CENTURY to
- * indicate an uninitialized state. Once the system default century date and year
- * are set, they do not change.
- */
- static UDate fgSystemDefaultCenturyStart;
-
- /**
- * See documentation for systemDefaultCenturyStart.
- */
- static int32_t fgSystemDefaultCenturyStartYear;
-
- /**
- * Default value that indicates the defaultCenturyStartYear is unitialized
- */
- static const int32_t fgSystemDefaultCenturyYear;
-
- /**
- * start of default century, as a date
- */
- static const UDate fgSystemDefaultCentury;
-
- /**
- * Returns the beginning date of the 100-year window that dates
- * with 2-digit years are considered to fall within.
- */
- UDate internalGetDefaultCenturyStart(void) const;
-
- /**
- * Returns the first year of the 100-year window that dates with
- * 2-digit years are considered to fall within.
- */
- int32_t internalGetDefaultCenturyStartYear(void) const;
-
- /**
- * Initializes the 100-year window that dates with 2-digit years
- * are considered to fall within so that its start date is 80 years
- * before the current time.
- */
- static void initializeSystemDefaultCentury(void);
};
U_NAMESPACE_END
/*
**********************************************************************
-* Copyright (C) 1999-2012, International Business Machines
+* Copyright (C) 1999-2013, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
* Date Name Description
// some other transliteration that is still in progress and holding the
// transliteration mutex. If so, do not lock the transliteration
// mutex again.
+ // TODO(andy): Need a better scheme for handling this.
UBool needToLock;
- UMTX_CHECK(NULL, (&text != gLockedText), needToLock);
+ umtx_lock(NULL);
+ needToLock = (&text != gLockedText);
+ umtx_unlock(NULL);
if (needToLock) {
umtx_lock(&transliteratorDataMutex);
gLockedText = &text;
if (U_FAILURE(status)) {
return;
}
- UBool updated;
- UMTX_CHECK(&gLock, fUpToDate, updated);
- if (!updated) {
- umtx_lock(&gLock);
- if (!fUpToDate) {
- RuleBasedTimeZone *ncThis = const_cast<RuleBasedTimeZone*>(this);
- ncThis->complete(status);
- }
- umtx_unlock(&gLock);
+ umtx_lock(&gLock);
+ if (!fUpToDate) {
+ RuleBasedTimeZone *ncThis = const_cast<RuleBasedTimeZone*>(this);
+ ncThis->complete(status);
}
+ umtx_unlock(&gLock);
}
void
//
// regexst.h
//
-// Copyright (C) 2004-2012, International Business Machines Corporation and others.
+// Copyright (C) 2004-2013, International Business Machines Corporation and others.
// All Rights Reserved.
//
// This file contains class RegexStaticSets
RegexStaticSets *RegexStaticSets::gStaticSets = NULL;
+UInitOnce gStaticSetsInitOnce = U_INITONCE_INITIALIZER;
RegexStaticSets::RegexStaticSets(UErrorCode *status)
:
RegexStaticSets::cleanup(void) {
delete RegexStaticSets::gStaticSets;
RegexStaticSets::gStaticSets = NULL;
+ gStaticSetsInitOnce.reset();
return TRUE;
}
regex_cleanup(void) {
return RegexStaticSets::cleanup();
}
-U_CDECL_END
-void RegexStaticSets::initGlobals(UErrorCode *status) {
- RegexStaticSets *p;
- UMTX_CHECK(NULL, gStaticSets, p);
- if (p == NULL) {
- p = new RegexStaticSets(status);
- if (p == NULL) {
- *status = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
- if (U_FAILURE(*status)) {
- delete p;
- return;
- }
- umtx_lock(NULL);
- if (gStaticSets == NULL) {
- gStaticSets = p;
- p = NULL;
- }
- umtx_unlock(NULL);
- if (p) {
- delete p;
- }
- ucln_i18n_registerCleanup(UCLN_I18N_REGEX, regex_cleanup);
+static void U_CALLCONV initStaticSets(UErrorCode &status) {
+ U_ASSERT(RegexStaticSets::gStaticSets == NULL);
+ ucln_i18n_registerCleanup(UCLN_I18N_REGEX, regex_cleanup);
+ RegexStaticSets::gStaticSets = new RegexStaticSets(&status);
+ if (U_FAILURE(status)) {
+ delete RegexStaticSets::gStaticSets;
+ RegexStaticSets::gStaticSets = NULL;
+ }
+ if (RegexStaticSets::gStaticSets == NULL && U_SUCCESS(status)) {
+ status = U_MEMORY_ALLOCATION_ERROR;
}
}
+U_CDECL_END
+void RegexStaticSets::initGlobals(UErrorCode *status) {
+ umtx_initOnce(gStaticSetsInitOnce, &initStaticSets, *status);
+}
U_NAMESPACE_END
#endif // !UCONFIG_NO_REGULAR_EXPRESSIONS
/*
* 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.
*/
static UMutex gLock = U_MUTEX_INITIALIZER;
if (U_FAILURE(status)) {
return;
}
- UBool initialized;
- UMTX_CHECK(&gLock, transitionRulesInitialized, initialized);
- if (!initialized) {
- umtx_lock(&gLock);
- if (!transitionRulesInitialized) {
- SimpleTimeZone *ncThis = const_cast<SimpleTimeZone*>(this);
- ncThis->initTransitionRules(status);
- }
- umtx_unlock(&gLock);
+ umtx_lock(&gLock);
+ if (!transitionRulesInitialized) {
+ SimpleTimeZone *ncThis = const_cast<SimpleTimeZone*>(this);
+ ncThis->initTransitionRules(status);
}
+ umtx_unlock(&gLock);
}
void
/*
*******************************************************************************
-* Copyright (C) 2009-2011, International Business Machines Corporation and *
+* Copyright (C) 2009-2013, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*
#include "unicode/uniset.h"
#include "unicode/udat.h"
#include "cmemory.h"
+#include "uassert.h"
#include "ucln_in.h"
#include "umutex.h"
U_NAMESPACE_BEGIN
-SimpleDateFormatStaticSets *SimpleDateFormatStaticSets::gStaticSets = NULL;
+SimpleDateFormatStaticSets *gStaticSets = NULL;
+UInitOnce gSimpleDateFormatStaticSetsInitOnce = U_INITONCE_INITIALIZER;
-SimpleDateFormatStaticSets::SimpleDateFormatStaticSets(UErrorCode *status)
+SimpleDateFormatStaticSets::SimpleDateFormatStaticSets(UErrorCode &status)
: fDateIgnorables(NULL),
fTimeIgnorables(NULL),
fOtherIgnorables(NULL)
{
- fDateIgnorables = new UnicodeSet(UNICODE_STRING("[-,./[:whitespace:]]", 20), *status);
- fTimeIgnorables = new UnicodeSet(UNICODE_STRING("[-.:[:whitespace:]]", 19), *status);
- fOtherIgnorables = new UnicodeSet(UNICODE_STRING("[:whitespace:]", 14), *status);
+ fDateIgnorables = new UnicodeSet(UNICODE_STRING("[-,./[:whitespace:]]", 20), status);
+ fTimeIgnorables = new UnicodeSet(UNICODE_STRING("[-.:[:whitespace:]]", 19), status);
+ fOtherIgnorables = new UnicodeSet(UNICODE_STRING("[:whitespace:]", 14), status);
// Check for null pointers
if (fDateIgnorables == NULL || fTimeIgnorables == NULL || fOtherIgnorables == NULL) {
delete fTimeIgnorables; fTimeIgnorables = NULL;
delete fOtherIgnorables; fOtherIgnorables = NULL;
- *status = U_MEMORY_ALLOCATION_ERROR;
+ status = U_MEMORY_ALLOCATION_ERROR;
}
UBool
SimpleDateFormatStaticSets::cleanup(void)
{
- delete SimpleDateFormatStaticSets::gStaticSets;
- SimpleDateFormatStaticSets::gStaticSets = NULL;
-
+ delete gStaticSets;
+ gStaticSets = NULL;
+ gSimpleDateFormatStaticSetsInitOnce.reset();
return TRUE;
}
{
return SimpleDateFormatStaticSets::cleanup();
}
-U_CDECL_END
-void SimpleDateFormatStaticSets::initSets(UErrorCode *status)
-{
- SimpleDateFormatStaticSets *p;
-
- UMTX_CHECK(NULL, gStaticSets, p);
- if (p == NULL) {
- p = new SimpleDateFormatStaticSets(status);
-
- if (p == NULL) {
- *status = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
-
- if (U_FAILURE(*status)) {
- delete p;
- return;
- }
-
- umtx_lock(NULL);
- if (gStaticSets == NULL) {
- gStaticSets = p;
- p = NULL;
- }
-
- umtx_unlock(NULL);
- if (p != NULL) {
- delete p;
- }
-
- ucln_i18n_registerCleanup(UCLN_I18N_SMPDTFMT, smpdtfmt_cleanup);
+static void U_CALLCONV smpdtfmt_initSets(UErrorCode &status) {
+ ucln_i18n_registerCleanup(UCLN_I18N_SMPDTFMT, smpdtfmt_cleanup);
+ U_ASSERT(gStaticSets == NULL);
+ gStaticSets = new SimpleDateFormatStaticSets(status);
+ if (gStaticSets == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
}
}
+U_CDECL_END
+
UnicodeSet *SimpleDateFormatStaticSets::getIgnorables(UDateFormatField fieldIndex)
{
- UErrorCode status = U_ZERO_ERROR;
-
- initSets(&status);
-
- if (U_FAILURE(status)) {
- return NULL;
- }
+ UErrorCode status = U_ZERO_ERROR;
+ umtx_initOnce(gSimpleDateFormatStaticSetsInitOnce, &smpdtfmt_initSets, status);
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
switch (fieldIndex) {
case UDAT_YEAR_FIELD:
}
}
-
U_NAMESPACE_END
#endif // #if !UCONFIG_NO_FORMATTING
/*
*******************************************************************************
-* Copyright (C) 2009-2011, International Business Machines Corporation and *
+* Copyright (C) 2009-2013, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*
class SimpleDateFormatStaticSets : public UMemory
{
public:
- static SimpleDateFormatStaticSets *gStaticSets; // Ptr to all lazily initialized constant
- // shared sets.
-
- SimpleDateFormatStaticSets(UErrorCode *status);
+ SimpleDateFormatStaticSets(UErrorCode &status);
~SimpleDateFormatStaticSets();
static void initSets(UErrorCode *status);
/*
*******************************************************************************
- * Copyright (C) 2003-2008, International Business Machines Corporation and *
+ * Copyright (C) 2003-2013, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*
}
#endif
-// default century
-const UDate TaiwanCalendar::fgSystemDefaultCentury = DBL_MIN;
-const int32_t TaiwanCalendar::fgSystemDefaultCenturyYear = -1;
-
-UDate TaiwanCalendar::fgSystemDefaultCenturyStart = DBL_MIN;
-int32_t TaiwanCalendar::fgSystemDefaultCenturyStartYear = -1;
-
+/**
+ * The system maintains a static default century start date and Year. They are
+ * initialized the first time they are used. Once the system default century date
+ * and year are set, they do not change.
+ */
+static UDate gSystemDefaultCenturyStart = DBL_MIN;
+static int32_t gSystemDefaultCenturyStartYear = -1;
+static UInitOnce gSystemDefaultCenturyInit = U_INITONCE_INITIALIZER;
UBool TaiwanCalendar::haveDefaultCentury() const
{
return TRUE;
}
-UDate TaiwanCalendar::defaultCenturyStart() const
-{
- return internalGetDefaultCenturyStart();
-}
-
-int32_t TaiwanCalendar::defaultCenturyStartYear() const
-{
- return internalGetDefaultCenturyStartYear();
-}
-
-UDate
-TaiwanCalendar::internalGetDefaultCenturyStart() const
-{
- // lazy-evaluate systemDefaultCenturyStart
- UBool needsUpdate;
- UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate);
-
- if (needsUpdate) {
- initializeSystemDefaultCentury();
- }
-
- // use defaultCenturyStart unless it's the flag value;
- // then use systemDefaultCenturyStart
-
- return fgSystemDefaultCenturyStart;
-}
-
-int32_t
-TaiwanCalendar::internalGetDefaultCenturyStartYear() const
-{
- // lazy-evaluate systemDefaultCenturyStartYear
- UBool needsUpdate;
- UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate);
-
- if (needsUpdate) {
- initializeSystemDefaultCentury();
- }
-
- // use defaultCenturyStart unless it's the flag value;
- // then use systemDefaultCenturyStartYear
-
- return fgSystemDefaultCenturyStartYear;
-}
-
-void
-TaiwanCalendar::initializeSystemDefaultCentury()
+static void U_CALLCONV initializeSystemDefaultCentury()
{
// initialize systemDefaultCentury and systemDefaultCenturyYear based
// on the current time. They'll be set to 80 years before
{
calendar.setTime(Calendar::getNow(), status);
calendar.add(UCAL_YEAR, -80, status);
- UDate newStart = calendar.getTime(status);
- int32_t newYear = calendar.get(UCAL_YEAR, status);
- umtx_lock(NULL);
- if (fgSystemDefaultCenturyStart == fgSystemDefaultCentury)
- {
- fgSystemDefaultCenturyStartYear = newYear;
- fgSystemDefaultCenturyStart = newStart;
- }
- umtx_unlock(NULL);
+
+ gSystemDefaultCenturyStart = calendar.getTime(status);
+ gSystemDefaultCenturyStartYear = calendar.get(UCAL_YEAR, status);
}
// We have no recourse upon failure unless we want to propagate the failure
// out.
}
+UDate TaiwanCalendar::defaultCenturyStart() const {
+ // lazy-evaluate systemDefaultCenturyStart
+ umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury);
+ return gSystemDefaultCenturyStart;
+}
+
+int32_t TaiwanCalendar::defaultCenturyStartYear() const {
+ // lazy-evaluate systemDefaultCenturyStartYear
+ umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury);
+ return gSystemDefaultCenturyStartYear;
+}
U_NAMESPACE_END
/*
********************************************************************************
- * Copyright (C) 2003-2007, International Business Machines Corporation
+ * Copyright (C) 2003-2013, International Business Machines Corporation
* and others. All Rights Reserved.
********************************************************************************
*
* @internal
*/
virtual int32_t defaultCenturyStartYear() const;
-
- private: // default century stuff.
- /**
- * The system maintains a static default century start date. This is initialized
- * the first time it is used. Before then, it is set to SYSTEM_DEFAULT_CENTURY to
- * indicate an uninitialized state. Once the system default century date and year
- * are set, they do not change.
- */
- static UDate fgSystemDefaultCenturyStart;
-
- /**
- * See documentation for systemDefaultCenturyStart.
- */
- static int32_t fgSystemDefaultCenturyStartYear;
-
- /**
- * Default value that indicates the defaultCenturyStartYear is unitialized
- */
- static const int32_t fgSystemDefaultCenturyYear;
-
- /**
- * start of default century, as a date
- */
- static const UDate fgSystemDefaultCentury;
-
- /**
- * Returns the beginning date of the 100-year window that dates
- * with 2-digit years are considered to fall within.
- */
- UDate internalGetDefaultCenturyStart(void) const;
-
- /**
- * Returns the first year of the 100-year window that dates with
- * 2-digit years are considered to fall within.
- */
- int32_t internalGetDefaultCenturyStartYear(void) const;
-
- /**
- * Initializes the 100-year window that dates with 2-digit years
- * are considered to fall within so that its start date is 80 years
- * before the current time.
- */
- static void initializeSystemDefaultCentury(void);
};
U_NAMESPACE_END
#include "unicode/utypes.h"
#include "unicode/ustring.h"
+#include "uassert.h"
#include "ustr_imp.h"
#ifdef U_DEBUG_TZ
static const int32_t GMT_ID_LENGTH = 3;
static const int32_t UNKNOWN_ZONE_ID_LENGTH = 11;
-static UMutex LOCK = U_MUTEX_INITIALIZER;
-static UMutex TZSET_LOCK = U_MUTEX_INITIALIZER;
static icu::TimeZone* DEFAULT_ZONE = NULL;
+static UInitOnce gDefaultZoneInitOnce = U_INITONCE_INITIALIZER;
+
static icu::TimeZone* _GMT = NULL;
static icu::TimeZone* _UNKNOWN_ZONE = NULL;
+static UInitOnce gStaticZonesInitOnce = U_INITONCE_INITIALIZER;
static char TZDATA_VERSION[16];
-static UBool TZDataVersionInitialized = FALSE;
+static UInitOnce gTZDataVersionInitOnce = U_INITONCE_INITIALIZER;
static int32_t* MAP_SYSTEM_ZONES = NULL;
static int32_t* MAP_CANONICAL_SYSTEM_ZONES = NULL;
static int32_t LEN_CANONICAL_SYSTEM_ZONES = 0;
static int32_t LEN_CANONICAL_SYSTEM_LOCATION_ZONES = 0;
+static UInitOnce gSystemZonesInitOnce = U_INITONCE_INITIALIZER;
+static UInitOnce gCanonicalZonesInitOnce = U_INITONCE_INITIALIZER;
+static UInitOnce gCanonicalLocationZonesInitOnce = U_INITONCE_INITIALIZER;
+
U_CDECL_BEGIN
static UBool U_CALLCONV timeZone_cleanup(void)
{
+ U_NAMESPACE_USE
delete DEFAULT_ZONE;
DEFAULT_ZONE = NULL;
+ gDefaultZoneInitOnce.reset();
delete _GMT;
_GMT = NULL;
-
delete _UNKNOWN_ZONE;
_UNKNOWN_ZONE = NULL;
+ gStaticZonesInitOnce.reset();
uprv_memset(TZDATA_VERSION, 0, sizeof(TZDATA_VERSION));
- TZDataVersionInitialized = FALSE;
+ gTZDataVersionInitOnce.reset();
LEN_SYSTEM_ZONES = 0;
uprv_free(MAP_SYSTEM_ZONES);
MAP_SYSTEM_ZONES = 0;
+ gSystemZonesInitOnce.reset();
LEN_CANONICAL_SYSTEM_ZONES = 0;
uprv_free(MAP_CANONICAL_SYSTEM_ZONES);
MAP_CANONICAL_SYSTEM_ZONES = 0;
+ gCanonicalZonesInitOnce.reset();
LEN_CANONICAL_SYSTEM_LOCATION_ZONES = 0;
uprv_free(MAP_CANONICAL_SYSTEM_LOCATION_ZONES);
MAP_CANONICAL_SYSTEM_LOCATION_ZONES = 0;
+ gCanonicalLocationZonesInitOnce.reset();
return TRUE;
}
namespace {
-void
-ensureStaticTimeZones() {
- UBool needsInit;
- UMTX_CHECK(&LOCK, (_GMT == NULL), needsInit); /* This is here to prevent race conditions. */
-
+void U_CALLCONV initStaticTimeZones() {
// Initialize _GMT independently of other static data; it should
// be valid even if we can't load the time zone UDataMemory.
- if (needsInit) {
- SimpleTimeZone *tmpUnknown =
- new SimpleTimeZone(0, UnicodeString(TRUE, UNKNOWN_ZONE_ID, UNKNOWN_ZONE_ID_LENGTH));
- SimpleTimeZone *tmpGMT = new SimpleTimeZone(0, UnicodeString(TRUE, GMT_ID, GMT_ID_LENGTH));
- umtx_lock(&LOCK);
- if (_UNKNOWN_ZONE == 0) {
- _UNKNOWN_ZONE = tmpUnknown;
- tmpUnknown = NULL;
- }
- if (_GMT == 0) {
- _GMT = tmpGMT;
- tmpGMT = NULL;
- }
- umtx_unlock(&LOCK);
- ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
- delete tmpUnknown;
- delete tmpGMT;
- }
+ ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
+ _UNKNOWN_ZONE = new SimpleTimeZone(0, UnicodeString(TRUE, UNKNOWN_ZONE_ID, UNKNOWN_ZONE_ID_LENGTH));
+ _GMT = new SimpleTimeZone(0, UnicodeString(TRUE, GMT_ID, GMT_ID_LENGTH));
}
} // anonymous namespace
const TimeZone& U_EXPORT2
TimeZone::getUnknown()
{
- ensureStaticTimeZones();
+ umtx_initOnce(gStaticZonesInitOnce, &initStaticTimeZones);
return *_UNKNOWN_ZONE;
}
const TimeZone* U_EXPORT2
TimeZone::getGMT(void)
{
- ensureStaticTimeZones();
+ umtx_initOnce(gStaticZonesInitOnce, &initStaticTimeZones);
return _GMT;
}
// -------------------------------------
-TimeZone* U_EXPORT2
-TimeZone::createTimeZone(const UnicodeString& ID)
-{
- /* We first try to lookup the zone ID in our system list. If this
- * fails, we try to parse it as a custom string GMT[+-]hh:mm. If
- * all else fails, we return GMT, which is probably not what the
- * user wants, but at least is a functioning TimeZone object.
- *
- * We cannot return NULL, because that would break compatibility
- * with the JDK.
- */
- TimeZone* result = createSystemTimeZone(ID);
-
- if (result == 0) {
- U_DEBUG_TZ_MSG(("failed to load system time zone with id - falling to custom"));
- result = createCustomTimeZone(ID);
- }
- if (result == 0) {
- U_DEBUG_TZ_MSG(("failed to load time zone with id - falling to Etc/Unknown(GMT)"));
- result = getUnknown().clone();
- }
- return result;
-}
-
-/**
- * Lookup the given name in our system zone table. If found,
- * instantiate a new zone of that name and return it. If not
- * found, return 0.
- */
-TimeZone*
-TimeZone::createSystemTimeZone(const UnicodeString& id) {
- UErrorCode ec = U_ZERO_ERROR;
- return createSystemTimeZone(id, ec);
-}
-
+namespace {
TimeZone*
-TimeZone::createSystemTimeZone(const UnicodeString& id, UErrorCode& ec) {
+createSystemTimeZone(const UnicodeString& id, UErrorCode& ec) {
if (U_FAILURE(ec)) {
return NULL;
}
return z;
}
+/**
+ * Lookup the given name in our system zone table. If found,
+ * instantiate a new zone of that name and return it. If not
+ * found, return 0.
+ */
+TimeZone*
+createSystemTimeZone(const UnicodeString& id) {
+ UErrorCode ec = U_ZERO_ERROR;
+ return createSystemTimeZone(id, ec);
+}
+
+}
+
+TimeZone* U_EXPORT2
+TimeZone::createTimeZone(const UnicodeString& ID)
+{
+ /* We first try to lookup the zone ID in our system list. If this
+ * fails, we try to parse it as a custom string GMT[+-]hh:mm. If
+ * all else fails, we return GMT, which is probably not what the
+ * user wants, but at least is a functioning TimeZone object.
+ *
+ * We cannot return NULL, because that would break compatibility
+ * with the JDK.
+ */
+ TimeZone* result = createSystemTimeZone(ID);
+
+ if (result == 0) {
+ U_DEBUG_TZ_MSG(("failed to load system time zone with id - falling to custom"));
+ result = createCustomTimeZone(ID);
+ }
+ if (result == 0) {
+ U_DEBUG_TZ_MSG(("failed to load time zone with id - falling to Etc/Unknown(GMT)"));
+ result = getUnknown().clone();
+ }
+ return result;
+}
+
// -------------------------------------
/**
- * Initialize DEFAULT_ZONE from the system default time zone. The
- * caller should confirm that DEFAULT_ZONE is NULL before calling.
+ * Initialize DEFAULT_ZONE from the system default time zone.
* Upon return, DEFAULT_ZONE will not be NULL, unless operator new()
* returns NULL.
- *
- * Must be called OUTSIDE mutex.
*/
-void
-TimeZone::initDefault()
+static void U_CALLCONV initDefault()
{
+ ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
+
+ // If setDefault() has already been called we can skip getting the
+ // default zone information from the system.
+ if (DEFAULT_ZONE != NULL) {
+ return;
+ }
+
// We access system timezone data through TPlatformUtilities,
// including tzset(), timezone, and tzname[].
int32_t rawOffset = 0;
// First, try to create a system timezone, based
// on the string ID in tzname[0].
- {
- // NOTE: Local mutex here. TimeZone mutex below
- // mutexed to avoid threading issues in the platform functions.
- // Some of the locale/timezone OS functions may not be thread safe,
- // so the intent is that any setting from anywhere within ICU
- // happens while the ICU mutex is held.
- // The operating system might actually use ICU to implement timezones.
- // So we may have ICU calling ICU here, like on AIX.
- // In order to prevent a double lock of a non-reentrant mutex in a
- // different part of ICU, we use TZSET_LOCK to allow only one instance
- // of ICU to query these thread unsafe OS functions at any given time.
- Mutex lock(&TZSET_LOCK);
- ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
- uprv_tzset(); // Initialize tz... system data
+ // NOTE: this code is safely single threaded, being only
+ // run via umtx_initOnce().
+ //
+ // Some of the locale/timezone OS functions may not be thread safe,
+ //
+ // The operating system might actually use ICU to implement timezones.
+ // So we may have ICU calling ICU here, like on AIX.
+ // There shouldn't be a problem with this; initOnce does not hold a mutex
+ // while the init function is being run.
- // Get the timezone ID from the host. This function should do
- // any required host-specific remapping; e.g., on Windows this
- // function maps the Date and Time control panel setting to an
- // ICU timezone ID.
- hostID = uprv_tzname(0);
+ uprv_tzset(); // Initialize tz... system data
- // Invert sign because UNIX semantics are backwards
- rawOffset = uprv_timezone() * -U_MILLIS_PER_SECOND;
- }
+ // Get the timezone ID from the host. This function should do
+ // any required host-specific remapping; e.g., on Windows this
+ // function maps the Date and Time control panel setting to an
+ // ICU timezone ID.
+ hostID = uprv_tzname(0);
- UBool initialized;
- UMTX_CHECK(&LOCK, (DEFAULT_ZONE != NULL), initialized);
- if (initialized) {
- /* Hrmph? Either a race condition happened, or tzset initialized ICU. */
- return;
- }
+ // Invert sign because UNIX semantics are backwards
+ rawOffset = uprv_timezone() * -U_MILLIS_PER_SECOND;
TimeZone* default_zone = NULL;
// If we _still_ don't have a time zone, use GMT.
if (default_zone == NULL) {
- const TimeZone* temptz = getGMT();
+ const TimeZone* temptz = TimeZone::getGMT();
// If we can't use GMT, get out.
if (temptz == NULL) {
return;
default_zone = temptz->clone();
}
- // If DEFAULT_ZONE is still NULL, set it up.
- umtx_lock(&LOCK);
- if (DEFAULT_ZONE == NULL) {
- DEFAULT_ZONE = default_zone;
- default_zone = NULL;
- ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
- }
- umtx_unlock(&LOCK);
+ // The only way for DEFAULT_ZONE to be non-null at this point is if the user
+ // made a thread-unsafe call to setDefault() or adoptDefault() in another
+ // thread while this thread was doing something that required getting the default.
+ U_ASSERT(DEFAULT_ZONE == NULL);
- delete default_zone;
+ DEFAULT_ZONE = default_zone;
}
// -------------------------------------
TimeZone* U_EXPORT2
TimeZone::createDefault()
{
- /* This is here to prevent race conditions. */
- UBool needsInit;
- UMTX_CHECK(&LOCK, (DEFAULT_ZONE == NULL), needsInit);
- if (needsInit) {
- initDefault();
- }
-
- Mutex lock(&LOCK); // In case adoptDefault is called
+ umtx_initOnce(gDefaultZoneInitOnce, initDefault);
return (DEFAULT_ZONE != NULL) ? DEFAULT_ZONE->clone() : NULL;
}
{
if (zone != NULL)
{
- TimeZone* old = NULL;
-
- umtx_lock(&LOCK);
- old = DEFAULT_ZONE;
+ TimeZone *old = DEFAULT_ZONE;
DEFAULT_ZONE = zone;
- umtx_unlock(&LOCK);
-
delete old;
ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
}
//----------------------------------------------------------------------
+
+static void U_CALLCONV initMap(USystemTimeZoneType type, UErrorCode& ec) {
+ ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
+
+ UResourceBundle *res = ures_openDirect(0, kZONEINFO, &ec);
+ res = ures_getByKey(res, kNAMES, res, &ec); // dereference Zones section
+ if (U_SUCCESS(ec)) {
+ int32_t size = ures_getSize(res);
+ int32_t *m = (int32_t *)uprv_malloc(size * sizeof(int32_t));
+ if (m == NULL) {
+ ec = U_MEMORY_ALLOCATION_ERROR;
+ } else {
+ int32_t numEntries = 0;
+ for (int32_t i = 0; i < size; i++) {
+ UnicodeString id = ures_getUnicodeStringByIndex(res, i, &ec);
+ if (U_FAILURE(ec)) {
+ break;
+ }
+ if (0 == id.compare(UNKNOWN_ZONE_ID, UNKNOWN_ZONE_ID_LENGTH)) {
+ // exclude Etc/Unknown
+ continue;
+ }
+ if (type == UCAL_ZONE_TYPE_CANONICAL || type == UCAL_ZONE_TYPE_CANONICAL_LOCATION) {
+ UnicodeString canonicalID;
+ ZoneMeta::getCanonicalCLDRID(id, canonicalID, ec);
+ if (U_FAILURE(ec)) {
+ break;
+ }
+ if (canonicalID != id) {
+ // exclude aliases
+ continue;
+ }
+ }
+ if (type == UCAL_ZONE_TYPE_CANONICAL_LOCATION) {
+ const UChar *region = TimeZone::getRegion(id, ec);
+ if (U_FAILURE(ec)) {
+ break;
+ }
+ if (u_strcmp(region, WORLD) == 0) {
+ // exclude non-location ("001")
+ continue;
+ }
+ }
+ m[numEntries++] = i;
+ }
+ if (U_SUCCESS(ec)) {
+ int32_t *tmp = m;
+ m = (int32_t *)uprv_realloc(tmp, numEntries * sizeof(int32_t));
+ if (m == NULL) {
+ // realloc failed.. use the original one even it has unused
+ // area at the end
+ m = tmp;
+ }
+
+ switch(type) {
+ case UCAL_ZONE_TYPE_ANY:
+ U_ASSERT(MAP_SYSTEM_ZONES == NULL);
+ MAP_SYSTEM_ZONES = m;
+ LEN_SYSTEM_ZONES = numEntries;
+ break;
+ case UCAL_ZONE_TYPE_CANONICAL:
+ U_ASSERT(MAP_CANONICAL_SYSTEM_ZONES == NULL);
+ MAP_CANONICAL_SYSTEM_ZONES = m;
+ LEN_CANONICAL_SYSTEM_ZONES = numEntries;
+ break;
+ case UCAL_ZONE_TYPE_CANONICAL_LOCATION:
+ U_ASSERT(MAP_CANONICAL_SYSTEM_LOCATION_ZONES == NULL);
+ MAP_CANONICAL_SYSTEM_LOCATION_ZONES = m;
+ LEN_CANONICAL_SYSTEM_LOCATION_ZONES = numEntries;
+ break;
+ }
+ }
+ }
+ }
+ ures_close(res);
+}
+
+
/**
* This is the default implementation for subclasses that do not
* override this method. This implementation calls through to the
int32_t* m = NULL;
switch (type) {
case UCAL_ZONE_TYPE_ANY:
+ umtx_initOnce(gSystemZonesInitOnce, &initMap, type, ec);
m = MAP_SYSTEM_ZONES;
len = LEN_SYSTEM_ZONES;
break;
case UCAL_ZONE_TYPE_CANONICAL:
+ umtx_initOnce(gCanonicalZonesInitOnce, &initMap, type, ec);
m = MAP_CANONICAL_SYSTEM_ZONES;
len = LEN_CANONICAL_SYSTEM_ZONES;
break;
case UCAL_ZONE_TYPE_CANONICAL_LOCATION:
+ umtx_initOnce(gCanonicalLocationZonesInitOnce, &initMap, type, ec);
m = MAP_CANONICAL_SYSTEM_LOCATION_ZONES;
len = LEN_CANONICAL_SYSTEM_LOCATION_ZONES;
break;
- }
- UBool needsInit = FALSE;
- UMTX_CHECK(&LOCK, (len == 0), needsInit);
- if (needsInit) {
- m = initMap(type, len, ec);
+ default:
+ ec = U_ILLEGAL_ARGUMENT_ERROR;
+ m = NULL;
+ len = 0;
+ break;
}
return m;
}
- static int32_t* initMap(USystemTimeZoneType type, int32_t& len, UErrorCode& ec) {
- len = 0;
- if (U_FAILURE(ec)) {
- return NULL;
- }
-
- int32_t *result = NULL;
-
- UResourceBundle *res = ures_openDirect(0, kZONEINFO, &ec);
- res = ures_getByKey(res, kNAMES, res, &ec); // dereference Zones section
- if (U_SUCCESS(ec)) {
- int32_t size = ures_getSize(res);
- int32_t *m = (int32_t *)uprv_malloc(size * sizeof(int32_t));
- if (m == NULL) {
- ec = U_MEMORY_ALLOCATION_ERROR;
- } else {
- int32_t numEntries = 0;
- for (int32_t i = 0; i < size; i++) {
- UnicodeString id = ures_getUnicodeStringByIndex(res, i, &ec);
- if (U_FAILURE(ec)) {
- break;
- }
- if (0 == id.compare(UNKNOWN_ZONE_ID, UNKNOWN_ZONE_ID_LENGTH)) {
- // exclude Etc/Unknown
- continue;
- }
- if (type == UCAL_ZONE_TYPE_CANONICAL || type == UCAL_ZONE_TYPE_CANONICAL_LOCATION) {
- UnicodeString canonicalID;
- ZoneMeta::getCanonicalCLDRID(id, canonicalID, ec);
- if (U_FAILURE(ec)) {
- break;
- }
- if (canonicalID != id) {
- // exclude aliases
- continue;
- }
- }
- if (type == UCAL_ZONE_TYPE_CANONICAL_LOCATION) {
- const UChar *region = TimeZone::getRegion(id, ec);
- if (U_FAILURE(ec)) {
- break;
- }
- if (u_strcmp(region, WORLD) == 0) {
- // exclude non-location ("001")
- continue;
- }
- }
- m[numEntries++] = i;
- }
- if (U_SUCCESS(ec)) {
- int32_t *tmp = m;
- m = (int32_t *)uprv_realloc(tmp, numEntries * sizeof(int32_t));
- if (m == NULL) {
- // realloc failed.. use the original one even it has unused
- // area at the end
- m = tmp;
- }
-
- umtx_lock(&LOCK);
- {
- switch(type) {
- case UCAL_ZONE_TYPE_ANY:
- if (MAP_SYSTEM_ZONES == NULL) {
- MAP_SYSTEM_ZONES = m;
- LEN_SYSTEM_ZONES = numEntries;
- m = NULL;
- ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
- }
- result = MAP_SYSTEM_ZONES;
- len = LEN_SYSTEM_ZONES;
- break;
- case UCAL_ZONE_TYPE_CANONICAL:
- if (MAP_CANONICAL_SYSTEM_ZONES == NULL) {
- MAP_CANONICAL_SYSTEM_ZONES = m;
- LEN_CANONICAL_SYSTEM_ZONES = numEntries;
- m = NULL;
- ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
- }
- result = MAP_CANONICAL_SYSTEM_ZONES;
- len = LEN_CANONICAL_SYSTEM_ZONES;
- break;
- case UCAL_ZONE_TYPE_CANONICAL_LOCATION:
- if (MAP_CANONICAL_SYSTEM_LOCATION_ZONES == NULL) {
- MAP_CANONICAL_SYSTEM_LOCATION_ZONES = m;
- LEN_CANONICAL_SYSTEM_LOCATION_ZONES = numEntries;
- m = NULL;
- ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
- }
- result = MAP_CANONICAL_SYSTEM_LOCATION_ZONES;
- len = LEN_CANONICAL_SYSTEM_LOCATION_ZONES;
- break;
- }
- }
- umtx_unlock(&LOCK);
- }
- uprv_free(m);
- }
- }
-
- ures_close(res);
- return result;
- }
-
public:
#define DEFAULT_FILTERED_MAP_SIZE 8
if (rawOffset != NULL) {
// Filter by raw offset
// Note: This is VERY inefficient
- TimeZone *z = TimeZone::createSystemTimeZone(id, ec);
+ TimeZone *z = createSystemTimeZone(id, ec);
if (U_FAILURE(ec)) {
break;
}
useDaylightTime() == other.useDaylightTime());
}
-const char*
-TimeZone::getTZDataVersion(UErrorCode& status)
-{
- /* This is here to prevent race conditions. */
- UBool needsInit;
- UMTX_CHECK(&LOCK, !TZDataVersionInitialized, needsInit);
- if (needsInit) {
- int32_t len = 0;
- UResourceBundle *bundle = ures_openDirect(NULL, kZONEINFO, &status);
- const UChar *tzver = ures_getStringByKey(bundle, kTZVERSION,
- &len, &status);
+static void U_CALLCONV initTZDataVersion(UErrorCode &status) {
+ ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
+ int32_t len = 0;
+ UResourceBundle *bundle = ures_openDirect(NULL, kZONEINFO, &status);
+ const UChar *tzver = ures_getStringByKey(bundle, kTZVERSION, &len, &status);
- if (U_SUCCESS(status)) {
- if (len >= (int32_t)sizeof(TZDATA_VERSION)) {
- // Ensure that there is always space for a trailing nul in TZDATA_VERSION
- len = sizeof(TZDATA_VERSION) - 1;
- }
- umtx_lock(&LOCK);
- if (!TZDataVersionInitialized) {
- u_UCharsToChars(tzver, TZDATA_VERSION, len);
- TZDataVersionInitialized = TRUE;
- }
- umtx_unlock(&LOCK);
- ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
+ if (U_SUCCESS(status)) {
+ if (len >= (int32_t)sizeof(TZDATA_VERSION)) {
+ // Ensure that there is always space for a trailing nul in TZDATA_VERSION
+ len = sizeof(TZDATA_VERSION) - 1;
}
-
- ures_close(bundle);
- }
- if (U_FAILURE(status)) {
- return NULL;
+ u_UCharsToChars(tzver, TZDATA_VERSION, len);
}
+ ures_close(bundle);
+
+}
+
+const char*
+TimeZone::getTZDataVersion(UErrorCode& status)
+{
+ umtx_initOnce(gTZDataVersionInitOnce, &initTZDataVersion, status);
return (const char*)TZDATA_VERSION;
}
// Time Zone ID/Short ID trie
static TextTrieMap *gZoneIdTrie = NULL;
-static UBool gZoneIdTrieInitialized = FALSE;
+static UInitOnce gZoneIdTrieInitOnce = U_INITONCE_INITIALIZER;
static TextTrieMap *gShortZoneIdTrie = NULL;
-static UBool gShortZoneIdTrieInitialized = FALSE;
+static UInitOnce gShortZoneIdTrieInitOnce = U_INITONCE_INITIALIZER;
static UMutex gLock = U_MUTEX_INITIALIZER;
delete gZoneIdTrie;
}
gZoneIdTrie = NULL;
- gZoneIdTrieInitialized = FALSE;
+ gZoneIdTrieInitOnce.reset();
if (gShortZoneIdTrie != NULL) {
delete gShortZoneIdTrie;
}
gShortZoneIdTrie = NULL;
- gShortZoneIdTrieInitialized = FALSE;
+ gShortZoneIdTrieInitOnce.reset();
return TRUE;
}
fTimeZoneNames = other.fTimeZoneNames->clone();
if (other.fTimeZoneGenericNames) {
+ // TODO: this test has dubious thread safety.
fTimeZoneGenericNames = other.fTimeZoneGenericNames->clone();
}
return NULL;
}
- UBool create;
- UMTX_CHECK(&gZoneMetaLock, (fTimeZoneGenericNames == NULL), create);
- if (create) {
+ umtx_lock(&gLock);
+ if (fTimeZoneGenericNames == NULL) {
TimeZoneFormat *nonConstThis = const_cast<TimeZoneFormat *>(this);
- umtx_lock(&gLock);
- {
- if (fTimeZoneGenericNames == NULL) {
- nonConstThis->fTimeZoneGenericNames = TimeZoneGenericNames::createInstance(fLocale, status);
- }
- }
- umtx_unlock(&gLock);
+ nonConstThis->fTimeZoneGenericNames = TimeZoneGenericNames::createInstance(fLocale, status);
}
+ umtx_unlock(&gLock);
return fTimeZoneGenericNames;
}
return fLen;
}
+
+static void U_CALLCONV initZoneIdTrie(UErrorCode &status) {
+ U_ASSERT(gZoneIdTrie == NULL);
+ ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONEFORMAT, tzfmt_cleanup);
+ gZoneIdTrie = new TextTrieMap(TRUE, NULL); // No deleter, because values are pooled by ZoneMeta
+ if (gZoneIdTrie == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ StringEnumeration *tzenum = TimeZone::createEnumeration();
+ const UnicodeString *id;
+ while ((id = tzenum->snext(status))) {
+ const UChar* uid = ZoneMeta::findTimeZoneID(*id);
+ if (uid) {
+ gZoneIdTrie->put(uid, const_cast<UChar *>(uid), status);
+ }
+ }
+ delete tzenum;
+}
+
+
UnicodeString&
TimeZoneFormat::parseZoneID(const UnicodeString& text, ParsePosition& pos, UnicodeString& tzID) const {
UErrorCode status = U_ZERO_ERROR;
- UBool initialized;
- UMTX_CHECK(&gLock, gZoneIdTrieInitialized, initialized);
- if (!initialized) {
- umtx_lock(&gLock);
- {
- if (!gZoneIdTrieInitialized) {
- StringEnumeration *tzenum = TimeZone::createEnumeration();
- TextTrieMap* trie = new TextTrieMap(TRUE, NULL); // No deleter, because values are pooled by ZoneMeta
- if (trie) {
- const UnicodeString *id;
- while ((id = tzenum->snext(status))) {
- const UChar* uid = ZoneMeta::findTimeZoneID(*id);
- if (uid) {
- trie->put(uid, const_cast<UChar *>(uid), status);
- }
- }
- if (U_SUCCESS(status)) {
- gZoneIdTrie = trie;
- gZoneIdTrieInitialized = initialized = TRUE;
- ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONEFORMAT, tzfmt_cleanup);
- } else {
- delete trie;
- }
- }
- delete tzenum;
- }
- }
- umtx_unlock(&gLock);
- }
+ umtx_initOnce(gZoneIdTrieInitOnce, &initZoneIdTrie, status);
int32_t start = pos.getIndex();
int32_t len = 0;
tzID.setToBogus();
- if (initialized) {
+ if (U_SUCCESS(status)) {
LocalPointer<ZoneIdMatchHandler> handler(new ZoneIdMatchHandler());
gZoneIdTrie->search(text, start, handler.getAlias(), status);
len = handler->getMatchLen();
return tzID;
}
-UnicodeString&
-TimeZoneFormat::parseShortZoneID(const UnicodeString& text, ParsePosition& pos, UnicodeString& tzID) const {
- UErrorCode status = U_ZERO_ERROR;
- UBool initialized;
- UMTX_CHECK(&gLock, gShortZoneIdTrieInitialized, initialized);
- if (!initialized) {
- umtx_lock(&gLock);
- {
- if (!gShortZoneIdTrieInitialized) {
- StringEnumeration *tzenum = TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_CANONICAL, NULL, NULL, status);
- if (U_SUCCESS(status)) {
- TextTrieMap* trie = new TextTrieMap(TRUE, NULL); // No deleter, because values are pooled by ZoneMeta
- if (trie) {
- const UnicodeString *id;
- while ((id = tzenum->snext(status))) {
- const UChar* uID = ZoneMeta::findTimeZoneID(*id);
- const UChar* shortID = ZoneMeta::getShortID(*id);
- if (shortID && uID) {
- trie->put(shortID, const_cast<UChar *>(uID), status);
- }
- }
- if (U_SUCCESS(status)) {
- gShortZoneIdTrie = trie;
- gShortZoneIdTrieInitialized = initialized = TRUE;
- ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONEFORMAT, tzfmt_cleanup);
- } else {
- delete trie;
- }
- }
+static void U_CALLCONV initShortZoneIdTrie(UErrorCode &status) {
+ U_ASSERT(gShortZoneIdTrie == NULL);
+ ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONEFORMAT, tzfmt_cleanup);
+ StringEnumeration *tzenum = TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_CANONICAL, NULL, NULL, status);
+ if (U_SUCCESS(status)) {
+ gShortZoneIdTrie = new TextTrieMap(TRUE, NULL); // No deleter, because values are pooled by ZoneMeta
+ if (gShortZoneIdTrie == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ } else {
+ const UnicodeString *id;
+ while ((id = tzenum->snext(status))) {
+ const UChar* uID = ZoneMeta::findTimeZoneID(*id);
+ const UChar* shortID = ZoneMeta::getShortID(*id);
+ if (shortID && uID) {
+ gShortZoneIdTrie->put(shortID, const_cast<UChar *>(uID), status);
}
- delete tzenum;
}
}
- umtx_unlock(&gLock);
}
+ delete tzenum;
+}
+
+
+UnicodeString&
+TimeZoneFormat::parseShortZoneID(const UnicodeString& text, ParsePosition& pos, UnicodeString& tzID) const {
+ UErrorCode status = U_ZERO_ERROR;
+ umtx_initOnce(gShortZoneIdTrieInitOnce, &initShortZoneIdTrie, status);
int32_t start = pos.getIndex();
int32_t len = 0;
tzID.setToBogus();
- if (initialized) {
+ if (U_SUCCESS(status)) {
LocalPointer<ZoneIdMatchHandler> handler(new ZoneIdMatchHandler());
gShortZoneIdTrie->search(text, start, handler.getAlias(), status);
len = handler->getMatchLen();
#include "cmemory.h"
#include "cstring.h"
+#include "mutex.h"
#include "uhash.h"
#include "uassert.h"
#include "umutex.h"
return NULL;
}
- UBool initialized;
- UMTX_CHECK(&gTZGNLock, gTZGNCoreCacheInitialized, initialized);
- if (!initialized) {
- // Create empty hashtable
- umtx_lock(&gTZGNLock);
- {
- if (!gTZGNCoreCacheInitialized) {
- gTZGNCoreCache = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
- if (U_SUCCESS(status)) {
- uhash_setKeyDeleter(gTZGNCoreCache, uprv_free);
- uhash_setValueDeleter(gTZGNCoreCache, deleteTZGNCoreRef);
- gTZGNCoreCacheInitialized = TRUE;
- ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONEGENERICNAMES, tzgnCore_cleanup);
- }
+ TZGNCoreRef *cacheEntry = NULL;
+ {
+ Mutex lock(&gTZGNLock);
+
+ if (!gTZGNCoreCacheInitialized) {
+ // Create empty hashtable
+ gTZGNCoreCache = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
+ if (U_SUCCESS(status)) {
+ uhash_setKeyDeleter(gTZGNCoreCache, uprv_free);
+ uhash_setValueDeleter(gTZGNCoreCache, deleteTZGNCoreRef);
+ gTZGNCoreCacheInitialized = TRUE;
+ ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONEGENERICNAMES, tzgnCore_cleanup);
}
}
- umtx_unlock(&gTZGNLock);
-
if (U_FAILURE(status)) {
return NULL;
}
- }
- // Check the cache, if not available, create new one and cache
- TZGNCoreRef *cacheEntry = NULL;
- umtx_lock(&gTZGNLock);
- {
+ // Check the cache, if not available, create new one and cache
const char *key = locale.getName();
cacheEntry = (TZGNCoreRef *)uhash_get(gTZGNCoreCache, key);
if (cacheEntry == NULL) {
sweepCache();
gAccessCount = 0;
}
- }
- umtx_unlock(&gTZGNLock);
+ } // End of mutex locked block
if (cacheEntry == NULL) {
delete instance;
#include "unicode/uenum.h"
#include "cmemory.h"
#include "cstring.h"
+#include "mutex.h"
#include "putilimp.h"
#include "tznames_impl.h"
#include "uassert.h"
}
TimeZoneNamesDelegate::TimeZoneNamesDelegate(const Locale& locale, UErrorCode& status) {
- UBool initialized;
- UMTX_CHECK(&gTimeZoneNamesLock, gTimeZoneNamesCacheInitialized, initialized);
- if (!initialized) {
- // Create empty hashtable
- umtx_lock(&gTimeZoneNamesLock);
- {
- if (!gTimeZoneNamesCacheInitialized) {
- gTimeZoneNamesCache = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
- if (U_SUCCESS(status)) {
- uhash_setKeyDeleter(gTimeZoneNamesCache, uprv_free);
- uhash_setValueDeleter(gTimeZoneNamesCache, deleteTimeZoneNamesCacheEntry);
- gTimeZoneNamesCacheInitialized = TRUE;
- ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONENAMES, timeZoneNames_cleanup);
- }
- }
+ Mutex lock(&gTimeZoneNamesLock);
+ if (!gTimeZoneNamesCacheInitialized) {
+ // Create empty hashtable if it is not already initialized.
+ gTimeZoneNamesCache = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
+ if (U_SUCCESS(status)) {
+ uhash_setKeyDeleter(gTimeZoneNamesCache, uprv_free);
+ uhash_setValueDeleter(gTimeZoneNamesCache, deleteTimeZoneNamesCacheEntry);
+ gTimeZoneNamesCacheInitialized = TRUE;
+ ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONENAMES, timeZoneNames_cleanup);
}
- umtx_unlock(&gTimeZoneNamesLock);
+ }
- if (U_FAILURE(status)) {
- return;
- }
+ if (U_FAILURE(status)) {
+ return;
}
// Check the cache, if not available, create new one and cache
TimeZoneNamesCacheEntry *cacheEntry = NULL;
- umtx_lock(&gTimeZoneNamesLock);
- {
- const char *key = locale.getName();
- cacheEntry = (TimeZoneNamesCacheEntry *)uhash_get(gTimeZoneNamesCache, key);
- if (cacheEntry == NULL) {
- TimeZoneNames *tznames = NULL;
- char *newKey = NULL;
-
- tznames = new TimeZoneNamesImpl(locale, status);
- if (tznames == NULL) {
+
+ const char *key = locale.getName();
+ cacheEntry = (TimeZoneNamesCacheEntry *)uhash_get(gTimeZoneNamesCache, key);
+ if (cacheEntry == NULL) {
+ TimeZoneNames *tznames = NULL;
+ char *newKey = NULL;
+
+ tznames = new TimeZoneNamesImpl(locale, status);
+ if (tznames == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ if (U_SUCCESS(status)) {
+ newKey = (char *)uprv_malloc(uprv_strlen(key) + 1);
+ if (newKey == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ } else {
+ uprv_strcpy(newKey, key);
+ }
+ }
+ if (U_SUCCESS(status)) {
+ cacheEntry = (TimeZoneNamesCacheEntry *)uprv_malloc(sizeof(TimeZoneNamesCacheEntry));
+ if (cacheEntry == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
+ } else {
+ cacheEntry->names = tznames;
+ cacheEntry->refCount = 1;
+ cacheEntry->lastAccess = (double)uprv_getUTCtime();
+
+ uhash_put(gTimeZoneNamesCache, newKey, cacheEntry, &status);
}
- if (U_SUCCESS(status)) {
- newKey = (char *)uprv_malloc(uprv_strlen(key) + 1);
- if (newKey == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- } else {
- uprv_strcpy(newKey, key);
- }
+ }
+ if (U_FAILURE(status)) {
+ if (tznames != NULL) {
+ delete tznames;
}
- if (U_SUCCESS(status)) {
- cacheEntry = (TimeZoneNamesCacheEntry *)uprv_malloc(sizeof(TimeZoneNamesCacheEntry));
- if (cacheEntry == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- } else {
- cacheEntry->names = tznames;
- cacheEntry->refCount = 1;
- cacheEntry->lastAccess = (double)uprv_getUTCtime();
-
- uhash_put(gTimeZoneNamesCache, newKey, cacheEntry, &status);
- }
+ if (newKey != NULL) {
+ uprv_free(newKey);
}
- if (U_FAILURE(status)) {
- if (tznames != NULL) {
- delete tznames;
- }
- if (newKey != NULL) {
- uprv_free(newKey);
- }
- if (cacheEntry != NULL) {
- uprv_free(cacheEntry);
- }
- cacheEntry = NULL;
+ if (cacheEntry != NULL) {
+ uprv_free(cacheEntry);
}
- } else {
- // Update the reference count
- cacheEntry->refCount++;
- cacheEntry->lastAccess = (double)uprv_getUTCtime();
- }
- gAccessCount++;
- if (gAccessCount >= SWEEP_INTERVAL) {
- // sweep
- sweepCache();
- gAccessCount = 0;
+ cacheEntry = NULL;
}
+ } else {
+ // Update the reference count
+ cacheEntry->refCount++;
+ cacheEntry->lastAccess = (double)uprv_getUTCtime();
+ }
+ gAccessCount++;
+ if (gAccessCount >= SWEEP_INTERVAL) {
+ // sweep
+ sweepCache();
+ gAccessCount = 0;
}
- umtx_unlock(&gTimeZoneNamesLock);
-
fTZnamesCacheEntry = cacheEntry;
}
#include "cmemory.h"
#include "cstring.h"
#include "uassert.h"
+#include "mutex.h"
#include "uresimp.h"
#include "ureslocs.h"
#include "zonemeta.h"
// needed for parsing operations, which are less common than formatting,
// and the Trie is big, which is why its creation is deferred until first use.
void TextTrieMap::buildTrie(UErrorCode &status) {
- umtx_lock(&TextTrieMutex);
if (fLazyContents != NULL) {
for (int32_t i=0; i<fLazyContents->size(); i+=2) {
const UChar *key = (UChar *)fLazyContents->elementAt(i);
delete fLazyContents;
fLazyContents = NULL;
}
- umtx_unlock(&TextTrieMutex);
}
void
TextTrieMap::search(const UnicodeString &text, int32_t start,
TextTrieMapSearchResultHandler *handler, UErrorCode &status) const {
- UBool trieNeedsInitialization = FALSE;
- UMTX_CHECK(&TextTrieMutex, fLazyContents != NULL, trieNeedsInitialization);
- if (trieNeedsInitialization) {
- TextTrieMap *nonConstThis = const_cast<TextTrieMap *>(this);
- nonConstThis->buildTrie(status);
+ {
+ // TODO: if locking the mutex for each check proves to be a performance problem,
+ // add a flag of type atomic_int32_t to class TextTrieMap, and use only
+ // the ICU atomic safe functions for assigning and testing.
+ // Don't test the pointer fLazyContents.
+ // Don't do unless it's really required.
+ Mutex lock(&TextTrieMutex);
+ if (fLazyContents != NULL) {
+ TextTrieMap *nonConstThis = const_cast<TextTrieMap *>(this);
+ nonConstThis->buildTrie(status);
+ }
}
if (fNodes == NULL) {
return;
#include "unicode/ustring.h"
#include "unicode/utf16.h"
#include "normalizer2impl.h"
+#include "uassert.h"
#include "ucol_bld.h"
#include "ucol_elm.h"
#include "ucol_cnt.h"
static const InverseUCATableHeader* _staticInvUCA = NULL;
static UDataMemory* invUCA_DATA_MEM = NULL;
+static UInitOnce gStaticInvUCAInitOnce = U_INITONCE_INITIALIZER;
U_CDECL_BEGIN
static UBool U_CALLCONV
udata_close(invUCA_DATA_MEM);
invUCA_DATA_MEM = NULL;
_staticInvUCA = NULL;
+ gStaticInvUCAInitOnce.reset();
return TRUE;
}
U_CDECL_END
-U_CAPI const InverseUCATableHeader * U_EXPORT2
-ucol_initInverseUCA(UErrorCode *status)
-{
- if(U_FAILURE(*status)) return NULL;
+static void U_CALLCONV initInverseUCA(UErrorCode &status) {
+ U_ASSERT(invUCA_DATA_MEM == NULL);
+ U_ASSERT(_staticInvUCA == NULL);
+ ucln_i18n_registerCleanup(UCLN_I18N_UCOL_BLD, ucol_bld_cleanup);
+ InverseUCATableHeader *newInvUCA = NULL;
+ UDataMemory *result = udata_openChoice(U_ICUDATA_COLL, INVC_DATA_TYPE, INVC_DATA_NAME, isAcceptableInvUCA, NULL, &status);
- UBool needsInit;
- UMTX_CHECK(NULL, (_staticInvUCA == NULL), needsInit);
-
- if(needsInit) {
- InverseUCATableHeader *newInvUCA = NULL;
- UDataMemory *result = udata_openChoice(U_ICUDATA_COLL, INVC_DATA_TYPE, INVC_DATA_NAME, isAcceptableInvUCA, NULL, status);
+ if(U_FAILURE(status)) {
+ if (result) {
+ udata_close(result);
+ }
+ // This is not needed, as we are talking about
+ // memory we got from UData
+ //uprv_free(newInvUCA);
+ return;
+ }
- if(U_FAILURE(*status)) {
- if (result) {
- udata_close(result);
- }
- // This is not needed, as we are talking about
- // memory we got from UData
- //uprv_free(newInvUCA);
+ if(result != NULL) { /* It looks like sometimes we can fail to find the data file */
+ newInvUCA = (InverseUCATableHeader *)udata_getMemory(result);
+ UCollator *UCA = ucol_initUCA(&status);
+ // UCA versions of UCA and inverse UCA should match
+ if(uprv_memcmp(newInvUCA->UCAVersion, UCA->image->UCAVersion, sizeof(UVersionInfo)) != 0) {
+ status = U_INVALID_FORMAT_ERROR;
+ udata_close(result);
+ return;
}
- if(result != NULL) { /* It looks like sometimes we can fail to find the data file */
- newInvUCA = (InverseUCATableHeader *)udata_getMemory(result);
- UCollator *UCA = ucol_initUCA(status);
- // UCA versions of UCA and inverse UCA should match
- if(uprv_memcmp(newInvUCA->UCAVersion, UCA->image->UCAVersion, sizeof(UVersionInfo)) != 0) {
- *status = U_INVALID_FORMAT_ERROR;
- udata_close(result);
- return NULL;
- }
+ invUCA_DATA_MEM = result;
+ _staticInvUCA = newInvUCA;
+ }
+}
- umtx_lock(NULL);
- if(_staticInvUCA == NULL) {
- invUCA_DATA_MEM = result;
- _staticInvUCA = newInvUCA;
- result = NULL;
- newInvUCA = NULL;
- }
- umtx_unlock(NULL);
- if(newInvUCA != NULL) {
- udata_close(result);
- // This is not needed, as we are talking about
- // memory we got from UData
- //uprv_free(newInvUCA);
- }
- else {
- ucln_i18n_registerCleanup(UCLN_I18N_UCOL_BLD, ucol_bld_cleanup);
- }
- }
- }
+U_CAPI const InverseUCATableHeader * U_EXPORT2
+ucol_initInverseUCA(UErrorCode *status)
+{
+ umtx_initOnce(gStaticInvUCAInitOnce, &initInverseUCA, *status);
return _staticInvUCA;
}
#include "putilimp.h"
#include "utracimp.h"
#include "cmemory.h"
+#include "uassert.h"
#include "uenumimp.h"
#include "ulist.h"
// static UCA. There is only one. Collators don't use it.
// It is referenced only in ucol_initUCA and ucol_cleanup
static UCollator* _staticUCA = NULL;
+static UInitOnce gStaticUCAInitOnce = U_INITONCE_INITIALIZER;
// static pointer to udata memory. Inited in ucol_initUCA
// used for cleanup in ucol_cleanup
static UDataMemory* UCA_DATA_MEM = NULL;
ucol_close(_staticUCA);
_staticUCA = NULL;
}
+ gStaticUCAInitOnce.reset();
return TRUE;
}
}
U_CDECL_END
-/* do not close UCA returned by ucol_initUCA! */
-UCollator *
-ucol_initUCA(UErrorCode *status) {
- if(U_FAILURE(*status)) {
- return NULL;
+static void U_CALLCONV ucol_initStaticUCA(UErrorCode &status) {
+ U_ASSERT(_staticUCA == NULL);
+ U_ASSERT(UCA_DATA_MEM == NULL);
+ ucln_i18n_registerCleanup(UCLN_I18N_UCOL_RES, ucol_res_cleanup);
+
+ UDataMemory *result = udata_openChoice(U_ICUDATA_COLL, UCA_DATA_TYPE, UCA_DATA_NAME, isAcceptableUCA, NULL, &status);
+ if(U_FAILURE(status)){
+ udata_close(result);
+ return;
}
- UBool needsInit;
- UMTX_CHECK(NULL, (_staticUCA == NULL), needsInit);
- if(needsInit) {
- UDataMemory *result = udata_openChoice(U_ICUDATA_COLL, UCA_DATA_TYPE, UCA_DATA_NAME, isAcceptableUCA, NULL, status);
+ _staticUCA = ucol_initCollator((const UCATableHeader *)udata_getMemory(result), NULL, NULL, &status);
+ if(U_SUCCESS(status)){
+ // Initalize variables for implicit generation
+ uprv_uca_initImplicitConstants(&status);
+ UCA_DATA_MEM = result;
- if(U_SUCCESS(*status)){
- UCollator *newUCA = ucol_initCollator((const UCATableHeader *)udata_getMemory(result), NULL, NULL, status);
- if(U_SUCCESS(*status)){
- // Initalize variables for implicit generation
- uprv_uca_initImplicitConstants(status);
+ }else{
+ ucol_close(_staticUCA);
+ _staticUCA = NULL;
+ udata_close(result);
+ }
+}
- umtx_lock(NULL);
- if(_staticUCA == NULL) {
- UCA_DATA_MEM = result;
- _staticUCA = newUCA;
- newUCA = NULL;
- result = NULL;
- }
- umtx_unlock(NULL);
- ucln_i18n_registerCleanup(UCLN_I18N_UCOL_RES, ucol_res_cleanup);
- if(newUCA != NULL) {
- ucol_close(newUCA);
- udata_close(result);
- }
- }else{
- ucol_close(newUCA);
- udata_close(result);
- }
- }
- else {
- udata_close(result);
- }
- }
+/* do not close UCA returned by ucol_initUCA! */
+UCollator *
+ucol_initUCA(UErrorCode *status) {
+ umtx_initOnce(gStaticUCAInitOnce, &ucol_initStaticUCA, *status);
return _staticUCA;
}
{
_staticUCA = NULL;
UCA_DATA_MEM = NULL;
+ gStaticUCAInitOnce.reset();
}
/****************************************************************************/
static const UChar EUR_STR[] = {0x0045,0x0055,0x0052,0};
// ISO codes mapping table
-static UHashtable* gIsoCodes = NULL;
-static UBool gIsoCodesInitialized = FALSE;
-
-static UMutex gIsoCodesLock = U_MUTEX_INITIALIZER;
+static const UHashtable* gIsoCodes = NULL;
+static UInitOnce gIsoCodesInitOnce = U_INITONCE_INITIALIZER;
//------------------------------------------------------------
// Code
isoCodes_cleanup(void)
{
if (gIsoCodes != NULL) {
- uhash_close(gIsoCodes);
+ uhash_close(const_cast<UHashtable *>(gIsoCodes));
gIsoCodes = NULL;
}
- gIsoCodesInitialized = FALSE;
-
+ gIsoCodesInitOnce.reset();
return TRUE;
}
// It is a simple round-robin replacement strategy.
static int8_t currentCacheEntryIndex = 0;
+static UMutex gCurrencyCacheMutex = U_MUTEX_INITIALIZER;
+
// Cache deletion
static void
deleteCurrencyNames(CurrencyNameStruct* currencyNames, int32_t count) {
CurrencyNameStruct* currencySymbols = NULL;
CurrencyNameCacheEntry* cacheEntry = NULL;
- umtx_lock(NULL);
+ umtx_lock(&gCurrencyCacheMutex);
// in order to handle racing correctly,
- // not putting 'search' in a separate function and using UMTX.
+ // not putting 'search' in a separate function.
int8_t found = -1;
for (int8_t i = 0; i < CURRENCY_NAME_CACHE_NUM; ++i) {
if (currCache[i]!= NULL &&
total_currency_symbol_count = cacheEntry->totalCurrencySymbolCount;
++(cacheEntry->refCount);
}
- umtx_unlock(NULL);
+ umtx_unlock(&gCurrencyCacheMutex);
if (found == -1) {
collectCurrencyNames(locale, ¤cyNames, &total_currency_name_count, ¤cySymbols, &total_currency_symbol_count, ec);
if (U_FAILURE(ec)) {
return;
}
- umtx_lock(NULL);
+ umtx_lock(&gCurrencyCacheMutex);
// check again.
int8_t found = -1;
for (int8_t i = 0; i < CURRENCY_NAME_CACHE_NUM; ++i) {
total_currency_symbol_count = cacheEntry->totalCurrencySymbolCount;
++(cacheEntry->refCount);
}
- umtx_unlock(NULL);
+ umtx_unlock(&gCurrencyCacheMutex);
}
int32_t start = pos.getIndex();
}
// decrease reference count
- umtx_lock(NULL);
+ umtx_lock(&gCurrencyCacheMutex);
--(cacheEntry->refCount);
if (cacheEntry->refCount == 0) { // remove
deleteCacheEntry(cacheEntry);
}
- umtx_unlock(NULL);
+ umtx_unlock(&gCurrencyCacheMutex);
}
}
static void U_CALLCONV
-ucurr_createCurrencyList(UErrorCode* status){
+ucurr_createCurrencyList(UHashtable *isoCodes, UErrorCode* status){
UErrorCode localStatus = U_ZERO_ERROR;
// Look up the CurrencyMap element in the root bundle.
entry->to = toDate;
localStatus = U_ZERO_ERROR;
- uhash_put(gIsoCodes, (UChar *)isoCode, entry, &localStatus);
+ uhash_put(isoCodes, (UChar *)isoCode, entry, &localStatus);
}
} else {
*status = localStatus;
};
U_CDECL_END
-U_CAPI UBool U_EXPORT2
-ucurr_isAvailable(const UChar* isoCode, UDate from, UDate to, UErrorCode* eErrorCode) {
- UErrorCode status = U_ZERO_ERROR;
- UBool initialized;
- UMTX_CHECK(&gIsoCodesLock, gIsoCodesInitialized, initialized);
-
- if (!initialized) {
- umtx_lock(&gIsoCodesLock);
- gIsoCodes = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status);
- if (U_FAILURE(status)) {
- umtx_unlock(&gIsoCodesLock);
- return FALSE;
- }
- uhash_setValueDeleter(gIsoCodes, deleteIsoCodeEntry);
- ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cleanup);
- ucurr_createCurrencyList(&status);
- if (U_FAILURE(status)) {
- umtx_unlock(&gIsoCodesLock);
- return FALSE;
- }
+static void U_CALLCONV initIsoCodes(UErrorCode &status) {
+ U_ASSERT(gIsoCodes == NULL);
+ ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cleanup);
- gIsoCodesInitialized = TRUE;
- umtx_unlock(&gIsoCodesLock);
+ UHashtable *isoCodes = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status);
+ if (U_FAILURE(status)) {
+ return;
}
+ uhash_setValueDeleter(isoCodes, deleteIsoCodeEntry);
- umtx_lock(&gIsoCodesLock);
- IsoCodeEntry* result = (IsoCodeEntry *) uhash_get(gIsoCodes, isoCode);
- umtx_unlock(&gIsoCodesLock);
+ ucurr_createCurrencyList(isoCodes, &status);
+ if (U_FAILURE(status)) {
+ uhash_close(isoCodes);
+ return;
+ }
+ gIsoCodes = isoCodes; // Note: gIsoCodes is const. Once set up here it is never altered,
+ // and read only access is safe without synchronization.
+}
+
+U_CAPI UBool U_EXPORT2
+ucurr_isAvailable(const UChar* isoCode, UDate from, UDate to, UErrorCode* eErrorCode) {
+ umtx_initOnce(gIsoCodesInitOnce, &initIsoCodes, *eErrorCode);
+ if (U_FAILURE(*eErrorCode)) {
+ return FALSE;
+ }
+
+ IsoCodeEntry* result = (IsoCodeEntry *) uhash_get(gIsoCodes, isoCode);
if (result == NULL) {
return FALSE;
} else if (from > to) {
} else if ((from > result->to) || (to < result->from)) {
return FALSE;
}
-
return TRUE;
}
class Hashtable;
class UnicodeSet;
class FieldPositionHandler;
+class DecimalFormatStaticSets;
// explicit template instantiation. see digitlst.h
#if defined (_MSC_VER)
int32_t precision() const;
/**
- * Initialize all fields of a new DecimalFormatter.
+ * Initialize all fields of a new DecimalFormatter to a safe default value.
* Common code for use by constructors.
*/
- void init(UErrorCode& status);
+ void init();
/**
* Do real work of constructing a new DecimalFormat.
*/
- void construct(UErrorCode& status,
+ void construct(UErrorCode& status,
UParseError& parseErr,
const UnicodeString* pattern = 0,
DecimalFormatSymbols* symbolsToAdopt = 0
UNumberFormatAttributeValue fParseAllInput;
#endif
+ // Decimal Format Static Sets singleton.
+ const DecimalFormatStaticSets *fStaticSets;
+
protected:
U_NAMESPACE_BEGIN
+// Forward Declaration
+void GenderInfo_initCache(UErrorCode &status);
+
/**
* GenderInfo computes the gender of a list as a whole given the gender of
* each element.
static const GenderInfo* getMaleTaintsInstance();
static const GenderInfo* loadInstance(const Locale& locale, UErrorCode& status);
+
friend class ::GenderInfoTest;
+ friend void GenderInfo_initCache(UErrorCode &status);
};
U_NAMESPACE_END
* @return the beginning year of the default century
*/
virtual int32_t defaultCenturyStartYear() const;
-
- private:
- /**
- * The system maintains a static default century start date. This is initialized
- * the first time it is used. Before then, it is set to SYSTEM_DEFAULT_CENTURY to
- * indicate an uninitialized state. Once the system default century date and year
- * are set, they do not change.
- */
- static UDate fgSystemDefaultCenturyStart;
-
- /**
- * See documentation for systemDefaultCenturyStart.
- */
- static int32_t fgSystemDefaultCenturyStartYear;
-
- /**
- * Default value that indicates the defaultCenturyStartYear is unitialized
- */
- static const int32_t fgSystemDefaultCenturyYear;
-
- /**
- * Default value that indicates the UDate of the beginning of the system default century
- */
- static const UDate fgSystemDefaultCentury;
-
- /**
- * Returns the beginning date of the 100-year window that dates with 2-digit years
- * are considered to fall within.
- * @return the beginning date of the 100-year window that dates with 2-digit years
- * are considered to fall within.
- */
- UDate internalGetDefaultCenturyStart(void) const;
-
- /**
- * Returns the first year of the 100-year window that dates with 2-digit years
- * are considered to fall within.
- * @return the first year of the 100-year window that dates with 2-digit years
- * are considered to fall within.
- */
- int32_t internalGetDefaultCenturyStartYear(void) const;
-
- /**
- * Initializes the 100-year window that dates with 2-digit years are considered
- * to fall within so that its start date is 80 years before the current time.
- */
- static void initializeSystemDefaultCentury(void);
-
};
U_NAMESPACE_END
* Sets the default time zone (i.e., what's returned by createDefault()) to be the
* specified time zone. If NULL is specified for the time zone, the default time
* zone is set to the default host time zone. This call adopts the TimeZone object
- * passed in; the clent is no longer responsible for deleting it.
+ * passed in; the client is no longer responsible for deleting it.
+ *
+ * <p>This function is not thread safe. It is an error for multiple threads
+ * to concurrently attempt to set the default time zone, or for any thread
+ * to attempt to reference the default zone while another thread is setting it.
*
* @param zone A pointer to the new TimeZone object to use as the default.
* @stable ICU 2.0
* Same as adoptDefault(), except that the TimeZone object passed in is NOT adopted;
* the caller remains responsible for deleting it.
*
+ * <p>See the thread safety note under adoptDefault().
+ *
* @param zone The given timezone.
* @system
* @stable ICU 2.0
*/
static const UChar* getRegion(const UnicodeString& id);
+ public:
/**
* Returns the region code associated with the given zone,
* or NULL if the zone is not known.
* @param id zone id string
* @param status Status parameter
* @return the region associated with the given zone
+ * @internal
*/
static const UChar* getRegion(const UnicodeString& id, UErrorCode& status);
+ private:
/**
* Parses the given custom time zone identifier
* @param id id A string of the form GMT[+-]hh:mm, GMT[+-]hhmm, or
static UnicodeString& formatCustomID(int32_t hour, int32_t min, int32_t sec,
UBool negative, UnicodeString& id);
- /**
- * Responsible for setting up DEFAULT_ZONE. Uses routines in TPlatformUtilities
- * (i.e., platform-specific calls) to get the current system time zone. Failing
- * that, uses the platform-specific default time zone. Failing that, uses GMT.
- */
- static void initDefault(void);
-
- // See source file for documentation
- /**
- * Lookup the given name in our system zone table. If found,
- * instantiate a new zone of that name and return it. If not
- * found, return 0.
- * @param name tthe given name of a system time zone.
- * @return the TimeZone indicated by the 'name'.
- */
- static TimeZone* createSystemTimeZone(const UnicodeString& name);
- static TimeZone* createSystemTimeZone(const UnicodeString& name, UErrorCode& ec);
-
UnicodeString fID; // this time zone's ID
friend class TZEnumeration;
/*
*******************************************************************************
-* Copyright (C) 2004-2012, International Business Machines
+* Copyright (C) 2004-2013, International Business Machines
* Corporation and others. All Rights Reserved.
*******************************************************************************
-* file name: regex.cpp
+* file name: uregex.cpp
*/
#include "unicode/utypes.h"
~RegularExpression();
int32_t fMagic;
RegexPattern *fPat;
- int32_t *fPatRefCount;
+ atomic_int32_t *fPatRefCount;
UChar *fPatString;
int32_t fPatStringLen;
RegexMatcher *fMatcher;
if (fPatRefCount!=NULL && umtx_atomic_dec(fPatRefCount)==0) {
delete fPat;
uprv_free(fPatString);
- uprv_free(fPatRefCount);
+ uprv_free((void *)fPatRefCount);
}
if (fOwnsText && fText!=NULL) {
uprv_free((void *)fText);
actualPatLen = u_strlen(pattern);
}
- RegularExpression *re = new RegularExpression;
- int32_t *refC = (int32_t *)uprv_malloc(sizeof(int32_t));
+ RegularExpression *re = new RegularExpression;
+ atomic_int32_t *refC = (atomic_int32_t *)uprv_malloc(sizeof(int32_t));
UChar *patBuf = (UChar *)uprv_malloc(sizeof(UChar)*(actualPatLen+1));
if (re == NULL || refC == NULL || patBuf == NULL) {
*status = U_MEMORY_ALLOCATION_ERROR;
delete re;
- uprv_free(refC);
+ uprv_free((void *)refC);
uprv_free(patBuf);
return NULL;
}
UErrorCode lengthStatus = U_ZERO_ERROR;
int32_t pattern16Length = utext_extract(pattern, 0, patternNativeLength, NULL, 0, &lengthStatus);
- int32_t *refC = (int32_t *)uprv_malloc(sizeof(int32_t));
+ atomic_int32_t *refC = (atomic_int32_t *)uprv_malloc(sizeof(int32_t));
UChar *patBuf = (UChar *)uprv_malloc(sizeof(UChar)*(pattern16Length+1));
if (re == NULL || refC == NULL || patBuf == NULL) {
*status = U_MEMORY_ALLOCATION_ERROR;
delete re;
- uprv_free(refC);
+ uprv_free((void *)refC);
uprv_free(patBuf);
return NULL;
}
// we are done.
uint32_t fMemLimit; // Limit of available raw data space
- int32_t fRefCount;
+ atomic_int32_t fRefCount;
// Confusable data
int32_t *fCFUKeys;
// CLDR Canonical ID mapping table
static UHashtable *gCanonicalIDCache = NULL;
-static UBool gCanonicalIDCacheInitialized = FALSE;
+static UInitOnce gCanonicalIDCacheInitOnce = U_INITONCE_INITIALIZER;
// Metazone mapping table
static UHashtable *gOlsonToMeta = NULL;
-static UBool gOlsonToMetaInitialized = FALSE;
+static UInitOnce gOlsonToMetaInitOnce = U_INITONCE_INITIALIZER;
// Available metazone IDs vector and table
static icu::UVector *gMetaZoneIDs = NULL;
static UHashtable *gMetaZoneIDTable = NULL;
-static UBool gMetaZoneIDsInitialized = FALSE;
+static UInitOnce gMetaZoneIDsInitOnce = U_INITONCE_INITIALIZER;
// Country info vectors
static icu::UVector *gSingleZoneCountries = NULL;
static icu::UVector *gMultiZonesCountries = NULL;
-static UBool gCountryInfoVectorsInitialized = FALSE;
+static UInitOnce gCountryInfoVectorsInitOnce = U_INITONCE_INITIALIZER;
U_CDECL_BEGIN
uhash_close(gCanonicalIDCache);
gCanonicalIDCache = NULL;
}
- gCanonicalIDCacheInitialized = FALSE;
+ gCanonicalIDCacheInitOnce.reset();
if (gOlsonToMeta != NULL) {
uhash_close(gOlsonToMeta);
gOlsonToMeta = NULL;
}
- gOlsonToMetaInitialized = FALSE;
+ gOlsonToMetaInitOnce.reset();
if (gMetaZoneIDTable != NULL) {
uhash_close(gMetaZoneIDTable);
+ gMetaZoneIDTable = NULL;
}
// delete after closing gMetaZoneIDTable, because it holds
// value objects held by the hashtable
delete gMetaZoneIDs;
- gMetaZoneIDsInitialized = FALSE;
+ gMetaZoneIDs = NULL;
+ gMetaZoneIDsInitOnce.reset();
delete gSingleZoneCountries;
+ gSingleZoneCountries = NULL;
delete gMultiZonesCountries;
- gCountryInfoVectorsInitialized = FALSE;
+ gMultiZonesCountries = NULL;
+ gCountryInfoVectorsInitOnce.reset();
return TRUE;
}
return 0;
}
+static void U_CALLCONV initCanonicalIDCache(UErrorCode &status) {
+ gCanonicalIDCache = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status);
+ if (gCanonicalIDCache == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ if (U_FAILURE(status)) {
+ gCanonicalIDCache = NULL;
+ }
+ // No key/value deleters - keys/values are from a resource bundle
+ ucln_i18n_registerCleanup(UCLN_I18N_ZONEMETA, zoneMeta_cleanup);
+}
+
+
const UChar* U_EXPORT2
ZoneMeta::getCanonicalCLDRID(const UnicodeString &tzid, UErrorCode& status) {
if (U_FAILURE(status)) {
}
// Checking the cached results
- UBool initialized;
- UMTX_CHECK(&gZoneMetaLock, gCanonicalIDCacheInitialized, initialized);
- if (!initialized) {
- // Create empty hashtable
- umtx_lock(&gZoneMetaLock);
- {
- if (!gCanonicalIDCacheInitialized) {
- gCanonicalIDCache = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status);
- if (gCanonicalIDCache == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- }
- if (U_FAILURE(status)) {
- gCanonicalIDCache = NULL;
- return NULL;
- }
- // No key/value deleters - keys/values are from a resource bundle
- gCanonicalIDCacheInitialized = TRUE;
- ucln_i18n_registerCleanup(UCLN_I18N_ZONEMETA, zoneMeta_cleanup);
- }
- }
- umtx_unlock(&gZoneMetaLock);
+ umtx_initOnce(gCanonicalIDCacheInitOnce, &initCanonicalIDCache, status);
+ if (U_FAILURE(status)) {
+ return NULL;
}
const UChar *canonicalID = NULL;
return getCanonicalCLDRID(tz.getID(tzID), status);
}
+static void U_CALLCONV countryInfoVectorsInit(UErrorCode &status) {
+ // Create empty vectors
+ // No deleters for these UVectors, it's a reference to a resource bundle string.
+ gSingleZoneCountries = new UVector(NULL, uhash_compareUChars, status);
+ if (gSingleZoneCountries == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ gMultiZonesCountries = new UVector(NULL, uhash_compareUChars, status);
+ if (gMultiZonesCountries == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+
+ if (U_FAILURE(status)) {
+ delete gSingleZoneCountries;
+ delete gMultiZonesCountries;
+ gSingleZoneCountries = NULL;
+ gMultiZonesCountries = NULL;
+ }
+ ucln_i18n_registerCleanup(UCLN_I18N_ZONEMETA, zoneMeta_cleanup);
+}
+
+
UnicodeString& U_EXPORT2
ZoneMeta::getCanonicalCountry(const UnicodeString &tzid, UnicodeString &country, UBool *isPrimary /* = NULL */) {
if (isPrimary != NULL) {
// Checking the cached results
UErrorCode status = U_ZERO_ERROR;
- UBool initialized;
- UMTX_CHECK(&gZoneMetaLock, gCountryInfoVectorsInitialized, initialized);
- if (!initialized) {
- // Create empty vectors
- umtx_lock(&gZoneMetaLock);
- {
- if (!gCountryInfoVectorsInitialized) {
- // No deleters for these UVectors, it's a reference to a resource bundle string.
- gSingleZoneCountries = new UVector(NULL, uhash_compareUChars, status);
- if (gSingleZoneCountries == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- }
- gMultiZonesCountries = new UVector(NULL, uhash_compareUChars, status);
- if (gMultiZonesCountries == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- }
-
- if (U_SUCCESS(status)) {
- gCountryInfoVectorsInitialized = TRUE;
- ucln_i18n_registerCleanup(UCLN_I18N_ZONEMETA, zoneMeta_cleanup);
- } else {
- delete gSingleZoneCountries;
- delete gMultiZonesCountries;
- }
- }
- }
- umtx_unlock(&gZoneMetaLock);
-
- if (U_FAILURE(status)) {
- return country;
- }
- U_ASSERT(gSingleZoneCountries != NULL);
- U_ASSERT(gMultiZonesCountries != NULL);
+ umtx_initOnce(gCountryInfoVectorsInitOnce, &countryInfoVectorsInit, status);
+ if (U_FAILURE(status)) {
+ return country;
}
// Check if it was already cached
return result;
}
+static void U_CALLCONV olsonToMetaInit(UErrorCode &status) {
+ U_ASSERT(gOlsonToMeta == NULL);
+ ucln_i18n_registerCleanup(UCLN_I18N_ZONEMETA, zoneMeta_cleanup);
+ gOlsonToMeta = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status);
+ if (U_FAILURE(status)) {
+ gOlsonToMeta = NULL;
+ } else {
+ uhash_setKeyDeleter(gOlsonToMeta, deleteUCharString);
+ uhash_setValueDeleter(gOlsonToMeta, deleteUVector);
+ }
+}
+
+
const UVector* U_EXPORT2
ZoneMeta::getMetazoneMappings(const UnicodeString &tzid) {
UErrorCode status = U_ZERO_ERROR;
return NULL;
}
- UBool initialized;
- UMTX_CHECK(&gZoneMetaLock, gOlsonToMetaInitialized, initialized);
- if (!initialized) {
- UHashtable *tmpOlsonToMeta = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status);
- if (U_FAILURE(status)) {
- return NULL;
- }
- uhash_setKeyDeleter(tmpOlsonToMeta, deleteUCharString);
- uhash_setValueDeleter(tmpOlsonToMeta, deleteUVector);
-
- umtx_lock(&gZoneMetaLock);
- {
- if (!gOlsonToMetaInitialized) {
- gOlsonToMeta = tmpOlsonToMeta;
- tmpOlsonToMeta = NULL;
- gOlsonToMetaInitialized = TRUE;
- }
- }
- umtx_unlock(&gZoneMetaLock);
-
- // OK to call the following multiple times with the same function
- ucln_i18n_registerCleanup(UCLN_I18N_ZONEMETA, zoneMeta_cleanup);
- if (tmpOlsonToMeta != NULL) {
- uhash_close(tmpOlsonToMeta);
- }
+ umtx_initOnce(gOlsonToMetaInitOnce, &olsonToMetaInit, status);
+ if (U_FAILURE(status)) {
+ return NULL;
}
// get the mapping from cache
return result;
}
-void
-ZoneMeta::initAvailableMetaZoneIDs () {
- UBool initialized;
- UMTX_CHECK(&gZoneMetaLock, gMetaZoneIDsInitialized, initialized);
- if (!initialized) {
- umtx_lock(&gZoneMetaLock);
- {
- if (!gMetaZoneIDsInitialized) {
- UErrorCode status = U_ZERO_ERROR;
- UHashtable *metaZoneIDTable = uhash_open(uhash_hashUnicodeString, uhash_compareUnicodeString, NULL, &status);
- uhash_setKeyDeleter(metaZoneIDTable, uprv_deleteUObject);
- // No valueDeleter, because the vector maintain the value objects
- UVector *metaZoneIDs = NULL;
- if (U_SUCCESS(status)) {
- metaZoneIDs = new UVector(NULL, uhash_compareUChars, status);
- if (metaZoneIDs == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- }
- } else {
- uhash_close(metaZoneIDTable);
- }
- if (U_SUCCESS(status)) {
- U_ASSERT(metaZoneIDs != NULL);
- metaZoneIDs->setDeleter(uprv_free);
-
- UResourceBundle *rb = ures_openDirect(NULL, gMetaZones, &status);
- UResourceBundle *bundle = ures_getByKey(rb, gMapTimezonesTag, NULL, &status);
- UResourceBundle res;
- ures_initStackObject(&res);
- while (U_SUCCESS(status) && ures_hasNext(bundle)) {
- ures_getNextResource(bundle, &res, &status);
- if (U_FAILURE(status)) {
- break;
- }
- const char *mzID = ures_getKey(&res);
- int32_t len = uprv_strlen(mzID);
- UChar *uMzID = (UChar*)uprv_malloc(sizeof(UChar) * (len + 1));
- if (uMzID == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- break;
- }
- u_charsToUChars(mzID, uMzID, len);
- uMzID[len] = 0;
- UnicodeString *usMzID = new UnicodeString(uMzID);
- if (uhash_get(metaZoneIDTable, usMzID) == NULL) {
- metaZoneIDs->addElement((void *)uMzID, status);
- uhash_put(metaZoneIDTable, (void *)usMzID, (void *)uMzID, &status);
- } else {
- uprv_free(uMzID);
- delete usMzID;
- }
- }
- if (U_SUCCESS(status)) {
- gMetaZoneIDs = metaZoneIDs;
- gMetaZoneIDTable = metaZoneIDTable;
- gMetaZoneIDsInitialized = TRUE;
- ucln_i18n_registerCleanup(UCLN_I18N_ZONEMETA, zoneMeta_cleanup);
- } else {
- uhash_close(metaZoneIDTable);
- delete metaZoneIDs;
- }
- ures_close(&res);
- ures_close(bundle);
- ures_close(rb);
- }
- }
+static void U_CALLCONV initAvailableMetaZoneIDs () {
+ U_ASSERT(gMetaZoneIDs == NULL);
+ U_ASSERT(gMetaZoneIDTable == NULL);
+ ucln_i18n_registerCleanup(UCLN_I18N_ZONEMETA, zoneMeta_cleanup);
+
+ UErrorCode status = U_ZERO_ERROR;
+ gMetaZoneIDTable = uhash_open(uhash_hashUnicodeString, uhash_compareUnicodeString, NULL, &status);
+ if (U_FAILURE(status) || gMetaZoneIDTable == NULL) {
+ gMetaZoneIDTable = NULL;
+ return;
+ }
+ uhash_setKeyDeleter(gMetaZoneIDTable, uprv_deleteUObject);
+ // No valueDeleter, because the vector maintain the value objects
+ gMetaZoneIDs = new UVector(NULL, uhash_compareUChars, status);
+ if (U_FAILURE(status) || gMetaZoneIDs == NULL) {
+ gMetaZoneIDs = NULL;
+ uhash_close(gMetaZoneIDTable);
+ gMetaZoneIDTable = NULL;
+ return;
+ }
+ gMetaZoneIDs->setDeleter(uprv_free);
+
+ UResourceBundle *rb = ures_openDirect(NULL, gMetaZones, &status);
+ UResourceBundle *bundle = ures_getByKey(rb, gMapTimezonesTag, NULL, &status);
+ UResourceBundle res;
+ ures_initStackObject(&res);
+ while (U_SUCCESS(status) && ures_hasNext(bundle)) {
+ ures_getNextResource(bundle, &res, &status);
+ if (U_FAILURE(status)) {
+ break;
}
- umtx_unlock(&gZoneMetaLock);
+ const char *mzID = ures_getKey(&res);
+ int32_t len = uprv_strlen(mzID);
+ UChar *uMzID = (UChar*)uprv_malloc(sizeof(UChar) * (len + 1));
+ if (uMzID == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ break;
+ }
+ u_charsToUChars(mzID, uMzID, len);
+ uMzID[len] = 0;
+ UnicodeString *usMzID = new UnicodeString(uMzID);
+ if (uhash_get(gMetaZoneIDTable, usMzID) == NULL) {
+ gMetaZoneIDs->addElement((void *)uMzID, status);
+ uhash_put(gMetaZoneIDTable, (void *)usMzID, (void *)uMzID, &status);
+ } else {
+ uprv_free(uMzID);
+ delete usMzID;
+ }
+ }
+ ures_close(&res);
+ ures_close(bundle);
+ ures_close(rb);
+
+ if (U_FAILURE(status)) {
+ uhash_close(gMetaZoneIDTable);
+ delete gMetaZoneIDs;
+ gMetaZoneIDTable = NULL;
+ gMetaZoneIDs = NULL;
}
}
const UVector*
ZoneMeta::getAvailableMetazoneIDs() {
- initAvailableMetaZoneIDs();
+ umtx_initOnce(gMetaZoneIDsInitOnce, &initAvailableMetaZoneIDs);
return gMetaZoneIDs;
}
const UChar*
ZoneMeta::findMetaZoneID(const UnicodeString& mzid) {
- initAvailableMetaZoneIDs();
+ umtx_initOnce(gMetaZoneIDsInitOnce, &initAvailableMetaZoneIDs);
+ if (gMetaZoneIDTable == NULL) {
+ return NULL;
+ }
return (const UChar*)uhash_get(gMetaZoneIDTable, &mzid);
}
private:
ZoneMeta(); // Prevent construction.
static UVector* createMetazoneMappings(const UnicodeString &tzid);
- static void initAvailableMetaZoneIDs();
static UnicodeString& formatCustomID(uint8_t hour, uint8_t min, uint8_t sec, UBool negative, UnicodeString& id);
static const UChar* getShortIDFromCanonical(const UChar* canonicalID);
};