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