2 *******************************************************************************
3 * Copyright (C) 2014-2015, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 *******************************************************************************
10 * Modification History:*
11 * Date Name Description
12 * 01/15/13 Emmons Original Port from ICU4J
13 ********************************************************************************
18 * \brief C++ API: Region classes (territory containment)
21 #include "unicode/region.h"
22 #include "unicode/utypes.h"
23 #include "unicode/uobject.h"
24 #include "unicode/unistr.h"
25 #include "unicode/ures.h"
26 #include "unicode/decimfmt.h"
33 #include "region_impl.h"
35 #if !UCONFIG_NO_FORMATTING
40 static void U_CALLCONV
41 deleteRegion(void *obj
) {
42 delete (icu::Region
*)obj
;
46 * Cleanup callback func
48 static UBool U_CALLCONV
region_cleanup(void)
50 icu::Region::cleanupRegionData();
59 static UInitOnce gRegionDataInitOnce
= U_INITONCE_INITIALIZER
;
60 static UVector
* availableRegions
[URGN_LIMIT
];
62 static UHashtable
*regionAliases
= NULL
;
63 static UHashtable
*regionIDMap
= NULL
;
64 static UHashtable
*numericCodeMap
= NULL
;
65 static UVector
*allRegions
= NULL
;
67 static const UChar UNKNOWN_REGION_ID
[] = { 0x5A, 0x5A, 0 }; /* "ZZ" */
68 static const UChar OUTLYING_OCEANIA_REGION_ID
[] = { 0x51, 0x4F, 0 }; /* "QO" */
69 static const UChar WORLD_ID
[] = { 0x30, 0x30, 0x31, 0 }; /* "001" */
70 static const UChar RANGE_MARKER
= 0x7e; /* "~" */
72 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RegionNameEnumeration
)
75 * Initializes the region data from the ICU resource bundles. The region data
76 * contains the basic relationships such as which regions are known, what the numeric
77 * codes are, any known aliases, and the territory containment data.
79 * If the region data has already loaded, then this method simply returns without doing
80 * anything meaningful.
82 void Region::loadRegionData(UErrorCode
&status
) {
84 // Construct service objs first
85 LocalUHashtablePointer
newRegionIDMap(uhash_open(uhash_hashUnicodeString
, uhash_compareUnicodeString
, NULL
, &status
));
86 LocalUHashtablePointer
newNumericCodeMap(uhash_open(uhash_hashLong
,uhash_compareLong
,NULL
,&status
));
87 LocalUHashtablePointer
newRegionAliases(uhash_open(uhash_hashUnicodeString
,uhash_compareUnicodeString
,NULL
,&status
));
88 LocalPointer
<DecimalFormat
> df(new DecimalFormat(status
), status
);
90 LocalPointer
<UVector
> continents(new UVector(uprv_deleteUObject
, uhash_compareUnicodeString
, status
), status
);
91 LocalPointer
<UVector
> groupings(new UVector(uprv_deleteUObject
, uhash_compareUnicodeString
, status
), status
);
92 allRegions
= new UVector(uprv_deleteUObject
, uhash_compareUnicodeString
, status
);
94 LocalUResourceBundlePointer
metadata(ures_openDirect(NULL
,"metadata",&status
));
95 LocalUResourceBundlePointer
metadataAlias(ures_getByKey(metadata
.getAlias(),"alias",NULL
,&status
));
96 LocalUResourceBundlePointer
territoryAlias(ures_getByKey(metadataAlias
.getAlias(),"territory",NULL
,&status
));
98 LocalUResourceBundlePointer
supplementalData(ures_openDirect(NULL
,"supplementalData",&status
));
99 LocalUResourceBundlePointer
codeMappings(ures_getByKey(supplementalData
.getAlias(),"codeMappings",NULL
,&status
));
101 LocalUResourceBundlePointer
idValidity(ures_getByKey(supplementalData
.getAlias(),"idValidity",NULL
,&status
));
102 LocalUResourceBundlePointer
regionList(ures_getByKey(idValidity
.getAlias(),"region",NULL
,&status
));
103 LocalUResourceBundlePointer
regionRegular(ures_getByKey(regionList
.getAlias(),"regular",NULL
,&status
));
104 LocalUResourceBundlePointer
regionMacro(ures_getByKey(regionList
.getAlias(),"macroregion",NULL
,&status
));
105 LocalUResourceBundlePointer
regionUnknown(ures_getByKey(regionList
.getAlias(),"unknown",NULL
,&status
));
107 LocalUResourceBundlePointer
territoryContainment(ures_getByKey(supplementalData
.getAlias(),"territoryContainment",NULL
,&status
));
108 LocalUResourceBundlePointer
worldContainment(ures_getByKey(territoryContainment
.getAlias(),"001",NULL
,&status
));
109 LocalUResourceBundlePointer
groupingContainment(ures_getByKey(territoryContainment
.getAlias(),"grouping",NULL
,&status
));
111 if (U_FAILURE(status
)) {
116 df
->setParseIntegerOnly(TRUE
);
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 while ( ures_hasNext(groupingContainment
.getAlias()) ) {
170 UnicodeString
*groupingName
= new UnicodeString(ures_getNextUnicodeString(groupingContainment
.getAlias(),NULL
,&status
));
171 groupings
->addElement(groupingName
,status
);
174 for ( int32_t i
= 0 ; i
< allRegions
->size() ; i
++ ) {
175 LocalPointer
<Region
> r(new Region(), status
);
176 if ( U_FAILURE(status
) ) {
179 UnicodeString
*regionName
= (UnicodeString
*)allRegions
->elementAt(i
);
180 r
->idStr
= *regionName
;
182 r
->idStr
.extract(0,r
->idStr
.length(),r
->id
,sizeof(r
->id
),US_INV
);
183 r
->type
= URGN_TERRITORY
; // Only temporary - figure out the real type later once the aliases are known.
186 UErrorCode ps
= U_ZERO_ERROR
;
187 df
->parse(r
->idStr
,result
,ps
);
188 if ( U_SUCCESS(ps
) ) {
189 r
->code
= result
.getLong(); // Convert string to number
190 uhash_iput(newNumericCodeMap
.getAlias(),r
->code
,(void *)(r
.getAlias()),&status
);
191 r
->type
= URGN_SUBCONTINENT
;
195 void* idStrAlias
= (void*)&(r
->idStr
); // about to orphan 'r'. Save this off.
196 uhash_put(newRegionIDMap
.getAlias(),idStrAlias
,(void *)(r
.orphan()),&status
); // regionIDMap takes ownership
199 // Process the territory aliases
200 while ( ures_hasNext(territoryAlias
.getAlias()) ) {
201 LocalUResourceBundlePointer
res(ures_getNextResource(territoryAlias
.getAlias(),NULL
,&status
));
202 const char *aliasFrom
= ures_getKey(res
.getAlias());
203 LocalPointer
<UnicodeString
> aliasFromStr(new UnicodeString(aliasFrom
, -1, US_INV
), status
);
204 UnicodeString aliasTo
= ures_getUnicodeStringByKey(res
.getAlias(),"replacement",&status
);
205 res
.adoptInstead(NULL
);
207 const Region
*aliasToRegion
= (Region
*) uhash_get(newRegionIDMap
.getAlias(),&aliasTo
);
208 Region
*aliasFromRegion
= (Region
*)uhash_get(newRegionIDMap
.getAlias(),aliasFromStr
.getAlias());
210 if ( aliasToRegion
!= NULL
&& aliasFromRegion
== NULL
) { // This is just an alias from some string to a region
211 uhash_put(newRegionAliases
.getAlias(),(void *)aliasFromStr
.orphan(), (void *)aliasToRegion
,&status
);
213 if ( aliasFromRegion
== NULL
) { // Deprecated region code not in the master codes list - so need to create a deprecated region for it.
214 LocalPointer
<Region
> newRgn(new Region
, status
);
215 if ( U_SUCCESS(status
) ) {
216 aliasFromRegion
= newRgn
.orphan();
220 aliasFromRegion
->idStr
.setTo(*aliasFromStr
);
221 aliasFromRegion
->idStr
.extract(0,aliasFromRegion
->idStr
.length(),aliasFromRegion
->id
,sizeof(aliasFromRegion
->id
),US_INV
);
222 uhash_put(newRegionIDMap
.getAlias(),(void *)&(aliasFromRegion
->idStr
),(void *)aliasFromRegion
,&status
);
224 UErrorCode ps
= U_ZERO_ERROR
;
225 df
->parse(aliasFromRegion
->idStr
,result
,ps
);
226 if ( U_SUCCESS(ps
) ) {
227 aliasFromRegion
->code
= result
.getLong(); // Convert string to number
228 uhash_iput(newNumericCodeMap
.getAlias(),aliasFromRegion
->code
,(void *)aliasFromRegion
,&status
);
230 aliasFromRegion
->code
= -1;
232 aliasFromRegion
->type
= URGN_DEPRECATED
;
234 aliasFromRegion
->type
= URGN_DEPRECATED
;
238 LocalPointer
<UVector
> newPreferredValues(new UVector(uprv_deleteUObject
, uhash_compareUnicodeString
, status
), status
);
239 aliasFromRegion
->preferredValues
= newPreferredValues
.orphan();
241 if( U_FAILURE(status
)) {
244 UnicodeString currentRegion
;
245 //currentRegion.remove(); TODO: was already 0 length?
246 for (int32_t i
= 0 ; i
< aliasTo
.length() ; i
++ ) {
247 if ( aliasTo
.charAt(i
) != 0x0020 ) {
248 currentRegion
.append(aliasTo
.charAt(i
));
250 if ( aliasTo
.charAt(i
) == 0x0020 || i
+1 == aliasTo
.length() ) {
251 Region
*target
= (Region
*)uhash_get(newRegionIDMap
.getAlias(),(void *)¤tRegion
);
253 LocalPointer
<UnicodeString
> preferredValue(new UnicodeString(target
->idStr
), status
);
254 aliasFromRegion
->preferredValues
->addElement((void *)preferredValue
.orphan(),status
); // may add null if err
256 currentRegion
.remove();
262 // Process the code mappings - This will allow us to assign numeric codes to most of the territories.
263 while ( ures_hasNext(codeMappings
.getAlias()) ) {
264 UResourceBundle
*mapping
= ures_getNextResource(codeMappings
.getAlias(),NULL
,&status
);
265 if ( ures_getType(mapping
) == URES_ARRAY
&& ures_getSize(mapping
) == 3) {
266 UnicodeString codeMappingID
= ures_getUnicodeStringByIndex(mapping
,0,&status
);
267 UnicodeString codeMappingNumber
= ures_getUnicodeStringByIndex(mapping
,1,&status
);
268 UnicodeString codeMapping3Letter
= ures_getUnicodeStringByIndex(mapping
,2,&status
);
270 Region
*r
= (Region
*)uhash_get(newRegionIDMap
.getAlias(),(void *)&codeMappingID
);
273 UErrorCode ps
= U_ZERO_ERROR
;
274 df
->parse(codeMappingNumber
,result
,ps
);
275 if ( U_SUCCESS(ps
) ) {
276 r
->code
= result
.getLong(); // Convert string to number
277 uhash_iput(newNumericCodeMap
.getAlias(),r
->code
,(void *)r
,&status
);
279 LocalPointer
<UnicodeString
> code3(new UnicodeString(codeMapping3Letter
), status
);
280 uhash_put(newRegionAliases
.getAlias(),(void *)code3
.orphan(), (void *)r
,&status
);
286 // Now fill in the special cases for WORLD, UNKNOWN, CONTINENTS, and GROUPINGS
288 UnicodeString
WORLD_ID_STRING(WORLD_ID
);
289 r
= (Region
*) uhash_get(newRegionIDMap
.getAlias(),(void *)&WORLD_ID_STRING
);
291 r
->type
= URGN_WORLD
;
294 UnicodeString
UNKNOWN_REGION_ID_STRING(UNKNOWN_REGION_ID
);
295 r
= (Region
*) uhash_get(newRegionIDMap
.getAlias(),(void *)&UNKNOWN_REGION_ID_STRING
);
297 r
->type
= URGN_UNKNOWN
;
300 for ( int32_t i
= 0 ; i
< continents
->size() ; i
++ ) {
301 r
= (Region
*) uhash_get(newRegionIDMap
.getAlias(),(void *)continents
->elementAt(i
));
303 r
->type
= URGN_CONTINENT
;
307 for ( int32_t i
= 0 ; i
< groupings
->size() ; i
++ ) {
308 r
= (Region
*) uhash_get(newRegionIDMap
.getAlias(),(void *)groupings
->elementAt(i
));
310 r
->type
= URGN_GROUPING
;
314 // Special case: The region code "QO" (Outlying Oceania) is a subcontinent code added by CLDR
315 // even though it looks like a territory code. Need to handle it here.
317 UnicodeString
OUTLYING_OCEANIA_REGION_ID_STRING(OUTLYING_OCEANIA_REGION_ID
);
318 r
= (Region
*) uhash_get(newRegionIDMap
.getAlias(),(void *)&OUTLYING_OCEANIA_REGION_ID_STRING
);
320 r
->type
= URGN_SUBCONTINENT
;
323 // Load territory containment info from the supplemental data.
324 while ( ures_hasNext(territoryContainment
.getAlias()) ) {
325 LocalUResourceBundlePointer
mapping(ures_getNextResource(territoryContainment
.getAlias(),NULL
,&status
));
326 if( U_FAILURE(status
) ) {
329 const char *parent
= ures_getKey(mapping
.getAlias());
330 if (uprv_strcmp(parent
, "containedGroupings") == 0 || uprv_strcmp(parent
, "deprecated") == 0) {
331 continue; // handle new pseudo-parent types added in ICU data per cldrbug 7808; for now just skip.
332 // #11232 is to do something useful with these.
334 UnicodeString parentStr
= UnicodeString(parent
, -1 , US_INV
);
335 Region
*parentRegion
= (Region
*) uhash_get(newRegionIDMap
.getAlias(),(void *)&parentStr
);
337 for ( int j
= 0 ; j
< ures_getSize(mapping
.getAlias()); j
++ ) {
338 UnicodeString child
= ures_getUnicodeStringByIndex(mapping
.getAlias(),j
,&status
);
339 Region
*childRegion
= (Region
*) uhash_get(newRegionIDMap
.getAlias(),(void *)&child
);
340 if ( parentRegion
!= NULL
&& childRegion
!= NULL
) {
342 // Add the child region to the set of regions contained by the parent
343 if (parentRegion
->containedRegions
== NULL
) {
344 parentRegion
->containedRegions
= new UVector(uprv_deleteUObject
, uhash_compareUnicodeString
, status
);
347 LocalPointer
<UnicodeString
> childStr(new UnicodeString(), status
);
348 if( U_FAILURE(status
) ) {
351 childStr
->fastCopyFrom(childRegion
->idStr
);
352 parentRegion
->containedRegions
->addElement((void *)childStr
.orphan(),status
);
354 // Set the parent region to be the containing region of the child.
355 // Regions of type GROUPING can't be set as the parent, since another region
356 // such as a SUBCONTINENT, CONTINENT, or WORLD must always be the parent.
357 if ( parentRegion
->type
!= URGN_GROUPING
) {
358 childRegion
->containingRegion
= parentRegion
;
364 // Create the availableRegions lists
365 int32_t pos
= UHASH_FIRST
;
366 while ( const UHashElement
* element
= uhash_nextElement(newRegionIDMap
.getAlias(),&pos
)) {
367 Region
*ar
= (Region
*)element
->value
.pointer
;
368 if ( availableRegions
[ar
->type
] == NULL
) {
369 LocalPointer
<UVector
> newAr(new UVector(uprv_deleteUObject
, uhash_compareUnicodeString
, status
), status
);
370 availableRegions
[ar
->type
] = newAr
.orphan();
372 LocalPointer
<UnicodeString
> arString(new UnicodeString(ar
->idStr
), status
);
373 if( U_FAILURE(status
) ) {
376 availableRegions
[ar
->type
]->addElement((void *)arString
.orphan(),status
);
379 ucln_i18n_registerCleanup(UCLN_I18N_REGION
, region_cleanup
);
381 numericCodeMap
= newNumericCodeMap
.orphan();
382 regionIDMap
= newRegionIDMap
.orphan();
383 regionAliases
= newRegionAliases
.orphan();
386 void Region::cleanupRegionData() {
387 for (int32_t i
= 0 ; i
< URGN_LIMIT
; i
++ ) {
388 if ( availableRegions
[i
] ) {
389 delete availableRegions
[i
];
394 uhash_close(regionAliases
);
397 if (numericCodeMap
) {
398 uhash_close(numericCodeMap
);
402 uhash_close(regionIDMap
);
405 allRegions
->removeAllElements(); // Don't need the temporary list anymore.
410 regionAliases
= numericCodeMap
= regionIDMap
= NULL
;
412 gRegionDataInitOnce
.reset();
418 containingRegion(NULL
),
419 containedRegions(NULL
),
420 preferredValues(NULL
) {
425 if (containedRegions
) {
426 delete containedRegions
;
428 if (preferredValues
) {
429 delete preferredValues
;
434 * Returns true if the two regions are equal.
435 * Per PMC, just use pointer compare, since we have at most one instance of each Region.
438 Region::operator==(const Region
&that
) const {
439 return (idStr
== that
.idStr
);
443 * Returns true if the two regions are NOT equal; that is, if operator ==() returns false.
444 * Per PMC, just use pointer compare, since we have at most one instance of each Region.
447 Region::operator!=(const Region
&that
) const {
448 return (idStr
!= that
.idStr
);
452 * Returns a pointer to a Region using the given region code. The region code can be either 2-letter ISO code,
453 * 3-letter ISO code, UNM.49 numeric code, or other valid Unicode Region Code as defined by the LDML specification.
454 * The identifier will be canonicalized internally using the supplemental metadata as defined in the CLDR.
455 * If the region code is NULL or not recognized, the appropriate error code will be set ( U_ILLEGAL_ARGUMENT_ERROR )
457 const Region
* U_EXPORT2
458 Region::getInstance(const char *region_code
, UErrorCode
&status
) {
460 umtx_initOnce(gRegionDataInitOnce
, &loadRegionData
, status
);
461 if (U_FAILURE(status
)) {
465 if ( !region_code
) {
466 status
= U_ILLEGAL_ARGUMENT_ERROR
;
470 UnicodeString regionCodeString
= UnicodeString(region_code
, -1, US_INV
);
471 Region
*r
= (Region
*)uhash_get(regionIDMap
,(void *)®ionCodeString
);
474 r
= (Region
*)uhash_get(regionAliases
,(void *)®ionCodeString
);
477 if ( !r
) { // Unknown region code
478 status
= U_ILLEGAL_ARGUMENT_ERROR
;
482 if ( r
->type
== URGN_DEPRECATED
&& r
->preferredValues
->size() == 1) {
483 StringEnumeration
*pv
= r
->getPreferredValues(status
);
485 const UnicodeString
*ustr
= pv
->snext(status
);
486 r
= (Region
*)uhash_get(regionIDMap
,(void *)ustr
);
495 * Returns a pointer to a Region using the given numeric region code. If the numeric region code is not recognized,
496 * the appropriate error code will be set ( U_ILLEGAL_ARGUMENT_ERROR ).
498 const Region
* U_EXPORT2
499 Region::getInstance (int32_t code
, UErrorCode
&status
) {
501 umtx_initOnce(gRegionDataInitOnce
, &loadRegionData
, status
);
502 if (U_FAILURE(status
)) {
506 Region
*r
= (Region
*)uhash_iget(numericCodeMap
,code
);
508 if ( !r
) { // Just in case there's an alias that's numeric, try to find it.
509 UnicodeString pat
= UNICODE_STRING_SIMPLE("0");
510 LocalPointer
<DecimalFormat
> df(new DecimalFormat(pat
,status
), status
);
511 if( U_FAILURE(status
) ) {
516 FieldPosition posIter
;
517 df
->format(code
,id
, posIter
, status
);
518 r
= (Region
*)uhash_get(regionAliases
,&id
);
521 if( U_FAILURE(status
) ) {
526 status
= U_ILLEGAL_ARGUMENT_ERROR
;
530 if ( r
->type
== URGN_DEPRECATED
&& r
->preferredValues
->size() == 1) {
531 StringEnumeration
*pv
= r
->getPreferredValues(status
);
533 const UnicodeString
*ustr
= pv
->snext(status
);
534 r
= (Region
*)uhash_get(regionIDMap
,(void *)ustr
);
543 * Returns an enumeration over the IDs of all known regions that match the given type.
545 StringEnumeration
* U_EXPORT2
546 Region::getAvailable(URegionType type
, UErrorCode
&status
) {
547 umtx_initOnce(gRegionDataInitOnce
, &loadRegionData
, status
); // returns immediately if U_FAILURE(status)
548 if (U_FAILURE(status
)) {
551 return new RegionNameEnumeration(availableRegions
[type
],status
);
555 * Returns a pointer to the region that contains this region. Returns NULL if this region is code "001" (World)
556 * or "ZZ" (Unknown region). For example, calling this method with region "IT" (Italy) returns the
557 * region "039" (Southern Europe).
560 Region::getContainingRegion() const {
561 UErrorCode status
= U_ZERO_ERROR
;
562 umtx_initOnce(gRegionDataInitOnce
, &loadRegionData
, status
);
563 return containingRegion
;
567 * Return a pointer to the region that geographically contains this region and matches the given type,
568 * moving multiple steps up the containment chain if necessary. Returns NULL if no containing region can be found
569 * that matches the given type. Note: The URegionTypes = "URGN_GROUPING", "URGN_DEPRECATED", or "URGN_UNKNOWN"
570 * are not appropriate for use in this API. NULL will be returned in this case. For example, calling this method
571 * with region "IT" (Italy) for type "URGN_CONTINENT" returns the region "150" ( Europe ).
574 Region::getContainingRegion(URegionType type
) const {
575 UErrorCode status
= U_ZERO_ERROR
;
576 umtx_initOnce(gRegionDataInitOnce
, &loadRegionData
, status
);
577 if ( containingRegion
== NULL
) {
581 return ( containingRegion
->type
== type
)? containingRegion
: containingRegion
->getContainingRegion(type
);
585 * Return an enumeration over the IDs of all the regions that are immediate children of this region in the
586 * region hierarchy. These returned regions could be either macro regions, territories, or a mixture of the two,
587 * depending on the containment data as defined in CLDR. This API may return NULL if this region doesn't have
588 * any sub-regions. For example, calling this method with region "150" (Europe) returns an enumeration containing
589 * the various sub regions of Europe - "039" (Southern Europe) - "151" (Eastern Europe) - "154" (Northern Europe)
590 * and "155" (Western Europe).
593 Region::getContainedRegions(UErrorCode
&status
) const {
594 umtx_initOnce(gRegionDataInitOnce
, &loadRegionData
, status
); // returns immediately if U_FAILURE(status)
595 if (U_FAILURE(status
)) {
598 return new RegionNameEnumeration(containedRegions
,status
);
602 * Returns an enumeration over the IDs of all the regions that are children of this region anywhere in the region
603 * hierarchy and match the given type. This API may return an empty enumeration if this region doesn't have any
604 * sub-regions that match the given type. For example, calling this method with region "150" (Europe) and type
605 * "URGN_TERRITORY" returns a set containing all the territories in Europe ( "FR" (France) - "IT" (Italy) - "DE" (Germany) etc. )
608 Region::getContainedRegions( URegionType type
, UErrorCode
&status
) const {
609 umtx_initOnce(gRegionDataInitOnce
, &loadRegionData
, status
); // returns immediately if U_FAILURE(status)
610 if (U_FAILURE(status
)) {
614 UVector
*result
= new UVector(NULL
, uhash_compareChars
, status
);
616 StringEnumeration
*cr
= getContainedRegions(status
);
618 for ( int32_t i
= 0 ; i
< cr
->count(status
) ; i
++ ) {
619 const char *id
= cr
->next(NULL
,status
);
620 const Region
*r
= Region::getInstance(id
,status
);
621 if ( r
->getType() == type
) {
622 result
->addElement((void *)&r
->idStr
,status
);
624 StringEnumeration
*children
= r
->getContainedRegions(type
, status
);
625 for ( int32_t j
= 0 ; j
< children
->count(status
) ; j
++ ) {
626 const char *id2
= children
->next(NULL
,status
);
627 const Region
*r2
= Region::getInstance(id2
,status
);
628 result
->addElement((void *)&r2
->idStr
,status
);
634 StringEnumeration
* resultEnumeration
= new RegionNameEnumeration(result
,status
);
636 return resultEnumeration
;
640 * Returns true if this region contains the supplied other region anywhere in the region hierarchy.
643 Region::contains(const Region
&other
) const {
644 UErrorCode status
= U_ZERO_ERROR
;
645 umtx_initOnce(gRegionDataInitOnce
, &loadRegionData
, status
);
647 if (!containedRegions
) {
650 if (containedRegions
->contains((void *)&other
.idStr
)) {
653 for ( int32_t i
= 0 ; i
< containedRegions
->size() ; i
++ ) {
654 UnicodeString
*crStr
= (UnicodeString
*)containedRegions
->elementAt(i
);
655 Region
*cr
= (Region
*) uhash_get(regionIDMap
,(void *)crStr
);
656 if ( cr
&& cr
->contains(other
) ) {
666 * For deprecated regions, return an enumeration over the IDs of the regions that are the preferred replacement
667 * regions for this region. Returns NULL for a non-deprecated region. For example, calling this method with region
668 * "SU" (Soviet Union) would return a list of the regions containing "RU" (Russia), "AM" (Armenia), "AZ" (Azerbaijan), etc...
671 Region::getPreferredValues(UErrorCode
&status
) const {
672 umtx_initOnce(gRegionDataInitOnce
, &loadRegionData
, status
); // returns immediately if U_FAILURE(status)
673 if (U_FAILURE(status
) || type
!= URGN_DEPRECATED
) {
676 return new RegionNameEnumeration(preferredValues
,status
);
681 * Return this region's canonical region code.
684 Region::getRegionCode() const {
689 Region::getNumericCode() const {
694 * Returns the region type of this region.
697 Region::getType() const {
701 RegionNameEnumeration::RegionNameEnumeration(UVector
*fNameList
, UErrorCode
& status
) {
703 if (fNameList
&& U_SUCCESS(status
)) {
704 fRegionNames
= new UVector(uprv_deleteUObject
, uhash_compareUnicodeString
, fNameList
->size(),status
);
705 for ( int32_t i
= 0 ; i
< fNameList
->size() ; i
++ ) {
706 UnicodeString
* this_region_name
= (UnicodeString
*)fNameList
->elementAt(i
);
707 UnicodeString
* new_region_name
= new UnicodeString(*this_region_name
);
708 fRegionNames
->addElement((void *)new_region_name
,status
);
717 RegionNameEnumeration::snext(UErrorCode
& status
) {
718 if (U_FAILURE(status
) || (fRegionNames
==NULL
)) {
721 const UnicodeString
* nextStr
= (const UnicodeString
*)fRegionNames
->elementAt(pos
);
729 RegionNameEnumeration::reset(UErrorCode
& /*status*/) {
734 RegionNameEnumeration::count(UErrorCode
& /*status*/) const {
735 return (fRegionNames
==NULL
) ? 0 : fRegionNames
->size();
738 RegionNameEnumeration::~RegionNameEnumeration() {
744 #endif /* #if !UCONFIG_NO_FORMATTING */