1 /* 2 ******************************************************************************* 3 * Copyright (C) 2013, International Business Machines Corporation and 4 * others. All Rights Reserved. 5 ******************************************************************************* 6 * 7 * 8 * File REGION.CPP 9 * 10 * Modification History:* 11 * Date Name Description 12 * 01/15/13 Emmons Original Port from ICU4J 13 ******************************************************************************** 14 */ 15 16 /** 17 * \file 18 * \brief C++ API: Region classes (territory containment) 19 */ 20 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" 27 #include "ucln_in.h" 28 #include "cstring.h" 29 #include "uhash.h" 30 #include "umutex.h" 31 #include "uresimp.h" 32 #include "region_impl.h" 33 34 #if !UCONFIG_NO_FORMATTING 35 36 37 U_CDECL_BEGIN 38 39 static void U_CALLCONV 40 deleteRegion(void *obj) { 41 delete (icu::Region *)obj; 42 } 43 44 /** 45 * Cleanup callback func 46 */ 47 static UBool U_CALLCONV region_cleanup(void) 48 { 49 icu::Region::cleanupRegionData(); 50 51 return TRUE; 52 } 53 54 U_CDECL_END 55 56 U_NAMESPACE_BEGIN 57 58 static UMutex gRegionDataLock = U_MUTEX_INITIALIZER; 59 static UBool regionDataIsLoaded = false; 60 static UVector* availableRegions[URGN_LIMIT]; 61 62 static UHashtable *regionAliases; 63 static UHashtable *regionIDMap; 64 static UHashtable *numericCodeMap; 65 66 static const UChar UNKNOWN_REGION_ID [] = { 0x5A, 0x5A, 0 }; /* "ZZ" */ 67 static const UChar OUTLYING_OCEANIA_REGION_ID [] = { 0x51, 0x4F, 0 }; /* "QO" */ 68 static const UChar WORLD_ID [] = { 0x30, 0x30, 0x31, 0 }; /* "001" */ 69 70 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RegionNameEnumeration) 71 72 /* 73 * Initializes the region data from the ICU resource bundles. The region data 74 * contains the basic relationships such as which regions are known, what the numeric 75 * codes are, any known aliases, and the territory containment data. 76 * 77 * If the region data has already loaded, then this method simply returns without doing 78 * anything meaningful. 79 */ 80 void Region::loadRegionData() { 81 82 if (regionDataIsLoaded) { 83 return; 84 } 85 86 umtx_lock(&gRegionDataLock); 87 88 if (regionDataIsLoaded) { // In case another thread gets to it before we do... 89 umtx_unlock(&gRegionDataLock); 90 return; 91 } 92 93 94 UErrorCode status = U_ZERO_ERROR; 95 96 UResourceBundle* regionCodes = NULL; 97 UResourceBundle* territoryAlias = NULL; 98 UResourceBundle* codeMappings = NULL; 99 UResourceBundle* worldContainment = NULL; 100 UResourceBundle* territoryContainment = NULL; 101 UResourceBundle* groupingContainment = NULL; 102 103 DecimalFormat *df = new DecimalFormat(status); 104 if (U_FAILURE(status)) { 105 umtx_unlock(&gRegionDataLock); 106 return; 107 } 108 df->setParseIntegerOnly(TRUE); 109 110 regionIDMap = uhash_open(uhash_hashUnicodeString,uhash_compareUnicodeString,NULL,&status); 111 uhash_setValueDeleter(regionIDMap, deleteRegion); 112 113 numericCodeMap = uhash_open(uhash_hashLong,uhash_compareLong,NULL,&status); 114 115 regionAliases = uhash_open(uhash_hashUnicodeString,uhash_compareUnicodeString,NULL,&status); 116 uhash_setKeyDeleter(regionAliases,uprv_deleteUObject); 117 118 UResourceBundle *rb = ures_openDirect(NULL,"metadata",&status); 119 regionCodes = ures_getByKey(rb,"regionCodes",NULL,&status); 120 territoryAlias = ures_getByKey(rb,"territoryAlias",NULL,&status); 121 122 UResourceBundle *rb2 = ures_openDirect(NULL,"supplementalData",&status); 123 codeMappings = ures_getByKey(rb2,"codeMappings",NULL,&status); 124 125 territoryContainment = ures_getByKey(rb2,"territoryContainment",NULL,&status); 126 worldContainment = ures_getByKey(territoryContainment,"001",NULL,&status); 127 groupingContainment = ures_getByKey(territoryContainment,"grouping",NULL,&status); 128 129 UVector *continents = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status); 130 131 while ( ures_hasNext(worldContainment) ) { 132 UnicodeString *continentName = new UnicodeString(ures_getNextUnicodeString(worldContainment,NULL,&status)); 133 continents->addElement(continentName,status); 134 } 135 136 UVector *groupings = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status); 137 while ( ures_hasNext(groupingContainment) ) { 138 UnicodeString *groupingName = new UnicodeString(ures_getNextUnicodeString(groupingContainment,NULL,&status)); 139 groupings->addElement(groupingName,status); 140 } 141 142 while ( ures_hasNext(regionCodes) ) { 143 UnicodeString regionID = ures_getNextUnicodeString(regionCodes,NULL,&status); 144 Region *r = new Region(); 145 r->idStr = regionID; 146 r->idStr.extract(0,r->idStr.length(),r->id,sizeof(r->id),US_INV); 147 r->type = URGN_TERRITORY; // Only temporary - figure out the real type later once the aliases are known. 148 149 uhash_put(regionIDMap,(void *)&(r->idStr),(void *)r,&status); 150 Formattable result; 151 UErrorCode ps = U_ZERO_ERROR; 152 df->parse(r->idStr,result,ps); 153 if ( U_SUCCESS(ps) ) { 154 r->code = result.getLong(); // Convert string to number 155 uhash_iput(numericCodeMap,r->code,(void *)r,&status); 156 r->type = URGN_SUBCONTINENT; 157 } else { 158 r->code = -1; 159 } 160 } 161 162 163 // Process the territory aliases 164 while ( ures_hasNext(territoryAlias) ) { 165 UResourceBundle *res = ures_getNextResource(territoryAlias,NULL,&status); 166 const char *aliasFrom = ures_getKey(res); 167 UnicodeString* aliasFromStr = new UnicodeString(aliasFrom, -1, US_INV); 168 UnicodeString aliasTo = ures_getUnicodeString(res,&status); 169 ures_close(res); 170 171 Region *aliasToRegion = (Region *) uhash_get(regionIDMap,&aliasTo); 172 Region *aliasFromRegion = (Region *)uhash_get(regionIDMap,aliasFromStr); 173 174 if ( aliasToRegion != NULL && aliasFromRegion == NULL ) { // This is just an alias from some string to a region 175 uhash_put(regionAliases,(void *)aliasFromStr, (void *)aliasToRegion,&status); 176 } else { 177 if ( aliasFromRegion == NULL ) { // Deprecated region code not in the master codes list - so need to create a deprecated region for it. 178 aliasFromRegion = new Region(); 179 aliasFromRegion->idStr.setTo(*aliasFromStr); 180 aliasFromRegion->idStr.extract(0,aliasFromRegion->idStr.length(),aliasFromRegion->id,sizeof(aliasFromRegion->id),US_INV); 181 uhash_put(regionIDMap,(void *)&(aliasFromRegion->idStr),(void *)aliasFromRegion,&status); 182 Formattable result; 183 UErrorCode ps = U_ZERO_ERROR; 184 df->parse(aliasFromRegion->idStr,result,ps); 185 if ( U_SUCCESS(ps) ) { 186 aliasFromRegion->code = result.getLong(); // Convert string to number 187 uhash_iput(numericCodeMap,aliasFromRegion->code,(void *)aliasFromRegion,&status); 188 } else { 189 aliasFromRegion->code = -1; 190 } 191 aliasFromRegion->type = URGN_DEPRECATED; 192 } else { 193 aliasFromRegion->type = URGN_DEPRECATED; 194 } 195 delete aliasFromStr; 196 197 aliasFromRegion->preferredValues = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status); 198 UnicodeString currentRegion; 199 currentRegion.remove(); 200 for (int32_t i = 0 ; i < aliasTo.length() ; i++ ) { 201 if ( aliasTo.charAt(i) != 0x0020 ) { 202 currentRegion.append(aliasTo.charAt(i)); 203 } 204 if ( aliasTo.charAt(i) == 0x0020 || i+1 == aliasTo.length() ) { 205 Region *target = (Region *)uhash_get(regionIDMap,(void *)¤tRegion); 206 if (target) { 207 UnicodeString *preferredValue = new UnicodeString(target->idStr); 208 aliasFromRegion->preferredValues->addElement((void *)preferredValue,status); 209 } 210 currentRegion.remove(); 211 } 212 } 213 } 214 } 215 216 // Process the code mappings - This will allow us to assign numeric codes to most of the territories. 217 while ( ures_hasNext(codeMappings) ) { 218 UResourceBundle *mapping = ures_getNextResource(codeMappings,NULL,&status); 219 if ( ures_getType(mapping) == URES_ARRAY && ures_getSize(mapping) == 3) { 220 UnicodeString codeMappingID = ures_getUnicodeStringByIndex(mapping,0,&status); 221 UnicodeString codeMappingNumber = ures_getUnicodeStringByIndex(mapping,1,&status); 222 UnicodeString codeMapping3Letter = ures_getUnicodeStringByIndex(mapping,2,&status); 223 224 Region *r = (Region *)uhash_get(regionIDMap,(void *)&codeMappingID); 225 if ( r ) { 226 Formattable result; 227 UErrorCode ps = U_ZERO_ERROR; 228 df->parse(codeMappingNumber,result,ps); 229 if ( U_SUCCESS(ps) ) { 230 r->code = result.getLong(); // Convert string to number 231 uhash_iput(numericCodeMap,r->code,(void *)r,&status); 232 } 233 UnicodeString *code3 = new UnicodeString(codeMapping3Letter); 234 uhash_put(regionAliases,(void *)code3, (void *)r,&status); 235 } 236 } 237 ures_close(mapping); 238 } 239 240 // Now fill in the special cases for WORLD, UNKNOWN, CONTINENTS, and GROUPINGS 241 Region *r; 242 UnicodeString WORLD_ID_STRING(WORLD_ID); 243 r = (Region *) uhash_get(regionIDMap,(void *)&WORLD_ID_STRING); 244 if ( r ) { 245 r->type = URGN_WORLD; 246 } 247 248 UnicodeString UNKNOWN_REGION_ID_STRING(UNKNOWN_REGION_ID); 249 r = (Region *) uhash_get(regionIDMap,(void *)&UNKNOWN_REGION_ID_STRING); 250 if ( r ) { 251 r->type = URGN_UNKNOWN; 252 } 253 254 for ( int32_t i = 0 ; i < continents->size() ; i++ ) { 255 r = (Region *) uhash_get(regionIDMap,(void *)continents->elementAt(i)); 256 if ( r ) { 257 r->type = URGN_CONTINENT; 258 } 259 } 260 delete continents; 261 262 for ( int32_t i = 0 ; i < groupings->size() ; i++ ) { 263 r = (Region *) uhash_get(regionIDMap,(void *)groupings->elementAt(i)); 264 if ( r ) { 265 r->type = URGN_GROUPING; 266 } 267 } 268 delete groupings; 269 270 // Special case: The region code "QO" (Outlying Oceania) is a subcontinent code added by CLDR 271 // even though it looks like a territory code. Need to handle it here. 272 273 UnicodeString OUTLYING_OCEANIA_REGION_ID_STRING(OUTLYING_OCEANIA_REGION_ID); 274 r = (Region *) uhash_get(regionIDMap,(void *)&OUTLYING_OCEANIA_REGION_ID_STRING); 275 if ( r ) { 276 r->type = URGN_SUBCONTINENT; 277 } 278 279 // Load territory containment info from the supplemental data. 280 while ( ures_hasNext(territoryContainment) ) { 281 UResourceBundle *mapping = ures_getNextResource(territoryContainment,NULL,&status); 282 const char *parent = ures_getKey(mapping); 283 UnicodeString parentStr = UnicodeString(parent, -1 , US_INV); 284 Region *parentRegion = (Region *) uhash_get(regionIDMap,(void *)&parentStr); 285 286 for ( int j = 0 ; j < ures_getSize(mapping); j++ ) { 287 UnicodeString child = ures_getUnicodeStringByIndex(mapping,j,&status); 288 Region *childRegion = (Region *) uhash_get(regionIDMap,(void *)&child); 289 if ( parentRegion != NULL && childRegion != NULL ) { 290 291 // Add the child region to the set of regions contained by the parent 292 if (parentRegion->containedRegions == NULL) { 293 parentRegion->containedRegions = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status); 294 } 295 296 UnicodeString *childStr = new UnicodeString(status); 297 childStr->fastCopyFrom(childRegion->idStr); 298 parentRegion->containedRegions->addElement((void *)childStr,status); 299 300 // Set the parent region to be the containing region of the child. 301 // Regions of type GROUPING can't be set as the parent, since another region 302 // such as a SUBCONTINENT, CONTINENT, or WORLD must always be the parent. 303 if ( parentRegion->type != URGN_GROUPING) { 304 childRegion->containingRegion = parentRegion; 305 } 306 } 307 } 308 ures_close(mapping); 309 } 310 311 // Create the availableRegions lists 312 int32_t pos = -1; 313 while ( const UHashElement* element = uhash_nextElement(regionIDMap,&pos)) { 314 Region *ar = (Region *)element->value.pointer; 315 if ( availableRegions[ar->type] == NULL ) { 316 availableRegions[ar->type] = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status); 317 } 318 UnicodeString *arString = new UnicodeString(ar->idStr); 319 availableRegions[ar->type]->addElement((void *)arString,status); 320 } 321 322 ures_close(territoryContainment); 323 ures_close(worldContainment); 324 ures_close(groupingContainment); 325 326 ures_close(codeMappings); 327 ures_close(rb2); 328 ures_close(territoryAlias); 329 ures_close(regionCodes); 330 ures_close(rb); 331 332 delete df; 333 334 ucln_i18n_registerCleanup(UCLN_I18N_REGION, region_cleanup); 335 336 regionDataIsLoaded = true; 337 umtx_unlock(&gRegionDataLock); 338 339 } 340 341 void Region::cleanupRegionData() { 342 343 for (int32_t i = 0 ; i < URGN_LIMIT ; i++ ) { 344 if ( availableRegions[i] ) { 345 delete availableRegions[i]; 346 } 347 } 348 349 if (regionAliases) { 350 uhash_close(regionAliases); 351 } 352 353 if (numericCodeMap) { 354 uhash_close(numericCodeMap); 355 } 356 357 if (regionIDMap) { 358 uhash_close(regionIDMap); 359 } 360 } 361 362 Region::Region () 363 : code(-1), 364 type(URGN_UNKNOWN), 365 containingRegion(NULL), 366 containedRegions(NULL), 367 preferredValues(NULL) { 368 id[0] = 0; 369 } 370 371 Region::~Region () { 372 if (containedRegions) { 373 delete containedRegions; 374 } 375 if (preferredValues) { 376 delete preferredValues; 377 } 378 } 379 380 /** 381 * Returns true if the two regions are equal. 382 */ 383 UBool 384 Region::operator==(const Region &that) const { 385 return (idStr == that.idStr); 386 } 387 388 /** 389 * Returns true if the two regions are NOT equal; that is, if operator ==() returns false. 390 */ 391 UBool 392 Region::operator!=(const Region &that) const { 393 return (idStr != that.idStr); 394 } 395 396 /** 397 * Returns a pointer to a Region using the given region code. The region code can be either 2-letter ISO code, 398 * 3-letter ISO code, UNM.49 numeric code, or other valid Unicode Region Code as defined by the LDML specification. 399 * The identifier will be canonicalized internally using the supplemental metadata as defined in the CLDR. 400 * If the region code is NULL or not recognized, the appropriate error code will be set ( U_ILLEGAL_ARGUMENT_ERROR ) 401 */ 402 const Region* U_EXPORT2 403 Region::getInstance(const char *region_code, UErrorCode &status) { 404 405 if ( !region_code ) { 406 status = U_ILLEGAL_ARGUMENT_ERROR; 407 return NULL; 408 } 409 410 loadRegionData(); 411 412 if (regionIDMap == NULL) { 413 status = U_ILLEGAL_ARGUMENT_ERROR; 414 return NULL; 415 } 416 417 UnicodeString regionCodeString = UnicodeString(region_code, -1, US_INV); 418 Region *r = (Region *)uhash_get(regionIDMap,(void *)®ionCodeString); 419 420 if ( !r ) { 421 r = (Region *)uhash_get(regionAliases,(void *)®ionCodeString); 422 } 423 424 if ( !r ) { // Unknown region code 425 status = U_ILLEGAL_ARGUMENT_ERROR; 426 return NULL; 427 } 428 429 if ( r->type == URGN_DEPRECATED && r->preferredValues->size() == 1) { 430 StringEnumeration *pv = r->getPreferredValues(); 431 pv->reset(status); 432 const UnicodeString *ustr = pv->snext(status); 433 r = (Region *)uhash_get(regionIDMap,(void *)ustr); 434 delete pv; 435 } 436 437 return r; 438 439 } 440 441 /** 442 * Returns a pointer to a Region using the given numeric region code. If the numeric region code is not recognized, 443 * the appropriate error code will be set ( U_ILLEGAL_ARGUMENT_ERROR ). 444 */ 445 const Region* U_EXPORT2 446 Region::getInstance (int32_t code, UErrorCode &status) { 447 448 loadRegionData(); 449 450 if (numericCodeMap == NULL) { 451 status = U_ILLEGAL_ARGUMENT_ERROR; 452 return NULL; 453 } 454 455 Region *r = (Region *)uhash_iget(numericCodeMap,code); 456 457 if ( !r ) { // Just in case there's an alias that's numeric, try to find it. 458 UErrorCode fs = U_ZERO_ERROR; 459 UnicodeString pat = UNICODE_STRING_SIMPLE("00#"); 460 DecimalFormat *df = new DecimalFormat(pat,fs); 461 462 UnicodeString id; 463 id.remove(); 464 df->format(code,id); 465 delete df; 466 r = (Region *)uhash_get(regionAliases,&id); 467 } 468 469 if ( !r ) { 470 status = U_ILLEGAL_ARGUMENT_ERROR; 471 return NULL; 472 } 473 474 if ( r->type == URGN_DEPRECATED && r->preferredValues->size() == 1) { 475 StringEnumeration *pv = r->getPreferredValues(); 476 pv->reset(status); 477 const UnicodeString *ustr = pv->snext(status); 478 r = (Region *)uhash_get(regionIDMap,(void *)ustr); 479 delete pv; 480 } 481 482 return r; 483 } 484 485 486 /** 487 * Returns an enumeration over the IDs of all known regions that match the given type. 488 */ 489 StringEnumeration* U_EXPORT2 490 Region::getAvailable(URegionType type) { 491 492 loadRegionData(); 493 UErrorCode status = U_ZERO_ERROR; 494 return new RegionNameEnumeration(availableRegions[type],status); 495 496 return NULL; 497 } 498 499 /** 500 * Returns a pointer to the region that contains this region. Returns NULL if this region is code "001" (World) 501 * or "ZZ" (Unknown region). For example, calling this method with region "IT" (Italy) returns the 502 * region "039" (Southern Europe). 503 */ 504 const Region* 505 Region::getContainingRegion() const { 506 loadRegionData(); 507 return containingRegion; 508 } 509 510 /** 511 * Return a pointer to the region that geographically contains this region and matches the given type, 512 * moving multiple steps up the containment chain if necessary. Returns NULL if no containing region can be found 513 * that matches the given type. Note: The URegionTypes = "URGN_GROUPING", "URGN_DEPRECATED", or "URGN_UNKNOWN" 514 * are not appropriate for use in this API. NULL will be returned in this case. For example, calling this method 515 * with region "IT" (Italy) for type "URGN_CONTINENT" returns the region "150" ( Europe ). 516 */ 517 const Region* 518 Region::getContainingRegion(URegionType type) const { 519 loadRegionData(); 520 if ( containingRegion == NULL ) { 521 return NULL; 522 } 523 524 if ( containingRegion->type == type ) { 525 return containingRegion; 526 } else { 527 return containingRegion->getContainingRegion(type); 528 } 529 } 530 531 /** 532 * Return an enumeration over the IDs of all the regions that are immediate children of this region in the 533 * region hierarchy. These returned regions could be either macro regions, territories, or a mixture of the two, 534 * depending on the containment data as defined in CLDR. This API may return NULL if this region doesn't have 535 * any sub-regions. For example, calling this method with region "150" (Europe) returns an enumeration containing 536 * the various sub regions of Europe - "039" (Southern Europe) - "151" (Eastern Europe) - "154" (Northern Europe) 537 * and "155" (Western Europe). 538 */ 539 StringEnumeration* 540 Region::getContainedRegions() const { 541 loadRegionData(); 542 UErrorCode status = U_ZERO_ERROR; 543 return new RegionNameEnumeration(containedRegions,status); 544 } 545 546 /** 547 * Returns an enumeration over the IDs of all the regions that are children of this region anywhere in the region 548 * hierarchy and match the given type. This API may return an empty enumeration if this region doesn't have any 549 * sub-regions that match the given type. For example, calling this method with region "150" (Europe) and type 550 * "URGN_TERRITORY" returns a set containing all the territories in Europe ( "FR" (France) - "IT" (Italy) - "DE" (Germany) etc. ) 551 */ 552 StringEnumeration* 553 Region::getContainedRegions( URegionType type ) const { 554 loadRegionData(); 555 556 UErrorCode status = U_ZERO_ERROR; 557 UVector *result = new UVector(NULL, uhash_compareChars, status); 558 559 StringEnumeration *cr = getContainedRegions(); 560 561 for ( int32_t i = 0 ; i < cr->count(status) ; i++ ) { 562 const char *id = cr->next(NULL,status); 563 const Region *r = Region::getInstance(id,status); 564 if ( r->getType() == type ) { 565 result->addElement((void *)&r->idStr,status); 566 } else { 567 StringEnumeration *children = r->getContainedRegions(type); 568 for ( int32_t j = 0 ; j < children->count(status) ; j++ ) { 569 const char *id2 = children->next(NULL,status); 570 const Region *r2 = Region::getInstance(id2,status); 571 result->addElement((void *)&r2->idStr,status); 572 } 573 delete children; 574 } 575 } 576 delete cr; 577 StringEnumeration* resultEnumeration = new RegionNameEnumeration(result,status); 578 delete result; 579 return resultEnumeration; 580 } 581 582 /** 583 * Returns true if this region contains the supplied other region anywhere in the region hierarchy. 584 */ 585 UBool 586 Region::contains(const Region &other) const { 587 loadRegionData(); 588 589 if (!containedRegions) { 590 return FALSE; 591 } 592 if (containedRegions->contains((void *)&other.idStr)) { 593 return TRUE; 594 } else { 595 for ( int32_t i = 0 ; i < containedRegions->size() ; i++ ) { 596 UnicodeString *crStr = (UnicodeString *)containedRegions->elementAt(i); 597 Region *cr = (Region *) uhash_get(regionIDMap,(void *)crStr); 598 if ( cr && cr->contains(other) ) { 599 return TRUE; 600 } 601 } 602 } 603 604 return FALSE; 605 } 606 607 /** 608 * For deprecated regions, return an enumeration over the IDs of the regions that are the preferred replacement 609 * regions for this region. Returns NULL for a non-deprecated region. For example, calling this method with region 610 * "SU" (Soviet Union) would return a list of the regions containing "RU" (Russia), "AM" (Armenia), "AZ" (Azerbaijan), etc... 611 */ 612 StringEnumeration* 613 Region::getPreferredValues() const { 614 loadRegionData(); 615 UErrorCode status = U_ZERO_ERROR; 616 if ( type == URGN_DEPRECATED ) { 617 return new RegionNameEnumeration(preferredValues,status); 618 } else { 619 return NULL; 620 } 621 } 622 623 624 /** 625 * Return this region's canonical region code. 626 */ 627 const char* 628 Region::getRegionCode() const { 629 return id; 630 } 631 632 int32_t 633 Region::getNumericCode() const { 634 return code; 635 } 636 637 /** 638 * Returns the region type of this region. 639 */ 640 URegionType 641 Region::getType() const { 642 return type; 643 } 644 645 RegionNameEnumeration::RegionNameEnumeration(UVector *fNameList, UErrorCode& status) { 646 pos=0; 647 if (fNameList && U_SUCCESS(status)) { 648 fRegionNames = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, fNameList->size(),status); 649 for ( int32_t i = 0 ; i < fNameList->size() ; i++ ) { 650 UnicodeString* this_region_name = (UnicodeString *)fNameList->elementAt(i); 651 UnicodeString* new_region_name = new UnicodeString(*this_region_name); 652 fRegionNames->addElement((void *)new_region_name,status); 653 } 654 } 655 else { 656 fRegionNames = NULL; 657 } 658 } 659 660 const UnicodeString* 661 RegionNameEnumeration::snext(UErrorCode& status) { 662 if (U_FAILURE(status) || (fRegionNames==NULL)) { 663 return NULL; 664 } 665 const UnicodeString* nextStr = (const UnicodeString *)fRegionNames->elementAt(pos); 666 if (nextStr!=NULL) { 667 pos++; 668 } 669 return nextStr; 670 } 671 672 void 673 RegionNameEnumeration::reset(UErrorCode& /*status*/) { 674 pos=0; 675 } 676 677 int32_t 678 RegionNameEnumeration::count(UErrorCode& /*status*/) const { 679 return (fRegionNames==NULL) ? 0 : fRegionNames->size(); 680 } 681 682 RegionNameEnumeration::~RegionNameEnumeration() { 683 delete fRegionNames; 684 } 685 686 U_NAMESPACE_END 687 688 #endif /* #if !UCONFIG_NO_FORMATTING */ 689 690 //eof 691