]> git.saurik.com Git - apple/icu.git/blame - icuSources/i18n/dtitvinf.cpp
ICU-551.24.tar.gz
[apple/icu.git] / icuSources / i18n / dtitvinf.cpp
CommitLineData
46f4442e 1/*******************************************************************************
b331163b 2* Copyright (C) 2008-2015, International Business Machines Corporation and
46f4442e
A
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
729e4ab9 16//TODO: define it in compiler time
46f4442e
A
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"
729e4ab9
A
26#include "unicode/uloc.h"
27#include "unicode/ures.h"
46f4442e
A
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
729e4ab9 213#define ULOC_LOCALE_IDENTIFIER_CAPACITY (ULOC_FULLNAME_CAPACITY + 1 + ULOC_KEYWORD_AND_VALUES_CAPACITY)
46f4442e
A
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];
46f4442e
A
224 uprv_strcpy(parentLocale, locName);
225 UErrorCode status = U_ZERO_ERROR;
b331163b 226 Hashtable skeletonKeyPairs(FALSE, status);
46f4442e
A
227 if ( U_FAILURE(status) ) {
228 return;
229 }
729e4ab9
A
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
46f4442e 246 do {
729e4ab9 247 UResourceBundle *rb, *calBundle, *calTypeBundle, *itvDtPtnResource;
46f4442e 248 rb = ures_open(NULL, parentLocale, &status);
4388f060
A
249 if ( U_FAILURE(status) ) {
250 break;
251 }
46f4442e 252 calBundle = ures_getByKey(rb, gCalendarTag, NULL, &status);
729e4ab9
A
253 calTypeBundle = ures_getByKey(calBundle, calendarTypeToUse, NULL, &status);
254 itvDtPtnResource = ures_getByKeyWithFallback(calTypeBundle,
46f4442e
A
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 ) {
4388f060
A
272 LocalUResourceBundlePointer oneRes(ures_getByIndex(itvDtPtnResource, index,
273 NULL, &status));
46f4442e 274 if ( U_SUCCESS(status) ) {
4388f060
A
275 const char* skeleton = ures_getKey(oneRes.getAlias());
276 if (skeleton == NULL) {
277 continue;
278 }
279 UnicodeString skeletonUniStr(skeleton, -1, US_INV);
46f4442e 280 if ( uprv_strcmp(skeleton, gFallbackPatternTag) == 0 ) {
46f4442e
A
281 continue; // fallback
282 }
4388f060
A
283
284 LocalUResourceBundlePointer intervalPatterns(ures_getByKey(
285 itvDtPtnResource, skeleton, NULL, &status));
286
46f4442e 287 if ( U_FAILURE(status) ) {
46f4442e
A
288 break;
289 }
290 if ( intervalPatterns == NULL ) {
46f4442e
A
291 continue;
292 }
4388f060 293
46f4442e 294 const char* key;
4388f060 295 int32_t ptnNum = ures_getSize(intervalPatterns.getAlias());
46f4442e
A
296 int32_t ptnIndex;
297 for ( ptnIndex = 0; ptnIndex < ptnNum; ++ptnIndex ) {
4388f060
A
298 UnicodeString pattern =
299 ures_getNextUnicodeString(intervalPatterns.getAlias(), &key, &status);
46f4442e
A
300 if ( U_FAILURE(status) ) {
301 break;
302 }
b331163b
A
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);
46f4442e
A
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;
729e4ab9 319 } else if ( !uprv_strcmp(key, "h") || !uprv_strcmp(key, "H") ) {
46f4442e
A
320 calendarField = UCAL_HOUR;
321 } else if ( !uprv_strcmp(key, "m") ) {
322 calendarField = UCAL_MINUTE;
323 }
324 if ( calendarField != UCAL_FIELD_COUNT ) {
4388f060 325 setIntervalPatternInternally(skeletonUniStr, calendarField, pattern,status);
46f4442e
A
326 }
327 }
46f4442e 328 }
46f4442e
A
329 }
330 }
331 ures_close(itvDtPtnResource);
729e4ab9 332 ures_close(calTypeBundle);
46f4442e 333 ures_close(calBundle);
4388f060 334
46f4442e 335 status = U_ZERO_ERROR;
4388f060
A
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 );
46f4442e
A
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' ) {
729e4ab9
A
409 if ( (fieldWidth <= 2 && anotherFieldWidth > 2) ||
410 (fieldWidth > 2 && anotherFieldWidth <= 2 )) {
46f4442e
A
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 ) {
46f4442e 469 copySkeleton = skeleton;
4388f060 470 copySkeleton.findAndReplace(UnicodeString(CHAR_Z), UnicodeString(CHAR_V));
46f4442e
A
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
b331163b 486 int32_t pos = UHASH_FIRST;
46f4442e
A
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;
b331163b
A
577 case UCAL_SECOND:
578 index = kIPI_SECOND;
579 break;
46f4442e
A
580 default:
581 status = U_ILLEGAL_ARGUMENT_ERROR;
582 }
583 return index;
584}
585
586
587
588void
589DateIntervalInfo::deleteHash(Hashtable* hTable)
590{
591 if ( hTable == NULL ) {
592 return;
593 }
b331163b 594 int32_t pos = UHASH_FIRST;
46f4442e
A
595 const UHashElement* element = NULL;
596 while ( (element = hTable->nextElement(pos)) != NULL ) {
46f4442e
A
597 const UHashTok valueTok = element->value;
598 const UnicodeString* value = (UnicodeString*)valueTok.pointer;
599 delete[] value;
600 }
601 delete fIntervalPatterns;
602}
603
604
605U_CDECL_BEGIN
606
607/**
608 * set hash table value comparator
609 *
610 * @param val1 one value in comparison
611 * @param val2 the other value in comparison
612 * @return TRUE if 2 values are the same, FALSE otherwise
613 */
729e4ab9 614static UBool U_CALLCONV dtitvinfHashTableValueComparator(UHashTok val1, UHashTok val2);
46f4442e 615
729e4ab9
A
616static UBool
617U_CALLCONV dtitvinfHashTableValueComparator(UHashTok val1, UHashTok val2) {
46f4442e
A
618 const UnicodeString* pattern1 = (UnicodeString*)val1.pointer;
619 const UnicodeString* pattern2 = (UnicodeString*)val2.pointer;
620 UBool ret = TRUE;
621 int8_t i;
729e4ab9 622 for ( i = 0; i < DateIntervalInfo::kMaxIntervalPatternIndex && ret == TRUE; ++i ) {
46f4442e
A
623 ret = (pattern1[i] == pattern2[i]);
624 }
625 return ret;
626}
627
729e4ab9 628U_CDECL_END
46f4442e
A
629
630
631Hashtable*
632DateIntervalInfo::initHash(UErrorCode& status) {
633 if ( U_FAILURE(status) ) {
634 return NULL;
635 }
636 Hashtable* hTable;
729e4ab9 637 if ( (hTable = new Hashtable(FALSE, status)) == NULL ) {
46f4442e
A
638 status = U_MEMORY_ALLOCATION_ERROR;
639 return NULL;
640 }
729e4ab9
A
641 if ( U_FAILURE(status) ) {
642 delete hTable;
643 return NULL;
644 }
645 hTable->setValueComparator(dtitvinfHashTableValueComparator);
46f4442e
A
646 return hTable;
647}
648
649
650void
651DateIntervalInfo::copyHash(const Hashtable* source,
652 Hashtable* target,
653 UErrorCode& status) {
654 if ( U_FAILURE(status) ) {
655 return;
656 }
b331163b 657 int32_t pos = UHASH_FIRST;
46f4442e
A
658 const UHashElement* element = NULL;
659 if ( source ) {
660 while ( (element = source->nextElement(pos)) != NULL ) {
661 const UHashTok keyTok = element->key;
662 const UnicodeString* key = (UnicodeString*)keyTok.pointer;
663 const UHashTok valueTok = element->value;
664 const UnicodeString* value = (UnicodeString*)valueTok.pointer;
665 UnicodeString* copy = new UnicodeString[kIPI_MAX_INDEX];
666 int8_t i;
667 for ( i = 0; i < kIPI_MAX_INDEX; ++i ) {
668 copy[i] = value[i];
669 }
670 target->put(UnicodeString(*key), copy, status);
671 if ( U_FAILURE(status) ) {
672 return;
673 }
674 }
675 }
676}
677
678
679U_NAMESPACE_END
680
681#endif