1 /*******************************************************************************
2 * Copyright (C) 2008-2016, International Business Machines Corporation and
3 * others. All Rights Reserved.
4 *******************************************************************************
8 *******************************************************************************
11 #include "unicode/dtitvinf.h"
14 #if !UCONFIG_NO_FORMATTING
16 //TODO: define it in compiler time
17 //#define DTITVINF_DEBUG 1
26 #include "unicode/msgfmt.h"
27 #include "unicode/uloc.h"
28 #include "unicode/ures.h"
29 #include "dtitv_impl.h"
43 #define PRINTMESG(msg) { std::cout << "(" << __FILE__ << ":" << __LINE__ << ") " << msg << "\n"; }
46 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateIntervalInfo
)
48 static const char gCalendarTag
[]="calendar";
49 static const char gGregorianTag
[]="gregorian";
50 static const char gIntervalDateTimePatternTag
[]="intervalFormats";
51 static const char gFallbackPatternTag
[]="fallback";
54 static const UChar gFirstPattern
[] = {LEFT_CURLY_BRACKET
, DIGIT_ZERO
, RIGHT_CURLY_BRACKET
};
56 static const UChar gSecondPattern
[] = {LEFT_CURLY_BRACKET
, DIGIT_ONE
, RIGHT_CURLY_BRACKET
};
59 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};
61 DateIntervalInfo::DateIntervalInfo(UErrorCode
& status
)
62 : fFallbackIntervalPattern(gDefaultFallbackPattern
),
63 fFirstDateInPtnIsLaterDate(false),
64 fIntervalPatterns(NULL
)
66 fIntervalPatterns
= initHash(status
);
71 DateIntervalInfo::DateIntervalInfo(const Locale
& locale
, UErrorCode
& status
)
72 : fFallbackIntervalPattern(gDefaultFallbackPattern
),
73 fFirstDateInPtnIsLaterDate(false),
74 fIntervalPatterns(NULL
)
76 initializeData(locale
, status
);
82 DateIntervalInfo::setIntervalPattern(const UnicodeString
& skeleton
,
83 UCalendarDateFields lrgDiffCalUnit
,
84 const UnicodeString
& intervalPattern
,
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
);
94 setIntervalPatternInternally(skeleton
, lrgDiffCalUnit
, intervalPattern
, status
);
100 DateIntervalInfo::setFallbackIntervalPattern(
101 const UnicodeString
& fallbackPattern
,
102 UErrorCode
& status
) {
103 if ( U_FAILURE(status
) ) {
106 int32_t firstPatternIndex
= fallbackPattern
.indexOf(gFirstPattern
,
107 UPRV_LENGTHOF(gFirstPattern
), 0);
108 int32_t secondPatternIndex
= fallbackPattern
.indexOf(gSecondPattern
,
109 UPRV_LENGTHOF(gSecondPattern
), 0);
110 if ( firstPatternIndex
== -1 || secondPatternIndex
== -1 ) {
111 status
= U_ILLEGAL_ARGUMENT_ERROR
;
114 if ( firstPatternIndex
> secondPatternIndex
) {
115 fFirstDateInPtnIsLaterDate
= true;
117 fFallbackIntervalPattern
= fallbackPattern
;
122 DateIntervalInfo::DateIntervalInfo(const DateIntervalInfo
& dtitvinf
)
124 fIntervalPatterns(NULL
)
132 DateIntervalInfo::operator=(const DateIntervalInfo
& dtitvinf
) {
133 if ( this == &dtitvinf
) {
137 UErrorCode status
= U_ZERO_ERROR
;
138 deleteHash(fIntervalPatterns
);
139 fIntervalPatterns
= initHash(status
);
140 copyHash(dtitvinf
.fIntervalPatterns
, fIntervalPatterns
, status
);
141 if ( U_FAILURE(status
) ) {
145 fFallbackIntervalPattern
= dtitvinf
.fFallbackIntervalPattern
;
146 fFirstDateInPtnIsLaterDate
= dtitvinf
.fFirstDateInPtnIsLaterDate
;
152 DateIntervalInfo::clone() const {
153 return new DateIntervalInfo(*this);
157 DateIntervalInfo::~DateIntervalInfo() {
158 deleteHash(fIntervalPatterns
);
159 fIntervalPatterns
= NULL
;
164 DateIntervalInfo::operator==(const DateIntervalInfo
& other
) const {
166 fFallbackIntervalPattern
== other
.fFallbackIntervalPattern
&&
167 fFirstDateInPtnIsLaterDate
== other
.fFirstDateInPtnIsLaterDate
);
169 if ( equal
== TRUE
) {
170 equal
= fIntervalPatterns
->equals(*(other
.fIntervalPatterns
));
178 DateIntervalInfo::getIntervalPattern(const UnicodeString
& skeleton
,
179 UCalendarDateFields field
,
180 UnicodeString
& result
,
181 UErrorCode
& status
) const {
182 if ( U_FAILURE(status
) ) {
186 const UnicodeString
* patternsOfOneSkeleton
= (UnicodeString
*) fIntervalPatterns
->get(skeleton
);
187 if ( patternsOfOneSkeleton
!= NULL
) {
188 IntervalPatternIndex index
= calendarFieldToIntervalIndex(field
, status
);
189 if ( U_FAILURE(status
) ) {
192 const UnicodeString
& intervalPattern
= patternsOfOneSkeleton
[index
];
193 if ( !intervalPattern
.isEmpty() ) {
194 result
= intervalPattern
;
202 DateIntervalInfo::getDefaultOrder() const {
203 return fFirstDateInPtnIsLaterDate
;
208 DateIntervalInfo::getFallbackIntervalPattern(UnicodeString
& result
) const {
209 result
= fFallbackIntervalPattern
;
213 #define ULOC_LOCALE_IDENTIFIER_CAPACITY (ULOC_FULLNAME_CAPACITY + 1 + ULOC_KEYWORD_AND_VALUES_CAPACITY)
216 static const int32_t PATH_PREFIX_LENGTH
= 17;
217 static const UChar PATH_PREFIX
[] = {SOLIDUS
, CAP_L
, CAP_O
, CAP_C
, CAP_A
, CAP_L
, CAP_E
, SOLIDUS
,
218 LOW_C
, LOW_A
, LOW_L
, LOW_E
, LOW_N
, LOW_D
, LOW_A
, LOW_R
, SOLIDUS
};
219 static const int32_t PATH_SUFFIX_LENGTH
= 16;
220 static const UChar PATH_SUFFIX
[] = {SOLIDUS
, LOW_I
, LOW_N
, LOW_T
, LOW_E
, LOW_R
, LOW_V
, LOW_A
,
221 LOW_L
, CAP_F
, LOW_O
, LOW_R
, LOW_M
, LOW_A
, LOW_T
, LOW_S
};
224 * Sink for enumerating all of the date interval skeletons.
225 * Contains inner sink structs, each one corresponding to a type of resource table.
226 * The outer struct finds the dateInterval table or an alias.
228 struct DateIntervalSink
: public ResourceTableSink
{
231 * Sink to handle each skeleton table.
233 struct SkeletonSink
: public ResourceTableSink
{
234 SkeletonSink(DateIntervalSink
&sink
) : outer(sink
) {}
235 virtual ~SkeletonSink();
237 virtual ResourceTableSink
*getOrCreateTableSink(
238 const char *key
, int32_t, UErrorCode
&errorCode
) {
239 if (U_SUCCESS(errorCode
)) {
240 outer
.currentSkeleton
= key
;
241 return &outer
.patternSink
;
246 DateIntervalSink
&outer
;
250 * Sink to store the date interval pattern for each skeleton pattern character.
252 struct PatternSink
: public ResourceTableSink
{
253 PatternSink(DateIntervalSink
&sink
) : outer(sink
) {}
254 virtual ~PatternSink();
256 virtual void put(const char *key
, const ResourceValue
&value
, UErrorCode
&errorCode
) {
257 if (U_FAILURE(errorCode
)) { return; }
260 UCalendarDateFields calendarField
= validateAndProcessPatternLetter(key
);
262 // If the calendar field has a valid value
263 if (calendarField
< UCAL_FIELD_COUNT
) {
264 // Set the interval pattern
265 setIntervalPatternIfAbsent(calendarField
, value
, errorCode
);
267 errorCode
= U_INVALID_FORMAT_ERROR
;
271 UCalendarDateFields
validateAndProcessPatternLetter(const char *patternLetter
) {
272 // Check that patternLetter is just one letter
274 if ((c0
= patternLetter
[0]) != 0 && patternLetter
[1] == 0) {
275 // Check that the pattern letter is accepted
278 } else if (c0
== 'M') {
280 } else if (c0
== 'd') {
282 } else if (c0
== 'a') {
284 } else if (c0
== 'h' || c0
== 'H') {
286 } else if (c0
== 'm') {
288 }// TODO(ticket:12190): Why icu4c doesn't accept the calendar field "s" but icu4j does?
290 return UCAL_FIELD_COUNT
;
294 * Stores the interval pattern for the current skeleton in the internal data structure
295 * if it's not present.
297 void setIntervalPatternIfAbsent(UCalendarDateFields lrgDiffCalUnit
,
298 const ResourceValue
&value
, UErrorCode
&errorCode
) {
299 // Check if the pattern has already been stored on the data structure
300 DateIntervalInfo::IntervalPatternIndex index
=
301 outer
.dateIntervalInfo
.calendarFieldToIntervalIndex(lrgDiffCalUnit
, errorCode
);
302 if (U_FAILURE(errorCode
)) { return; }
304 UnicodeString
skeleton(outer
.currentSkeleton
, -1, US_INV
);
305 UnicodeString
* patternsOfOneSkeleton
=
306 (UnicodeString
*)(outer
.dateIntervalInfo
.fIntervalPatterns
->get(skeleton
));
308 if (patternsOfOneSkeleton
== NULL
|| patternsOfOneSkeleton
[index
].isEmpty()) {
309 UnicodeString pattern
= value
.getUnicodeString(errorCode
);
310 outer
.dateIntervalInfo
.setIntervalPatternInternally(skeleton
, lrgDiffCalUnit
,
315 DateIntervalSink
&outer
;
319 DateIntervalSink(DateIntervalInfo
&diInfo
, const char *currentCalendarType
)
320 : skeletonSink(*this), patternSink(*this), dateIntervalInfo(diInfo
),
321 nextCalendarType(currentCalendarType
, -1, US_INV
), currentSkeleton(NULL
) { }
322 virtual ~DateIntervalSink();
324 virtual void put(const char *key
, const ResourceValue
&value
, UErrorCode
&errorCode
) {
325 // Check if it's an alias of intervalFormats
326 if (U_FAILURE(errorCode
) || value
.getType() != URES_ALIAS
327 || uprv_strcmp(key
, gIntervalDateTimePatternTag
) != 0) {
331 // Get the calendar type for the alias path.
332 const UnicodeString
&aliasPath
= value
.getAliasUnicodeString(errorCode
);
333 if (U_FAILURE(errorCode
)) { return; }
335 nextCalendarType
.remove();
336 getCalendarTypeFromPath(aliasPath
, nextCalendarType
, errorCode
);
338 if (U_FAILURE(errorCode
)) {
339 resetNextCalendarType();
343 virtual ResourceTableSink
*getOrCreateTableSink(
344 const char *key
, int32_t, UErrorCode
&errorCode
) {
345 // Check if it's the intervalFormat table
346 if (U_SUCCESS(errorCode
) && uprv_strcmp(key
, gIntervalDateTimePatternTag
) == 0) {
347 return &skeletonSink
;
353 * Extracts the calendar type from the path.
355 static void getCalendarTypeFromPath(const UnicodeString
&path
, UnicodeString
&calendarType
,
356 UErrorCode
&errorCode
) {
357 if (U_FAILURE(errorCode
)) { return; }
359 if (!path
.startsWith(PATH_PREFIX
, PATH_PREFIX_LENGTH
) || !path
.endsWith(PATH_SUFFIX
, PATH_SUFFIX_LENGTH
)) {
360 errorCode
= U_INVALID_FORMAT_ERROR
;
364 path
.extractBetween(PATH_PREFIX_LENGTH
, path
.length() - PATH_SUFFIX_LENGTH
, calendarType
);
367 const UnicodeString
&getNextCalendarType() {
368 return nextCalendarType
;
371 void resetNextCalendarType() {
372 nextCalendarType
.setToBogus();
377 DateIntervalInfo
&dateIntervalInfo
;
379 // Next calendar type
380 UnicodeString nextCalendarType
;
382 // Current skeleton table being enumerated
383 const char *currentSkeleton
;
386 // Virtual destructors must be defined out of line.
387 DateIntervalSink::SkeletonSink::~SkeletonSink() {}
388 DateIntervalSink::PatternSink::~PatternSink() {}
389 DateIntervalSink::~DateIntervalSink() {}
394 DateIntervalInfo::initializeData(const Locale
& locale
, UErrorCode
& status
)
396 fIntervalPatterns
= initHash(status
);
397 if (U_FAILURE(status
)) {
400 const char *locName
= locale
.getName();
402 // Get the correct calendar type
403 const char * calendarTypeToUse
= gGregorianTag
; // initial default
404 char calendarType
[ULOC_KEYWORDS_CAPACITY
]; // to be filled in with the type to use, if all goes well
405 char localeWithCalendarKey
[ULOC_LOCALE_IDENTIFIER_CAPACITY
];
406 // obtain a locale that always has the calendar key value that should be used
407 (void)ures_getFunctionalEquivalent(localeWithCalendarKey
, ULOC_LOCALE_IDENTIFIER_CAPACITY
, NULL
,
408 "calendar", "calendar", locName
, NULL
, FALSE
, &status
);
409 localeWithCalendarKey
[ULOC_LOCALE_IDENTIFIER_CAPACITY
-1] = 0; // ensure null termination
410 // now get the calendar key value from that locale
411 int32_t calendarTypeLen
= uloc_getKeywordValue(localeWithCalendarKey
, "calendar", calendarType
,
412 ULOC_KEYWORDS_CAPACITY
, &status
);
413 if (U_SUCCESS(status
) && calendarTypeLen
< ULOC_KEYWORDS_CAPACITY
) {
414 calendarTypeToUse
= calendarType
;
416 status
= U_ZERO_ERROR
;
418 // Instantiate the resource bundles
419 UResourceBundle
*rb
, *calBundle
;
420 rb
= ures_open(NULL
, locName
, &status
);
421 if (U_FAILURE(status
)) {
424 calBundle
= ures_getByKeyWithFallback(rb
, gCalendarTag
, NULL
, &status
);
427 if (U_SUCCESS(status
)) {
428 UResourceBundle
*calTypeBundle
, *itvDtPtnResource
;
430 // Get the fallback pattern
432 int32_t resStrLen
= 0;
433 calTypeBundle
= ures_getByKeyWithFallback(calBundle
, calendarTypeToUse
, NULL
, &status
);
434 itvDtPtnResource
= ures_getByKeyWithFallback(calTypeBundle
,
435 gIntervalDateTimePatternTag
, NULL
, &status
);
436 resStr
= ures_getStringByKeyWithFallback(itvDtPtnResource
, gFallbackPatternTag
,
437 &resStrLen
, &status
);
438 if ( U_SUCCESS(status
) ) {
439 UnicodeString pattern
= UnicodeString(TRUE
, resStr
, resStrLen
);
440 setFallbackIntervalPattern(pattern
, status
);
442 ures_close(itvDtPtnResource
);
443 ures_close(calTypeBundle
);
446 // Instantiate the sink
447 DateIntervalSink
sink(*this, calendarTypeToUse
);
448 const UnicodeString
&calendarTypeToUseUString
= sink
.getNextCalendarType();
450 // Already loaded calendar types
451 Hashtable
loadedCalendarTypes(FALSE
, status
);
453 if (U_SUCCESS(status
)) {
454 while (!calendarTypeToUseUString
.isBogus()) {
455 // Set an error when a loop is detected
456 if (loadedCalendarTypes
.geti(calendarTypeToUseUString
) == 1) {
457 status
= U_INVALID_FORMAT_ERROR
;
461 // Register the calendar type to avoid loops
462 loadedCalendarTypes
.puti(calendarTypeToUseUString
, 1, status
);
463 if (U_FAILURE(status
)) { break; }
465 // Get the calendar string
466 CharString calTypeBuffer
;
467 calTypeBuffer
.appendInvariantChars(calendarTypeToUseUString
, status
);
468 if (U_FAILURE(status
)) { break; }
469 const char *calType
= calTypeBuffer
.data();
471 // Reset the next calendar type to load.
472 sink
.resetNextCalendarType();
474 // Get all resources for this calendar type
475 ures_getAllTableItemsWithFallback(calBundle
, calType
, sink
, status
);
480 // Close the opened resource bundles
481 ures_close(calBundle
);
486 DateIntervalInfo::setIntervalPatternInternally(const UnicodeString
& skeleton
,
487 UCalendarDateFields lrgDiffCalUnit
,
488 const UnicodeString
& intervalPattern
,
489 UErrorCode
& status
) {
490 IntervalPatternIndex index
= calendarFieldToIntervalIndex(lrgDiffCalUnit
,status
);
491 if ( U_FAILURE(status
) ) {
494 UnicodeString
* patternsOfOneSkeleton
= (UnicodeString
*)(fIntervalPatterns
->get(skeleton
));
495 UBool emptyHash
= false;
496 if ( patternsOfOneSkeleton
== NULL
) {
497 patternsOfOneSkeleton
= new UnicodeString
[kIPI_MAX_INDEX
];
501 patternsOfOneSkeleton
[index
] = intervalPattern
;
502 if ( emptyHash
== TRUE
) {
503 fIntervalPatterns
->put(skeleton
, patternsOfOneSkeleton
, status
);
510 DateIntervalInfo::parseSkeleton(const UnicodeString
& skeleton
,
511 int32_t* skeletonFieldWidth
) {
512 const int8_t PATTERN_CHAR_BASE
= 0x41;
514 for ( i
= 0; i
< skeleton
.length(); ++i
) {
515 // it is an ASCII char in skeleton
516 int8_t ch
= (int8_t)skeleton
.charAt(i
);
517 ++skeletonFieldWidth
[ch
- PATTERN_CHAR_BASE
];
524 DateIntervalInfo::stringNumeric(int32_t fieldWidth
, int32_t anotherFieldWidth
,
525 char patternLetter
) {
526 if ( patternLetter
== 'M' ) {
527 if ( (fieldWidth
<= 2 && anotherFieldWidth
> 2) ||
528 (fieldWidth
> 2 && anotherFieldWidth
<= 2 )) {
538 DateIntervalInfo::getBestSkeleton(const UnicodeString
& skeleton
,
539 int8_t& bestMatchDistanceInfo
) const {
540 #ifdef DTITVINF_DEBUG
544 skeleton
.extract(0, skeleton
.length(), result
, "UTF-8");
545 sprintf(mesg
, "in getBestSkeleton: skeleton: %s; \n", result
);
550 int32_t inputSkeletonFieldWidth
[] =
552 // A B C D E F G H I J K L M N O
553 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
554 // P Q R S T U V W X Y Z
555 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
556 // a b c d e f g h i j k l m n o
557 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
558 // p q r s t u v w x y z
559 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
562 int32_t skeletonFieldWidth
[] =
564 // A B C D E F G H I J K L M N O
565 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
566 // P Q R S T U V W X Y Z
567 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
568 // a b c d e f g h i j k l m n o
569 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
570 // p q r s t u v w x y z
571 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
574 const int32_t DIFFERENT_FIELD
= 0x1000;
575 const int32_t STRING_NUMERIC_DIFFERENCE
= 0x100;
576 const int32_t BASE
= 0x41;
577 const UChar CHAR_V
= 0x0076;
578 const UChar CHAR_Z
= 0x007A;
580 // hack for 'v' and 'z'.
581 // resource bundle only have time skeletons ending with 'v',
582 // but not for time skeletons ending with 'z'.
583 UBool replaceZWithV
= false;
584 const UnicodeString
* inputSkeleton
= &skeleton
;
585 UnicodeString copySkeleton
;
586 if ( skeleton
.indexOf(CHAR_Z
) != -1 ) {
587 copySkeleton
= skeleton
;
588 copySkeleton
.findAndReplace(UnicodeString(CHAR_Z
), UnicodeString(CHAR_V
));
589 inputSkeleton
= ©Skeleton
;
590 replaceZWithV
= true;
593 parseSkeleton(*inputSkeleton
, inputSkeletonFieldWidth
);
594 int32_t bestDistance
= MAX_POSITIVE_INT
;
595 const UnicodeString
* bestSkeleton
= NULL
;
597 // 0 means exact the same skeletons;
598 // 1 means having the same field, but with different length,
599 // 2 means only z/v differs
600 // -1 means having different field.
601 bestMatchDistanceInfo
= 0;
602 int8_t fieldLength
= UPRV_LENGTHOF(skeletonFieldWidth
);
604 int32_t pos
= UHASH_FIRST
;
605 const UHashElement
* elem
= NULL
;
606 while ( (elem
= fIntervalPatterns
->nextElement(pos
)) != NULL
) {
607 const UHashTok keyTok
= elem
->key
;
608 UnicodeString
* skeleton
= (UnicodeString
*)keyTok
.pointer
;
609 #ifdef DTITVINF_DEBUG
610 skeleton
->extract(0, skeleton
->length(), result
, "UTF-8");
611 sprintf(mesg
, "available skeletons: skeleton: %s; \n", result
);
615 // clear skeleton field width
617 for ( i
= 0; i
< fieldLength
; ++i
) {
618 skeletonFieldWidth
[i
] = 0;
620 parseSkeleton(*skeleton
, skeletonFieldWidth
);
621 // calculate distance
622 int32_t distance
= 0;
623 int8_t fieldDifference
= 1;
624 for ( i
= 0; i
< fieldLength
; ++i
) {
625 int32_t inputFieldWidth
= inputSkeletonFieldWidth
[i
];
626 int32_t fieldWidth
= skeletonFieldWidth
[i
];
627 if ( inputFieldWidth
== fieldWidth
) {
630 if ( inputFieldWidth
== 0 ) {
631 fieldDifference
= -1;
632 distance
+= DIFFERENT_FIELD
;
633 } else if ( fieldWidth
== 0 ) {
634 fieldDifference
= -1;
635 distance
+= DIFFERENT_FIELD
;
636 } else if (stringNumeric(inputFieldWidth
, fieldWidth
,
638 distance
+= STRING_NUMERIC_DIFFERENCE
;
640 distance
+= (inputFieldWidth
> fieldWidth
) ?
641 (inputFieldWidth
- fieldWidth
) :
642 (fieldWidth
- inputFieldWidth
);
645 if ( distance
< bestDistance
) {
646 bestSkeleton
= skeleton
;
647 bestDistance
= distance
;
648 bestMatchDistanceInfo
= fieldDifference
;
650 if ( distance
== 0 ) {
651 bestMatchDistanceInfo
= 0;
655 if ( replaceZWithV
&& bestMatchDistanceInfo
!= -1 ) {
656 bestMatchDistanceInfo
= 2;
663 DateIntervalInfo::IntervalPatternIndex
664 DateIntervalInfo::calendarFieldToIntervalIndex(UCalendarDateFields field
,
665 UErrorCode
& status
) {
666 if ( U_FAILURE(status
) ) {
667 return kIPI_MAX_INDEX
;
669 IntervalPatternIndex index
= kIPI_MAX_INDEX
;
681 case UCAL_DAY_OF_WEEK
:
682 //case UCAL_DAY_OF_MONTH:
689 case UCAL_HOUR_OF_DAY
:
699 status
= U_ILLEGAL_ARGUMENT_ERROR
;
707 DateIntervalInfo::deleteHash(Hashtable
* hTable
)
709 if ( hTable
== NULL
) {
712 int32_t pos
= UHASH_FIRST
;
713 const UHashElement
* element
= NULL
;
714 while ( (element
= hTable
->nextElement(pos
)) != NULL
) {
715 const UHashTok valueTok
= element
->value
;
716 const UnicodeString
* value
= (UnicodeString
*)valueTok
.pointer
;
719 delete fIntervalPatterns
;
726 * set hash table value comparator
728 * @param val1 one value in comparison
729 * @param val2 the other value in comparison
730 * @return TRUE if 2 values are the same, FALSE otherwise
732 static UBool U_CALLCONV
dtitvinfHashTableValueComparator(UHashTok val1
, UHashTok val2
);
735 U_CALLCONV
dtitvinfHashTableValueComparator(UHashTok val1
, UHashTok val2
) {
736 const UnicodeString
* pattern1
= (UnicodeString
*)val1
.pointer
;
737 const UnicodeString
* pattern2
= (UnicodeString
*)val2
.pointer
;
740 for ( i
= 0; i
< DateIntervalInfo::kMaxIntervalPatternIndex
&& ret
== TRUE
; ++i
) {
741 ret
= (pattern1
[i
] == pattern2
[i
]);
750 DateIntervalInfo::initHash(UErrorCode
& status
) {
751 if ( U_FAILURE(status
) ) {
755 if ( (hTable
= new Hashtable(FALSE
, status
)) == NULL
) {
756 status
= U_MEMORY_ALLOCATION_ERROR
;
759 if ( U_FAILURE(status
) ) {
763 hTable
->setValueComparator(dtitvinfHashTableValueComparator
);
769 DateIntervalInfo::copyHash(const Hashtable
* source
,
771 UErrorCode
& status
) {
772 if ( U_FAILURE(status
) ) {
775 int32_t pos
= UHASH_FIRST
;
776 const UHashElement
* element
= NULL
;
778 while ( (element
= source
->nextElement(pos
)) != NULL
) {
779 const UHashTok keyTok
= element
->key
;
780 const UnicodeString
* key
= (UnicodeString
*)keyTok
.pointer
;
781 const UHashTok valueTok
= element
->value
;
782 const UnicodeString
* value
= (UnicodeString
*)valueTok
.pointer
;
783 UnicodeString
* copy
= new UnicodeString
[kIPI_MAX_INDEX
];
785 for ( i
= 0; i
< kIPI_MAX_INDEX
; ++i
) {
788 target
->put(UnicodeString(*key
), copy
, status
);
789 if ( U_FAILURE(status
) ) {