1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 *******************************************************************************
5 * Copyright (C) 2014-2016, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 *******************************************************************************
12 * Modification History:*
13 * Date Name Description
14 * 01/15/13 Emmons Original Port from ICU4J
15 ********************************************************************************
20 * \brief C++ API: Region classes (territory containment)
23 #include "unicode/region.h"
24 #include "unicode/utypes.h"
25 #include "unicode/uobject.h"
26 #include "unicode/unistr.h"
27 #include "unicode/ures.h"
34 #include "region_impl.h"
37 #if !UCONFIG_NO_FORMATTING
42 static void U_CALLCONV
43 deleteRegion(void *obj
) {
44 delete (icu::Region
*)obj
;
48 * Cleanup callback func
50 static UBool U_CALLCONV
region_cleanup(void)
52 icu::Region::cleanupRegionData();
61 static UInitOnce gRegionDataInitOnce
= U_INITONCE_INITIALIZER
;
62 static UVector
* availableRegions
[URGN_LIMIT
];
64 static UHashtable
*regionAliases
= NULL
;
65 static UHashtable
*regionIDMap
= NULL
;
66 static UHashtable
*numericCodeMap
= NULL
;
67 static UVector
*allRegions
= NULL
;
69 static const UChar UNKNOWN_REGION_ID
[] = { 0x5A, 0x5A, 0 }; /* "ZZ" */
70 static const UChar OUTLYING_OCEANIA_REGION_ID
[] = { 0x51, 0x4F, 0 }; /* "QO" */
71 static const UChar WORLD_ID
[] = { 0x30, 0x30, 0x31, 0 }; /* "001" */
72 static const UChar RANGE_MARKER
= 0x7E; /* '~' */
74 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RegionNameEnumeration
)
77 * Initializes the region data from the ICU resource bundles. The region data
78 * contains the basic relationships such as which regions are known, what the numeric
79 * codes are, any known aliases, and the territory containment data.
81 * If the region data has already loaded, then this method simply returns without doing
82 * anything meaningful.
84 void U_CALLCONV
Region::loadRegionData(UErrorCode
&status
) {
86 // Construct service objs first
87 LocalUHashtablePointer
newRegionIDMap(uhash_open(uhash_hashUnicodeString
, uhash_compareUnicodeString
, NULL
, &status
));
88 LocalUHashtablePointer
newNumericCodeMap(uhash_open(uhash_hashLong
,uhash_compareLong
,NULL
,&status
));
89 LocalUHashtablePointer
newRegionAliases(uhash_open(uhash_hashUnicodeString
,uhash_compareUnicodeString
,NULL
,&status
));
91 LocalPointer
<UVector
> continents(new UVector(uprv_deleteUObject
, uhash_compareUnicodeString
, status
), status
);
92 LocalPointer
<UVector
> groupings(new UVector(uprv_deleteUObject
, uhash_compareUnicodeString
, status
), status
);
93 allRegions
= new UVector(uprv_deleteUObject
, uhash_compareUnicodeString
, status
);
95 LocalUResourceBundlePointer
metadata(ures_openDirect(NULL
,"metadata",&status
));
96 LocalUResourceBundlePointer
metadataAlias(ures_getByKey(metadata
.getAlias(),"alias",NULL
,&status
));
97 LocalUResourceBundlePointer
territoryAlias(ures_getByKey(metadataAlias
.getAlias(),"territory",NULL
,&status
));
99 LocalUResourceBundlePointer
supplementalData(ures_openDirect(NULL
,"supplementalData",&status
));
100 LocalUResourceBundlePointer
codeMappings(ures_getByKey(supplementalData
.getAlias(),"codeMappings",NULL
,&status
));
102 LocalUResourceBundlePointer
idValidity(ures_getByKey(supplementalData
.getAlias(),"idValidity",NULL
,&status
));
103 LocalUResourceBundlePointer
regionList(ures_getByKey(idValidity
.getAlias(),"region",NULL
,&status
));
104 LocalUResourceBundlePointer
regionRegular(ures_getByKey(regionList
.getAlias(),"regular",NULL
,&status
));
105 LocalUResourceBundlePointer
regionMacro(ures_getByKey(regionList
.getAlias(),"macroregion",NULL
,&status
));
106 LocalUResourceBundlePointer
regionUnknown(ures_getByKey(regionList
.getAlias(),"unknown",NULL
,&status
));
108 LocalUResourceBundlePointer
territoryContainment(ures_getByKey(supplementalData
.getAlias(),"territoryContainment",NULL
,&status
));
109 LocalUResourceBundlePointer
worldContainment(ures_getByKey(territoryContainment
.getAlias(),"001",NULL
,&status
));
110 LocalUResourceBundlePointer
groupingContainment(ures_getByKey(territoryContainment
.getAlias(),"grouping",NULL
,&status
));
112 if (U_FAILURE(status
)) {
117 uhash_setValueDeleter(newRegionIDMap
.getAlias(), deleteRegion
); // regionIDMap owns objs
118 uhash_setKeyDeleter(newRegionAliases
.getAlias(), uprv_deleteUObject
); // regionAliases owns the string keys
121 while ( ures_hasNext(regionRegular
.getAlias()) ) {
122 UnicodeString regionName
= ures_getNextUnicodeString(regionRegular
.getAlias(),NULL
,&status
);
123 int32_t rangeMarkerLocation
= regionName
.indexOf(RANGE_MARKER
);
125 regionName
.extract(buf
,6,status
);
126 if ( rangeMarkerLocation
> 0 ) {
127 UChar endRange
= regionName
.charAt(rangeMarkerLocation
+1);
128 buf
[rangeMarkerLocation
] = 0;
129 while ( buf
[rangeMarkerLocation
-1] <= endRange
) {
130 LocalPointer
<UnicodeString
> newRegion(new UnicodeString(buf
), status
);
131 allRegions
->addElement(newRegion
.orphan(),status
);
132 buf
[rangeMarkerLocation
-1]++;
135 LocalPointer
<UnicodeString
> newRegion(new UnicodeString(regionName
), status
);
136 allRegions
->addElement(newRegion
.orphan(),status
);
140 while ( ures_hasNext(regionMacro
.getAlias()) ) {
141 UnicodeString regionName
= ures_getNextUnicodeString(regionMacro
.getAlias(),NULL
,&status
);
142 int32_t rangeMarkerLocation
= regionName
.indexOf(RANGE_MARKER
);
144 regionName
.extract(buf
,6,status
);
145 if ( rangeMarkerLocation
> 0 ) {
146 UChar endRange
= regionName
.charAt(rangeMarkerLocation
+1);
147 buf
[rangeMarkerLocation
] = 0;
148 while ( buf
[rangeMarkerLocation
-1] <= endRange
) {
149 LocalPointer
<UnicodeString
> newRegion(new UnicodeString(buf
), status
);
150 allRegions
->addElement(newRegion
.orphan(),status
);
151 buf
[rangeMarkerLocation
-1]++;
154 LocalPointer
<UnicodeString
> newRegion(new UnicodeString(regionName
), status
);
155 allRegions
->addElement(newRegion
.orphan(),status
);
159 while ( ures_hasNext(regionUnknown
.getAlias()) ) {
160 LocalPointer
<UnicodeString
> regionName (new UnicodeString(ures_getNextUnicodeString(regionUnknown
.getAlias(),NULL
,&status
),status
));
161 allRegions
->addElement(regionName
.orphan(),status
);
164 while ( ures_hasNext(worldContainment
.getAlias()) ) {
165 UnicodeString
*continentName
= new UnicodeString(ures_getNextUnicodeString(worldContainment
.getAlias(),NULL
,&status
));
166 continents
->addElement(continentName
,status
);
169 UResourceBundle
*groupingBundle
= nullptr;
170 while ( ures_hasNext(groupingContainment
.getAlias()) ) {
171 groupingBundle
= ures_getNextResource(groupingContainment
.getAlias(), groupingBundle
, &status
);
172 if (U_FAILURE(status
)) {
175 UnicodeString
*groupingName
= new UnicodeString(ures_getKey(groupingBundle
), -1, US_INV
);
177 groupings
->addElement(groupingName
,status
);
180 ures_close(groupingBundle
);
182 for ( int32_t i
= 0 ; i
< allRegions
->size() ; i
++ ) {
183 LocalPointer
<Region
> r(new Region(), status
);
184 if ( U_FAILURE(status
) ) {
187 UnicodeString
*regionName
= (UnicodeString
*)allRegions
->elementAt(i
);
188 r
->idStr
= *regionName
;
190 r
->idStr
.extract(0,r
->idStr
.length(),r
->id
,sizeof(r
->id
),US_INV
);
191 r
->fType
= URGN_TERRITORY
; // Only temporary - figure out the real type later once the aliases are known.
194 int32_t result
= ICU_Utility::parseAsciiInteger(r
->idStr
, pos
);
196 r
->code
= result
; // Convert string to number
197 uhash_iput(newNumericCodeMap
.getAlias(),r
->code
,(void *)(r
.getAlias()),&status
);
198 r
->fType
= URGN_SUBCONTINENT
;
202 void* idStrAlias
= (void*)&(r
->idStr
); // about to orphan 'r'. Save this off.
203 uhash_put(newRegionIDMap
.getAlias(),idStrAlias
,(void *)(r
.orphan()),&status
); // regionIDMap takes ownership
206 // Process the territory aliases
207 while ( ures_hasNext(territoryAlias
.getAlias()) ) {
208 LocalUResourceBundlePointer
res(ures_getNextResource(territoryAlias
.getAlias(),NULL
,&status
));
209 const char *aliasFrom
= ures_getKey(res
.getAlias());
210 LocalPointer
<UnicodeString
> aliasFromStr(new UnicodeString(aliasFrom
, -1, US_INV
), status
);
211 UnicodeString aliasTo
= ures_getUnicodeStringByKey(res
.getAlias(),"replacement",&status
);
212 res
.adoptInstead(NULL
);
214 const Region
*aliasToRegion
= (Region
*) uhash_get(newRegionIDMap
.getAlias(),&aliasTo
);
215 Region
*aliasFromRegion
= (Region
*)uhash_get(newRegionIDMap
.getAlias(),aliasFromStr
.getAlias());
217 if ( aliasToRegion
!= NULL
&& aliasFromRegion
== NULL
) { // This is just an alias from some string to a region
218 uhash_put(newRegionAliases
.getAlias(),(void *)aliasFromStr
.orphan(), (void *)aliasToRegion
,&status
);
220 if ( aliasFromRegion
== NULL
) { // Deprecated region code not in the master codes list - so need to create a deprecated region for it.
221 LocalPointer
<Region
> newRgn(new Region
, status
);
222 if ( U_SUCCESS(status
) ) {
223 aliasFromRegion
= newRgn
.orphan();
227 aliasFromRegion
->idStr
.setTo(*aliasFromStr
);
228 aliasFromRegion
->idStr
.extract(0,aliasFromRegion
->idStr
.length(),aliasFromRegion
->id
,sizeof(aliasFromRegion
->id
),US_INV
);
229 uhash_put(newRegionIDMap
.getAlias(),(void *)&(aliasFromRegion
->idStr
),(void *)aliasFromRegion
,&status
);
231 int32_t result
= ICU_Utility::parseAsciiInteger(aliasFromRegion
->idStr
, pos
);
233 aliasFromRegion
->code
= result
; // Convert string to number
234 uhash_iput(newNumericCodeMap
.getAlias(),aliasFromRegion
->code
,(void *)aliasFromRegion
,&status
);
236 aliasFromRegion
->code
= -1;
238 aliasFromRegion
->fType
= URGN_DEPRECATED
;
240 aliasFromRegion
->fType
= URGN_DEPRECATED
;
244 LocalPointer
<UVector
> newPreferredValues(new UVector(uprv_deleteUObject
, uhash_compareUnicodeString
, status
), status
);
245 aliasFromRegion
->preferredValues
= newPreferredValues
.orphan();
247 if( U_FAILURE(status
)) {
250 UnicodeString currentRegion
;
251 //currentRegion.remove(); TODO: was already 0 length?
252 for (int32_t i
= 0 ; i
< aliasTo
.length() ; i
++ ) {
253 if ( aliasTo
.charAt(i
) != 0x0020 ) {
254 currentRegion
.append(aliasTo
.charAt(i
));
256 if ( aliasTo
.charAt(i
) == 0x0020 || i
+1 == aliasTo
.length() ) {
257 Region
*target
= (Region
*)uhash_get(newRegionIDMap
.getAlias(),(void *)¤tRegion
);
259 LocalPointer
<UnicodeString
> preferredValue(new UnicodeString(target
->idStr
), status
);
260 aliasFromRegion
->preferredValues
->addElement((void *)preferredValue
.orphan(),status
); // may add null if err
262 currentRegion
.remove();
268 // Process the code mappings - This will allow us to assign numeric codes to most of the territories.
269 while ( ures_hasNext(codeMappings
.getAlias()) ) {
270 UResourceBundle
*mapping
= ures_getNextResource(codeMappings
.getAlias(),NULL
,&status
);
271 if ( ures_getType(mapping
) == URES_ARRAY
&& ures_getSize(mapping
) == 3) {
272 UnicodeString codeMappingID
= ures_getUnicodeStringByIndex(mapping
,0,&status
);
273 UnicodeString codeMappingNumber
= ures_getUnicodeStringByIndex(mapping
,1,&status
);
274 UnicodeString codeMapping3Letter
= ures_getUnicodeStringByIndex(mapping
,2,&status
);
276 Region
*r
= (Region
*)uhash_get(newRegionIDMap
.getAlias(),(void *)&codeMappingID
);
279 int32_t result
= ICU_Utility::parseAsciiInteger(codeMappingNumber
, pos
);
281 r
->code
= result
; // Convert string to number
282 uhash_iput(newNumericCodeMap
.getAlias(),r
->code
,(void *)r
,&status
);
284 LocalPointer
<UnicodeString
> code3(new UnicodeString(codeMapping3Letter
), status
);
285 uhash_put(newRegionAliases
.getAlias(),(void *)code3
.orphan(), (void *)r
,&status
);
291 // Now fill in the special cases for WORLD, UNKNOWN, CONTINENTS, and GROUPINGS
293 UnicodeString
WORLD_ID_STRING(WORLD_ID
);
294 r
= (Region
*) uhash_get(newRegionIDMap
.getAlias(),(void *)&WORLD_ID_STRING
);
296 r
->fType
= URGN_WORLD
;
299 UnicodeString
UNKNOWN_REGION_ID_STRING(UNKNOWN_REGION_ID
);
300 r
= (Region
*) uhash_get(newRegionIDMap
.getAlias(),(void *)&UNKNOWN_REGION_ID_STRING
);
302 r
->fType
= URGN_UNKNOWN
;
305 for ( int32_t i
= 0 ; i
< continents
->size() ; i
++ ) {
306 r
= (Region
*) uhash_get(newRegionIDMap
.getAlias(),(void *)continents
->elementAt(i
));
308 r
->fType
= URGN_CONTINENT
;
312 for ( int32_t i
= 0 ; i
< groupings
->size() ; i
++ ) {
313 r
= (Region
*) uhash_get(newRegionIDMap
.getAlias(),(void *)groupings
->elementAt(i
));
315 r
->fType
= URGN_GROUPING
;
319 // Special case: The region code "QO" (Outlying Oceania) is a subcontinent code added by CLDR
320 // even though it looks like a territory code. Need to handle it here.
322 UnicodeString
OUTLYING_OCEANIA_REGION_ID_STRING(OUTLYING_OCEANIA_REGION_ID
);
323 r
= (Region
*) uhash_get(newRegionIDMap
.getAlias(),(void *)&OUTLYING_OCEANIA_REGION_ID_STRING
);
325 r
->fType
= URGN_SUBCONTINENT
;
328 // Load territory containment info from the supplemental data.
329 while ( ures_hasNext(territoryContainment
.getAlias()) ) {
330 LocalUResourceBundlePointer
mapping(ures_getNextResource(territoryContainment
.getAlias(),NULL
,&status
));
331 if( U_FAILURE(status
) ) {
334 const char *parent
= ures_getKey(mapping
.getAlias());
335 if (uprv_strcmp(parent
, "containedGroupings") == 0 || uprv_strcmp(parent
, "deprecated") == 0) {
336 continue; // handle new pseudo-parent types added in ICU data per cldrbug 7808; for now just skip.
337 // #11232 is to do something useful with these.
339 UnicodeString parentStr
= UnicodeString(parent
, -1 , US_INV
);
340 Region
*parentRegion
= (Region
*) uhash_get(newRegionIDMap
.getAlias(),(void *)&parentStr
);
342 for ( int j
= 0 ; j
< ures_getSize(mapping
.getAlias()); j
++ ) {
343 UnicodeString child
= ures_getUnicodeStringByIndex(mapping
.getAlias(),j
,&status
);
344 Region
*childRegion
= (Region
*) uhash_get(newRegionIDMap
.getAlias(),(void *)&child
);
345 if ( parentRegion
!= NULL
&& childRegion
!= NULL
) {
347 // Add the child region to the set of regions contained by the parent
348 if (parentRegion
->containedRegions
== NULL
) {
349 parentRegion
->containedRegions
= new UVector(uprv_deleteUObject
, uhash_compareUnicodeString
, status
);
352 LocalPointer
<UnicodeString
> childStr(new UnicodeString(), status
);
353 if( U_FAILURE(status
) ) {
356 childStr
->fastCopyFrom(childRegion
->idStr
);
357 parentRegion
->containedRegions
->addElement((void *)childStr
.orphan(),status
);
359 // Set the parent region to be the containing region of the child.
360 // Regions of type GROUPING can't be set as the parent, since another region
361 // such as a SUBCONTINENT, CONTINENT, or WORLD must always be the parent.
362 if ( parentRegion
->fType
!= URGN_GROUPING
) {
363 childRegion
->containingRegion
= parentRegion
;
369 // Create the availableRegions lists
370 int32_t pos
= UHASH_FIRST
;
371 while ( const UHashElement
* element
= uhash_nextElement(newRegionIDMap
.getAlias(),&pos
)) {
372 Region
*ar
= (Region
*)element
->value
.pointer
;
373 if ( availableRegions
[ar
->fType
] == NULL
) {
374 LocalPointer
<UVector
> newAr(new UVector(uprv_deleteUObject
, uhash_compareUnicodeString
, status
), status
);
375 availableRegions
[ar
->fType
] = newAr
.orphan();
377 LocalPointer
<UnicodeString
> arString(new UnicodeString(ar
->idStr
), status
);
378 if( U_FAILURE(status
) ) {
381 availableRegions
[ar
->fType
]->addElement((void *)arString
.orphan(),status
);
384 ucln_i18n_registerCleanup(UCLN_I18N_REGION
, region_cleanup
);
386 numericCodeMap
= newNumericCodeMap
.orphan();
387 regionIDMap
= newRegionIDMap
.orphan();
388 regionAliases
= newRegionAliases
.orphan();
391 void Region::cleanupRegionData() {
392 for (int32_t i
= 0 ; i
< URGN_LIMIT
; i
++ ) {
393 if ( availableRegions
[i
] ) {
394 delete availableRegions
[i
];
399 uhash_close(regionAliases
);
402 if (numericCodeMap
) {
403 uhash_close(numericCodeMap
);
407 uhash_close(regionIDMap
);
410 allRegions
->removeAllElements(); // Don't need the temporary list anymore.
415 regionAliases
= numericCodeMap
= regionIDMap
= NULL
;
417 gRegionDataInitOnce
.reset();
423 containingRegion(NULL
),
424 containedRegions(NULL
),
425 preferredValues(NULL
) {
430 if (containedRegions
) {
431 delete containedRegions
;
433 if (preferredValues
) {
434 delete preferredValues
;
439 * Returns true if the two regions are equal.
440 * Per PMC, just use pointer compare, since we have at most one instance of each Region.
443 Region::operator==(const Region
&that
) const {
444 return (idStr
== that
.idStr
);
448 * Returns true if the two regions are NOT equal; that is, if operator ==() returns false.
449 * Per PMC, just use pointer compare, since we have at most one instance of each Region.
452 Region::operator!=(const Region
&that
) const {
453 return (idStr
!= that
.idStr
);
457 * Returns a pointer to a Region using the given region code. The region code can be either 2-letter ISO code,
458 * 3-letter ISO code, UNM.49 numeric code, or other valid Unicode Region Code as defined by the LDML specification.
459 * The identifier will be canonicalized internally using the supplemental metadata as defined in the CLDR.
460 * If the region code is NULL or not recognized, the appropriate error code will be set ( U_ILLEGAL_ARGUMENT_ERROR )
462 const Region
* U_EXPORT2
463 Region::getInstance(const char *region_code
, UErrorCode
&status
) {
465 umtx_initOnce(gRegionDataInitOnce
, &loadRegionData
, status
);
466 if (U_FAILURE(status
)) {
470 if ( !region_code
) {
471 status
= U_ILLEGAL_ARGUMENT_ERROR
;
475 UnicodeString regionCodeString
= UnicodeString(region_code
, -1, US_INV
);
476 Region
*r
= (Region
*)uhash_get(regionIDMap
,(void *)®ionCodeString
);
479 r
= (Region
*)uhash_get(regionAliases
,(void *)®ionCodeString
);
482 if ( !r
) { // Unknown region code
483 status
= U_ILLEGAL_ARGUMENT_ERROR
;
487 if ( r
->fType
== URGN_DEPRECATED
&& r
->preferredValues
->size() == 1) {
488 StringEnumeration
*pv
= r
->getPreferredValues(status
);
490 const UnicodeString
*ustr
= pv
->snext(status
);
491 r
= (Region
*)uhash_get(regionIDMap
,(void *)ustr
);
500 * Returns a pointer to a Region using the given numeric region code. If the numeric region code is not recognized,
501 * the appropriate error code will be set ( U_ILLEGAL_ARGUMENT_ERROR ).
503 const Region
* U_EXPORT2
504 Region::getInstance (int32_t code
, UErrorCode
&status
) {
506 umtx_initOnce(gRegionDataInitOnce
, &loadRegionData
, status
);
507 if (U_FAILURE(status
)) {
511 Region
*r
= (Region
*)uhash_iget(numericCodeMap
,code
);
513 if ( !r
) { // Just in case there's an alias that's numeric, try to find it.
515 ICU_Utility::appendNumber(id
, code
, 10, 1);
516 r
= (Region
*)uhash_get(regionAliases
,&id
);
519 if( U_FAILURE(status
) ) {
524 status
= U_ILLEGAL_ARGUMENT_ERROR
;
528 if ( r
->fType
== URGN_DEPRECATED
&& r
->preferredValues
->size() == 1) {
529 StringEnumeration
*pv
= r
->getPreferredValues(status
);
531 const UnicodeString
*ustr
= pv
->snext(status
);
532 r
= (Region
*)uhash_get(regionIDMap
,(void *)ustr
);
541 * Returns an enumeration over the IDs of all known regions that match the given type.
543 StringEnumeration
* U_EXPORT2
544 Region::getAvailable(URegionType type
, UErrorCode
&status
) {
545 umtx_initOnce(gRegionDataInitOnce
, &loadRegionData
, status
); // returns immediately if U_FAILURE(status)
546 if (U_FAILURE(status
)) {
549 return new RegionNameEnumeration(availableRegions
[type
],status
);
553 * Returns a pointer to the region that contains this region. Returns NULL if this region is code "001" (World)
554 * or "ZZ" (Unknown region). For example, calling this method with region "IT" (Italy) returns the
555 * region "039" (Southern Europe).
558 Region::getContainingRegion() const {
559 UErrorCode status
= U_ZERO_ERROR
;
560 umtx_initOnce(gRegionDataInitOnce
, &loadRegionData
, status
);
561 return containingRegion
;
565 * Return a pointer to the region that geographically contains this region and matches the given type,
566 * moving multiple steps up the containment chain if necessary. Returns NULL if no containing region can be found
567 * that matches the given type. Note: The URegionTypes = "URGN_GROUPING", "URGN_DEPRECATED", or "URGN_UNKNOWN"
568 * are not appropriate for use in this API. NULL will be returned in this case. For example, calling this method
569 * with region "IT" (Italy) for type "URGN_CONTINENT" returns the region "150" ( Europe ).
572 Region::getContainingRegion(URegionType type
) const {
573 UErrorCode status
= U_ZERO_ERROR
;
574 umtx_initOnce(gRegionDataInitOnce
, &loadRegionData
, status
);
575 if ( containingRegion
== NULL
) {
579 return ( containingRegion
->fType
== type
)? containingRegion
: containingRegion
->getContainingRegion(type
);
583 * Return an enumeration over the IDs of all the regions that are immediate children of this region in the
584 * region hierarchy. These returned regions could be either macro regions, territories, or a mixture of the two,
585 * depending on the containment data as defined in CLDR. This API may return NULL if this region doesn't have
586 * any sub-regions. For example, calling this method with region "150" (Europe) returns an enumeration containing
587 * the various sub regions of Europe - "039" (Southern Europe) - "151" (Eastern Europe) - "154" (Northern Europe)
588 * and "155" (Western Europe).
591 Region::getContainedRegions(UErrorCode
&status
) const {
592 umtx_initOnce(gRegionDataInitOnce
, &loadRegionData
, status
); // returns immediately if U_FAILURE(status)
593 if (U_FAILURE(status
)) {
596 return new RegionNameEnumeration(containedRegions
,status
);
600 * Returns an enumeration over the IDs of all the regions that are children of this region anywhere in the region
601 * hierarchy and match the given type. This API may return an empty enumeration if this region doesn't have any
602 * sub-regions that match the given type. For example, calling this method with region "150" (Europe) and type
603 * "URGN_TERRITORY" returns a set containing all the territories in Europe ( "FR" (France) - "IT" (Italy) - "DE" (Germany) etc. )
606 Region::getContainedRegions( URegionType type
, UErrorCode
&status
) const {
607 umtx_initOnce(gRegionDataInitOnce
, &loadRegionData
, status
); // returns immediately if U_FAILURE(status)
608 if (U_FAILURE(status
)) {
612 UVector
*result
= new UVector(NULL
, uhash_compareChars
, status
);
614 StringEnumeration
*cr
= getContainedRegions(status
);
616 for ( int32_t i
= 0 ; i
< cr
->count(status
) ; i
++ ) {
617 const char *regionId
= cr
->next(NULL
,status
);
618 const Region
*r
= Region::getInstance(regionId
,status
);
619 if ( r
->getType() == type
) {
620 result
->addElement((void *)&r
->idStr
,status
);
622 StringEnumeration
*children
= r
->getContainedRegions(type
, status
);
623 for ( int32_t j
= 0 ; j
< children
->count(status
) ; j
++ ) {
624 const char *id2
= children
->next(NULL
,status
);
625 const Region
*r2
= Region::getInstance(id2
,status
);
626 result
->addElement((void *)&r2
->idStr
,status
);
632 StringEnumeration
* resultEnumeration
= new RegionNameEnumeration(result
,status
);
634 return resultEnumeration
;
638 * Returns true if this region contains the supplied other region anywhere in the region hierarchy.
641 Region::contains(const Region
&other
) const {
642 UErrorCode status
= U_ZERO_ERROR
;
643 umtx_initOnce(gRegionDataInitOnce
, &loadRegionData
, status
);
645 if (!containedRegions
) {
648 if (containedRegions
->contains((void *)&other
.idStr
)) {
651 for ( int32_t i
= 0 ; i
< containedRegions
->size() ; i
++ ) {
652 UnicodeString
*crStr
= (UnicodeString
*)containedRegions
->elementAt(i
);
653 Region
*cr
= (Region
*) uhash_get(regionIDMap
,(void *)crStr
);
654 if ( cr
&& cr
->contains(other
) ) {
664 * For deprecated regions, return an enumeration over the IDs of the regions that are the preferred replacement
665 * regions for this region. Returns NULL for a non-deprecated region. For example, calling this method with region
666 * "SU" (Soviet Union) would return a list of the regions containing "RU" (Russia), "AM" (Armenia), "AZ" (Azerbaijan), etc...
669 Region::getPreferredValues(UErrorCode
&status
) const {
670 umtx_initOnce(gRegionDataInitOnce
, &loadRegionData
, status
); // returns immediately if U_FAILURE(status)
671 if (U_FAILURE(status
) || fType
!= URGN_DEPRECATED
) {
674 return new RegionNameEnumeration(preferredValues
,status
);
679 * Return this region's canonical region code.
682 Region::getRegionCode() const {
687 Region::getNumericCode() const {
692 * Returns the region type of this region.
695 Region::getType() const {
699 RegionNameEnumeration::RegionNameEnumeration(UVector
*fNameList
, UErrorCode
& status
) {
701 if (fNameList
&& U_SUCCESS(status
)) {
702 fRegionNames
= new UVector(uprv_deleteUObject
, uhash_compareUnicodeString
, fNameList
->size(),status
);
703 for ( int32_t i
= 0 ; i
< fNameList
->size() ; i
++ ) {
704 UnicodeString
* this_region_name
= (UnicodeString
*)fNameList
->elementAt(i
);
705 UnicodeString
* new_region_name
= new UnicodeString(*this_region_name
);
706 fRegionNames
->addElement((void *)new_region_name
,status
);
715 RegionNameEnumeration::snext(UErrorCode
& status
) {
716 if (U_FAILURE(status
) || (fRegionNames
==NULL
)) {
719 const UnicodeString
* nextStr
= (const UnicodeString
*)fRegionNames
->elementAt(pos
);
727 RegionNameEnumeration::reset(UErrorCode
& /*status*/) {
732 RegionNameEnumeration::count(UErrorCode
& /*status*/) const {
733 return (fRegionNames
==NULL
) ? 0 : fRegionNames
->size();
736 RegionNameEnumeration::~RegionNameEnumeration() {
742 #endif /* #if !UCONFIG_NO_FORMATTING */