| Index: source/i18n/region.cpp
|
| diff --git a/source/i18n/region.cpp b/source/i18n/region.cpp
|
| index 23d33b5bfe46149c3160014a2125b72c61ca7886..21123a16322845b84d5f1a8248727ff4571d8fbd 100644
|
| --- a/source/i18n/region.cpp
|
| +++ b/source/i18n/region.cpp
|
| @@ -1,6 +1,6 @@
|
| /*
|
| *******************************************************************************
|
| -* Copyright (C) 2013, International Business Machines Corporation and
|
| +* Copyright (C) 2014, International Business Machines Corporation and
|
| * others. All Rights Reserved.
|
| *******************************************************************************
|
| *
|
| @@ -26,6 +26,7 @@
|
| #include "unicode/decimfmt.h"
|
| #include "ucln_in.h"
|
| #include "cstring.h"
|
| +#include "mutex.h"
|
| #include "uhash.h"
|
| #include "umutex.h"
|
| #include "uresimp.h"
|
| @@ -55,8 +56,7 @@ U_CDECL_END
|
|
|
| U_NAMESPACE_BEGIN
|
|
|
| -static UMutex gRegionDataLock = U_MUTEX_INITIALIZER;
|
| -static UBool regionDataIsLoaded = false;
|
| +static UInitOnce gRegionDataInitOnce = U_INITONCE_INITIALIZER;
|
| static UVector* availableRegions[URGN_LIMIT];
|
|
|
| static UHashtable *regionAliases;
|
| @@ -77,70 +77,65 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RegionNameEnumeration)
|
| * If the region data has already loaded, then this method simply returns without doing
|
| * anything meaningful.
|
| */
|
| -void Region::loadRegionData() {
|
| -
|
| - if (regionDataIsLoaded) {
|
| +void Region::loadRegionData(UErrorCode &status) {
|
| + LocalPointer<DecimalFormat> df(new DecimalFormat(status));
|
| + if (U_FAILURE(status)) {
|
| return;
|
| }
|
| -
|
| - umtx_lock(&gRegionDataLock);
|
| -
|
| - if (regionDataIsLoaded) { // In case another thread gets to it before we do...
|
| - umtx_unlock(&gRegionDataLock);
|
| + if (df == NULL) {
|
| + status = U_MEMORY_ALLOCATION_ERROR;
|
| return;
|
| }
|
| + df->setParseIntegerOnly(TRUE);
|
|
|
| -
|
| - UErrorCode status = U_ZERO_ERROR;
|
| -
|
| - UResourceBundle* regionCodes = NULL;
|
| - UResourceBundle* territoryAlias = NULL;
|
| - UResourceBundle* codeMappings = NULL;
|
| - UResourceBundle* worldContainment = NULL;
|
| - UResourceBundle* territoryContainment = NULL;
|
| - UResourceBundle* groupingContainment = NULL;
|
| -
|
| - DecimalFormat *df = new DecimalFormat(status);
|
| + regionIDMap = uhash_open(uhash_hashUnicodeString, uhash_compareUnicodeString, NULL, &status);
|
| if (U_FAILURE(status)) {
|
| - umtx_unlock(&gRegionDataLock);
|
| return;
|
| }
|
| - df->setParseIntegerOnly(TRUE);
|
| -
|
| - regionIDMap = uhash_open(uhash_hashUnicodeString,uhash_compareUnicodeString,NULL,&status);
|
| + if (regionIDMap == NULL) {
|
| + status = U_MEMORY_ALLOCATION_ERROR;
|
| + return;
|
| + }
|
| uhash_setValueDeleter(regionIDMap, deleteRegion);
|
|
|
| numericCodeMap = uhash_open(uhash_hashLong,uhash_compareLong,NULL,&status);
|
|
|
| regionAliases = uhash_open(uhash_hashUnicodeString,uhash_compareUnicodeString,NULL,&status);
|
| + if (U_FAILURE(status)) {
|
| + return;
|
| + }
|
| + if (regionAliases == NULL) {
|
| + status = U_MEMORY_ALLOCATION_ERROR;
|
| + return;
|
| + }
|
| uhash_setKeyDeleter(regionAliases,uprv_deleteUObject);
|
|
|
| - UResourceBundle *rb = ures_openDirect(NULL,"metadata",&status);
|
| - regionCodes = ures_getByKey(rb,"regionCodes",NULL,&status);
|
| - territoryAlias = ures_getByKey(rb,"territoryAlias",NULL,&status);
|
| + LocalUResourceBundlePointer rb(ures_openDirect(NULL,"metadata",&status));
|
| + LocalUResourceBundlePointer regionCodes(ures_getByKey(rb.getAlias(),"regionCodes",NULL,&status));
|
| + LocalUResourceBundlePointer territoryAlias(ures_getByKey(rb.getAlias(),"territoryAlias",NULL,&status));
|
|
|
| - UResourceBundle *rb2 = ures_openDirect(NULL,"supplementalData",&status);
|
| - codeMappings = ures_getByKey(rb2,"codeMappings",NULL,&status);
|
| + LocalUResourceBundlePointer rb2(ures_openDirect(NULL,"supplementalData",&status));
|
| + LocalUResourceBundlePointer codeMappings(ures_getByKey(rb2.getAlias(),"codeMappings",NULL,&status));
|
|
|
| - territoryContainment = ures_getByKey(rb2,"territoryContainment",NULL,&status);
|
| - worldContainment = ures_getByKey(territoryContainment,"001",NULL,&status);
|
| - groupingContainment = ures_getByKey(territoryContainment,"grouping",NULL,&status);
|
| + LocalUResourceBundlePointer territoryContainment(ures_getByKey(rb2.getAlias(),"territoryContainment",NULL,&status));
|
| + LocalUResourceBundlePointer worldContainment(ures_getByKey(territoryContainment.getAlias(),"001",NULL,&status));
|
| + LocalUResourceBundlePointer groupingContainment(ures_getByKey(territoryContainment.getAlias(),"grouping",NULL,&status));
|
|
|
| UVector *continents = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status);
|
|
|
| - while ( ures_hasNext(worldContainment) ) {
|
| - UnicodeString *continentName = new UnicodeString(ures_getNextUnicodeString(worldContainment,NULL,&status));
|
| + while ( ures_hasNext(worldContainment.getAlias()) ) {
|
| + UnicodeString *continentName = new UnicodeString(ures_getNextUnicodeString(worldContainment.getAlias(),NULL,&status));
|
| continents->addElement(continentName,status);
|
| }
|
|
|
| UVector *groupings = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status);
|
| - while ( ures_hasNext(groupingContainment) ) {
|
| - UnicodeString *groupingName = new UnicodeString(ures_getNextUnicodeString(groupingContainment,NULL,&status));
|
| + while ( ures_hasNext(groupingContainment.getAlias()) ) {
|
| + UnicodeString *groupingName = new UnicodeString(ures_getNextUnicodeString(groupingContainment.getAlias(),NULL,&status));
|
| groupings->addElement(groupingName,status);
|
| }
|
|
|
| - while ( ures_hasNext(regionCodes) ) {
|
| - UnicodeString regionID = ures_getNextUnicodeString(regionCodes,NULL,&status);
|
| + while ( ures_hasNext(regionCodes.getAlias()) ) {
|
| + UnicodeString regionID = ures_getNextUnicodeString(regionCodes.getAlias(), NULL, &status);
|
| Region *r = new Region();
|
| r->idStr = regionID;
|
| r->idStr.extract(0,r->idStr.length(),r->id,sizeof(r->id),US_INV);
|
| @@ -161,8 +156,8 @@ void Region::loadRegionData() {
|
|
|
|
|
| // Process the territory aliases
|
| - while ( ures_hasNext(territoryAlias) ) {
|
| - UResourceBundle *res = ures_getNextResource(territoryAlias,NULL,&status);
|
| + while ( ures_hasNext(territoryAlias.getAlias()) ) {
|
| + UResourceBundle *res = ures_getNextResource(territoryAlias.getAlias(),NULL,&status);
|
| const char *aliasFrom = ures_getKey(res);
|
| UnicodeString* aliasFromStr = new UnicodeString(aliasFrom, -1, US_INV);
|
| UnicodeString aliasTo = ures_getUnicodeString(res,&status);
|
| @@ -214,8 +209,8 @@ void Region::loadRegionData() {
|
| }
|
|
|
| // Process the code mappings - This will allow us to assign numeric codes to most of the territories.
|
| - while ( ures_hasNext(codeMappings) ) {
|
| - UResourceBundle *mapping = ures_getNextResource(codeMappings,NULL,&status);
|
| + while ( ures_hasNext(codeMappings.getAlias()) ) {
|
| + UResourceBundle *mapping = ures_getNextResource(codeMappings.getAlias(),NULL,&status);
|
| if ( ures_getType(mapping) == URES_ARRAY && ures_getSize(mapping) == 3) {
|
| UnicodeString codeMappingID = ures_getUnicodeStringByIndex(mapping,0,&status);
|
| UnicodeString codeMappingNumber = ures_getUnicodeStringByIndex(mapping,1,&status);
|
| @@ -277,9 +272,14 @@ void Region::loadRegionData() {
|
| }
|
|
|
| // Load territory containment info from the supplemental data.
|
| - while ( ures_hasNext(territoryContainment) ) {
|
| - UResourceBundle *mapping = ures_getNextResource(territoryContainment,NULL,&status);
|
| + while ( ures_hasNext(territoryContainment.getAlias()) ) {
|
| + UResourceBundle *mapping = ures_getNextResource(territoryContainment.getAlias(),NULL,&status);
|
| const char *parent = ures_getKey(mapping);
|
| + if (uprv_strcmp(parent, "containedGroupings") == 0 || uprv_strcmp(parent, "deprecated") == 0) {
|
| + ures_close(mapping);
|
| + continue; // handle new pseudo-parent types added in ICU data per cldrbug 7808; for now just skip.
|
| + // #11232 is to do something useful with these.
|
| + }
|
| UnicodeString parentStr = UnicodeString(parent, -1 , US_INV);
|
| Region *parentRegion = (Region *) uhash_get(regionIDMap,(void *)&parentStr);
|
|
|
| @@ -319,27 +319,10 @@ void Region::loadRegionData() {
|
| availableRegions[ar->type]->addElement((void *)arString,status);
|
| }
|
|
|
| - ures_close(territoryContainment);
|
| - ures_close(worldContainment);
|
| - ures_close(groupingContainment);
|
| -
|
| - ures_close(codeMappings);
|
| - ures_close(rb2);
|
| - ures_close(territoryAlias);
|
| - ures_close(regionCodes);
|
| - ures_close(rb);
|
| -
|
| - delete df;
|
| -
|
| ucln_i18n_registerCleanup(UCLN_I18N_REGION, region_cleanup);
|
| -
|
| - regionDataIsLoaded = true;
|
| - umtx_unlock(&gRegionDataLock);
|
| -
|
| }
|
|
|
| void Region::cleanupRegionData() {
|
| -
|
| for (int32_t i = 0 ; i < URGN_LIMIT ; i++ ) {
|
| if ( availableRegions[i] ) {
|
| delete availableRegions[i];
|
| @@ -357,6 +340,7 @@ void Region::cleanupRegionData() {
|
| if (regionIDMap) {
|
| uhash_close(regionIDMap);
|
| }
|
| + gRegionDataInitOnce.reset();
|
| }
|
|
|
| Region::Region ()
|
| @@ -402,14 +386,12 @@ Region::operator!=(const Region &that) const {
|
| const Region* U_EXPORT2
|
| Region::getInstance(const char *region_code, UErrorCode &status) {
|
|
|
| - if ( !region_code ) {
|
| - status = U_ILLEGAL_ARGUMENT_ERROR;
|
| + umtx_initOnce(gRegionDataInitOnce, &loadRegionData, status);
|
| + if (U_FAILURE(status)) {
|
| return NULL;
|
| }
|
|
|
| - loadRegionData();
|
| -
|
| - if (regionIDMap == NULL) {
|
| + if ( !region_code ) {
|
| status = U_ILLEGAL_ARGUMENT_ERROR;
|
| return NULL;
|
| }
|
| @@ -445,10 +427,8 @@ Region::getInstance(const char *region_code, UErrorCode &status) {
|
| const Region* U_EXPORT2
|
| Region::getInstance (int32_t code, UErrorCode &status) {
|
|
|
| - loadRegionData();
|
| -
|
| - if (numericCodeMap == NULL) {
|
| - status = U_ILLEGAL_ARGUMENT_ERROR;
|
| + umtx_initOnce(gRegionDataInitOnce, &loadRegionData, status);
|
| + if (U_FAILURE(status)) {
|
| return NULL;
|
| }
|
|
|
| @@ -488,12 +468,12 @@ Region::getInstance (int32_t code, UErrorCode &status) {
|
| */
|
| StringEnumeration* U_EXPORT2
|
| Region::getAvailable(URegionType type) {
|
| -
|
| - loadRegionData();
|
| UErrorCode status = U_ZERO_ERROR;
|
| + umtx_initOnce(gRegionDataInitOnce, &loadRegionData, status);
|
| + if (U_FAILURE(status)) {
|
| + return NULL;
|
| + }
|
| return new RegionNameEnumeration(availableRegions[type],status);
|
| -
|
| - return NULL;
|
| }
|
|
|
| /**
|
| @@ -503,7 +483,8 @@ Region::getAvailable(URegionType type) {
|
| */
|
| const Region*
|
| Region::getContainingRegion() const {
|
| - loadRegionData();
|
| + UErrorCode status = U_ZERO_ERROR;
|
| + umtx_initOnce(gRegionDataInitOnce, &loadRegionData, status);
|
| return containingRegion;
|
| }
|
|
|
| @@ -516,7 +497,8 @@ Region::getContainingRegion() const {
|
| */
|
| const Region*
|
| Region::getContainingRegion(URegionType type) const {
|
| - loadRegionData();
|
| + UErrorCode status = U_ZERO_ERROR;
|
| + umtx_initOnce(gRegionDataInitOnce, &loadRegionData, status);
|
| if ( containingRegion == NULL ) {
|
| return NULL;
|
| }
|
| @@ -538,8 +520,8 @@ Region::getContainingRegion(URegionType type) const {
|
| */
|
| StringEnumeration*
|
| Region::getContainedRegions() const {
|
| - loadRegionData();
|
| UErrorCode status = U_ZERO_ERROR;
|
| + umtx_initOnce(gRegionDataInitOnce, &loadRegionData, status);
|
| return new RegionNameEnumeration(containedRegions,status);
|
| }
|
|
|
| @@ -551,9 +533,12 @@ Region::getContainedRegions() const {
|
| */
|
| StringEnumeration*
|
| Region::getContainedRegions( URegionType type ) const {
|
| - loadRegionData();
|
| -
|
| UErrorCode status = U_ZERO_ERROR;
|
| + umtx_initOnce(gRegionDataInitOnce, &loadRegionData, status);
|
| + if (U_FAILURE(status)) {
|
| + return NULL;
|
| + }
|
| +
|
| UVector *result = new UVector(NULL, uhash_compareChars, status);
|
|
|
| StringEnumeration *cr = getContainedRegions();
|
| @@ -584,7 +569,8 @@ Region::getContainedRegions( URegionType type ) const {
|
| */
|
| UBool
|
| Region::contains(const Region &other) const {
|
| - loadRegionData();
|
| + UErrorCode status = U_ZERO_ERROR;
|
| + umtx_initOnce(gRegionDataInitOnce, &loadRegionData, status);
|
|
|
| if (!containedRegions) {
|
| return FALSE;
|
| @@ -611,8 +597,8 @@ Region::contains(const Region &other) const {
|
| */
|
| StringEnumeration*
|
| Region::getPreferredValues() const {
|
| - loadRegionData();
|
| UErrorCode status = U_ZERO_ERROR;
|
| + umtx_initOnce(gRegionDataInitOnce, &loadRegionData, status);
|
| if ( type == URGN_DEPRECATED ) {
|
| return new RegionNameEnumeration(preferredValues,status);
|
| } else {
|
|
|