12e5b6d6dSopenharmony_ci// © 2016 and later: Unicode, Inc. and others.
22e5b6d6dSopenharmony_ci// License & terms of use: http://www.unicode.org/copyright.html
32e5b6d6dSopenharmony_ci/*
42e5b6d6dSopenharmony_ci*******************************************************************************
52e5b6d6dSopenharmony_ci* Copyright (C) 2014-2016, International Business Machines Corporation and
62e5b6d6dSopenharmony_ci* others. All Rights Reserved.
72e5b6d6dSopenharmony_ci*******************************************************************************
82e5b6d6dSopenharmony_ci*
92e5b6d6dSopenharmony_ci*
102e5b6d6dSopenharmony_ci* File REGION.CPP
112e5b6d6dSopenharmony_ci*
122e5b6d6dSopenharmony_ci* Modification History:*
132e5b6d6dSopenharmony_ci*   Date        Name        Description
142e5b6d6dSopenharmony_ci* 01/15/13      Emmons      Original Port from ICU4J
152e5b6d6dSopenharmony_ci********************************************************************************
162e5b6d6dSopenharmony_ci*/
172e5b6d6dSopenharmony_ci
182e5b6d6dSopenharmony_ci/**
192e5b6d6dSopenharmony_ci * \file
202e5b6d6dSopenharmony_ci * \brief C++ API: Region classes (territory containment)
212e5b6d6dSopenharmony_ci */
222e5b6d6dSopenharmony_ci
232e5b6d6dSopenharmony_ci#include "unicode/region.h"
242e5b6d6dSopenharmony_ci#include "unicode/utypes.h"
252e5b6d6dSopenharmony_ci#include "unicode/uobject.h"
262e5b6d6dSopenharmony_ci#include "unicode/unistr.h"
272e5b6d6dSopenharmony_ci#include "unicode/ures.h"
282e5b6d6dSopenharmony_ci#include "ucln_in.h"
292e5b6d6dSopenharmony_ci#include "cstring.h"
302e5b6d6dSopenharmony_ci#include "mutex.h"
312e5b6d6dSopenharmony_ci#include "uhash.h"
322e5b6d6dSopenharmony_ci#include "umutex.h"
332e5b6d6dSopenharmony_ci#include "uresimp.h"
342e5b6d6dSopenharmony_ci#include "region_impl.h"
352e5b6d6dSopenharmony_ci#include "util.h"
362e5b6d6dSopenharmony_ci
372e5b6d6dSopenharmony_ci#if !UCONFIG_NO_FORMATTING
382e5b6d6dSopenharmony_ci
392e5b6d6dSopenharmony_ci
402e5b6d6dSopenharmony_ciU_CDECL_BEGIN
412e5b6d6dSopenharmony_ci
422e5b6d6dSopenharmony_ci/**
432e5b6d6dSopenharmony_ci * Cleanup callback func
442e5b6d6dSopenharmony_ci */
452e5b6d6dSopenharmony_cistatic UBool U_CALLCONV region_cleanup(void)
462e5b6d6dSopenharmony_ci{
472e5b6d6dSopenharmony_ci    icu::Region::cleanupRegionData();
482e5b6d6dSopenharmony_ci
492e5b6d6dSopenharmony_ci    return true;
502e5b6d6dSopenharmony_ci}
512e5b6d6dSopenharmony_ci
522e5b6d6dSopenharmony_ciU_CDECL_END
532e5b6d6dSopenharmony_ci
542e5b6d6dSopenharmony_ciU_NAMESPACE_BEGIN
552e5b6d6dSopenharmony_ci
562e5b6d6dSopenharmony_cistatic UInitOnce gRegionDataInitOnce {};
572e5b6d6dSopenharmony_cistatic UVector* availableRegions[URGN_LIMIT];
582e5b6d6dSopenharmony_ci
592e5b6d6dSopenharmony_cistatic UHashtable *regionAliases = NULL;
602e5b6d6dSopenharmony_cistatic UHashtable *regionIDMap = NULL;
612e5b6d6dSopenharmony_cistatic UHashtable *numericCodeMap = NULL;
622e5b6d6dSopenharmony_cistatic UVector *allRegions = NULL;
632e5b6d6dSopenharmony_ci
642e5b6d6dSopenharmony_cistatic const UChar UNKNOWN_REGION_ID [] = { 0x5A, 0x5A, 0 };  /* "ZZ" */
652e5b6d6dSopenharmony_cistatic const UChar OUTLYING_OCEANIA_REGION_ID [] = { 0x51, 0x4F, 0 };  /* "QO" */
662e5b6d6dSopenharmony_cistatic const UChar WORLD_ID [] = { 0x30, 0x30, 0x31, 0 };  /* "001" */
672e5b6d6dSopenharmony_cistatic const UChar RANGE_MARKER = 0x7E; /* '~' */
682e5b6d6dSopenharmony_ci
692e5b6d6dSopenharmony_ciUOBJECT_DEFINE_RTTI_IMPLEMENTATION(RegionNameEnumeration)
702e5b6d6dSopenharmony_ci
712e5b6d6dSopenharmony_ci/*
722e5b6d6dSopenharmony_ci * Initializes the region data from the ICU resource bundles.  The region data
732e5b6d6dSopenharmony_ci * contains the basic relationships such as which regions are known, what the numeric
742e5b6d6dSopenharmony_ci * codes are, any known aliases, and the territory containment data.
752e5b6d6dSopenharmony_ci *
762e5b6d6dSopenharmony_ci * If the region data has already loaded, then this method simply returns without doing
772e5b6d6dSopenharmony_ci * anything meaningful.
782e5b6d6dSopenharmony_ci */
792e5b6d6dSopenharmony_civoid U_CALLCONV Region::loadRegionData(UErrorCode &status) {
802e5b6d6dSopenharmony_ci
812e5b6d6dSopenharmony_ci    // Construct service objs first
822e5b6d6dSopenharmony_ci    LocalUHashtablePointer newRegionIDMap(uhash_open(uhash_hashUnicodeString, uhash_compareUnicodeString, NULL, &status));
832e5b6d6dSopenharmony_ci    LocalUHashtablePointer newNumericCodeMap(uhash_open(uhash_hashLong,uhash_compareLong,NULL,&status));
842e5b6d6dSopenharmony_ci    LocalUHashtablePointer newRegionAliases(uhash_open(uhash_hashUnicodeString,uhash_compareUnicodeString,NULL,&status));
852e5b6d6dSopenharmony_ci
862e5b6d6dSopenharmony_ci    LocalPointer<UVector> continents(new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status), status);
872e5b6d6dSopenharmony_ci    LocalPointer<UVector> groupings(new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status), status);
882e5b6d6dSopenharmony_ci    LocalPointer<UVector> lpAllRegions(new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status), status);
892e5b6d6dSopenharmony_ci    allRegions = lpAllRegions.orphan();
902e5b6d6dSopenharmony_ci
912e5b6d6dSopenharmony_ci    LocalUResourceBundlePointer metadata(ures_openDirect(NULL,"metadata",&status));
922e5b6d6dSopenharmony_ci    LocalUResourceBundlePointer metadataAlias(ures_getByKey(metadata.getAlias(),"alias",NULL,&status));
932e5b6d6dSopenharmony_ci    LocalUResourceBundlePointer territoryAlias(ures_getByKey(metadataAlias.getAlias(),"territory",NULL,&status));
942e5b6d6dSopenharmony_ci
952e5b6d6dSopenharmony_ci    LocalUResourceBundlePointer supplementalData(ures_openDirect(NULL,"supplementalData",&status));
962e5b6d6dSopenharmony_ci    LocalUResourceBundlePointer codeMappings(ures_getByKey(supplementalData.getAlias(),"codeMappings",NULL,&status));
972e5b6d6dSopenharmony_ci
982e5b6d6dSopenharmony_ci    LocalUResourceBundlePointer idValidity(ures_getByKey(supplementalData.getAlias(),"idValidity",NULL,&status));
992e5b6d6dSopenharmony_ci    LocalUResourceBundlePointer regionList(ures_getByKey(idValidity.getAlias(),"region",NULL,&status));
1002e5b6d6dSopenharmony_ci    LocalUResourceBundlePointer regionRegular(ures_getByKey(regionList.getAlias(),"regular",NULL,&status));
1012e5b6d6dSopenharmony_ci    LocalUResourceBundlePointer regionMacro(ures_getByKey(regionList.getAlias(),"macroregion",NULL,&status));
1022e5b6d6dSopenharmony_ci    LocalUResourceBundlePointer regionUnknown(ures_getByKey(regionList.getAlias(),"unknown",NULL,&status));
1032e5b6d6dSopenharmony_ci
1042e5b6d6dSopenharmony_ci    LocalUResourceBundlePointer territoryContainment(ures_getByKey(supplementalData.getAlias(),"territoryContainment",NULL,&status));
1052e5b6d6dSopenharmony_ci    LocalUResourceBundlePointer worldContainment(ures_getByKey(territoryContainment.getAlias(),"001",NULL,&status));
1062e5b6d6dSopenharmony_ci    LocalUResourceBundlePointer groupingContainment(ures_getByKey(territoryContainment.getAlias(),"grouping",NULL,&status));
1072e5b6d6dSopenharmony_ci
1082e5b6d6dSopenharmony_ci    ucln_i18n_registerCleanup(UCLN_I18N_REGION, region_cleanup);
1092e5b6d6dSopenharmony_ci    if (U_FAILURE(status)) {
1102e5b6d6dSopenharmony_ci        return;
1112e5b6d6dSopenharmony_ci    }
1122e5b6d6dSopenharmony_ci
1132e5b6d6dSopenharmony_ci    // now, initialize
1142e5b6d6dSopenharmony_ci    uhash_setValueDeleter(newRegionIDMap.getAlias(), uprv_deleteUObject);  // regionIDMap owns objs
1152e5b6d6dSopenharmony_ci    uhash_setKeyDeleter(newRegionAliases.getAlias(), uprv_deleteUObject);  // regionAliases owns the string keys
1162e5b6d6dSopenharmony_ci
1172e5b6d6dSopenharmony_ci
1182e5b6d6dSopenharmony_ci    while (U_SUCCESS(status) && ures_hasNext(regionRegular.getAlias())) {
1192e5b6d6dSopenharmony_ci        UnicodeString regionName = ures_getNextUnicodeString(regionRegular.getAlias(),NULL,&status);
1202e5b6d6dSopenharmony_ci        int32_t rangeMarkerLocation = regionName.indexOf(RANGE_MARKER);
1212e5b6d6dSopenharmony_ci        UChar buf[6];
1222e5b6d6dSopenharmony_ci        regionName.extract(buf,6,status);
1232e5b6d6dSopenharmony_ci        if ( rangeMarkerLocation > 0 ) {
1242e5b6d6dSopenharmony_ci            UChar endRange = regionName.charAt(rangeMarkerLocation+1);
1252e5b6d6dSopenharmony_ci            buf[rangeMarkerLocation] = 0;
1262e5b6d6dSopenharmony_ci            while (U_SUCCESS(status) && buf[rangeMarkerLocation-1] <= endRange) {
1272e5b6d6dSopenharmony_ci                LocalPointer<UnicodeString> newRegion(new UnicodeString(buf), status);
1282e5b6d6dSopenharmony_ci                allRegions->adoptElement(newRegion.orphan(), status);
1292e5b6d6dSopenharmony_ci                buf[rangeMarkerLocation-1]++;
1302e5b6d6dSopenharmony_ci            }
1312e5b6d6dSopenharmony_ci        } else {
1322e5b6d6dSopenharmony_ci            LocalPointer<UnicodeString> newRegion(new UnicodeString(regionName), status);
1332e5b6d6dSopenharmony_ci            allRegions->adoptElement(newRegion.orphan(), status);
1342e5b6d6dSopenharmony_ci        }
1352e5b6d6dSopenharmony_ci    }
1362e5b6d6dSopenharmony_ci
1372e5b6d6dSopenharmony_ci    while (U_SUCCESS(status) && ures_hasNext(regionMacro.getAlias())) {
1382e5b6d6dSopenharmony_ci        UnicodeString regionName = ures_getNextUnicodeString(regionMacro.getAlias(),NULL,&status);
1392e5b6d6dSopenharmony_ci        int32_t rangeMarkerLocation = regionName.indexOf(RANGE_MARKER);
1402e5b6d6dSopenharmony_ci        UChar buf[6];
1412e5b6d6dSopenharmony_ci        regionName.extract(buf,6,status);
1422e5b6d6dSopenharmony_ci        if ( rangeMarkerLocation > 0 ) {
1432e5b6d6dSopenharmony_ci            UChar endRange = regionName.charAt(rangeMarkerLocation+1);
1442e5b6d6dSopenharmony_ci            buf[rangeMarkerLocation] = 0;
1452e5b6d6dSopenharmony_ci            while ( buf[rangeMarkerLocation-1] <= endRange && U_SUCCESS(status)) {
1462e5b6d6dSopenharmony_ci                LocalPointer<UnicodeString> newRegion(new UnicodeString(buf), status);
1472e5b6d6dSopenharmony_ci                allRegions->adoptElement(newRegion.orphan(),status);
1482e5b6d6dSopenharmony_ci                buf[rangeMarkerLocation-1]++;
1492e5b6d6dSopenharmony_ci            }
1502e5b6d6dSopenharmony_ci        } else {
1512e5b6d6dSopenharmony_ci            LocalPointer<UnicodeString> newRegion(new UnicodeString(regionName), status);
1522e5b6d6dSopenharmony_ci            allRegions->adoptElement(newRegion.orphan(),status);
1532e5b6d6dSopenharmony_ci        }
1542e5b6d6dSopenharmony_ci    }
1552e5b6d6dSopenharmony_ci
1562e5b6d6dSopenharmony_ci    while (U_SUCCESS(status) && ures_hasNext(regionUnknown.getAlias())) {
1572e5b6d6dSopenharmony_ci        LocalPointer<UnicodeString> regionName (
1582e5b6d6dSopenharmony_ci            new UnicodeString(ures_getNextUnicodeString(regionUnknown.getAlias(), nullptr, &status), status));
1592e5b6d6dSopenharmony_ci        allRegions->adoptElement(regionName.orphan(),status);
1602e5b6d6dSopenharmony_ci    }
1612e5b6d6dSopenharmony_ci
1622e5b6d6dSopenharmony_ci    while (U_SUCCESS(status) && ures_hasNext(worldContainment.getAlias())) {
1632e5b6d6dSopenharmony_ci        UnicodeString *continentName = new UnicodeString(ures_getNextUnicodeString(worldContainment.getAlias(),NULL,&status));
1642e5b6d6dSopenharmony_ci        continents->adoptElement(continentName,status);
1652e5b6d6dSopenharmony_ci    }
1662e5b6d6dSopenharmony_ci    if (U_FAILURE(status)) {
1672e5b6d6dSopenharmony_ci        return;
1682e5b6d6dSopenharmony_ci    }
1692e5b6d6dSopenharmony_ci
1702e5b6d6dSopenharmony_ci    for ( int32_t i = 0 ; i < allRegions->size() ; i++ ) {
1712e5b6d6dSopenharmony_ci        LocalPointer<Region> r(new Region(), status);
1722e5b6d6dSopenharmony_ci        if ( U_FAILURE(status) ) {
1732e5b6d6dSopenharmony_ci           return;
1742e5b6d6dSopenharmony_ci        }
1752e5b6d6dSopenharmony_ci        UnicodeString *regionName = (UnicodeString *)allRegions->elementAt(i);
1762e5b6d6dSopenharmony_ci        r->idStr = *regionName;
1772e5b6d6dSopenharmony_ci
1782e5b6d6dSopenharmony_ci        r->idStr.extract(0,r->idStr.length(),r->id,sizeof(r->id),US_INV);
1792e5b6d6dSopenharmony_ci        r->fType = URGN_TERRITORY; // Only temporary - figure out the real type later once the aliases are known.
1802e5b6d6dSopenharmony_ci
1812e5b6d6dSopenharmony_ci        int32_t pos = 0;
1822e5b6d6dSopenharmony_ci        int32_t result = ICU_Utility::parseAsciiInteger(r->idStr, pos);
1832e5b6d6dSopenharmony_ci        if (pos > 0) {
1842e5b6d6dSopenharmony_ci            r->code = result; // Convert string to number
1852e5b6d6dSopenharmony_ci            uhash_iput(newNumericCodeMap.getAlias(),r->code,(void *)(r.getAlias()),&status);
1862e5b6d6dSopenharmony_ci            r->fType = URGN_SUBCONTINENT;
1872e5b6d6dSopenharmony_ci        } else {
1882e5b6d6dSopenharmony_ci            r->code = -1;
1892e5b6d6dSopenharmony_ci        }
1902e5b6d6dSopenharmony_ci        void* idStrAlias = (void*)&(r->idStr); // about to orphan 'r'. Save this off.
1912e5b6d6dSopenharmony_ci        uhash_put(newRegionIDMap.getAlias(),idStrAlias,(void *)(r.orphan()),&status); // regionIDMap takes ownership
1922e5b6d6dSopenharmony_ci    }
1932e5b6d6dSopenharmony_ci
1942e5b6d6dSopenharmony_ci    UResourceBundle *groupingBundle = nullptr;
1952e5b6d6dSopenharmony_ci    while (U_SUCCESS(status) && ures_hasNext(groupingContainment.getAlias())) {
1962e5b6d6dSopenharmony_ci        groupingBundle = ures_getNextResource(groupingContainment.getAlias(), groupingBundle, &status);
1972e5b6d6dSopenharmony_ci        if (U_FAILURE(status)) {
1982e5b6d6dSopenharmony_ci            break;
1992e5b6d6dSopenharmony_ci        }
2002e5b6d6dSopenharmony_ci        UnicodeString *groupingName = new UnicodeString(ures_getKey(groupingBundle), -1, US_INV);
2012e5b6d6dSopenharmony_ci        LocalPointer<UnicodeString> lpGroupingName(groupingName, status);
2022e5b6d6dSopenharmony_ci        groupings->adoptElement(lpGroupingName.orphan(), status);
2032e5b6d6dSopenharmony_ci        if (U_FAILURE(status)) {
2042e5b6d6dSopenharmony_ci            break;
2052e5b6d6dSopenharmony_ci        }
2062e5b6d6dSopenharmony_ci        Region *grouping = (Region *) uhash_get(newRegionIDMap.getAlias(), groupingName);
2072e5b6d6dSopenharmony_ci        if (grouping != NULL) {
2082e5b6d6dSopenharmony_ci            for (int32_t i = 0; i < ures_getSize(groupingBundle) && U_SUCCESS(status); i++) {
2092e5b6d6dSopenharmony_ci                UnicodeString child = ures_getUnicodeStringByIndex(groupingBundle, i, &status);
2102e5b6d6dSopenharmony_ci                if (U_SUCCESS(status)) {
2112e5b6d6dSopenharmony_ci                    if (grouping->containedRegions == NULL) {
2122e5b6d6dSopenharmony_ci                        LocalPointer<UVector> lpContainedRegions(
2132e5b6d6dSopenharmony_ci                            new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status), status);
2142e5b6d6dSopenharmony_ci                        grouping->containedRegions = lpContainedRegions.orphan();
2152e5b6d6dSopenharmony_ci                        if (U_FAILURE(status)) {
2162e5b6d6dSopenharmony_ci                            break;
2172e5b6d6dSopenharmony_ci                        }
2182e5b6d6dSopenharmony_ci                    }
2192e5b6d6dSopenharmony_ci                    LocalPointer<UnicodeString> lpChildCopy(new UnicodeString(child), status);
2202e5b6d6dSopenharmony_ci                    grouping->containedRegions->adoptElement(lpChildCopy.orphan(), status);
2212e5b6d6dSopenharmony_ci                }
2222e5b6d6dSopenharmony_ci            }
2232e5b6d6dSopenharmony_ci        }
2242e5b6d6dSopenharmony_ci    }
2252e5b6d6dSopenharmony_ci    ures_close(groupingBundle);
2262e5b6d6dSopenharmony_ci
2272e5b6d6dSopenharmony_ci    // Process the territory aliases
2282e5b6d6dSopenharmony_ci    while (U_SUCCESS(status) && ures_hasNext(territoryAlias.getAlias())) {
2292e5b6d6dSopenharmony_ci        LocalUResourceBundlePointer res(ures_getNextResource(territoryAlias.getAlias(),NULL,&status));
2302e5b6d6dSopenharmony_ci        const char *aliasFrom = ures_getKey(res.getAlias());
2312e5b6d6dSopenharmony_ci        LocalPointer<UnicodeString> aliasFromStr(new UnicodeString(aliasFrom, -1, US_INV), status);
2322e5b6d6dSopenharmony_ci        UnicodeString aliasTo = ures_getUnicodeStringByKey(res.getAlias(),"replacement",&status);
2332e5b6d6dSopenharmony_ci        res.adoptInstead(NULL);
2342e5b6d6dSopenharmony_ci
2352e5b6d6dSopenharmony_ci        const Region *aliasToRegion = (Region *) uhash_get(newRegionIDMap.getAlias(),&aliasTo);
2362e5b6d6dSopenharmony_ci        Region *aliasFromRegion = (Region *)uhash_get(newRegionIDMap.getAlias(),aliasFromStr.getAlias());
2372e5b6d6dSopenharmony_ci
2382e5b6d6dSopenharmony_ci        if ( aliasToRegion != NULL && aliasFromRegion == NULL ) { // This is just an alias from some string to a region
2392e5b6d6dSopenharmony_ci            uhash_put(newRegionAliases.getAlias(),(void *)aliasFromStr.orphan(), (void *)aliasToRegion,&status);
2402e5b6d6dSopenharmony_ci        } else {
2412e5b6d6dSopenharmony_ci            if ( aliasFromRegion == NULL ) { // Deprecated region code not in the primary codes list - so need to create a deprecated region for it.
2422e5b6d6dSopenharmony_ci                LocalPointer<Region> newRgn(new Region, status);
2432e5b6d6dSopenharmony_ci                if ( U_SUCCESS(status) ) {
2442e5b6d6dSopenharmony_ci                    aliasFromRegion = newRgn.orphan();
2452e5b6d6dSopenharmony_ci                } else {
2462e5b6d6dSopenharmony_ci                    return; // error out
2472e5b6d6dSopenharmony_ci                }
2482e5b6d6dSopenharmony_ci                aliasFromRegion->idStr.setTo(*aliasFromStr);
2492e5b6d6dSopenharmony_ci                aliasFromRegion->idStr.extract(0,aliasFromRegion->idStr.length(),aliasFromRegion->id,sizeof(aliasFromRegion->id),US_INV);
2502e5b6d6dSopenharmony_ci                uhash_put(newRegionIDMap.getAlias(),(void *)&(aliasFromRegion->idStr),(void *)aliasFromRegion,&status);
2512e5b6d6dSopenharmony_ci                int32_t pos = 0;
2522e5b6d6dSopenharmony_ci                int32_t result = ICU_Utility::parseAsciiInteger(aliasFromRegion->idStr, pos);
2532e5b6d6dSopenharmony_ci                if ( pos > 0 ) {
2542e5b6d6dSopenharmony_ci                    aliasFromRegion->code = result; // Convert string to number
2552e5b6d6dSopenharmony_ci                    uhash_iput(newNumericCodeMap.getAlias(),aliasFromRegion->code,(void *)aliasFromRegion,&status);
2562e5b6d6dSopenharmony_ci                } else {
2572e5b6d6dSopenharmony_ci                    aliasFromRegion->code = -1;
2582e5b6d6dSopenharmony_ci                }
2592e5b6d6dSopenharmony_ci                aliasFromRegion->fType = URGN_DEPRECATED;
2602e5b6d6dSopenharmony_ci            } else {
2612e5b6d6dSopenharmony_ci                aliasFromRegion->fType = URGN_DEPRECATED;
2622e5b6d6dSopenharmony_ci            }
2632e5b6d6dSopenharmony_ci
2642e5b6d6dSopenharmony_ci            {
2652e5b6d6dSopenharmony_ci                LocalPointer<UVector> newPreferredValues(new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status), status);
2662e5b6d6dSopenharmony_ci                aliasFromRegion->preferredValues = newPreferredValues.orphan();
2672e5b6d6dSopenharmony_ci            }
2682e5b6d6dSopenharmony_ci            if( U_FAILURE(status)) {
2692e5b6d6dSopenharmony_ci                return;
2702e5b6d6dSopenharmony_ci            }
2712e5b6d6dSopenharmony_ci            UnicodeString currentRegion;
2722e5b6d6dSopenharmony_ci            //currentRegion.remove();   TODO: was already 0 length?
2732e5b6d6dSopenharmony_ci            for (int32_t i = 0 ; i < aliasTo.length() && U_SUCCESS(status); i++ ) {
2742e5b6d6dSopenharmony_ci                if ( aliasTo.charAt(i) != 0x0020 ) {
2752e5b6d6dSopenharmony_ci                    currentRegion.append(aliasTo.charAt(i));
2762e5b6d6dSopenharmony_ci                }
2772e5b6d6dSopenharmony_ci                if ( aliasTo.charAt(i) == 0x0020 || i+1 == aliasTo.length() ) {
2782e5b6d6dSopenharmony_ci                    Region *target = (Region *)uhash_get(newRegionIDMap.getAlias(),(void *)&currentRegion);
2792e5b6d6dSopenharmony_ci                    if (target) {
2802e5b6d6dSopenharmony_ci                        LocalPointer<UnicodeString> preferredValue(new UnicodeString(target->idStr), status);
2812e5b6d6dSopenharmony_ci                        aliasFromRegion->preferredValues->adoptElement(preferredValue.orphan(),status);  // may add null if err
2822e5b6d6dSopenharmony_ci                    }
2832e5b6d6dSopenharmony_ci                    currentRegion.remove();
2842e5b6d6dSopenharmony_ci                }
2852e5b6d6dSopenharmony_ci            }
2862e5b6d6dSopenharmony_ci        }
2872e5b6d6dSopenharmony_ci    }
2882e5b6d6dSopenharmony_ci
2892e5b6d6dSopenharmony_ci    // Process the code mappings - This will allow us to assign numeric codes to most of the territories.
2902e5b6d6dSopenharmony_ci    while (U_SUCCESS(status) && ures_hasNext(codeMappings.getAlias())) {
2912e5b6d6dSopenharmony_ci        UResourceBundle *mapping = ures_getNextResource(codeMappings.getAlias(),NULL,&status);
2922e5b6d6dSopenharmony_ci        if (U_SUCCESS(status) && ures_getType(mapping) == URES_ARRAY && ures_getSize(mapping) == 3) {
2932e5b6d6dSopenharmony_ci            UnicodeString codeMappingID = ures_getUnicodeStringByIndex(mapping,0,&status);
2942e5b6d6dSopenharmony_ci            UnicodeString codeMappingNumber = ures_getUnicodeStringByIndex(mapping,1,&status);
2952e5b6d6dSopenharmony_ci            UnicodeString codeMapping3Letter = ures_getUnicodeStringByIndex(mapping,2,&status);
2962e5b6d6dSopenharmony_ci
2972e5b6d6dSopenharmony_ci            Region *r = (Region *)uhash_get(newRegionIDMap.getAlias(),(void *)&codeMappingID);
2982e5b6d6dSopenharmony_ci            if ( r ) {
2992e5b6d6dSopenharmony_ci                int32_t pos = 0;
3002e5b6d6dSopenharmony_ci                int32_t result = ICU_Utility::parseAsciiInteger(codeMappingNumber, pos);
3012e5b6d6dSopenharmony_ci                if ( pos > 0 ) {
3022e5b6d6dSopenharmony_ci                    r->code = result; // Convert string to number
3032e5b6d6dSopenharmony_ci                    uhash_iput(newNumericCodeMap.getAlias(),r->code,(void *)r,&status);
3042e5b6d6dSopenharmony_ci                }
3052e5b6d6dSopenharmony_ci                LocalPointer<UnicodeString> code3(new UnicodeString(codeMapping3Letter), status);
3062e5b6d6dSopenharmony_ci                uhash_put(newRegionAliases.getAlias(),(void *)code3.orphan(), (void *)r,&status);
3072e5b6d6dSopenharmony_ci            }
3082e5b6d6dSopenharmony_ci        }
3092e5b6d6dSopenharmony_ci        ures_close(mapping);
3102e5b6d6dSopenharmony_ci    }
3112e5b6d6dSopenharmony_ci
3122e5b6d6dSopenharmony_ci    // Now fill in the special cases for WORLD, UNKNOWN, CONTINENTS, and GROUPINGS
3132e5b6d6dSopenharmony_ci    Region *r;
3142e5b6d6dSopenharmony_ci    UnicodeString WORLD_ID_STRING(WORLD_ID);
3152e5b6d6dSopenharmony_ci    r = (Region *) uhash_get(newRegionIDMap.getAlias(),(void *)&WORLD_ID_STRING);
3162e5b6d6dSopenharmony_ci    if ( r ) {
3172e5b6d6dSopenharmony_ci        r->fType = URGN_WORLD;
3182e5b6d6dSopenharmony_ci    }
3192e5b6d6dSopenharmony_ci
3202e5b6d6dSopenharmony_ci    UnicodeString UNKNOWN_REGION_ID_STRING(UNKNOWN_REGION_ID);
3212e5b6d6dSopenharmony_ci    r = (Region *) uhash_get(newRegionIDMap.getAlias(),(void *)&UNKNOWN_REGION_ID_STRING);
3222e5b6d6dSopenharmony_ci    if ( r ) {
3232e5b6d6dSopenharmony_ci        r->fType = URGN_UNKNOWN;
3242e5b6d6dSopenharmony_ci    }
3252e5b6d6dSopenharmony_ci
3262e5b6d6dSopenharmony_ci    for ( int32_t i = 0 ; i < continents->size() ; i++ ) {
3272e5b6d6dSopenharmony_ci        r = (Region *) uhash_get(newRegionIDMap.getAlias(),(void *)continents->elementAt(i));
3282e5b6d6dSopenharmony_ci        if ( r ) {
3292e5b6d6dSopenharmony_ci            r->fType = URGN_CONTINENT;
3302e5b6d6dSopenharmony_ci        }
3312e5b6d6dSopenharmony_ci    }
3322e5b6d6dSopenharmony_ci
3332e5b6d6dSopenharmony_ci    for ( int32_t i = 0 ; i < groupings->size() ; i++ ) {
3342e5b6d6dSopenharmony_ci        r = (Region *) uhash_get(newRegionIDMap.getAlias(),(void *)groupings->elementAt(i));
3352e5b6d6dSopenharmony_ci        if ( r ) {
3362e5b6d6dSopenharmony_ci            r->fType = URGN_GROUPING;
3372e5b6d6dSopenharmony_ci        }
3382e5b6d6dSopenharmony_ci    }
3392e5b6d6dSopenharmony_ci
3402e5b6d6dSopenharmony_ci    // Special case: The region code "QO" (Outlying Oceania) is a subcontinent code added by CLDR
3412e5b6d6dSopenharmony_ci    // even though it looks like a territory code.  Need to handle it here.
3422e5b6d6dSopenharmony_ci
3432e5b6d6dSopenharmony_ci    UnicodeString OUTLYING_OCEANIA_REGION_ID_STRING(OUTLYING_OCEANIA_REGION_ID);
3442e5b6d6dSopenharmony_ci    r = (Region *) uhash_get(newRegionIDMap.getAlias(),(void *)&OUTLYING_OCEANIA_REGION_ID_STRING);
3452e5b6d6dSopenharmony_ci    if ( r ) {
3462e5b6d6dSopenharmony_ci        r->fType = URGN_SUBCONTINENT;
3472e5b6d6dSopenharmony_ci    }
3482e5b6d6dSopenharmony_ci
3492e5b6d6dSopenharmony_ci    // Load territory containment info from the supplemental data.
3502e5b6d6dSopenharmony_ci    while ( ures_hasNext(territoryContainment.getAlias()) ) {
3512e5b6d6dSopenharmony_ci        LocalUResourceBundlePointer mapping(ures_getNextResource(territoryContainment.getAlias(),NULL,&status));
3522e5b6d6dSopenharmony_ci        if( U_FAILURE(status) ) {
3532e5b6d6dSopenharmony_ci            return;  // error out
3542e5b6d6dSopenharmony_ci        }
3552e5b6d6dSopenharmony_ci        const char *parent = ures_getKey(mapping.getAlias());
3562e5b6d6dSopenharmony_ci        if (uprv_strcmp(parent, "containedGroupings") == 0 || uprv_strcmp(parent, "deprecated") == 0) {
3572e5b6d6dSopenharmony_ci            continue; // handle new pseudo-parent types added in ICU data per cldrbug 7808; for now just skip.
3582e5b6d6dSopenharmony_ci            // #11232 is to do something useful with these.
3592e5b6d6dSopenharmony_ci        }
3602e5b6d6dSopenharmony_ci        UnicodeString parentStr = UnicodeString(parent, -1 , US_INV);
3612e5b6d6dSopenharmony_ci        Region *parentRegion = (Region *) uhash_get(newRegionIDMap.getAlias(),(void *)&parentStr);
3622e5b6d6dSopenharmony_ci
3632e5b6d6dSopenharmony_ci        for ( int j = 0 ; j < ures_getSize(mapping.getAlias()); j++ ) {
3642e5b6d6dSopenharmony_ci            UnicodeString child = ures_getUnicodeStringByIndex(mapping.getAlias(),j,&status);
3652e5b6d6dSopenharmony_ci            Region *childRegion = (Region *) uhash_get(newRegionIDMap.getAlias(),(void *)&child);
3662e5b6d6dSopenharmony_ci            if ( parentRegion != NULL && childRegion != NULL ) {
3672e5b6d6dSopenharmony_ci
3682e5b6d6dSopenharmony_ci                // Add the child region to the set of regions contained by the parent
3692e5b6d6dSopenharmony_ci                if (parentRegion->containedRegions == NULL) {
3702e5b6d6dSopenharmony_ci                    LocalPointer<UVector> lpContainedRegions(
3712e5b6d6dSopenharmony_ci                        new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status), status);
3722e5b6d6dSopenharmony_ci                    parentRegion->containedRegions = lpContainedRegions.orphan();
3732e5b6d6dSopenharmony_ci                    if (U_FAILURE(status)) {
3742e5b6d6dSopenharmony_ci                        return;
3752e5b6d6dSopenharmony_ci                    }
3762e5b6d6dSopenharmony_ci                }
3772e5b6d6dSopenharmony_ci
3782e5b6d6dSopenharmony_ci                LocalPointer<UnicodeString> childStr(new UnicodeString(), status);
3792e5b6d6dSopenharmony_ci                if (U_FAILURE(status)) {
3802e5b6d6dSopenharmony_ci                    return;  // error out
3812e5b6d6dSopenharmony_ci                }
3822e5b6d6dSopenharmony_ci                childStr->fastCopyFrom(childRegion->idStr);
3832e5b6d6dSopenharmony_ci                parentRegion->containedRegions->adoptElement(childStr.orphan(),status);
3842e5b6d6dSopenharmony_ci                if (U_FAILURE(status)) {
3852e5b6d6dSopenharmony_ci                    return;
3862e5b6d6dSopenharmony_ci                }
3872e5b6d6dSopenharmony_ci
3882e5b6d6dSopenharmony_ci                // Set the parent region to be the containing region of the child.
3892e5b6d6dSopenharmony_ci                // Regions of type GROUPING can't be set as the parent, since another region
3902e5b6d6dSopenharmony_ci                // such as a SUBCONTINENT, CONTINENT, or WORLD must always be the parent.
3912e5b6d6dSopenharmony_ci                if ( parentRegion->fType != URGN_GROUPING) {
3922e5b6d6dSopenharmony_ci                    childRegion->containingRegion = parentRegion;
3932e5b6d6dSopenharmony_ci                }
3942e5b6d6dSopenharmony_ci            }
3952e5b6d6dSopenharmony_ci        }
3962e5b6d6dSopenharmony_ci    }
3972e5b6d6dSopenharmony_ci
3982e5b6d6dSopenharmony_ci    // Create the availableRegions lists
3992e5b6d6dSopenharmony_ci    int32_t pos = UHASH_FIRST;
4002e5b6d6dSopenharmony_ci    while ( const UHashElement* element = uhash_nextElement(newRegionIDMap.getAlias(),&pos)) {
4012e5b6d6dSopenharmony_ci        Region *ar = (Region *)element->value.pointer;
4022e5b6d6dSopenharmony_ci        if ( availableRegions[ar->fType] == NULL ) {
4032e5b6d6dSopenharmony_ci            LocalPointer<UVector> newAr(new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status), status);
4042e5b6d6dSopenharmony_ci            availableRegions[ar->fType] = newAr.orphan();
4052e5b6d6dSopenharmony_ci        }
4062e5b6d6dSopenharmony_ci        LocalPointer<UnicodeString> arString(new UnicodeString(ar->idStr), status);
4072e5b6d6dSopenharmony_ci        if( U_FAILURE(status) ) {
4082e5b6d6dSopenharmony_ci            return;  // error out
4092e5b6d6dSopenharmony_ci        }
4102e5b6d6dSopenharmony_ci        availableRegions[ar->fType]->adoptElement(arString.orphan(), status);
4112e5b6d6dSopenharmony_ci    }
4122e5b6d6dSopenharmony_ci
4132e5b6d6dSopenharmony_ci    // copy hashtables
4142e5b6d6dSopenharmony_ci    numericCodeMap = newNumericCodeMap.orphan();
4152e5b6d6dSopenharmony_ci    regionIDMap = newRegionIDMap.orphan();
4162e5b6d6dSopenharmony_ci    regionAliases = newRegionAliases.orphan();
4172e5b6d6dSopenharmony_ci}
4182e5b6d6dSopenharmony_ci
4192e5b6d6dSopenharmony_civoid Region::cleanupRegionData() {
4202e5b6d6dSopenharmony_ci    for (int32_t i = 0 ; i < URGN_LIMIT ; i++ ) {
4212e5b6d6dSopenharmony_ci        if ( availableRegions[i] ) {
4222e5b6d6dSopenharmony_ci            delete availableRegions[i];
4232e5b6d6dSopenharmony_ci            availableRegions[i] = nullptr;
4242e5b6d6dSopenharmony_ci        }
4252e5b6d6dSopenharmony_ci    }
4262e5b6d6dSopenharmony_ci
4272e5b6d6dSopenharmony_ci    if (regionAliases) {
4282e5b6d6dSopenharmony_ci        uhash_close(regionAliases);
4292e5b6d6dSopenharmony_ci    }
4302e5b6d6dSopenharmony_ci
4312e5b6d6dSopenharmony_ci    if (numericCodeMap) {
4322e5b6d6dSopenharmony_ci        uhash_close(numericCodeMap);
4332e5b6d6dSopenharmony_ci    }
4342e5b6d6dSopenharmony_ci
4352e5b6d6dSopenharmony_ci    if (regionIDMap) {
4362e5b6d6dSopenharmony_ci        uhash_close(regionIDMap);
4372e5b6d6dSopenharmony_ci    }
4382e5b6d6dSopenharmony_ci    if (allRegions) {
4392e5b6d6dSopenharmony_ci        delete allRegions;
4402e5b6d6dSopenharmony_ci        allRegions = NULL;
4412e5b6d6dSopenharmony_ci    }
4422e5b6d6dSopenharmony_ci
4432e5b6d6dSopenharmony_ci    regionAliases = numericCodeMap = regionIDMap = NULL;
4442e5b6d6dSopenharmony_ci
4452e5b6d6dSopenharmony_ci    gRegionDataInitOnce.reset();
4462e5b6d6dSopenharmony_ci}
4472e5b6d6dSopenharmony_ci
4482e5b6d6dSopenharmony_ciRegion::Region ()
4492e5b6d6dSopenharmony_ci        : code(-1),
4502e5b6d6dSopenharmony_ci          fType(URGN_UNKNOWN),
4512e5b6d6dSopenharmony_ci          containingRegion(NULL),
4522e5b6d6dSopenharmony_ci          containedRegions(NULL),
4532e5b6d6dSopenharmony_ci          preferredValues(NULL) {
4542e5b6d6dSopenharmony_ci    id[0] = 0;
4552e5b6d6dSopenharmony_ci}
4562e5b6d6dSopenharmony_ci
4572e5b6d6dSopenharmony_ciRegion::~Region () {
4582e5b6d6dSopenharmony_ci        if (containedRegions) {
4592e5b6d6dSopenharmony_ci            delete containedRegions;
4602e5b6d6dSopenharmony_ci        }
4612e5b6d6dSopenharmony_ci        if (preferredValues) {
4622e5b6d6dSopenharmony_ci            delete preferredValues;
4632e5b6d6dSopenharmony_ci        }
4642e5b6d6dSopenharmony_ci}
4652e5b6d6dSopenharmony_ci
4662e5b6d6dSopenharmony_ci/**
4672e5b6d6dSopenharmony_ci * Returns true if the two regions are equal.
4682e5b6d6dSopenharmony_ci * Per PMC, just use pointer compare, since we have at most one instance of each Region.
4692e5b6d6dSopenharmony_ci */
4702e5b6d6dSopenharmony_cibool
4712e5b6d6dSopenharmony_ciRegion::operator==(const Region &that) const {
4722e5b6d6dSopenharmony_ci    return (idStr == that.idStr);
4732e5b6d6dSopenharmony_ci}
4742e5b6d6dSopenharmony_ci
4752e5b6d6dSopenharmony_ci/**
4762e5b6d6dSopenharmony_ci * Returns true if the two regions are NOT equal; that is, if operator ==() returns false.
4772e5b6d6dSopenharmony_ci * Per PMC, just use pointer compare, since we have at most one instance of each Region.
4782e5b6d6dSopenharmony_ci */
4792e5b6d6dSopenharmony_cibool
4802e5b6d6dSopenharmony_ciRegion::operator!=(const Region &that) const {
4812e5b6d6dSopenharmony_ci        return (idStr != that.idStr);
4822e5b6d6dSopenharmony_ci}
4832e5b6d6dSopenharmony_ci
4842e5b6d6dSopenharmony_ci/**
4852e5b6d6dSopenharmony_ci * Returns a pointer to a Region using the given region code.  The region code can be either 2-letter ISO code,
4862e5b6d6dSopenharmony_ci * 3-letter ISO code,  UNM.49 numeric code, or other valid Unicode Region Code as defined by the LDML specification.
4872e5b6d6dSopenharmony_ci * The identifier will be canonicalized internally using the supplemental metadata as defined in the CLDR.
4882e5b6d6dSopenharmony_ci * If the region code is NULL or not recognized, the appropriate error code will be set ( U_ILLEGAL_ARGUMENT_ERROR )
4892e5b6d6dSopenharmony_ci */
4902e5b6d6dSopenharmony_ciconst Region* U_EXPORT2
4912e5b6d6dSopenharmony_ciRegion::getInstance(const char *region_code, UErrorCode &status) {
4922e5b6d6dSopenharmony_ci
4932e5b6d6dSopenharmony_ci    umtx_initOnce(gRegionDataInitOnce, &loadRegionData, status);
4942e5b6d6dSopenharmony_ci    if (U_FAILURE(status)) {
4952e5b6d6dSopenharmony_ci        return NULL;
4962e5b6d6dSopenharmony_ci    }
4972e5b6d6dSopenharmony_ci
4982e5b6d6dSopenharmony_ci    if ( !region_code ) {
4992e5b6d6dSopenharmony_ci        status = U_ILLEGAL_ARGUMENT_ERROR;
5002e5b6d6dSopenharmony_ci        return NULL;
5012e5b6d6dSopenharmony_ci    }
5022e5b6d6dSopenharmony_ci
5032e5b6d6dSopenharmony_ci    UnicodeString regionCodeString = UnicodeString(region_code, -1, US_INV);
5042e5b6d6dSopenharmony_ci    Region *r = (Region *)uhash_get(regionIDMap,(void *)&regionCodeString);
5052e5b6d6dSopenharmony_ci
5062e5b6d6dSopenharmony_ci    if ( !r ) {
5072e5b6d6dSopenharmony_ci        r = (Region *)uhash_get(regionAliases,(void *)&regionCodeString);
5082e5b6d6dSopenharmony_ci    }
5092e5b6d6dSopenharmony_ci
5102e5b6d6dSopenharmony_ci    if ( !r ) { // Unknown region code
5112e5b6d6dSopenharmony_ci        status = U_ILLEGAL_ARGUMENT_ERROR;
5122e5b6d6dSopenharmony_ci        return NULL;
5132e5b6d6dSopenharmony_ci    }
5142e5b6d6dSopenharmony_ci
5152e5b6d6dSopenharmony_ci    if ( r->fType == URGN_DEPRECATED && r->preferredValues->size() == 1) {
5162e5b6d6dSopenharmony_ci        StringEnumeration *pv = r->getPreferredValues(status);
5172e5b6d6dSopenharmony_ci        pv->reset(status);
5182e5b6d6dSopenharmony_ci        const UnicodeString *ustr = pv->snext(status);
5192e5b6d6dSopenharmony_ci        r = (Region *)uhash_get(regionIDMap,(void *)ustr);
5202e5b6d6dSopenharmony_ci        delete pv;
5212e5b6d6dSopenharmony_ci    }
5222e5b6d6dSopenharmony_ci
5232e5b6d6dSopenharmony_ci    return r;
5242e5b6d6dSopenharmony_ci
5252e5b6d6dSopenharmony_ci}
5262e5b6d6dSopenharmony_ci
5272e5b6d6dSopenharmony_ci/**
5282e5b6d6dSopenharmony_ci * Returns a pointer to a Region using the given numeric region code. If the numeric region code is not recognized,
5292e5b6d6dSopenharmony_ci * the appropriate error code will be set ( U_ILLEGAL_ARGUMENT_ERROR ).
5302e5b6d6dSopenharmony_ci */
5312e5b6d6dSopenharmony_ciconst Region* U_EXPORT2
5322e5b6d6dSopenharmony_ciRegion::getInstance (int32_t code, UErrorCode &status) {
5332e5b6d6dSopenharmony_ci
5342e5b6d6dSopenharmony_ci    umtx_initOnce(gRegionDataInitOnce, &loadRegionData, status);
5352e5b6d6dSopenharmony_ci    if (U_FAILURE(status)) {
5362e5b6d6dSopenharmony_ci        return NULL;
5372e5b6d6dSopenharmony_ci    }
5382e5b6d6dSopenharmony_ci
5392e5b6d6dSopenharmony_ci    Region *r = (Region *)uhash_iget(numericCodeMap,code);
5402e5b6d6dSopenharmony_ci
5412e5b6d6dSopenharmony_ci    if ( !r ) { // Just in case there's an alias that's numeric, try to find it.
5422e5b6d6dSopenharmony_ci        UnicodeString id;
5432e5b6d6dSopenharmony_ci        ICU_Utility::appendNumber(id, code, 10, 1);
5442e5b6d6dSopenharmony_ci        r = (Region *)uhash_get(regionAliases,&id);
5452e5b6d6dSopenharmony_ci    }
5462e5b6d6dSopenharmony_ci
5472e5b6d6dSopenharmony_ci    if( U_FAILURE(status) ) {
5482e5b6d6dSopenharmony_ci        return NULL;
5492e5b6d6dSopenharmony_ci    }
5502e5b6d6dSopenharmony_ci
5512e5b6d6dSopenharmony_ci    if ( !r ) {
5522e5b6d6dSopenharmony_ci        status = U_ILLEGAL_ARGUMENT_ERROR;
5532e5b6d6dSopenharmony_ci        return NULL;
5542e5b6d6dSopenharmony_ci    }
5552e5b6d6dSopenharmony_ci
5562e5b6d6dSopenharmony_ci    if ( r->fType == URGN_DEPRECATED && r->preferredValues->size() == 1) {
5572e5b6d6dSopenharmony_ci        StringEnumeration *pv = r->getPreferredValues(status);
5582e5b6d6dSopenharmony_ci        pv->reset(status);
5592e5b6d6dSopenharmony_ci        const UnicodeString *ustr = pv->snext(status);
5602e5b6d6dSopenharmony_ci        r = (Region *)uhash_get(regionIDMap,(void *)ustr);
5612e5b6d6dSopenharmony_ci        delete pv;
5622e5b6d6dSopenharmony_ci    }
5632e5b6d6dSopenharmony_ci
5642e5b6d6dSopenharmony_ci    return r;
5652e5b6d6dSopenharmony_ci}
5662e5b6d6dSopenharmony_ci
5672e5b6d6dSopenharmony_ci
5682e5b6d6dSopenharmony_ci/**
5692e5b6d6dSopenharmony_ci * Returns an enumeration over the IDs of all known regions that match the given type.
5702e5b6d6dSopenharmony_ci */
5712e5b6d6dSopenharmony_ciStringEnumeration* U_EXPORT2
5722e5b6d6dSopenharmony_ciRegion::getAvailable(URegionType type, UErrorCode &status) {
5732e5b6d6dSopenharmony_ci    umtx_initOnce(gRegionDataInitOnce, &loadRegionData, status); // returns immediately if U_FAILURE(status)
5742e5b6d6dSopenharmony_ci    if (U_FAILURE(status)) {
5752e5b6d6dSopenharmony_ci        return NULL;
5762e5b6d6dSopenharmony_ci    }
5772e5b6d6dSopenharmony_ci    return new RegionNameEnumeration(availableRegions[type],status);
5782e5b6d6dSopenharmony_ci}
5792e5b6d6dSopenharmony_ci
5802e5b6d6dSopenharmony_ci/**
5812e5b6d6dSopenharmony_ci * Returns a pointer to the region that contains this region.  Returns NULL if this region is code "001" (World)
5822e5b6d6dSopenharmony_ci * or "ZZ" (Unknown region). For example, calling this method with region "IT" (Italy) returns the
5832e5b6d6dSopenharmony_ci * region "039" (Southern Europe).
5842e5b6d6dSopenharmony_ci */
5852e5b6d6dSopenharmony_ciconst Region*
5862e5b6d6dSopenharmony_ciRegion::getContainingRegion() const {
5872e5b6d6dSopenharmony_ci    UErrorCode status = U_ZERO_ERROR;
5882e5b6d6dSopenharmony_ci    umtx_initOnce(gRegionDataInitOnce, &loadRegionData, status);
5892e5b6d6dSopenharmony_ci    return containingRegion;
5902e5b6d6dSopenharmony_ci}
5912e5b6d6dSopenharmony_ci
5922e5b6d6dSopenharmony_ci/**
5932e5b6d6dSopenharmony_ci * Return a pointer to the region that geographically contains this region and matches the given type,
5942e5b6d6dSopenharmony_ci * moving multiple steps up the containment chain if necessary.  Returns NULL if no containing region can be found
5952e5b6d6dSopenharmony_ci * that matches the given type. Note: The URegionTypes = "URGN_GROUPING", "URGN_DEPRECATED", or "URGN_UNKNOWN"
5962e5b6d6dSopenharmony_ci * are not appropriate for use in this API. NULL will be returned in this case. For example, calling this method
5972e5b6d6dSopenharmony_ci * with region "IT" (Italy) for type "URGN_CONTINENT" returns the region "150" ( Europe ).
5982e5b6d6dSopenharmony_ci */
5992e5b6d6dSopenharmony_ciconst Region*
6002e5b6d6dSopenharmony_ciRegion::getContainingRegion(URegionType type) const {
6012e5b6d6dSopenharmony_ci    UErrorCode status = U_ZERO_ERROR;
6022e5b6d6dSopenharmony_ci    umtx_initOnce(gRegionDataInitOnce, &loadRegionData, status);
6032e5b6d6dSopenharmony_ci    if ( containingRegion == NULL ) {
6042e5b6d6dSopenharmony_ci        return NULL;
6052e5b6d6dSopenharmony_ci    }
6062e5b6d6dSopenharmony_ci
6072e5b6d6dSopenharmony_ci    return ( containingRegion->fType == type)? containingRegion: containingRegion->getContainingRegion(type);
6082e5b6d6dSopenharmony_ci}
6092e5b6d6dSopenharmony_ci
6102e5b6d6dSopenharmony_ci/**
6112e5b6d6dSopenharmony_ci * Return an enumeration over the IDs of all the regions that are immediate children of this region in the
6122e5b6d6dSopenharmony_ci * region hierarchy. These returned regions could be either macro regions, territories, or a mixture of the two,
6132e5b6d6dSopenharmony_ci * depending on the containment data as defined in CLDR.  This API may return NULL if this region doesn't have
6142e5b6d6dSopenharmony_ci * any sub-regions. For example, calling this method with region "150" (Europe) returns an enumeration containing
6152e5b6d6dSopenharmony_ci * the various sub regions of Europe - "039" (Southern Europe) - "151" (Eastern Europe) - "154" (Northern Europe)
6162e5b6d6dSopenharmony_ci * and "155" (Western Europe).
6172e5b6d6dSopenharmony_ci */
6182e5b6d6dSopenharmony_ciStringEnumeration*
6192e5b6d6dSopenharmony_ciRegion::getContainedRegions(UErrorCode &status) const {
6202e5b6d6dSopenharmony_ci    umtx_initOnce(gRegionDataInitOnce, &loadRegionData, status); // returns immediately if U_FAILURE(status)
6212e5b6d6dSopenharmony_ci    if (U_FAILURE(status)) {
6222e5b6d6dSopenharmony_ci        return NULL;
6232e5b6d6dSopenharmony_ci    }
6242e5b6d6dSopenharmony_ci    return new RegionNameEnumeration(containedRegions,status);
6252e5b6d6dSopenharmony_ci}
6262e5b6d6dSopenharmony_ci
6272e5b6d6dSopenharmony_ci/**
6282e5b6d6dSopenharmony_ci * Returns an enumeration over the IDs of all the regions that are children of this region anywhere in the region
6292e5b6d6dSopenharmony_ci * hierarchy and match the given type.  This API may return an empty enumeration if this region doesn't have any
6302e5b6d6dSopenharmony_ci * sub-regions that match the given type. For example, calling this method with region "150" (Europe) and type
6312e5b6d6dSopenharmony_ci * "URGN_TERRITORY" returns a set containing all the territories in Europe ( "FR" (France) - "IT" (Italy) - "DE" (Germany) etc. )
6322e5b6d6dSopenharmony_ci */
6332e5b6d6dSopenharmony_ciStringEnumeration*
6342e5b6d6dSopenharmony_ciRegion::getContainedRegions( URegionType type, UErrorCode &status ) const {
6352e5b6d6dSopenharmony_ci    umtx_initOnce(gRegionDataInitOnce, &loadRegionData, status); // returns immediately if U_FAILURE(status)
6362e5b6d6dSopenharmony_ci
6372e5b6d6dSopenharmony_ci    UVector result(nullptr, uhash_compareChars, status);
6382e5b6d6dSopenharmony_ci    LocalPointer<StringEnumeration> cr(getContainedRegions(status), status);
6392e5b6d6dSopenharmony_ci    if (U_FAILURE(status)) {
6402e5b6d6dSopenharmony_ci        return nullptr;
6412e5b6d6dSopenharmony_ci    }
6422e5b6d6dSopenharmony_ci
6432e5b6d6dSopenharmony_ci    const char *regionId;
6442e5b6d6dSopenharmony_ci    while((regionId = cr->next(nullptr, status)) != nullptr && U_SUCCESS(status)) {
6452e5b6d6dSopenharmony_ci        const Region *r = Region::getInstance(regionId, status);
6462e5b6d6dSopenharmony_ci        if ( r->getType() == type) {
6472e5b6d6dSopenharmony_ci            result.addElement(const_cast<UnicodeString *>(&r->idStr), status);
6482e5b6d6dSopenharmony_ci        } else {
6492e5b6d6dSopenharmony_ci            LocalPointer<StringEnumeration> children(r->getContainedRegions(type, status));
6502e5b6d6dSopenharmony_ci            const char *id2;
6512e5b6d6dSopenharmony_ci            while(U_SUCCESS(status) && ((id2 = children->next(nullptr, status)) != nullptr)) {
6522e5b6d6dSopenharmony_ci                const Region *r2 = Region::getInstance(id2,status);
6532e5b6d6dSopenharmony_ci                result.addElement(const_cast<UnicodeString *>(&r2->idStr), status);
6542e5b6d6dSopenharmony_ci            }
6552e5b6d6dSopenharmony_ci        }
6562e5b6d6dSopenharmony_ci    }
6572e5b6d6dSopenharmony_ci    LocalPointer<StringEnumeration> resultEnumeration(
6582e5b6d6dSopenharmony_ci        new RegionNameEnumeration(&result, status), status);
6592e5b6d6dSopenharmony_ci    return U_SUCCESS(status) ? resultEnumeration.orphan() : nullptr;
6602e5b6d6dSopenharmony_ci}
6612e5b6d6dSopenharmony_ci
6622e5b6d6dSopenharmony_ci/**
6632e5b6d6dSopenharmony_ci * Returns true if this region contains the supplied other region anywhere in the region hierarchy.
6642e5b6d6dSopenharmony_ci */
6652e5b6d6dSopenharmony_ciUBool
6662e5b6d6dSopenharmony_ciRegion::contains(const Region &other) const {
6672e5b6d6dSopenharmony_ci    UErrorCode status = U_ZERO_ERROR;
6682e5b6d6dSopenharmony_ci    umtx_initOnce(gRegionDataInitOnce, &loadRegionData, status);
6692e5b6d6dSopenharmony_ci
6702e5b6d6dSopenharmony_ci    if (!containedRegions) {
6712e5b6d6dSopenharmony_ci          return false;
6722e5b6d6dSopenharmony_ci    }
6732e5b6d6dSopenharmony_ci    if (containedRegions->contains((void *)&other.idStr)) {
6742e5b6d6dSopenharmony_ci        return true;
6752e5b6d6dSopenharmony_ci    } else {
6762e5b6d6dSopenharmony_ci        for ( int32_t i = 0 ; i < containedRegions->size() ; i++ ) {
6772e5b6d6dSopenharmony_ci            UnicodeString *crStr = (UnicodeString *)containedRegions->elementAt(i);
6782e5b6d6dSopenharmony_ci            Region *cr = (Region *) uhash_get(regionIDMap,(void *)crStr);
6792e5b6d6dSopenharmony_ci            if ( cr && cr->contains(other) ) {
6802e5b6d6dSopenharmony_ci                return true;
6812e5b6d6dSopenharmony_ci            }
6822e5b6d6dSopenharmony_ci        }
6832e5b6d6dSopenharmony_ci    }
6842e5b6d6dSopenharmony_ci
6852e5b6d6dSopenharmony_ci    return false;
6862e5b6d6dSopenharmony_ci}
6872e5b6d6dSopenharmony_ci
6882e5b6d6dSopenharmony_ci/**
6892e5b6d6dSopenharmony_ci * For deprecated regions, return an enumeration over the IDs of the regions that are the preferred replacement
6902e5b6d6dSopenharmony_ci * regions for this region.  Returns NULL for a non-deprecated region.  For example, calling this method with region
6912e5b6d6dSopenharmony_ci * "SU" (Soviet Union) would return a list of the regions containing "RU" (Russia), "AM" (Armenia), "AZ" (Azerbaijan), etc...
6922e5b6d6dSopenharmony_ci */
6932e5b6d6dSopenharmony_ciStringEnumeration*
6942e5b6d6dSopenharmony_ciRegion::getPreferredValues(UErrorCode &status) const {
6952e5b6d6dSopenharmony_ci    umtx_initOnce(gRegionDataInitOnce, &loadRegionData, status); // returns immediately if U_FAILURE(status)
6962e5b6d6dSopenharmony_ci    if (U_FAILURE(status) || fType != URGN_DEPRECATED) {
6972e5b6d6dSopenharmony_ci        return NULL;
6982e5b6d6dSopenharmony_ci    }
6992e5b6d6dSopenharmony_ci    return new RegionNameEnumeration(preferredValues,status);
7002e5b6d6dSopenharmony_ci}
7012e5b6d6dSopenharmony_ci
7022e5b6d6dSopenharmony_ci
7032e5b6d6dSopenharmony_ci/**
7042e5b6d6dSopenharmony_ci * Return this region's canonical region code.
7052e5b6d6dSopenharmony_ci */
7062e5b6d6dSopenharmony_ciconst char*
7072e5b6d6dSopenharmony_ciRegion::getRegionCode() const {
7082e5b6d6dSopenharmony_ci    return id;
7092e5b6d6dSopenharmony_ci}
7102e5b6d6dSopenharmony_ci
7112e5b6d6dSopenharmony_ciint32_t
7122e5b6d6dSopenharmony_ciRegion::getNumericCode() const {
7132e5b6d6dSopenharmony_ci    return code;
7142e5b6d6dSopenharmony_ci}
7152e5b6d6dSopenharmony_ci
7162e5b6d6dSopenharmony_ci/**
7172e5b6d6dSopenharmony_ci * Returns the region type of this region.
7182e5b6d6dSopenharmony_ci */
7192e5b6d6dSopenharmony_ciURegionType
7202e5b6d6dSopenharmony_ciRegion::getType() const {
7212e5b6d6dSopenharmony_ci    return fType;
7222e5b6d6dSopenharmony_ci}
7232e5b6d6dSopenharmony_ci
7242e5b6d6dSopenharmony_ciRegionNameEnumeration::RegionNameEnumeration(UVector *nameList, UErrorCode& status) :
7252e5b6d6dSopenharmony_ci        pos(0), fRegionNames(nullptr) {
7262e5b6d6dSopenharmony_ci    // TODO: https://unicode-org.atlassian.net/browse/ICU-21829
7272e5b6d6dSopenharmony_ci    // Is all of the copying going on here really necessary?
7282e5b6d6dSopenharmony_ci    if (nameList && U_SUCCESS(status)) {
7292e5b6d6dSopenharmony_ci        LocalPointer<UVector> regionNames(
7302e5b6d6dSopenharmony_ci            new UVector(uprv_deleteUObject, uhash_compareUnicodeString, nameList->size(), status), status);
7312e5b6d6dSopenharmony_ci        for ( int32_t i = 0 ; U_SUCCESS(status) && i < nameList->size() ; i++ ) {
7322e5b6d6dSopenharmony_ci            UnicodeString* this_region_name = (UnicodeString *)nameList->elementAt(i);
7332e5b6d6dSopenharmony_ci            LocalPointer<UnicodeString> new_region_name(new UnicodeString(*this_region_name), status);
7342e5b6d6dSopenharmony_ci            regionNames->adoptElement(new_region_name.orphan(), status);
7352e5b6d6dSopenharmony_ci        }
7362e5b6d6dSopenharmony_ci        if (U_SUCCESS(status)) {
7372e5b6d6dSopenharmony_ci            fRegionNames = regionNames.orphan();
7382e5b6d6dSopenharmony_ci        }
7392e5b6d6dSopenharmony_ci    }
7402e5b6d6dSopenharmony_ci}
7412e5b6d6dSopenharmony_ci
7422e5b6d6dSopenharmony_ciconst UnicodeString*
7432e5b6d6dSopenharmony_ciRegionNameEnumeration::snext(UErrorCode& status) {
7442e5b6d6dSopenharmony_ci  if (U_FAILURE(status) || (fRegionNames==NULL)) {
7452e5b6d6dSopenharmony_ci    return NULL;
7462e5b6d6dSopenharmony_ci  }
7472e5b6d6dSopenharmony_ci  const UnicodeString* nextStr = (const UnicodeString *)fRegionNames->elementAt(pos);
7482e5b6d6dSopenharmony_ci  if (nextStr!=NULL) {
7492e5b6d6dSopenharmony_ci    pos++;
7502e5b6d6dSopenharmony_ci  }
7512e5b6d6dSopenharmony_ci  return nextStr;
7522e5b6d6dSopenharmony_ci}
7532e5b6d6dSopenharmony_ci
7542e5b6d6dSopenharmony_civoid
7552e5b6d6dSopenharmony_ciRegionNameEnumeration::reset(UErrorCode& /*status*/) {
7562e5b6d6dSopenharmony_ci    pos=0;
7572e5b6d6dSopenharmony_ci}
7582e5b6d6dSopenharmony_ci
7592e5b6d6dSopenharmony_ciint32_t
7602e5b6d6dSopenharmony_ciRegionNameEnumeration::count(UErrorCode& /*status*/) const {
7612e5b6d6dSopenharmony_ci    return (fRegionNames==NULL) ? 0 : fRegionNames->size();
7622e5b6d6dSopenharmony_ci}
7632e5b6d6dSopenharmony_ci
7642e5b6d6dSopenharmony_ciRegionNameEnumeration::~RegionNameEnumeration() {
7652e5b6d6dSopenharmony_ci    delete fRegionNames;
7662e5b6d6dSopenharmony_ci}
7672e5b6d6dSopenharmony_ci
7682e5b6d6dSopenharmony_ciU_NAMESPACE_END
7692e5b6d6dSopenharmony_ci
7702e5b6d6dSopenharmony_ci#endif /* #if !UCONFIG_NO_FORMATTING */
7712e5b6d6dSopenharmony_ci
7722e5b6d6dSopenharmony_ci//eof
773