dtitvinf.cpp revision 1b7d32f919554dda9c193b32188251337bc756f1
1/******************************************************************************* 2* Copyright (C) 2008-2015, International Business Machines Corporation and 3* others. All Rights Reserved. 4******************************************************************************* 5* 6* File DTITVINF.CPP 7* 8******************************************************************************* 9*/ 10 11#include "unicode/dtitvinf.h" 12 13 14#if !UCONFIG_NO_FORMATTING 15 16//TODO: define it in compiler time 17//#define DTITVINF_DEBUG 1 18 19 20#ifdef DTITVINF_DEBUG 21#include <iostream> 22#endif 23 24#include "cstring.h" 25#include "unicode/msgfmt.h" 26#include "unicode/uloc.h" 27#include "unicode/ures.h" 28#include "dtitv_impl.h" 29#include "hash.h" 30#include "gregoimp.h" 31#include "uresimp.h" 32#include "hash.h" 33#include "gregoimp.h" 34#include "uresimp.h" 35 36 37U_NAMESPACE_BEGIN 38 39 40#ifdef DTITVINF_DEBUG 41#define PRINTMESG(msg) { std::cout << "(" << __FILE__ << ":" << __LINE__ << ") " << msg << "\n"; } 42#endif 43 44UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateIntervalInfo) 45 46static const char gCalendarTag[]="calendar"; 47static const char gGregorianTag[]="gregorian"; 48static const char gIntervalDateTimePatternTag[]="intervalFormats"; 49static const char gFallbackPatternTag[]="fallback"; 50 51// {0} 52static const UChar gFirstPattern[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET}; 53// {1} 54static const UChar gSecondPattern[] = {LEFT_CURLY_BRACKET, DIGIT_ONE, RIGHT_CURLY_BRACKET}; 55 56// default fall-back 57static const UChar gDefaultFallbackPattern[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, EN_DASH, SPACE, LEFT_CURLY_BRACKET, DIGIT_ONE, RIGHT_CURLY_BRACKET, 0}; 58 59 60 61DateIntervalInfo::DateIntervalInfo(UErrorCode& status) 62: fFallbackIntervalPattern(gDefaultFallbackPattern), 63 fFirstDateInPtnIsLaterDate(false), 64 fIntervalPatterns(NULL) 65{ 66 fIntervalPatterns = initHash(status); 67} 68 69 70 71DateIntervalInfo::DateIntervalInfo(const Locale& locale, UErrorCode& status) 72: fFallbackIntervalPattern(gDefaultFallbackPattern), 73 fFirstDateInPtnIsLaterDate(false), 74 fIntervalPatterns(NULL) 75{ 76 initializeData(locale, status); 77} 78 79 80 81void 82DateIntervalInfo::setIntervalPattern(const UnicodeString& skeleton, 83 UCalendarDateFields lrgDiffCalUnit, 84 const UnicodeString& intervalPattern, 85 UErrorCode& status) { 86 87 if ( lrgDiffCalUnit == UCAL_HOUR_OF_DAY ) { 88 setIntervalPatternInternally(skeleton, UCAL_AM_PM, intervalPattern, status); 89 setIntervalPatternInternally(skeleton, UCAL_HOUR, intervalPattern, status); 90 } else if ( lrgDiffCalUnit == UCAL_DAY_OF_MONTH || 91 lrgDiffCalUnit == UCAL_DAY_OF_WEEK ) { 92 setIntervalPatternInternally(skeleton, UCAL_DATE, intervalPattern, status); 93 } else { 94 setIntervalPatternInternally(skeleton, lrgDiffCalUnit, intervalPattern, status); 95 } 96} 97 98 99void 100DateIntervalInfo::setFallbackIntervalPattern( 101 const UnicodeString& fallbackPattern, 102 UErrorCode& status) { 103 if ( U_FAILURE(status) ) { 104 return; 105 } 106 int32_t firstPatternIndex = fallbackPattern.indexOf(gFirstPattern, 107 sizeof(gFirstPattern)/sizeof(gFirstPattern[0]), 0); 108 int32_t secondPatternIndex = fallbackPattern.indexOf(gSecondPattern, 109 sizeof(gSecondPattern)/sizeof(gSecondPattern[0]), 0); 110 if ( firstPatternIndex == -1 || secondPatternIndex == -1 ) { 111 status = U_ILLEGAL_ARGUMENT_ERROR; 112 return; 113 } 114 if ( firstPatternIndex > secondPatternIndex ) { 115 fFirstDateInPtnIsLaterDate = true; 116 } 117 fFallbackIntervalPattern = fallbackPattern; 118} 119 120 121 122DateIntervalInfo::DateIntervalInfo(const DateIntervalInfo& dtitvinf) 123: UObject(dtitvinf), 124 fIntervalPatterns(NULL) 125{ 126 *this = dtitvinf; 127} 128 129 130 131DateIntervalInfo& 132DateIntervalInfo::operator=(const DateIntervalInfo& dtitvinf) { 133 if ( this == &dtitvinf ) { 134 return *this; 135 } 136 137 UErrorCode status = U_ZERO_ERROR; 138 deleteHash(fIntervalPatterns); 139 fIntervalPatterns = initHash(status); 140 copyHash(dtitvinf.fIntervalPatterns, fIntervalPatterns, status); 141 if ( U_FAILURE(status) ) { 142 return *this; 143 } 144 145 fFallbackIntervalPattern = dtitvinf.fFallbackIntervalPattern; 146 fFirstDateInPtnIsLaterDate = dtitvinf.fFirstDateInPtnIsLaterDate; 147 return *this; 148} 149 150 151DateIntervalInfo* 152DateIntervalInfo::clone() const { 153 return new DateIntervalInfo(*this); 154} 155 156 157DateIntervalInfo::~DateIntervalInfo() { 158 deleteHash(fIntervalPatterns); 159 fIntervalPatterns = NULL; 160} 161 162 163UBool 164DateIntervalInfo::operator==(const DateIntervalInfo& other) const { 165 UBool equal = ( 166 fFallbackIntervalPattern == other.fFallbackIntervalPattern && 167 fFirstDateInPtnIsLaterDate == other.fFirstDateInPtnIsLaterDate ); 168 169 if ( equal == TRUE ) { 170 equal = fIntervalPatterns->equals(*(other.fIntervalPatterns)); 171 } 172 173 return equal; 174} 175 176 177UnicodeString& 178DateIntervalInfo::getIntervalPattern(const UnicodeString& skeleton, 179 UCalendarDateFields field, 180 UnicodeString& result, 181 UErrorCode& status) const { 182 if ( U_FAILURE(status) ) { 183 return result; 184 } 185 186 const UnicodeString* patternsOfOneSkeleton = (UnicodeString*) fIntervalPatterns->get(skeleton); 187 if ( patternsOfOneSkeleton != NULL ) { 188 IntervalPatternIndex index = calendarFieldToIntervalIndex(field, status); 189 if ( U_FAILURE(status) ) { 190 return result; 191 } 192 const UnicodeString& intervalPattern = patternsOfOneSkeleton[index]; 193 if ( !intervalPattern.isEmpty() ) { 194 result = intervalPattern; 195 } 196 } 197 return result; 198} 199 200 201UBool 202DateIntervalInfo::getDefaultOrder() const { 203 return fFirstDateInPtnIsLaterDate; 204} 205 206 207UnicodeString& 208DateIntervalInfo::getFallbackIntervalPattern(UnicodeString& result) const { 209 result = fFallbackIntervalPattern; 210 return result; 211} 212 213#define ULOC_LOCALE_IDENTIFIER_CAPACITY (ULOC_FULLNAME_CAPACITY + 1 + ULOC_KEYWORD_AND_VALUES_CAPACITY) 214 215void 216DateIntervalInfo::initializeData(const Locale& locale, UErrorCode& err) 217{ 218 fIntervalPatterns = initHash(err); 219 if ( U_FAILURE(err) ) { 220 return; 221 } 222 const char *locName = locale.getName(); 223 char parentLocale[ULOC_FULLNAME_CAPACITY]; 224 uprv_strcpy(parentLocale, locName); 225 UErrorCode status = U_ZERO_ERROR; 226 Hashtable skeletonKeyPairs(FALSE, status); 227 if ( U_FAILURE(status) ) { 228 return; 229 } 230 231 // determine calendar type 232 const char * calendarTypeToUse = gGregorianTag; // initial default 233 char calendarType[ULOC_KEYWORDS_CAPACITY]; // to be filled in with the type to use, if all goes well 234 char localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY]; 235 // obtain a locale that always has the calendar key value that should be used 236 (void)ures_getFunctionalEquivalent(localeWithCalendarKey, ULOC_LOCALE_IDENTIFIER_CAPACITY, NULL, 237 "calendar", "calendar", locName, NULL, FALSE, &status); 238 localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY-1] = 0; // ensure null termination 239 // now get the calendar key value from that locale 240 int32_t calendarTypeLen = uloc_getKeywordValue(localeWithCalendarKey, "calendar", calendarType, ULOC_KEYWORDS_CAPACITY, &status); 241 if (U_SUCCESS(status) && calendarTypeLen < ULOC_KEYWORDS_CAPACITY) { 242 calendarTypeToUse = calendarType; 243 } 244 status = U_ZERO_ERROR; 245 246 do { 247 UResourceBundle *rb, *calBundle, *calTypeBundle, *itvDtPtnResource; 248 rb = ures_open(NULL, parentLocale, &status); 249 if ( U_FAILURE(status) ) { 250 break; 251 } 252 calBundle = ures_getByKey(rb, gCalendarTag, NULL, &status); 253 calTypeBundle = ures_getByKey(calBundle, calendarTypeToUse, NULL, &status); 254 itvDtPtnResource = ures_getByKeyWithFallback(calTypeBundle, 255 gIntervalDateTimePatternTag, NULL, &status); 256 257 if ( U_SUCCESS(status) ) { 258 // look for fallback first, since it establishes the default order 259 const UChar* resStr; 260 int32_t resStrLen = 0; 261 resStr = ures_getStringByKeyWithFallback(itvDtPtnResource, 262 gFallbackPatternTag, 263 &resStrLen, &status); 264 if ( U_SUCCESS(status) ) { 265 UnicodeString pattern = UnicodeString(TRUE, resStr, resStrLen); 266 setFallbackIntervalPattern(pattern, status); 267 } 268 269 int32_t size = ures_getSize(itvDtPtnResource); 270 int32_t index; 271 for ( index = 0; index < size; ++index ) { 272 LocalUResourceBundlePointer oneRes(ures_getByIndex(itvDtPtnResource, index, 273 NULL, &status)); 274 if ( U_SUCCESS(status) ) { 275 const char* skeleton = ures_getKey(oneRes.getAlias()); 276 if (skeleton == NULL) { 277 continue; 278 } 279 UnicodeString skeletonUniStr(skeleton, -1, US_INV); 280 if ( uprv_strcmp(skeleton, gFallbackPatternTag) == 0 ) { 281 continue; // fallback 282 } 283 284 LocalUResourceBundlePointer intervalPatterns(ures_getByKey( 285 itvDtPtnResource, skeleton, NULL, &status)); 286 287 if ( U_FAILURE(status) ) { 288 break; 289 } 290 if ( intervalPatterns == NULL ) { 291 continue; 292 } 293 294 const char* key; 295 int32_t ptnNum = ures_getSize(intervalPatterns.getAlias()); 296 int32_t ptnIndex; 297 for ( ptnIndex = 0; ptnIndex < ptnNum; ++ptnIndex ) { 298 UnicodeString pattern = 299 ures_getNextUnicodeString(intervalPatterns.getAlias(), &key, &status); 300 if ( U_FAILURE(status) ) { 301 break; 302 } 303 UnicodeString keyUniStr(key, -1, US_INV); 304 UnicodeString skeletonKeyPair(skeletonUniStr + keyUniStr); 305 if ( skeletonKeyPairs.geti(skeletonKeyPair) == 1 ) { 306 continue; 307 } 308 skeletonKeyPairs.puti(skeletonKeyPair, 1, status); 309 310 UCalendarDateFields calendarField = UCAL_FIELD_COUNT; 311 if ( !uprv_strcmp(key, "y") ) { 312 calendarField = UCAL_YEAR; 313 } else if ( !uprv_strcmp(key, "M") ) { 314 calendarField = UCAL_MONTH; 315 } else if ( !uprv_strcmp(key, "d") ) { 316 calendarField = UCAL_DATE; 317 } else if ( !uprv_strcmp(key, "a") ) { 318 calendarField = UCAL_AM_PM; 319 } else if ( !uprv_strcmp(key, "h") || !uprv_strcmp(key, "H") ) { 320 calendarField = UCAL_HOUR; 321 } else if ( !uprv_strcmp(key, "m") ) { 322 calendarField = UCAL_MINUTE; 323 } 324 if ( calendarField != UCAL_FIELD_COUNT ) { 325 setIntervalPatternInternally(skeletonUniStr, calendarField, pattern,status); 326 } 327 } 328 } 329 } 330 } 331 ures_close(itvDtPtnResource); 332 ures_close(calTypeBundle); 333 ures_close(calBundle); 334 335 status = U_ZERO_ERROR; 336 // Find the name of the appropriate parent locale (from %%Parent if present, else 337 // uloc_getParent on the actual locale name) 338 // (It would be nice to have a ures function that did this...) 339 int32_t locNameLen; 340 const UChar * parentUName = ures_getStringByKey(rb, "%%Parent", &locNameLen, &status); 341 if (U_SUCCESS(status) && status != U_USING_FALLBACK_WARNING && locNameLen < ULOC_FULLNAME_CAPACITY) { 342 u_UCharsToChars(parentUName, parentLocale, locNameLen + 1); 343 } else { 344 status = U_ZERO_ERROR; 345 // Get the actual name of the current locale being used 346 const char *curLocaleName=ures_getLocaleByType(rb, ULOC_ACTUAL_LOCALE, &status); 347 if ( U_FAILURE(status) ) { 348 curLocaleName = parentLocale; 349 status = U_ZERO_ERROR; 350 } 351 uloc_getParent(curLocaleName, parentLocale, ULOC_FULLNAME_CAPACITY, &status); 352 if (U_FAILURE(err) || err == U_STRING_NOT_TERMINATED_WARNING) { 353 parentLocale[0] = 0; // just fallback to root, will cause us to stop 354 status = U_ZERO_ERROR; 355 } 356 } 357 // Now we can close the current locale bundle 358 ures_close(rb); 359 // If the new current locale is root, then stop 360 // (unlike for DateTimePatternGenerator, DateIntervalFormat does not go all the way up 361 // to root to find additional data for non-root locales) 362 } while ( parentLocale[0] != 0 && uprv_strcmp(parentLocale,"root")!=0 ); 363} 364 365 366 367void 368DateIntervalInfo::setIntervalPatternInternally(const UnicodeString& skeleton, 369 UCalendarDateFields lrgDiffCalUnit, 370 const UnicodeString& intervalPattern, 371 UErrorCode& status) { 372 IntervalPatternIndex index = calendarFieldToIntervalIndex(lrgDiffCalUnit,status); 373 if ( U_FAILURE(status) ) { 374 return; 375 } 376 UnicodeString* patternsOfOneSkeleton = (UnicodeString*)(fIntervalPatterns->get(skeleton)); 377 UBool emptyHash = false; 378 if ( patternsOfOneSkeleton == NULL ) { 379 patternsOfOneSkeleton = new UnicodeString[kIPI_MAX_INDEX]; 380 emptyHash = true; 381 } 382 383 patternsOfOneSkeleton[index] = intervalPattern; 384 if ( emptyHash == TRUE ) { 385 fIntervalPatterns->put(skeleton, patternsOfOneSkeleton, status); 386 } 387} 388 389 390 391void 392DateIntervalInfo::parseSkeleton(const UnicodeString& skeleton, 393 int32_t* skeletonFieldWidth) { 394 const int8_t PATTERN_CHAR_BASE = 0x41; 395 int32_t i; 396 for ( i = 0; i < skeleton.length(); ++i ) { 397 // it is an ASCII char in skeleton 398 int8_t ch = (int8_t)skeleton.charAt(i); 399 ++skeletonFieldWidth[ch - PATTERN_CHAR_BASE]; 400 } 401} 402 403 404 405UBool 406DateIntervalInfo::stringNumeric(int32_t fieldWidth, int32_t anotherFieldWidth, 407 char patternLetter) { 408 if ( patternLetter == 'M' ) { 409 if ( (fieldWidth <= 2 && anotherFieldWidth > 2) || 410 (fieldWidth > 2 && anotherFieldWidth <= 2 )) { 411 return true; 412 } 413 } 414 return false; 415} 416 417 418 419const UnicodeString* 420DateIntervalInfo::getBestSkeleton(const UnicodeString& skeleton, 421 int8_t& bestMatchDistanceInfo) const { 422#ifdef DTITVINF_DEBUG 423 char result[1000]; 424 char result_1[1000]; 425 char mesg[2000]; 426 skeleton.extract(0, skeleton.length(), result, "UTF-8"); 427 sprintf(mesg, "in getBestSkeleton: skeleton: %s; \n", result); 428 PRINTMESG(mesg) 429#endif 430 431 432 int32_t inputSkeletonFieldWidth[] = 433 { 434 // A B C D E F G H I J K L M N O 435 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 436 // P Q R S T U V W X Y Z 437 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 438 // a b c d e f g h i j k l m n o 439 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 440 // p q r s t u v w x y z 441 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 442 }; 443 444 int32_t skeletonFieldWidth[] = 445 { 446 // A B C D E F G H I J K L M N O 447 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 448 // P Q R S T U V W X Y Z 449 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 450 // a b c d e f g h i j k l m n o 451 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 452 // p q r s t u v w x y z 453 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 454 }; 455 456 const int32_t DIFFERENT_FIELD = 0x1000; 457 const int32_t STRING_NUMERIC_DIFFERENCE = 0x100; 458 const int32_t BASE = 0x41; 459 const UChar CHAR_V = 0x0076; 460 const UChar CHAR_Z = 0x007A; 461 462 // hack for 'v' and 'z'. 463 // resource bundle only have time skeletons ending with 'v', 464 // but not for time skeletons ending with 'z'. 465 UBool replaceZWithV = false; 466 const UnicodeString* inputSkeleton = &skeleton; 467 UnicodeString copySkeleton; 468 if ( skeleton.indexOf(CHAR_Z) != -1 ) { 469 copySkeleton = skeleton; 470 copySkeleton.findAndReplace(UnicodeString(CHAR_Z), UnicodeString(CHAR_V)); 471 inputSkeleton = ©Skeleton; 472 replaceZWithV = true; 473 } 474 475 parseSkeleton(*inputSkeleton, inputSkeletonFieldWidth); 476 int32_t bestDistance = MAX_POSITIVE_INT; 477 const UnicodeString* bestSkeleton = NULL; 478 479 // 0 means exact the same skeletons; 480 // 1 means having the same field, but with different length, 481 // 2 means only z/v differs 482 // -1 means having different field. 483 bestMatchDistanceInfo = 0; 484 int8_t fieldLength = sizeof(skeletonFieldWidth)/sizeof(skeletonFieldWidth[0]); 485 486 int32_t pos = UHASH_FIRST; 487 const UHashElement* elem = NULL; 488 while ( (elem = fIntervalPatterns->nextElement(pos)) != NULL ) { 489 const UHashTok keyTok = elem->key; 490 UnicodeString* skeleton = (UnicodeString*)keyTok.pointer; 491#ifdef DTITVINF_DEBUG 492 skeleton->extract(0, skeleton->length(), result, "UTF-8"); 493 sprintf(mesg, "available skeletons: skeleton: %s; \n", result); 494 PRINTMESG(mesg) 495#endif 496 497 // clear skeleton field width 498 int8_t i; 499 for ( i = 0; i < fieldLength; ++i ) { 500 skeletonFieldWidth[i] = 0; 501 } 502 parseSkeleton(*skeleton, skeletonFieldWidth); 503 // calculate distance 504 int32_t distance = 0; 505 int8_t fieldDifference = 1; 506 for ( i = 0; i < fieldLength; ++i ) { 507 int32_t inputFieldWidth = inputSkeletonFieldWidth[i]; 508 int32_t fieldWidth = skeletonFieldWidth[i]; 509 if ( inputFieldWidth == fieldWidth ) { 510 continue; 511 } 512 if ( inputFieldWidth == 0 ) { 513 fieldDifference = -1; 514 distance += DIFFERENT_FIELD; 515 } else if ( fieldWidth == 0 ) { 516 fieldDifference = -1; 517 distance += DIFFERENT_FIELD; 518 } else if (stringNumeric(inputFieldWidth, fieldWidth, 519 (char)(i+BASE) ) ) { 520 distance += STRING_NUMERIC_DIFFERENCE; 521 } else { 522 distance += (inputFieldWidth > fieldWidth) ? 523 (inputFieldWidth - fieldWidth) : 524 (fieldWidth - inputFieldWidth); 525 } 526 } 527 if ( distance < bestDistance ) { 528 bestSkeleton = skeleton; 529 bestDistance = distance; 530 bestMatchDistanceInfo = fieldDifference; 531 } 532 if ( distance == 0 ) { 533 bestMatchDistanceInfo = 0; 534 break; 535 } 536 } 537 if ( replaceZWithV && bestMatchDistanceInfo != -1 ) { 538 bestMatchDistanceInfo = 2; 539 } 540 return bestSkeleton; 541} 542 543 544 545DateIntervalInfo::IntervalPatternIndex 546DateIntervalInfo::calendarFieldToIntervalIndex(UCalendarDateFields field, 547 UErrorCode& status) { 548 if ( U_FAILURE(status) ) { 549 return kIPI_MAX_INDEX; 550 } 551 IntervalPatternIndex index = kIPI_MAX_INDEX; 552 switch ( field ) { 553 case UCAL_ERA: 554 index = kIPI_ERA; 555 break; 556 case UCAL_YEAR: 557 index = kIPI_YEAR; 558 break; 559 case UCAL_MONTH: 560 index = kIPI_MONTH; 561 break; 562 case UCAL_DATE: 563 case UCAL_DAY_OF_WEEK: 564 //case UCAL_DAY_OF_MONTH: 565 index = kIPI_DATE; 566 break; 567 case UCAL_AM_PM: 568 index = kIPI_AM_PM; 569 break; 570 case UCAL_HOUR: 571 case UCAL_HOUR_OF_DAY: 572 index = kIPI_HOUR; 573 break; 574 case UCAL_MINUTE: 575 index = kIPI_MINUTE; 576 break; 577 default: 578 status = U_ILLEGAL_ARGUMENT_ERROR; 579 } 580 return index; 581} 582 583 584 585void 586DateIntervalInfo::deleteHash(Hashtable* hTable) 587{ 588 if ( hTable == NULL ) { 589 return; 590 } 591 int32_t pos = UHASH_FIRST; 592 const UHashElement* element = NULL; 593 while ( (element = hTable->nextElement(pos)) != NULL ) { 594 const UHashTok valueTok = element->value; 595 const UnicodeString* value = (UnicodeString*)valueTok.pointer; 596 delete[] value; 597 } 598 delete fIntervalPatterns; 599} 600 601 602U_CDECL_BEGIN 603 604/** 605 * set hash table value comparator 606 * 607 * @param val1 one value in comparison 608 * @param val2 the other value in comparison 609 * @return TRUE if 2 values are the same, FALSE otherwise 610 */ 611static UBool U_CALLCONV dtitvinfHashTableValueComparator(UHashTok val1, UHashTok val2); 612 613static UBool 614U_CALLCONV dtitvinfHashTableValueComparator(UHashTok val1, UHashTok val2) { 615 const UnicodeString* pattern1 = (UnicodeString*)val1.pointer; 616 const UnicodeString* pattern2 = (UnicodeString*)val2.pointer; 617 UBool ret = TRUE; 618 int8_t i; 619 for ( i = 0; i < DateIntervalInfo::kMaxIntervalPatternIndex && ret == TRUE; ++i ) { 620 ret = (pattern1[i] == pattern2[i]); 621 } 622 return ret; 623} 624 625U_CDECL_END 626 627 628Hashtable* 629DateIntervalInfo::initHash(UErrorCode& status) { 630 if ( U_FAILURE(status) ) { 631 return NULL; 632 } 633 Hashtable* hTable; 634 if ( (hTable = new Hashtable(FALSE, status)) == NULL ) { 635 status = U_MEMORY_ALLOCATION_ERROR; 636 return NULL; 637 } 638 if ( U_FAILURE(status) ) { 639 delete hTable; 640 return NULL; 641 } 642 hTable->setValueComparator(dtitvinfHashTableValueComparator); 643 return hTable; 644} 645 646 647void 648DateIntervalInfo::copyHash(const Hashtable* source, 649 Hashtable* target, 650 UErrorCode& status) { 651 if ( U_FAILURE(status) ) { 652 return; 653 } 654 int32_t pos = UHASH_FIRST; 655 const UHashElement* element = NULL; 656 if ( source ) { 657 while ( (element = source->nextElement(pos)) != NULL ) { 658 const UHashTok keyTok = element->key; 659 const UnicodeString* key = (UnicodeString*)keyTok.pointer; 660 const UHashTok valueTok = element->value; 661 const UnicodeString* value = (UnicodeString*)valueTok.pointer; 662 UnicodeString* copy = new UnicodeString[kIPI_MAX_INDEX]; 663 int8_t i; 664 for ( i = 0; i < kIPI_MAX_INDEX; ++i ) { 665 copy[i] = value[i]; 666 } 667 target->put(UnicodeString(*key), copy, status); 668 if ( U_FAILURE(status) ) { 669 return; 670 } 671 } 672 } 673} 674 675 676U_NAMESPACE_END 677 678#endif 679