• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
DateIntervalInfo(UErrorCode & status)59 DateIntervalInfo::DateIntervalInfo(UErrorCode& status)
60 :   fFallbackIntervalPattern(gDefaultFallbackPattern),
61     fFirstDateInPtnIsLaterDate(false),
62     fIntervalPatterns(NULL)
63 {
64     fIntervalPatterns = initHash(status);
65 }
66 
67 
68 
DateIntervalInfo(const Locale & locale,UErrorCode & status)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
setIntervalPattern(const UnicodeString & skeleton,UCalendarDateFields lrgDiffCalUnit,const UnicodeString & intervalPattern,UErrorCode & status)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
setFallbackIntervalPattern(const UnicodeString & fallbackPattern,UErrorCode & status)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 
DateIntervalInfo(const DateIntervalInfo & dtitvinf)120 DateIntervalInfo::DateIntervalInfo(const DateIntervalInfo& dtitvinf)
121 :   UObject(dtitvinf),
122     fIntervalPatterns(NULL)
123 {
124     *this = dtitvinf;
125 }
126 
127 
128 
129 DateIntervalInfo&
operator =(const DateIntervalInfo & dtitvinf)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*
clone() const150 DateIntervalInfo::clone() const {
151     return new DateIntervalInfo(*this);
152 }
153 
154 
~DateIntervalInfo()155 DateIntervalInfo::~DateIntervalInfo() {
156     deleteHash(fIntervalPatterns);
157     fIntervalPatterns = NULL;
158 }
159 
160 
161 UBool
operator ==(const DateIntervalInfo & other) const162 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&
getIntervalPattern(const UnicodeString & skeleton,UCalendarDateFields field,UnicodeString & result,UErrorCode & status) const176 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
getDefaultOrder() const200 DateIntervalInfo::getDefaultOrder() const {
201     return fFirstDateInPtnIsLaterDate;
202 }
203 
204 
205 UnicodeString&
getFallbackIntervalPattern(UnicodeString & result) const206 DateIntervalInfo::getFallbackIntervalPattern(UnicodeString& result) const {
207     result = fFallbackIntervalPattern;
208     return result;
209 }
210 
211 
212 void
initializeData(const Locale & locale,UErrorCode & err)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
setIntervalPatternInternally(const UnicodeString & skeleton,UCalendarDateFields lrgDiffCalUnit,const UnicodeString & intervalPattern,UErrorCode & status)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
parseSkeleton(const UnicodeString & skeleton,int32_t * skeletonFieldWidth)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
stringNumeric(int32_t fieldWidth,int32_t anotherFieldWidth,char patternLetter)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*
getBestSkeleton(const UnicodeString & skeleton,int8_t & bestMatchDistanceInfo) const380 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
calendarFieldToIntervalIndex(UCalendarDateFields field,UErrorCode & status)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
deleteHash(Hashtable * hTable)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
dtitvinfHashTableValueComparator(UHashTok val1,UHashTok val2)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*
initHash(UErrorCode & status)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
copyHash(const Hashtable * source,Hashtable * target,UErrorCode & status)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