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"
28 #include "unicode/decimfmt.h"
35 #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
));
90 LocalPointer
<DecimalFormat
> df(new DecimalFormat(status
), status
);
92 LocalPointer
<UVector
> continents(new UVector(uprv_deleteUObject
, uhash_compareUnicodeString
, status
), status
);
93 LocalPointer
<UVector
> groupings(new UVector(uprv_deleteUObject
, uhash_compareUnicodeString
, status
), status
);
94 allRegions
= new UVector(uprv_deleteUObject
, uhash_compareUnicodeString
, status
);
96 LocalUResourceBundlePointer
metadata(ures_openDirect(NULL
,"metadata",&status
));
97 LocalUResourceBundlePointer
metadataAlias(ures_getByKey(metadata
.getAlias(),"alias",NULL
,&status
));
98 LocalUResourceBundlePointer
territoryAlias(ures_getByKey(metadataAlias
.getAlias(),"territory",NULL
,&status
));
100 LocalUResourceBundlePointer
supplementalData(ures_openDirect(NULL
,"supplementalData",&status
));
101 LocalUResourceBundlePointer
codeMappings(ures_getByKey(supplementalData
.getAlias(),"codeMappings",NULL
,&status
));
103 LocalUResourceBundlePointer
idValidity(ures_getByKey(supplementalData
.getAlias(),"idValidity",NULL
,&status
));
104 LocalUResourceBundlePointer
regionList(ures_getByKey(idValidity
.getAlias(),"region",NULL
,&status
));
105 LocalUResourceBundlePointer
regionRegular(ures_getByKey(regionList
.getAlias(),"regular",NULL
,&status
));
106 LocalUResourceBundlePointer
regionMacro(ures_getByKey(regionList
.getAlias(),"macroregion",NULL
,&status
));
107 LocalUResourceBundlePointer
regionUnknown(ures_getByKey(regionList
.getAlias(),"unknown",NULL
,&status
));
109 LocalUResourceBundlePointer
territoryContainment(ures_getByKey(supplementalData
.getAlias(),"territoryContainment",NULL
,&status
));
110 LocalUResourceBundlePointer
worldContainment(ures_getByKey(territoryContainment
.getAlias(),"001",NULL
,&status
));
111 LocalUResourceBundlePointer
groupingContainment(ures_getByKey(territoryContainment
.getAlias(),"grouping",NULL
,&status
));
113 if (U_FAILURE(status
)) {
118 df
->setParseIntegerOnly(TRUE
);
119 uhash_setValueDeleter(newRegionIDMap
.getAlias(), deleteRegion
); // regionIDMap owns objs
120 uhash_setKeyDeleter(newRegionAliases
.getAlias(), uprv_deleteUObject
); // regionAliases owns the string keys
123 while ( ures_hasNext(regionRegular
.getAlias()) ) {
124 UnicodeString regionName
= ures_getNextUnicodeString(regionRegular
.getAlias(),NULL
,&status
);
125 int32_t rangeMarkerLocation
= regionName
.indexOf(RANGE_MARKER
);
127 regionName
.extract(buf
,6,status
);
128 if ( rangeMarkerLocation
> 0 ) {
129 UChar endRange
= regionName
.charAt(rangeMarkerLocation
+1);
130 buf
[rangeMarkerLocation
] = 0;
131 while ( buf
[rangeMarkerLocation
-1] <= endRange
) {
132 LocalPointer
<UnicodeString
> newRegion(new UnicodeString(buf
), status
);
133 allRegions
->addElement(newRegion
.orphan(),status
);
134 buf
[rangeMarkerLocation
-1]++;
137 LocalPointer
<UnicodeString
> newRegion(new UnicodeString(regionName
), status
);
138 allRegions
->addElement(newRegion
.orphan(),status
);
142 while ( ures_hasNext(regionMacro
.getAlias()) ) {
143 UnicodeString regionName
= ures_getNextUnicodeString(regionMacro
.getAlias(),NULL
,&status
);
144 int32_t rangeMarkerLocation
= regionName
.indexOf(RANGE_MARKER
);
146 regionName
.extract(buf
,6,status
);
147 if ( rangeMarkerLocation
> 0 ) {
148 UChar endRange
= regionName
.charAt(rangeMarkerLocation
+1);
149 buf
[rangeMarkerLocation
] = 0;
150 while ( buf
[rangeMarkerLocation
-1] <= endRange
) {
151 LocalPointer
<UnicodeString
> newRegion(new UnicodeString(buf
), status
);
152 allRegions
->addElement(newRegion
.orphan(),status
);
153 buf
[rangeMarkerLocation
-1]++;
156 LocalPointer
<UnicodeString
> newRegion(new UnicodeString(regionName
), status
);
157 allRegions
->addElement(newRegion
.orphan(),status
);
161 while ( ures_hasNext(regionUnknown
.getAlias()) ) {
162 LocalPointer
<UnicodeString
> regionName (new UnicodeString(ures_getNextUnicodeString(regionUnknown
.getAlias(),NULL
,&status
),status
));
163 allRegions
->addElement(regionName
.orphan(),status
);
166 while ( ures_hasNext(worldContainment
.getAlias()) ) {
167 UnicodeString
*continentName
= new UnicodeString(ures_getNextUnicodeString(worldContainment
.getAlias(),NULL
,&status
));
168 continents
->addElement(continentName
,status
);
171 UResourceBundle
*groupingBundle
= nullptr;
172 while ( ures_hasNext(groupingContainment
.getAlias()) ) {
173 groupingBundle
= ures_getNextResource(groupingContainment
.getAlias(), groupingBundle
, &status
);
174 if (U_FAILURE(status
)) {
177 UnicodeString
*groupingName
= new UnicodeString(ures_getKey(groupingBundle
), -1, US_INV
);
179 groupings
->addElement(groupingName
,status
);
182 ures_close(groupingBundle
);
184 for ( int32_t i
= 0 ; i
< allRegions
->size() ; i
++ ) {
185 LocalPointer
<Region
> r(new Region(), status
);
186 if ( U_FAILURE(status
) ) {
189 UnicodeString
*regionName
= (UnicodeString
*)allRegions
->elementAt(i
);
190 r
->idStr
= *regionName
;
192 r
->idStr
.extract(0,r
->idStr
.length(),r
->id
,sizeof(r
->id
),US_INV
);
193 r
->fType
= URGN_TERRITORY
; // Only temporary - figure out the real type later once the aliases are known.
196 UErrorCode ps
= U_ZERO_ERROR
;
197 df
->parse(r
->idStr
,result
,ps
);
198 if ( U_SUCCESS(ps
) ) {
199 r
->code
= result
.getLong(); // Convert string to number
200 uhash_iput(newNumericCodeMap
.getAlias(),r
->code
,(void *)(r
.getAlias()),&status
);
201 r
->fType
= URGN_SUBCONTINENT
;
205 void* idStrAlias
= (void*)&(r
->idStr
); // about to orphan 'r'. Save this off.
206 uhash_put(newRegionIDMap
.getAlias(),idStrAlias
,(void *)(r
.orphan()),&status
); // regionIDMap takes ownership
209 // Process the territory aliases
210 while ( ures_hasNext(territoryAlias
.getAlias()) ) {
211 LocalUResourceBundlePointer
res(ures_getNextResource(territoryAlias
.getAlias(),NULL
,&status
));
212 const char *aliasFrom
= ures_getKey(res
.getAlias());
213 LocalPointer
<UnicodeString
> aliasFromStr(new UnicodeString(aliasFrom
, -1, US_INV
), status
);
214 UnicodeString aliasTo
= ures_getUnicodeStringByKey(res
.getAlias(),"replacement",&status
);
215 res
.adoptInstead(NULL
);
217 const Region
*aliasToRegion
= (Region
*) uhash_get(newRegionIDMap
.getAlias(),&aliasTo
);
218 Region
*aliasFromRegion
= (Region
*)uhash_get(newRegionIDMap
.getAlias(),aliasFromStr
.getAlias());
220 if ( aliasToRegion
!= NULL
&& aliasFromRegion
== NULL
) { // This is just an alias from some string to a region
221 uhash_put(newRegionAliases
.getAlias(),(void *)aliasFromStr
.orphan(), (void *)aliasToRegion
,&status
);
223 if ( aliasFromRegion
== NULL
) { // Deprecated region code not in the master codes list - so need to create a deprecated region for it.
224 LocalPointer
<Region
> newRgn(new Region
, status
);
225 if ( U_SUCCESS(status
) ) {
226 aliasFromRegion
= newRgn
.orphan();
230 aliasFromRegion
->idStr
.setTo(*aliasFromStr
);
231 aliasFromRegion
->idStr
.extract(0,aliasFromRegion
->idStr
.length(),aliasFromRegion
->id
,sizeof(aliasFromRegion
->id
),US_INV
);
232 uhash_put(newRegionIDMap
.getAlias(),(void *)&(aliasFromRegion
->idStr
),(void *)aliasFromRegion
,&status
);
234 UErrorCode ps
= U_ZERO_ERROR
;
235 df
->parse(aliasFromRegion
->idStr
,result
,ps
);
236 if ( U_SUCCESS(ps
) ) {
237 aliasFromRegion
->code
= result
.getLong(); // Convert string to number
238 uhash_iput(newNumericCodeMap
.getAlias(),aliasFromRegion
->code
,(void *)aliasFromRegion
,&status
);
240 aliasFromRegion
->code
= -1;
242 aliasFromRegion
->fType
= URGN_DEPRECATED
;
244 aliasFromRegion
->fType
= URGN_DEPRECATED
;
248 LocalPointer
<UVector
> newPreferredValues(new UVector(uprv_deleteUObject
, uhash_compareUnicodeString
, status
), status
);
249 aliasFromRegion
->preferredValues
= newPreferredValues
.orphan();
251 if( U_FAILURE(status
)) {
254 UnicodeString currentRegion
;
255 //currentRegion.remove(); TODO: was already 0 length?
256 for (int32_t i
= 0 ; i
< aliasTo
.length() ; i
++ ) {
257 if ( aliasTo
.charAt(i
) != 0x0020 ) {
258 currentRegion
.append(aliasTo
.charAt(i
));
260 if ( aliasTo
.charAt(i
) == 0x0020 || i
+1 == aliasTo
.length() ) {
261 Region
*target
= (Region
*)uhash_get(newRegionIDMap
.getAlias(),(void *)¤tRegion
);
263 LocalPointer
<UnicodeString
> preferredValue(new UnicodeString(target
->idStr
), status
);
264 aliasFromRegion
->preferredValues
->addElement((void *)preferredValue
.orphan(),status
); // may add null if err
266 currentRegion
.remove();
272 // Process the code mappings - This will allow us to assign numeric codes to most of the territories.
273 while ( ures_hasNext(codeMappings
.getAlias()) ) {
274 UResourceBundle
*mapping
= ures_getNextResource(codeMappings
.getAlias(),NULL
,&status
);
275 if ( ures_getType(mapping
) == URES_ARRAY
&& ures_getSize(mapping
) == 3) {
276 UnicodeString codeMappingID
= ures_getUnicodeStringByIndex(mapping
,0,&status
);
277 UnicodeString codeMappingNumber
= ures_getUnicodeStringByIndex(mapping
,1,&status
);
278 UnicodeString codeMapping3Letter
= ures_getUnicodeStringByIndex(mapping
,2,&status
);
280 Region
*r
= (Region
*)uhash_get(newRegionIDMap
.getAlias(),(void *)&codeMappingID
);
283 UErrorCode ps
= U_ZERO_ERROR
;
284 df
->parse(codeMappingNumber
,result
,ps
);
285 if ( U_SUCCESS(ps
) ) {
286 r
->code
= result
.getLong(); // Convert string to number
287 uhash_iput(newNumericCodeMap
.getAlias(),r
->code
,(void *)r
,&status
);
289 LocalPointer
<UnicodeString
> code3(new UnicodeString(codeMapping3Letter
), status
);
290 uhash_put(newRegionAliases
.getAlias(),(void *)code3
.orphan(), (void *)r
,&status
);
296 // Now fill in the special cases for WORLD, UNKNOWN, CONTINENTS, and GROUPINGS
298 UnicodeString
WORLD_ID_STRING(WORLD_ID
);
299 r
= (Region
*) uhash_get(newRegionIDMap
.getAlias(),(void *)&WORLD_ID_STRING
);
301 r
->fType
= URGN_WORLD
;
304 UnicodeString
UNKNOWN_REGION_ID_STRING(UNKNOWN_REGION_ID
);
305 r
= (Region
*) uhash_get(newRegionIDMap
.getAlias(),(void *)&UNKNOWN_REGION_ID_STRING
);
307 r
->fType
= URGN_UNKNOWN
;
310 for ( int32_t i
= 0 ; i
< continents
->size() ; i
++ ) {
311 r
= (Region
*) uhash_get(newRegionIDMap
.getAlias(),(void *)continents
->elementAt(i
));
313 r
->fType
= URGN_CONTINENT
;
317 for ( int32_t i
= 0 ; i
< groupings
->size() ; i
++ ) {
318 r
= (Region
*) uhash_get(newRegionIDMap
.getAlias(),(void *)groupings
->elementAt(i
));
320 r
->fType
= URGN_GROUPING
;
324 // Special case: The region code "QO" (Outlying Oceania) is a subcontinent code added by CLDR
325 // even though it looks like a territory code. Need to handle it here.
327 UnicodeString
OUTLYING_OCEANIA_REGION_ID_STRING(OUTLYING_OCEANIA_REGION_ID
);
328 r
= (Region
*) uhash_get(newRegionIDMap
.getAlias(),(void *)&OUTLYING_OCEANIA_REGION_ID_STRING
);
330 r
->fType
= URGN_SUBCONTINENT
;
333 // Load territory containment info from the supplemental data.
334 while ( ures_hasNext(territoryContainment
.getAlias()) ) {
335 LocalUResourceBundlePointer
mapping(ures_getNextResource(territoryContainment
.getAlias(),NULL
,&status
));
336 if( U_FAILURE(status
) ) {
339 const char *parent
= ures_getKey(mapping
.getAlias());
340 if (uprv_strcmp(parent
, "containedGroupings") == 0 || uprv_strcmp(parent
, "deprecated") == 0) {
341 continue; // handle new pseudo-parent types added in ICU data per cldrbug 7808; for now just skip.
342 // #11232 is to do something useful with these.
344 UnicodeString parentStr
= UnicodeString(parent
, -1 , US_INV
);
345 Region
*parentRegion
= (Region
*) uhash_get(newRegionIDMap
.getAlias(),(void *)&parentStr
);
347 for ( int j
= 0 ; j
< ures_getSize(mapping
.getAlias()); j
++ ) {
348 UnicodeString child
= ures_getUnicodeStringByIndex(mapping
.getAlias(),j
,&status
);
349 Region
*childRegion
= (Region
*) uhash_get(newRegionIDMap
.getAlias(),(void *)&child
);
350 if ( parentRegion
!= NULL
&& childRegion
!= NULL
) {
352 // Add the child region to the set of regions contained by the parent
353 if (parentRegion
->containedRegions
== NULL
) {
354 parentRegion
->containedRegions
= new UVector(uprv_deleteUObject
, uhash_compareUnicodeString
, status
);
357 LocalPointer
<UnicodeString
> childStr(new UnicodeString(), status
);
358 if( U_FAILURE(status
) ) {
361 childStr
->fastCopyFrom(childRegion
->idStr
);
362 parentRegion
->containedRegions
->addElement((void *)childStr
.orphan(),status
);
364 // Set the parent region to be the containing region of the child.
365 // Regions of type GROUPING can't be set as the parent, since another region
366 // such as a SUBCONTINENT, CONTINENT, or WORLD must always be the parent.
367 if ( parentRegion
->fType
!= URGN_GROUPING
) {
368 childRegion
->containingRegion
= parentRegion
;
374 // Create the availableRegions lists
375 int32_t pos
= UHASH_FIRST
;
376 while ( const UHashElement
* element
= uhash_nextElement(newRegionIDMap
.getAlias(),&pos
)) {
377 Region
*ar
= (Region
*)element
->value
.pointer
;
378 if ( availableRegions
[ar
->fType
] == NULL
) {
379 LocalPointer
<UVector
> newAr(new UVector(uprv_deleteUObject
, uhash_compareUnicodeString
, status
), status
);
380 availableRegions
[ar
->fType
] = newAr
.orphan();
382 LocalPointer
<UnicodeString
> arString(new UnicodeString(ar
->idStr
), status
);
383 if( U_FAILURE(status
) ) {
386 availableRegions
[ar
->fType
]->addElement((void *)arString
.orphan(),status
);
389 ucln_i18n_registerCleanup(UCLN_I18N_REGION
, region_cleanup
);
391 numericCodeMap
= newNumericCodeMap
.orphan();
392 regionIDMap
= newRegionIDMap
.orphan();
393 regionAliases
= newRegionAliases
.orphan();
396 void Region::cleanupRegionData() {
397 for (int32_t i
= 0 ; i
< URGN_LIMIT
; i
++ ) {
398 if ( availableRegions
[i
] ) {
399 delete availableRegions
[i
];
404 uhash_close(regionAliases
);
407 if (numericCodeMap
) {
408 uhash_close(numericCodeMap
);
412 uhash_close(regionIDMap
);
415 allRegions
->removeAllElements(); // Don't need the temporary list anymore.
420 regionAliases
= numericCodeMap
= regionIDMap
= NULL
;
422 gRegionDataInitOnce
.reset();
428 containingRegion(NULL
),
429 containedRegions(NULL
),
430 preferredValues(NULL
) {
435 if (containedRegions
) {
436 delete containedRegions
;
438 if (preferredValues
) {
439 delete preferredValues
;
444 * Returns true if the two regions are equal.
445 * Per PMC, just use pointer compare, since we have at most one instance of each Region.
448 Region::operator==(const Region
&that
) const {
449 return (idStr
== that
.idStr
);
453 * Returns true if the two regions are NOT equal; that is, if operator ==() returns false.
454 * Per PMC, just use pointer compare, since we have at most one instance of each Region.
457 Region::operator!=(const Region
&that
) const {
458 return (idStr
!= that
.idStr
);
462 * Returns a pointer to a Region using the given region code. The region code can be either 2-letter ISO code,
463 * 3-letter ISO code, UNM.49 numeric code, or other valid Unicode Region Code as defined by the LDML specification.
464 * The identifier will be canonicalized internally using the supplemental metadata as defined in the CLDR.
465 * If the region code is NULL or not recognized, the appropriate error code will be set ( U_ILLEGAL_ARGUMENT_ERROR )
467 const Region
* U_EXPORT2
468 Region::getInstance(const char *region_code
, UErrorCode
&status
) {
470 umtx_initOnce(gRegionDataInitOnce
, &loadRegionData
, status
);
471 if (U_FAILURE(status
)) {
475 if ( !region_code
) {
476 status
= U_ILLEGAL_ARGUMENT_ERROR
;
480 UnicodeString regionCodeString
= UnicodeString(region_code
, -1, US_INV
);
481 Region
*r
= (Region
*)uhash_get(regionIDMap
,(void *)®ionCodeString
);
484 r
= (Region
*)uhash_get(regionAliases
,(void *)®ionCodeString
);
487 if ( !r
) { // Unknown region code
488 status
= U_ILLEGAL_ARGUMENT_ERROR
;
492 if ( r
->fType
== URGN_DEPRECATED
&& r
->preferredValues
->size() == 1) {
493 StringEnumeration
*pv
= r
->getPreferredValues(status
);
495 const UnicodeString
*ustr
= pv
->snext(status
);
496 r
= (Region
*)uhash_get(regionIDMap
,(void *)ustr
);
505 * Returns a pointer to a Region using the given numeric region code. If the numeric region code is not recognized,
506 * the appropriate error code will be set ( U_ILLEGAL_ARGUMENT_ERROR ).
508 const Region
* U_EXPORT2
509 Region::getInstance (int32_t code
, UErrorCode
&status
) {
511 umtx_initOnce(gRegionDataInitOnce
, &loadRegionData
, status
);
512 if (U_FAILURE(status
)) {
516 Region
*r
= (Region
*)uhash_iget(numericCodeMap
,code
);
518 if ( !r
) { // Just in case there's an alias that's numeric, try to find it.
519 UnicodeString pat
= UNICODE_STRING_SIMPLE("0");
520 LocalPointer
<DecimalFormat
> df(new DecimalFormat(pat
,status
), status
);
521 if( U_FAILURE(status
) ) {
526 FieldPosition posIter
;
527 df
->format(code
,id
, posIter
, status
);
528 r
= (Region
*)uhash_get(regionAliases
,&id
);
531 if( U_FAILURE(status
) ) {
536 status
= U_ILLEGAL_ARGUMENT_ERROR
;
540 if ( r
->fType
== URGN_DEPRECATED
&& r
->preferredValues
->size() == 1) {
541 StringEnumeration
*pv
= r
->getPreferredValues(status
);
543 const UnicodeString
*ustr
= pv
->snext(status
);
544 r
= (Region
*)uhash_get(regionIDMap
,(void *)ustr
);
553 * Returns an enumeration over the IDs of all known regions that match the given type.
555 StringEnumeration
* U_EXPORT2
556 Region::getAvailable(URegionType type
, UErrorCode
&status
) {
557 umtx_initOnce(gRegionDataInitOnce
, &loadRegionData
, status
); // returns immediately if U_FAILURE(status)
558 if (U_FAILURE(status
)) {
561 return new RegionNameEnumeration(availableRegions
[type
],status
);
565 * Returns a pointer to the region that contains this region. Returns NULL if this region is code "001" (World)
566 * or "ZZ" (Unknown region). For example, calling this method with region "IT" (Italy) returns the
567 * region "039" (Southern Europe).
570 Region::getContainingRegion() const {
571 UErrorCode status
= U_ZERO_ERROR
;
572 umtx_initOnce(gRegionDataInitOnce
, &loadRegionData
, status
);
573 return containingRegion
;
577 * Return a pointer to the region that geographically contains this region and matches the given type,
578 * moving multiple steps up the containment chain if necessary. Returns NULL if no containing region can be found
579 * that matches the given type. Note: The URegionTypes = "URGN_GROUPING", "URGN_DEPRECATED", or "URGN_UNKNOWN"
580 * are not appropriate for use in this API. NULL will be returned in this case. For example, calling this method
581 * with region "IT" (Italy) for type "URGN_CONTINENT" returns the region "150" ( Europe ).
584 Region::getContainingRegion(URegionType type
) const {
585 UErrorCode status
= U_ZERO_ERROR
;
586 umtx_initOnce(gRegionDataInitOnce
, &loadRegionData
, status
);
587 if ( containingRegion
== NULL
) {
591 return ( containingRegion
->fType
== type
)? containingRegion
: containingRegion
->getContainingRegion(type
);
595 * Return an enumeration over the IDs of all the regions that are immediate children of this region in the
596 * region hierarchy. These returned regions could be either macro regions, territories, or a mixture of the two,
597 * depending on the containment data as defined in CLDR. This API may return NULL if this region doesn't have
598 * any sub-regions. For example, calling this method with region "150" (Europe) returns an enumeration containing
599 * the various sub regions of Europe - "039" (Southern Europe) - "151" (Eastern Europe) - "154" (Northern Europe)
600 * and "155" (Western Europe).
603 Region::getContainedRegions(UErrorCode
&status
) const {
604 umtx_initOnce(gRegionDataInitOnce
, &loadRegionData
, status
); // returns immediately if U_FAILURE(status)
605 if (U_FAILURE(status
)) {
608 return new RegionNameEnumeration(containedRegions
,status
);
612 * Returns an enumeration over the IDs of all the regions that are children of this region anywhere in the region
613 * hierarchy and match the given type. This API may return an empty enumeration if this region doesn't have any
614 * sub-regions that match the given type. For example, calling this method with region "150" (Europe) and type
615 * "URGN_TERRITORY" returns a set containing all the territories in Europe ( "FR" (France) - "IT" (Italy) - "DE" (Germany) etc. )
618 Region::getContainedRegions( URegionType type
, UErrorCode
&status
) const {
619 umtx_initOnce(gRegionDataInitOnce
, &loadRegionData
, status
); // returns immediately if U_FAILURE(status)
620 if (U_FAILURE(status
)) {
624 UVector
*result
= new UVector(NULL
, uhash_compareChars
, status
);
626 StringEnumeration
*cr
= getContainedRegions(status
);
628 for ( int32_t i
= 0 ; i
< cr
->count(status
) ; i
++ ) {
629 const char *regionId
= cr
->next(NULL
,status
);
630 const Region
*r
= Region::getInstance(regionId
,status
);
631 if ( r
->getType() == type
) {
632 result
->addElement((void *)&r
->idStr
,status
);
634 StringEnumeration
*children
= r
->getContainedRegions(type
, status
);
635 for ( int32_t j
= 0 ; j
< children
->count(status
) ; j
++ ) {
636 const char *id2
= children
->next(NULL
,status
);
637 const Region
*r2
= Region::getInstance(id2
,status
);
638 result
->addElement((void *)&r2
->idStr
,status
);
644 StringEnumeration
* resultEnumeration
= new RegionNameEnumeration(result
,status
);
646 return resultEnumeration
;
650 * Returns true if this region contains the supplied other region anywhere in the region hierarchy.
653 Region::contains(const Region
&other
) const {
654 UErrorCode status
= U_ZERO_ERROR
;
655 umtx_initOnce(gRegionDataInitOnce
, &loadRegionData
, status
);
657 if (!containedRegions
) {
660 if (containedRegions
->contains((void *)&other
.idStr
)) {
663 for ( int32_t i
= 0 ; i
< containedRegions
->size() ; i
++ ) {
664 UnicodeString
*crStr
= (UnicodeString
*)containedRegions
->elementAt(i
);
665 Region
*cr
= (Region
*) uhash_get(regionIDMap
,(void *)crStr
);
666 if ( cr
&& cr
->contains(other
) ) {
676 * For deprecated regions, return an enumeration over the IDs of the regions that are the preferred replacement
677 * regions for this region. Returns NULL for a non-deprecated region. For example, calling this method with region
678 * "SU" (Soviet Union) would return a list of the regions containing "RU" (Russia), "AM" (Armenia), "AZ" (Azerbaijan), etc...
681 Region::getPreferredValues(UErrorCode
&status
) const {
682 umtx_initOnce(gRegionDataInitOnce
, &loadRegionData
, status
); // returns immediately if U_FAILURE(status)
683 if (U_FAILURE(status
) || fType
!= URGN_DEPRECATED
) {
686 return new RegionNameEnumeration(preferredValues
,status
);
691 * Return this region's canonical region code.
694 Region::getRegionCode() const {
699 Region::getNumericCode() const {
704 * Returns the region type of this region.
707 Region::getType() const {
711 RegionNameEnumeration::RegionNameEnumeration(UVector
*fNameList
, UErrorCode
& status
) {
713 if (fNameList
&& U_SUCCESS(status
)) {
714 fRegionNames
= new UVector(uprv_deleteUObject
, uhash_compareUnicodeString
, fNameList
->size(),status
);
715 for ( int32_t i
= 0 ; i
< fNameList
->size() ; i
++ ) {
716 UnicodeString
* this_region_name
= (UnicodeString
*)fNameList
->elementAt(i
);
717 UnicodeString
* new_region_name
= new UnicodeString(*this_region_name
);
718 fRegionNames
->addElement((void *)new_region_name
,status
);
727 RegionNameEnumeration::snext(UErrorCode
& status
) {
728 if (U_FAILURE(status
) || (fRegionNames
==NULL
)) {
731 const UnicodeString
* nextStr
= (const UnicodeString
*)fRegionNames
->elementAt(pos
);
739 RegionNameEnumeration::reset(UErrorCode
& /*status*/) {
744 RegionNameEnumeration::count(UErrorCode
& /*status*/) const {
745 return (fRegionNames
==NULL
) ? 0 : fRegionNames
->size();
748 RegionNameEnumeration::~RegionNameEnumeration() {
754 #endif /* #if !UCONFIG_NO_FORMATTING */