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 = &copySkeleton;
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