1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*******************************************************************************
4 * Copyright (C) 2008-2016, International Business Machines Corporation and
5 * others. All Rights Reserved.
6 *******************************************************************************
10 *******************************************************************************
13 #include "unicode/dtitvinf.h"
16 #if !UCONFIG_NO_FORMATTING
18 //TODO: define it in compiler time
19 //#define DTITVINF_DEBUG 1
28 #include "unicode/msgfmt.h"
29 #include "unicode/uloc.h"
30 #include "unicode/ures.h"
31 #include "dtitv_impl.h"
45 #define PRINTMESG(msg) { std::cout << "(" << __FILE__ << ":" << __LINE__ << ") " << msg << "\n"; }
48 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateIntervalInfo
)
50 static const char gCalendarTag
[]="calendar";
51 static const char gGregorianTag
[]="gregorian";
52 static const char gIntervalDateTimePatternTag
[]="intervalFormats";
53 static const char gFallbackPatternTag
[]="fallback";
56 static const UChar gFirstPattern
[] = {LEFT_CURLY_BRACKET
, DIGIT_ZERO
, RIGHT_CURLY_BRACKET
};
58 static const UChar gSecondPattern
[] = {LEFT_CURLY_BRACKET
, DIGIT_ONE
, RIGHT_CURLY_BRACKET
};
61 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};
63 DateIntervalInfo::DateIntervalInfo(UErrorCode
& status
)
64 : fFallbackIntervalPattern(gDefaultFallbackPattern
),
65 fFirstDateInPtnIsLaterDate(false),
66 fIntervalPatterns(NULL
)
68 fIntervalPatterns
= initHash(status
);
73 DateIntervalInfo::DateIntervalInfo(const Locale
& locale
, UErrorCode
& status
)
74 : fFallbackIntervalPattern(gDefaultFallbackPattern
),
75 fFirstDateInPtnIsLaterDate(false),
76 fIntervalPatterns(NULL
)
78 initializeData(locale
, status
);
84 DateIntervalInfo::setIntervalPattern(const UnicodeString
& skeleton
,
85 UCalendarDateFields lrgDiffCalUnit
,
86 const UnicodeString
& intervalPattern
,
89 if ( lrgDiffCalUnit
== UCAL_HOUR_OF_DAY
) {
90 setIntervalPatternInternally(skeleton
, UCAL_AM_PM
, intervalPattern
, status
);
91 setIntervalPatternInternally(skeleton
, UCAL_HOUR
, intervalPattern
, status
);
92 } else if ( lrgDiffCalUnit
== UCAL_DAY_OF_MONTH
||
93 lrgDiffCalUnit
== UCAL_DAY_OF_WEEK
) {
94 setIntervalPatternInternally(skeleton
, UCAL_DATE
, intervalPattern
, status
);
96 setIntervalPatternInternally(skeleton
, lrgDiffCalUnit
, intervalPattern
, status
);
102 DateIntervalInfo::setFallbackIntervalPattern(
103 const UnicodeString
& fallbackPattern
,
104 UErrorCode
& status
) {
105 if ( U_FAILURE(status
) ) {
108 int32_t firstPatternIndex
= fallbackPattern
.indexOf(gFirstPattern
,
109 UPRV_LENGTHOF(gFirstPattern
), 0);
110 int32_t secondPatternIndex
= fallbackPattern
.indexOf(gSecondPattern
,
111 UPRV_LENGTHOF(gSecondPattern
), 0);
112 if ( firstPatternIndex
== -1 || secondPatternIndex
== -1 ) {
113 status
= U_ILLEGAL_ARGUMENT_ERROR
;
116 if ( firstPatternIndex
> secondPatternIndex
) {
117 fFirstDateInPtnIsLaterDate
= true;
119 fFallbackIntervalPattern
= fallbackPattern
;
124 DateIntervalInfo::DateIntervalInfo(const DateIntervalInfo
& dtitvinf
)
126 fIntervalPatterns(NULL
)
134 DateIntervalInfo::operator=(const DateIntervalInfo
& dtitvinf
) {
135 if ( this == &dtitvinf
) {
139 UErrorCode status
= U_ZERO_ERROR
;
140 deleteHash(fIntervalPatterns
);
141 fIntervalPatterns
= initHash(status
);
142 copyHash(dtitvinf
.fIntervalPatterns
, fIntervalPatterns
, status
);
143 if ( U_FAILURE(status
) ) {
147 fFallbackIntervalPattern
= dtitvinf
.fFallbackIntervalPattern
;
148 fFirstDateInPtnIsLaterDate
= dtitvinf
.fFirstDateInPtnIsLaterDate
;
154 DateIntervalInfo::clone() const {
155 return new DateIntervalInfo(*this);
159 DateIntervalInfo::~DateIntervalInfo() {
160 deleteHash(fIntervalPatterns
);
161 fIntervalPatterns
= NULL
;
166 DateIntervalInfo::operator==(const DateIntervalInfo
& other
) const {
168 fFallbackIntervalPattern
== other
.fFallbackIntervalPattern
&&
169 fFirstDateInPtnIsLaterDate
== other
.fFirstDateInPtnIsLaterDate
);
171 if ( equal
== TRUE
) {
172 equal
= fIntervalPatterns
->equals(*(other
.fIntervalPatterns
));
180 DateIntervalInfo::getIntervalPattern(const UnicodeString
& skeleton
,
181 UCalendarDateFields field
,
182 UnicodeString
& result
,
183 UErrorCode
& status
) const {
184 if ( U_FAILURE(status
) ) {
188 const UnicodeString
* patternsOfOneSkeleton
= (UnicodeString
*) fIntervalPatterns
->get(skeleton
);
189 if ( patternsOfOneSkeleton
!= NULL
) {
190 IntervalPatternIndex index
= calendarFieldToIntervalIndex(field
, status
);
191 if ( U_FAILURE(status
) ) {
194 const UnicodeString
& intervalPattern
= patternsOfOneSkeleton
[index
];
195 if ( !intervalPattern
.isEmpty() ) {
196 result
= intervalPattern
;
204 DateIntervalInfo::getDefaultOrder() const {
205 return fFirstDateInPtnIsLaterDate
;
210 DateIntervalInfo::getFallbackIntervalPattern(UnicodeString
& result
) const {
211 result
= fFallbackIntervalPattern
;
215 #define ULOC_LOCALE_IDENTIFIER_CAPACITY (ULOC_FULLNAME_CAPACITY + 1 + ULOC_KEYWORD_AND_VALUES_CAPACITY)
218 static const int32_t PATH_PREFIX_LENGTH
= 17;
219 static const UChar PATH_PREFIX
[] = {SOLIDUS
, CAP_L
, CAP_O
, CAP_C
, CAP_A
, CAP_L
, CAP_E
, SOLIDUS
,
220 LOW_C
, LOW_A
, LOW_L
, LOW_E
, LOW_N
, LOW_D
, LOW_A
, LOW_R
, SOLIDUS
};
221 static const int32_t PATH_SUFFIX_LENGTH
= 16;
222 static const UChar PATH_SUFFIX
[] = {SOLIDUS
, LOW_I
, LOW_N
, LOW_T
, LOW_E
, LOW_R
, LOW_V
, LOW_A
,
223 LOW_L
, CAP_F
, LOW_O
, LOW_R
, LOW_M
, LOW_A
, LOW_T
, LOW_S
};
226 * Sink for enumerating all of the date interval skeletons.
228 struct DateIntervalInfo::DateIntervalSink
: public ResourceSink
{
231 DateIntervalInfo
&dateIntervalInfo
;
233 // Next calendar type
234 UnicodeString nextCalendarType
;
236 DateIntervalSink(DateIntervalInfo
&diInfo
, const char *currentCalendarType
)
237 : dateIntervalInfo(diInfo
), nextCalendarType(currentCalendarType
, -1, US_INV
) { }
238 virtual ~DateIntervalSink();
240 virtual void put(const char *key
, ResourceValue
&value
, UBool
/*noFallback*/, UErrorCode
&errorCode
) {
241 if (U_FAILURE(errorCode
)) { return; }
243 // Iterate over all the calendar entries and only pick the 'intervalFormats' table.
244 ResourceTable dateIntervalData
= value
.getTable(errorCode
);
245 if (U_FAILURE(errorCode
)) { return; }
246 for (int32_t i
= 0; dateIntervalData
.getKeyAndValue(i
, key
, value
); i
++) {
247 if (uprv_strcmp(key
, gIntervalDateTimePatternTag
) != 0) {
251 // Handle aliases and tables. Ignore the rest.
252 if (value
.getType() == URES_ALIAS
) {
253 // Get the calendar type for the alias path.
254 const UnicodeString
&aliasPath
= value
.getAliasUnicodeString(errorCode
);
255 if (U_FAILURE(errorCode
)) { return; }
257 nextCalendarType
.remove();
258 getCalendarTypeFromPath(aliasPath
, nextCalendarType
, errorCode
);
260 if (U_FAILURE(errorCode
)) {
261 resetNextCalendarType();
265 } else if (value
.getType() == URES_TABLE
) {
266 // Iterate over all the skeletons in the 'intervalFormat' table.
267 ResourceTable skeletonData
= value
.getTable(errorCode
);
268 if (U_FAILURE(errorCode
)) { return; }
269 for (int32_t j
= 0; skeletonData
.getKeyAndValue(j
, key
, value
); j
++) {
270 if (value
.getType() == URES_TABLE
) {
271 // Process the skeleton
272 processSkeletonTable(key
, value
, errorCode
);
273 if (U_FAILURE(errorCode
)) { return; }
282 * Processes the patterns for a skeleton table
284 void processSkeletonTable(const char *key
, ResourceValue
&value
, UErrorCode
&errorCode
) {
285 if (U_FAILURE(errorCode
)) { return; }
287 // Iterate over all the patterns in the current skeleton table
288 const char *currentSkeleton
= key
;
289 ResourceTable patternData
= value
.getTable(errorCode
);
290 if (U_FAILURE(errorCode
)) { return; }
291 for (int32_t k
= 0; patternData
.getKeyAndValue(k
, key
, value
); k
++) {
292 if (value
.getType() == URES_STRING
) {
294 UCalendarDateFields calendarField
= validateAndProcessPatternLetter(key
);
296 // If the calendar field has a valid value
297 if (calendarField
< UCAL_FIELD_COUNT
) {
298 // Set the interval pattern
299 setIntervalPatternIfAbsent(currentSkeleton
, calendarField
, value
, errorCode
);
300 if (U_FAILURE(errorCode
)) { return; }
307 * Extracts the calendar type from the path.
309 static void getCalendarTypeFromPath(const UnicodeString
&path
, UnicodeString
&calendarType
,
310 UErrorCode
&errorCode
) {
311 if (U_FAILURE(errorCode
)) { return; }
313 if (!path
.startsWith(PATH_PREFIX
, PATH_PREFIX_LENGTH
) || !path
.endsWith(PATH_SUFFIX
, PATH_SUFFIX_LENGTH
)) {
314 errorCode
= U_INVALID_FORMAT_ERROR
;
318 path
.extractBetween(PATH_PREFIX_LENGTH
, path
.length() - PATH_SUFFIX_LENGTH
, calendarType
);
322 * Validates and processes the pattern letter
324 UCalendarDateFields
validateAndProcessPatternLetter(const char *patternLetter
) {
325 // Check that patternLetter is just one letter
327 if ((c0
= patternLetter
[0]) != 0 && patternLetter
[1] == 0) {
328 // Check that the pattern letter is accepted
331 } else if (c0
== 'y') {
333 } else if (c0
== 'M') {
335 } else if (c0
== 'd') {
337 } else if (c0
== 'a') {
339 } else if (c0
== 'h' || c0
== 'H') {
341 } else if (c0
== 'm') {
343 }// TODO(ticket:12190): Why icu4c doesn't accept the calendar field "s" but icu4j does?
345 return UCAL_FIELD_COUNT
;
349 * Stores the interval pattern for the current skeleton in the internal data structure
350 * if it's not present.
352 void setIntervalPatternIfAbsent(const char *currentSkeleton
, UCalendarDateFields lrgDiffCalUnit
,
353 const ResourceValue
&value
, UErrorCode
&errorCode
) {
354 // Check if the pattern has already been stored on the data structure
355 IntervalPatternIndex index
=
356 dateIntervalInfo
.calendarFieldToIntervalIndex(lrgDiffCalUnit
, errorCode
);
357 if (U_FAILURE(errorCode
)) { return; }
359 UnicodeString
skeleton(currentSkeleton
, -1, US_INV
);
360 UnicodeString
* patternsOfOneSkeleton
=
361 (UnicodeString
*)(dateIntervalInfo
.fIntervalPatterns
->get(skeleton
));
363 if (patternsOfOneSkeleton
== NULL
|| patternsOfOneSkeleton
[index
].isEmpty()) {
364 UnicodeString pattern
= value
.getUnicodeString(errorCode
);
365 dateIntervalInfo
.setIntervalPatternInternally(skeleton
, lrgDiffCalUnit
,
370 const UnicodeString
&getNextCalendarType() {
371 return nextCalendarType
;
374 void resetNextCalendarType() {
375 nextCalendarType
.setToBogus();
379 // Virtual destructors must be defined out of line.
380 DateIntervalInfo::DateIntervalSink::~DateIntervalSink() {}
385 DateIntervalInfo::initializeData(const Locale
& locale
, UErrorCode
& status
)
387 fIntervalPatterns
= initHash(status
);
388 if (U_FAILURE(status
)) {
391 const char *locName
= locale
.getName();
393 // Get the correct calendar type
394 const char * calendarTypeToUse
= gGregorianTag
; // initial default
395 char calendarType
[ULOC_KEYWORDS_CAPACITY
]; // to be filled in with the type to use, if all goes well
396 char localeWithCalendarKey
[ULOC_LOCALE_IDENTIFIER_CAPACITY
];
397 // obtain a locale that always has the calendar key value that should be used
398 (void)ures_getFunctionalEquivalent(localeWithCalendarKey
, ULOC_LOCALE_IDENTIFIER_CAPACITY
, NULL
,
399 "calendar", "calendar", locName
, NULL
, FALSE
, &status
);
400 localeWithCalendarKey
[ULOC_LOCALE_IDENTIFIER_CAPACITY
-1] = 0; // ensure null termination
401 // now get the calendar key value from that locale
402 int32_t calendarTypeLen
= uloc_getKeywordValue(localeWithCalendarKey
, "calendar", calendarType
,
403 ULOC_KEYWORDS_CAPACITY
, &status
);
404 if (U_SUCCESS(status
) && calendarTypeLen
< ULOC_KEYWORDS_CAPACITY
) {
405 calendarTypeToUse
= calendarType
;
407 status
= U_ZERO_ERROR
;
409 // Instantiate the resource bundles
410 UResourceBundle
*rb
, *calBundle
;
411 rb
= ures_open(NULL
, locName
, &status
);
412 if (U_FAILURE(status
)) {
415 calBundle
= ures_getByKeyWithFallback(rb
, gCalendarTag
, NULL
, &status
);
418 if (U_SUCCESS(status
)) {
419 UResourceBundle
*calTypeBundle
, *itvDtPtnResource
;
421 // Get the fallback pattern
423 int32_t resStrLen
= 0;
424 calTypeBundle
= ures_getByKeyWithFallback(calBundle
, calendarTypeToUse
, NULL
, &status
);
425 itvDtPtnResource
= ures_getByKeyWithFallback(calTypeBundle
,
426 gIntervalDateTimePatternTag
, NULL
, &status
);
427 resStr
= ures_getStringByKeyWithFallback(itvDtPtnResource
, gFallbackPatternTag
,
428 &resStrLen
, &status
);
429 if ( U_SUCCESS(status
) ) {
430 UnicodeString pattern
= UnicodeString(TRUE
, resStr
, resStrLen
);
431 setFallbackIntervalPattern(pattern
, status
);
433 ures_close(itvDtPtnResource
);
434 ures_close(calTypeBundle
);
437 // Instantiate the sink
438 DateIntervalSink
sink(*this, calendarTypeToUse
);
439 const UnicodeString
&calendarTypeToUseUString
= sink
.getNextCalendarType();
441 // Already loaded calendar types
442 Hashtable
loadedCalendarTypes(FALSE
, status
);
444 if (U_SUCCESS(status
)) {
445 while (!calendarTypeToUseUString
.isBogus()) {
446 // Set an error when a loop is detected
447 if (loadedCalendarTypes
.geti(calendarTypeToUseUString
) == 1) {
448 status
= U_INVALID_FORMAT_ERROR
;
452 // Register the calendar type to avoid loops
453 loadedCalendarTypes
.puti(calendarTypeToUseUString
, 1, status
);
454 if (U_FAILURE(status
)) { break; }
456 // Get the calendar string
457 CharString calTypeBuffer
;
458 calTypeBuffer
.appendInvariantChars(calendarTypeToUseUString
, status
);
459 if (U_FAILURE(status
)) { break; }
460 const char *calType
= calTypeBuffer
.data();
462 // Reset the next calendar type to load.
463 sink
.resetNextCalendarType();
465 // Get all resources for this calendar type
466 ures_getAllItemsWithFallback(calBundle
, calType
, sink
, status
);
471 // Close the opened resource bundles
472 ures_close(calBundle
);
477 DateIntervalInfo::setIntervalPatternInternally(const UnicodeString
& skeleton
,
478 UCalendarDateFields lrgDiffCalUnit
,
479 const UnicodeString
& intervalPattern
,
480 UErrorCode
& status
) {
481 IntervalPatternIndex index
= calendarFieldToIntervalIndex(lrgDiffCalUnit
,status
);
482 if ( U_FAILURE(status
) ) {
485 UnicodeString
* patternsOfOneSkeleton
= (UnicodeString
*)(fIntervalPatterns
->get(skeleton
));
486 UBool emptyHash
= false;
487 if ( patternsOfOneSkeleton
== NULL
) {
488 patternsOfOneSkeleton
= new UnicodeString
[kIPI_MAX_INDEX
];
492 patternsOfOneSkeleton
[index
] = intervalPattern
;
493 if ( emptyHash
== TRUE
) {
494 fIntervalPatterns
->put(skeleton
, patternsOfOneSkeleton
, status
);
501 DateIntervalInfo::parseSkeleton(const UnicodeString
& skeleton
,
502 int32_t* skeletonFieldWidth
) {
503 const int8_t PATTERN_CHAR_BASE
= 0x41;
505 for ( i
= 0; i
< skeleton
.length(); ++i
) {
506 // it is an ASCII char in skeleton
507 int8_t ch
= (int8_t)skeleton
.charAt(i
);
508 ++skeletonFieldWidth
[ch
- PATTERN_CHAR_BASE
];
515 DateIntervalInfo::stringNumeric(int32_t fieldWidth
, int32_t anotherFieldWidth
,
516 char patternLetter
) {
517 if ( patternLetter
== 'M' ) {
518 if ( (fieldWidth
<= 2 && anotherFieldWidth
> 2) ||
519 (fieldWidth
> 2 && anotherFieldWidth
<= 2 )) {
529 DateIntervalInfo::getBestSkeleton(const UnicodeString
& skeleton
,
530 int8_t& bestMatchDistanceInfo
) const {
531 #ifdef DTITVINF_DEBUG
535 skeleton
.extract(0, skeleton
.length(), result
, "UTF-8");
536 sprintf(mesg
, "in getBestSkeleton: skeleton: %s; \n", result
);
541 int32_t inputSkeletonFieldWidth
[] =
543 // A B C D E F G H I J K L M N O
544 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
545 // P Q R S T U V W X Y Z
546 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
547 // a b c d e f g h i j k l m n o
548 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
549 // p q r s t u v w x y z
550 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
553 int32_t skeletonFieldWidth
[] =
555 // A B C D E F G H I J K L M N O
556 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
557 // P Q R S T U V W X Y Z
558 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
559 // a b c d e f g h i j k l m n o
560 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
561 // p q r s t u v w x y z
562 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
565 const int32_t DIFFERENT_FIELD
= 0x1000;
566 const int32_t STRING_NUMERIC_DIFFERENCE
= 0x100;
567 const int32_t BASE
= 0x41;
568 const UChar CHAR_V
= 0x0076;
569 const UChar CHAR_Z
= 0x007A;
571 // hack for 'v' and 'z'.
572 // resource bundle only have time skeletons ending with 'v',
573 // but not for time skeletons ending with 'z'.
574 UBool replaceZWithV
= false;
575 const UnicodeString
* inputSkeleton
= &skeleton
;
576 UnicodeString copySkeleton
;
577 if ( skeleton
.indexOf(CHAR_Z
) != -1 ) {
578 copySkeleton
= skeleton
;
579 copySkeleton
.findAndReplace(UnicodeString(CHAR_Z
), UnicodeString(CHAR_V
));
580 inputSkeleton
= ©Skeleton
;
581 replaceZWithV
= true;
584 parseSkeleton(*inputSkeleton
, inputSkeletonFieldWidth
);
585 int32_t bestDistance
= MAX_POSITIVE_INT
;
586 const UnicodeString
* bestSkeleton
= NULL
;
588 // 0 means exact the same skeletons;
589 // 1 means having the same field, but with different length,
590 // 2 means only z/v differs
591 // -1 means having different field.
592 bestMatchDistanceInfo
= 0;
593 int8_t fieldLength
= UPRV_LENGTHOF(skeletonFieldWidth
);
595 int32_t pos
= UHASH_FIRST
;
596 const UHashElement
* elem
= NULL
;
597 while ( (elem
= fIntervalPatterns
->nextElement(pos
)) != NULL
) {
598 const UHashTok keyTok
= elem
->key
;
599 UnicodeString
* newSkeleton
= (UnicodeString
*)keyTok
.pointer
;
600 #ifdef DTITVINF_DEBUG
601 skeleton
->extract(0, skeleton
->length(), result
, "UTF-8");
602 sprintf(mesg
, "available skeletons: skeleton: %s; \n", result
);
606 // clear skeleton field width
608 for ( i
= 0; i
< fieldLength
; ++i
) {
609 skeletonFieldWidth
[i
] = 0;
611 parseSkeleton(*newSkeleton
, skeletonFieldWidth
);
612 // calculate distance
613 int32_t distance
= 0;
614 int8_t fieldDifference
= 1;
615 for ( i
= 0; i
< fieldLength
; ++i
) {
616 int32_t inputFieldWidth
= inputSkeletonFieldWidth
[i
];
617 int32_t fieldWidth
= skeletonFieldWidth
[i
];
618 if ( inputFieldWidth
== fieldWidth
) {
621 if ( inputFieldWidth
== 0 ) {
622 fieldDifference
= -1;
623 distance
+= DIFFERENT_FIELD
;
624 } else if ( fieldWidth
== 0 ) {
625 fieldDifference
= -1;
626 distance
+= DIFFERENT_FIELD
;
627 } else if (stringNumeric(inputFieldWidth
, fieldWidth
,
629 distance
+= STRING_NUMERIC_DIFFERENCE
;
631 distance
+= (inputFieldWidth
> fieldWidth
) ?
632 (inputFieldWidth
- fieldWidth
) :
633 (fieldWidth
- inputFieldWidth
);
636 if ( distance
< bestDistance
) {
637 bestSkeleton
= newSkeleton
;
638 bestDistance
= distance
;
639 bestMatchDistanceInfo
= fieldDifference
;
641 if ( distance
== 0 ) {
642 bestMatchDistanceInfo
= 0;
646 if ( replaceZWithV
&& bestMatchDistanceInfo
!= -1 ) {
647 bestMatchDistanceInfo
= 2;
654 DateIntervalInfo::IntervalPatternIndex
655 DateIntervalInfo::calendarFieldToIntervalIndex(UCalendarDateFields field
,
656 UErrorCode
& status
) {
657 if ( U_FAILURE(status
) ) {
658 return kIPI_MAX_INDEX
;
660 IntervalPatternIndex index
= kIPI_MAX_INDEX
;
672 case UCAL_DAY_OF_WEEK
:
673 //case UCAL_DAY_OF_MONTH:
680 case UCAL_HOUR_OF_DAY
:
690 status
= U_ILLEGAL_ARGUMENT_ERROR
;
698 DateIntervalInfo::deleteHash(Hashtable
* hTable
)
700 if ( hTable
== NULL
) {
703 int32_t pos
= UHASH_FIRST
;
704 const UHashElement
* element
= NULL
;
705 while ( (element
= hTable
->nextElement(pos
)) != NULL
) {
706 const UHashTok valueTok
= element
->value
;
707 const UnicodeString
* value
= (UnicodeString
*)valueTok
.pointer
;
710 delete fIntervalPatterns
;
717 * set hash table value comparator
719 * @param val1 one value in comparison
720 * @param val2 the other value in comparison
721 * @return TRUE if 2 values are the same, FALSE otherwise
723 static UBool U_CALLCONV
dtitvinfHashTableValueComparator(UHashTok val1
, UHashTok val2
);
726 U_CALLCONV
dtitvinfHashTableValueComparator(UHashTok val1
, UHashTok val2
) {
727 const UnicodeString
* pattern1
= (UnicodeString
*)val1
.pointer
;
728 const UnicodeString
* pattern2
= (UnicodeString
*)val2
.pointer
;
731 for ( i
= 0; i
< DateIntervalInfo::kMaxIntervalPatternIndex
&& ret
== TRUE
; ++i
) {
732 ret
= (pattern1
[i
] == pattern2
[i
]);
741 DateIntervalInfo::initHash(UErrorCode
& status
) {
742 if ( U_FAILURE(status
) ) {
746 if ( (hTable
= new Hashtable(FALSE
, status
)) == NULL
) {
747 status
= U_MEMORY_ALLOCATION_ERROR
;
750 if ( U_FAILURE(status
) ) {
754 hTable
->setValueComparator(dtitvinfHashTableValueComparator
);
760 DateIntervalInfo::copyHash(const Hashtable
* source
,
762 UErrorCode
& status
) {
763 if ( U_FAILURE(status
) ) {
766 int32_t pos
= UHASH_FIRST
;
767 const UHashElement
* element
= NULL
;
769 while ( (element
= source
->nextElement(pos
)) != NULL
) {
770 const UHashTok keyTok
= element
->key
;
771 const UnicodeString
* key
= (UnicodeString
*)keyTok
.pointer
;
772 const UHashTok valueTok
= element
->value
;
773 const UnicodeString
* value
= (UnicodeString
*)valueTok
.pointer
;
774 UnicodeString
* copy
= new UnicodeString
[kIPI_MAX_INDEX
];
776 for ( i
= 0; i
< kIPI_MAX_INDEX
; ++i
) {
779 target
->put(UnicodeString(*key
), copy
, status
);
780 if ( U_FAILURE(status
) ) {