Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(8)

Unified Diff: source/i18n/smpdtfmt.cpp

Issue 1621843002: ICU 56 update step 1 (Closed) Base URL: https://chromium.googlesource.com/chromium/deps/icu.git@561
Patch Set: Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « source/i18n/smallintformatter.cpp ('k') | source/i18n/timezone.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: source/i18n/smpdtfmt.cpp
diff --git a/source/i18n/smpdtfmt.cpp b/source/i18n/smpdtfmt.cpp
index 901664115cc773d2b57651e90f2de01a8c12871c..01c9f7c7981b40e3e62b06091baa559c8c2909a5 100644
--- a/source/i18n/smpdtfmt.cpp
+++ b/source/i18n/smpdtfmt.cpp
@@ -1,6 +1,6 @@
/*
*******************************************************************************
-* Copyright (C) 1997-2014, International Business Machines Corporation and *
+* Copyright (C) 1997-2015, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*
@@ -60,6 +60,8 @@
#include "umutex.h"
#include <float.h>
#include "smpdtfst.h"
+#include "sharednumberformat.h"
+#include "ustr_imp.h"
#if defined( U_DEBUG_CALSVC ) || defined (U_DEBUG_CAL)
#include <stdio.h>
@@ -71,8 +73,6 @@
U_NAMESPACE_BEGIN
-static const UChar PATTERN_CHAR_BASE = 0x40;
-
/**
* Last-resort string to use for "GMT" when constructing time zone strings.
*/
@@ -181,7 +181,7 @@ static const int32_t gFieldRangeBias[] = {
-1, // 'k' - UDAT_HOUR_OF_DAY1_FIELD
-1, // 'H' - UDAT_HOUR_OF_DAY0_FIELD
0, // 'm' - UDAT_MINUTE_FIELD
- 0, // 's' - UDAT_SEOND_FIELD
+ 0, // 's' - UDAT_SECOND_FIELD
-1, // 'S' - UDAT_FRACTIONAL_SECOND_FIELD (0-999?)
-1, // 'E' - UDAT_DAY_OF_WEEK_FIELD (1-7?)
-1, // 'D' - UDAT_DAY_OF_YEAR_FIELD (1 - 366?)
@@ -209,6 +209,11 @@ static const int32_t gFieldRangeBias[] = {
-1, // 'X' - UDAT_TIMEZONE_ISO_FIELD
-1, // 'x' - UDAT_TIMEZONE_ISO_LOCAL_FIELD
-1, // 'r' - UDAT_RELATED_YEAR_FIELD
+#if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
+ -1, // ':' - UDAT_TIME_SEPARATOR_FIELD
+#else
+ -1, // (no pattern character currently) - UDAT_TIME_SEPARATOR_FIELD
+#endif
};
// When calendar uses hebr numbering (i.e. he@calendar=hebrew),
@@ -220,25 +225,149 @@ static UMutex LOCK = U_MUTEX_INITIALIZER;
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleDateFormat)
+SimpleDateFormat::NSOverride::~NSOverride() {
+ if (snf != NULL) {
+ snf->removeRef();
+ }
+}
+
+
+void SimpleDateFormat::NSOverride::free() {
+ NSOverride *cur = this;
+ while (cur) {
+ NSOverride *next = cur->next;
+ delete cur;
+ cur = next;
+ }
+}
+
+// no matter what the locale's default number format looked like, we want
+// to modify it so that it doesn't use thousands separators, doesn't always
+// show the decimal point, and recognizes integers only when parsing
+static void fixNumberFormatForDates(NumberFormat &nf) {
+ nf.setGroupingUsed(FALSE);
+ DecimalFormat* decfmt = dynamic_cast<DecimalFormat*>(&nf);
+ if (decfmt != NULL) {
+ decfmt->setDecimalSeparatorAlwaysShown(FALSE);
+ }
+ nf.setParseIntegerOnly(TRUE);
+ nf.setMinimumFractionDigits(0); // To prevent "Jan 1.00, 1997.00"
+}
+
+static const SharedNumberFormat *createSharedNumberFormat(
+ NumberFormat *nfToAdopt) {
+ fixNumberFormatForDates(*nfToAdopt);
+ const SharedNumberFormat *result = new SharedNumberFormat(nfToAdopt);
+ if (result == NULL) {
+ delete nfToAdopt;
+ }
+ return result;
+}
+
+static const SharedNumberFormat *createSharedNumberFormat(
+ const Locale &loc, UErrorCode &status) {
+ NumberFormat *nf = NumberFormat::createInstance(loc, status);
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ const SharedNumberFormat *result = createSharedNumberFormat(nf);
+ if (result == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ return result;
+}
+
+static const SharedNumberFormat **allocSharedNumberFormatters() {
+ const SharedNumberFormat **result = (const SharedNumberFormat**)
+ uprv_malloc(UDAT_FIELD_COUNT * sizeof(const SharedNumberFormat*));
+ if (result == NULL) {
+ return NULL;
+ }
+ for (int32_t i = 0; i < UDAT_FIELD_COUNT; ++i) {
+ result[i] = NULL;
+ }
+ return result;
+}
+
+static void freeSharedNumberFormatters(const SharedNumberFormat ** list) {
+ for (int32_t i = 0; i < UDAT_FIELD_COUNT; ++i) {
+ SharedObject::clearPtr(list[i]);
+ }
+ uprv_free(list);
+}
+
+const NumberFormat *SimpleDateFormat::getNumberFormatByIndex(
+ UDateFormatField index) const {
+ if (fSharedNumberFormatters == NULL ||
+ fSharedNumberFormatters[index] == NULL) {
+ return fNumberFormat;
+ }
+ return &(**fSharedNumberFormatters[index]);
+}
+
+class SimpleDateFormatMutableNFNode {
+ public:
+ const NumberFormat *key;
+ NumberFormat *value;
+ SimpleDateFormatMutableNFNode()
+ : key(NULL), value(NULL) { }
+ ~SimpleDateFormatMutableNFNode() {
+ delete value;
+ }
+ private:
+ SimpleDateFormatMutableNFNode(const SimpleDateFormatMutableNFNode &);
+ SimpleDateFormatMutableNFNode &operator=(const SimpleDateFormatMutableNFNode &);
+};
+
+// Single threaded cache of non const NumberFormats. Designed to be stack
+// allocated and used for a single format call.
+class SimpleDateFormatMutableNFs : public UMemory {
+ public:
+ SimpleDateFormatMutableNFs() {
+ }
+
+ // Returns a non-const clone of nf which can be safely modified.
+ // Subsequent calls with same nf will return the same non-const clone.
+ // This object maintains ownership of all returned non-const
+ // NumberFormat objects. On memory allocation error returns NULL.
+ // Caller must check for NULL return value.
+ NumberFormat *get(const NumberFormat *nf) {
+ if (nf == NULL) {
+ return NULL;
+ }
+ int32_t idx = 0;
+ while (nodes[idx].value) {
+ if (nf == nodes[idx].key) {
+ return nodes[idx].value;
+ }
+ ++idx;
+ }
+ U_ASSERT(idx < UDAT_FIELD_COUNT);
+ nodes[idx].key = nf;
+ nodes[idx].value = (NumberFormat *) nf->clone();
+ return nodes[idx].value;
+ }
+ private:
+ // +1 extra for sentinel. If each field had its own NumberFormat, this
+ // cache would have to allocate UDAT_FIELD_COUNT mutable versions worst
+ // case.
+ SimpleDateFormatMutableNFNode nodes[UDAT_FIELD_COUNT + 1];
+ SimpleDateFormatMutableNFs(const SimpleDateFormatMutableNFs &);
+ SimpleDateFormatMutableNFs &operator=(const SimpleDateFormatMutableNFs &);
+};
+
//----------------------------------------------------------------------
SimpleDateFormat::~SimpleDateFormat()
{
delete fSymbols;
- if (fNumberFormatters) {
- uprv_free(fNumberFormatters);
+ if (fSharedNumberFormatters) {
+ freeSharedNumberFormatters(fSharedNumberFormatters);
}
if (fTimeZoneFormat) {
delete fTimeZoneFormat;
}
- while (fOverrideList) {
- NSOverride *cur = fOverrideList;
- fOverrideList = cur->next;
- delete cur->nf;
- uprv_free(cur);
- }
-
#if !UCONFIG_NO_BREAK_ITERATION
delete fCapitalizationBrkIter;
#endif
@@ -250,8 +379,7 @@ SimpleDateFormat::SimpleDateFormat(UErrorCode& status)
: fLocale(Locale::getDefault()),
fSymbols(NULL),
fTimeZoneFormat(NULL),
- fNumberFormatters(NULL),
- fOverrideList(NULL),
+ fSharedNumberFormatters(NULL),
fCapitalizationBrkIter(NULL)
{
initializeBooleanAttributes();
@@ -267,14 +395,14 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
fLocale(Locale::getDefault()),
fSymbols(NULL),
fTimeZoneFormat(NULL),
- fNumberFormatters(NULL),
- fOverrideList(NULL),
+ fSharedNumberFormatters(NULL),
fCapitalizationBrkIter(NULL)
{
fDateOverride.setToBogus();
fTimeOverride.setToBogus();
initializeBooleanAttributes();
- initializeSymbols(fLocale, initializeCalendar(NULL,fLocale,status), status);
+ initializeCalendar(NULL,fLocale,status);
+ fSymbols = DateFormatSymbols::createForLocale(fLocale, status);
initialize(fLocale, status);
initializeDefaultCentury();
@@ -288,14 +416,14 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
fLocale(Locale::getDefault()),
fSymbols(NULL),
fTimeZoneFormat(NULL),
- fNumberFormatters(NULL),
- fOverrideList(NULL),
+ fSharedNumberFormatters(NULL),
fCapitalizationBrkIter(NULL)
{
fDateOverride.setTo(override);
fTimeOverride.setToBogus();
initializeBooleanAttributes();
- initializeSymbols(fLocale, initializeCalendar(NULL,fLocale,status), status);
+ initializeCalendar(NULL,fLocale,status);
+ fSymbols = DateFormatSymbols::createForLocale(fLocale, status);
initialize(fLocale, status);
initializeDefaultCentury();
@@ -311,8 +439,7 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
: fPattern(pattern),
fLocale(locale),
fTimeZoneFormat(NULL),
- fNumberFormatters(NULL),
- fOverrideList(NULL),
+ fSharedNumberFormatters(NULL),
fCapitalizationBrkIter(NULL)
{
@@ -320,7 +447,8 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
fTimeOverride.setToBogus();
initializeBooleanAttributes();
- initializeSymbols(fLocale, initializeCalendar(NULL,fLocale,status), status);
+ initializeCalendar(NULL,fLocale,status);
+ fSymbols = DateFormatSymbols::createForLocale(fLocale, status);
initialize(fLocale, status);
initializeDefaultCentury();
}
@@ -334,8 +462,7 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
: fPattern(pattern),
fLocale(locale),
fTimeZoneFormat(NULL),
- fNumberFormatters(NULL),
- fOverrideList(NULL),
+ fSharedNumberFormatters(NULL),
fCapitalizationBrkIter(NULL)
{
@@ -343,7 +470,8 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
fTimeOverride.setToBogus();
initializeBooleanAttributes();
- initializeSymbols(fLocale, initializeCalendar(NULL,fLocale,status), status);
+ initializeCalendar(NULL,fLocale,status);
+ fSymbols = DateFormatSymbols::createForLocale(fLocale, status);
initialize(fLocale, status);
initializeDefaultCentury();
@@ -360,8 +488,7 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
fLocale(Locale::getDefault()),
fSymbols(symbolsToAdopt),
fTimeZoneFormat(NULL),
- fNumberFormatters(NULL),
- fOverrideList(NULL),
+ fSharedNumberFormatters(NULL),
fCapitalizationBrkIter(NULL)
{
@@ -383,8 +510,7 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
fLocale(Locale::getDefault()),
fSymbols(new DateFormatSymbols(symbols)),
fTimeZoneFormat(NULL),
- fNumberFormatters(NULL),
- fOverrideList(NULL),
+ fSharedNumberFormatters(NULL),
fCapitalizationBrkIter(NULL)
{
@@ -407,8 +533,7 @@ SimpleDateFormat::SimpleDateFormat(EStyle timeStyle,
: fLocale(locale),
fSymbols(NULL),
fTimeZoneFormat(NULL),
- fNumberFormatters(NULL),
- fOverrideList(NULL),
+ fSharedNumberFormatters(NULL),
fCapitalizationBrkIter(NULL)
{
initializeBooleanAttributes();
@@ -431,13 +556,13 @@ SimpleDateFormat::SimpleDateFormat(const Locale& locale,
fLocale(locale),
fSymbols(NULL),
fTimeZoneFormat(NULL),
- fNumberFormatters(NULL),
- fOverrideList(NULL),
+ fSharedNumberFormatters(NULL),
fCapitalizationBrkIter(NULL)
{
if (U_FAILURE(status)) return;
initializeBooleanAttributes();
- initializeSymbols(fLocale, initializeCalendar(NULL, fLocale, status),status);
+ initializeCalendar(NULL, fLocale, status);
+ fSymbols = DateFormatSymbols::createForLocale(fLocale, status);
if (U_FAILURE(status))
{
status = U_ZERO_ERROR;
@@ -467,8 +592,7 @@ SimpleDateFormat::SimpleDateFormat(const SimpleDateFormat& other)
fLocale(other.fLocale),
fSymbols(NULL),
fTimeZoneFormat(NULL),
- fNumberFormatters(NULL),
- fOverrideList(NULL),
+ fSharedNumberFormatters(NULL),
fCapitalizationBrkIter(NULL)
{
initializeBooleanAttributes();
@@ -483,6 +607,8 @@ SimpleDateFormat& SimpleDateFormat::operator=(const SimpleDateFormat& other)
return *this;
}
DateFormat::operator=(other);
+ fDateOverride = other.fDateOverride;
+ fTimeOverride = other.fTimeOverride;
delete fSymbols;
fSymbols = NULL;
@@ -509,6 +635,21 @@ SimpleDateFormat& SimpleDateFormat::operator=(const SimpleDateFormat& other)
}
#endif
+ if (fSharedNumberFormatters != NULL) {
+ freeSharedNumberFormatters(fSharedNumberFormatters);
+ fSharedNumberFormatters = NULL;
+ }
+ if (other.fSharedNumberFormatters != NULL) {
+ fSharedNumberFormatters = allocSharedNumberFormatters();
+ if (fSharedNumberFormatters) {
+ for (int32_t i = 0; i < UDAT_FIELD_COUNT; ++i) {
+ SharedObject::copyPtr(
+ other.fSharedNumberFormatters[i],
+ fSharedNumberFormatters[i]);
+ }
+ }
+ }
+
return *this;
}
@@ -570,7 +711,7 @@ void SimpleDateFormat::construct(EStyle timeStyle,
ures_getLocaleByType(dateTimePatterns, ULOC_ACTUAL_LOCALE, &status));
// create a symbols object from the locale
- initializeSymbols(locale,fCalendar, status);
+ fSymbols = DateFormatSymbols::createForLocale(locale, status);
if (U_FAILURE(status)) return;
/* test for NULL */
if (fSymbols == 0) {
@@ -741,29 +882,10 @@ SimpleDateFormat::initializeCalendar(TimeZone* adoptZone, const Locale& locale,
if(!U_FAILURE(status)) {
fCalendar = Calendar::createInstance(adoptZone?adoptZone:TimeZone::createDefault(), locale, status);
}
- if (U_SUCCESS(status) && fCalendar == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- }
return fCalendar;
}
void
-SimpleDateFormat::initializeSymbols(const Locale& locale, Calendar* calendar, UErrorCode& status)
-{
- if(U_FAILURE(status)) {
- fSymbols = NULL;
- } else {
- // pass in calendar type - use NULL (default) if no calendar set (or err).
- fSymbols = new DateFormatSymbols(locale, calendar?calendar->getType() :NULL , status);
- // Null pointer check
- if (fSymbols == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
- }
-}
-
-void
SimpleDateFormat::initialize(const Locale& locale,
UErrorCode& status)
{
@@ -774,18 +896,7 @@ SimpleDateFormat::initialize(const Locale& locale,
fNumberFormat = NumberFormat::createInstance(locale, status);
if (fNumberFormat != NULL && U_SUCCESS(status))
{
- // no matter what the locale's default number format looked like, we want
- // to modify it so that it doesn't use thousands separators, doesn't always
- // show the decimal point, and recognizes integers only when parsing
-
- fNumberFormat->setGroupingUsed(FALSE);
- DecimalFormat* decfmt = dynamic_cast<DecimalFormat*>(fNumberFormat);
- if (decfmt != NULL) {
- decfmt->setDecimalSeparatorAlwaysShown(FALSE);
- }
- fNumberFormat->setParseIntegerOnly(TRUE);
- fNumberFormat->setMinimumFractionDigits(0); // To prevent "Jan 1.00, 1997.00"
-
+ fixNumberFormatForDates(*fNumberFormat);
//fNumberFormat->setLenient(TRUE); // Java uses a custom DateNumberFormat to format/parse
initNumberFormatters(locale,status);
@@ -823,7 +934,7 @@ void SimpleDateFormat::initializeBooleanAttributes()
setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, true, status);
setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, true, status);
- setBooleanAttribute(UDAT_PARSE_PARTIAL_MATCH, true, status);
+ setBooleanAttribute(UDAT_PARSE_PARTIAL_LITERAL_MATCH, true, status);
setBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, true, status);
}
@@ -901,6 +1012,11 @@ SimpleDateFormat::_format(Calendar& cal, UnicodeString& appendTo,
int32_t fieldNum = 0;
UDisplayContext capitalizationContext = getContext(UDISPCTX_TYPE_CAPITALIZATION, status);
+ // Create temporary cache of mutable number format objects. This way
+ // subFormat won't have to clone the const NumberFormat for each field.
+ // if several fields share the same NumberFormat, which will almost
+ // always be the case, this is a big save.
+ SimpleDateFormatMutableNFs mutableNFs;
// loop through the pattern string character by character
for (int32_t i = 0; i < fPattern.length() && U_SUCCESS(status); ++i) {
UChar ch = fPattern[i];
@@ -908,7 +1024,7 @@ SimpleDateFormat::_format(Calendar& cal, UnicodeString& appendTo,
// Use subFormat() to format a repeated pattern character
// when a different pattern or non-pattern character is seen
if (ch != prevCh && count > 0) {
- subFormat(appendTo, prevCh, count, capitalizationContext, fieldNum++, handler, *workCal, status);
+ subFormat(appendTo, prevCh, count, capitalizationContext, fieldNum++, handler, *workCal, mutableNFs, status);
count = 0;
}
if (ch == QUOTE) {
@@ -921,8 +1037,7 @@ SimpleDateFormat::_format(Calendar& cal, UnicodeString& appendTo,
inQuote = ! inQuote;
}
}
- else if ( ! inQuote && ((ch >= 0x0061 /*'a'*/ && ch <= 0x007A /*'z'*/)
- || (ch >= 0x0041 /*'A'*/ && ch <= 0x005A /*'Z'*/))) {
+ else if (!inQuote && isSyntaxChar(ch)) {
// ch is a date-time pattern character to be interpreted
// by subFormat(); count the number of times it is repeated
prevCh = ch;
@@ -936,7 +1051,7 @@ SimpleDateFormat::_format(Calendar& cal, UnicodeString& appendTo,
// Format the last item in the pattern, if any
if (count > 0) {
- subFormat(appendTo, prevCh, count, capitalizationContext, fieldNum++, handler, *workCal, status);
+ subFormat(appendTo, prevCh, count, capitalizationContext, fieldNum++, handler, *workCal, mutableNFs, status);
}
if (calClone != NULL) {
@@ -967,23 +1082,79 @@ SimpleDateFormat::fgCalendarFieldToLevel[] =
/*A?.*/ 40, 0, 0
};
-
-/* Map calendar field LETTER into calendar field level.
- * the larger the level, the smaller the field unit.
- * NOTE: if new fields adds in, the table needs to update.
- */
-const int32_t
-SimpleDateFormat::fgPatternCharToLevel[] = {
- // A B C D E F G H I J K L M N O
- -1, 40, -1, -1, 20, 30, 30, 0, 50, -1, -1, 50, 20, 20, -1, 0,
- // P Q R S T U V W X Y Z
- -1, 20, -1, 80, -1, 10, 0, 30, 0, 10, 0, -1, -1, -1, -1, -1,
- // a b c d e f g h i j k l m n o
- -1, 40, -1, 30, 30, 30, -1, 0, 50, -1, -1, 50, -1, 60, -1, -1,
- // p q r s t u v w x y z
- -1, 20, 10, 70, -1, 10, 0, 20, 0, 10, 0, -1, -1, -1, -1, -1
-};
-
+int32_t SimpleDateFormat::getLevelFromChar(UChar ch) {
+ // Map date field LETTER into calendar field level.
+ // the larger the level, the smaller the field unit.
+ // NOTE: if new fields adds in, the table needs to update.
+ static const int32_t mapCharToLevel[] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ //
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ // ! " # $ % & ' ( ) * + , - . /
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+#if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
+ // 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1,
+#else
+ // 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+#endif
+ // @ A B C D E F G H I J K L M N O
+ -1, 40, -1, -1, 20, 30, 30, 0, 50, -1, -1, 50, 20, 20, -1, 0,
+ // P Q R S T U V W X Y Z [ \ ] ^ _
+ -1, 20, -1, 80, -1, 10, 0, 30, 0, 10, 0, -1, -1, -1, -1, -1,
+ // ` a b c d e f g h i j k l m n o
+ -1, 40, -1, 30, 30, 30, -1, 0, 50, -1, -1, 50, 0, 60, -1, -1,
+ // p q r s t u v w x y z { | } ~
+ -1, 20, 10, 70, -1, 10, 0, 20, 0, 10, 0, -1, -1, -1, -1, -1
+ };
+
+ return ch < UPRV_LENGTHOF(mapCharToLevel) ? mapCharToLevel[ch] : -1;
+}
+
+UBool SimpleDateFormat::isSyntaxChar(UChar ch) {
+ static const UBool mapCharToIsSyntax[] = {
+ //
+ FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
+ //
+ FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
+ //
+ FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
+ //
+ FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
+ // ! " # $ % & '
+ FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
+ // ( ) * + , - . /
+ FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
+ // 0 1 2 3 4 5 6 7
+ FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
+#if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
+ // 8 9 : ; < = > ?
+ FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE,
+#else
+ // 8 9 : ; < = > ?
+ FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
+#endif
+ // @ A B C D E F G
+ FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
+ // H I J K L M N O
+ TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
+ // P Q R S T U V W
+ TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
+ // X Y Z [ \ ] ^ _
+ TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE,
+ // ` a b c d e f g
+ FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
+ // h i j k l m n o
+ TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
+ // p q r s t u v w
+ TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
+ // x y z { | } ~
+ TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE
+ };
+
+ return ch < UPRV_LENGTHOF(mapCharToIsSyntax) ? mapCharToIsSyntax[ch] : FALSE;
+}
// Map index into pattern character string to Calendar field number.
const UCalendarDateFields
@@ -1007,6 +1178,11 @@ SimpleDateFormat::fgPatternIndexToCalendarField[] =
/*O*/ UCAL_ZONE_OFFSET,
/*Xx*/ UCAL_ZONE_OFFSET, UCAL_ZONE_OFFSET,
/*r*/ UCAL_EXTENDED_YEAR,
+#if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
+ /*:*/ UCAL_FIELD_COUNT, /* => no useful mapping to any calendar field */
+#else
+ /*no pattern char for UDAT_TIME_SEPARATOR_FIELD*/ UCAL_FIELD_COUNT, /* => no useful mapping to any calendar field */
+#endif
};
// Map index into pattern character string to DateFormat field number
@@ -1030,6 +1206,11 @@ SimpleDateFormat::fgPatternIndexToDateFormatField[] = {
/*O*/ UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD,
/*Xx*/ UDAT_TIMEZONE_ISO_FIELD, UDAT_TIMEZONE_ISO_LOCAL_FIELD,
/*r*/ UDAT_RELATED_YEAR_FIELD,
+#if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
+ /*:*/ UDAT_TIME_SEPARATOR_FIELD,
+#else
+ /*no pattern char for UDAT_TIME_SEPARATOR_FIELD*/ UDAT_TIME_SEPARATOR_FIELD,
+#endif
};
//----------------------------------------------------------------------
@@ -1073,13 +1254,9 @@ SimpleDateFormat::initNumberFormatters(const Locale &locale,UErrorCode &status)
return;
}
umtx_lock(&LOCK);
- if (fNumberFormatters == NULL) {
- fNumberFormatters = (NumberFormat**)uprv_malloc(UDAT_FIELD_COUNT * sizeof(NumberFormat*));
- if (fNumberFormatters) {
- for (int32_t i = 0; i < UDAT_FIELD_COUNT; i++) {
- fNumberFormatters[i] = fNumberFormat;
- }
- } else {
+ if (fSharedNumberFormatters == NULL) {
+ fSharedNumberFormatters = allocSharedNumberFormatters();
+ if (fSharedNumberFormatters == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
}
}
@@ -1099,13 +1276,12 @@ SimpleDateFormat::processOverrideString(const Locale &locale, const UnicodeStrin
return;
}
- U_ASSERT(fNumberFormatters != NULL);
-
int32_t start = 0;
int32_t len;
UnicodeString nsName;
UnicodeString ovrField;
UBool moreToProcess = TRUE;
+ NSOverride *overrideList = NULL;
while (moreToProcess) {
int32_t delimiterPosition = str.indexOf((UChar)ULOC_KEYWORD_ITEM_SEPARATOR_UNICODE,start);
@@ -1127,55 +1303,42 @@ SimpleDateFormat::processOverrideString(const Locale &locale, const UnicodeStrin
int32_t nsNameHash = nsName.hashCode();
// See if the numbering system is in the override list, if not, then add it.
- NSOverride *cur = fOverrideList;
- NumberFormat *nf = NULL;
+ NSOverride *cur = overrideList;
+ const SharedNumberFormat *snf = NULL;
UBool found = FALSE;
while ( cur && !found ) {
if ( cur->hash == nsNameHash ) {
- nf = cur->nf;
+ snf = cur->snf;
found = TRUE;
}
cur = cur->next;
}
if (!found) {
- cur = (NSOverride *)uprv_malloc(sizeof(NSOverride));
- if (cur) {
+ LocalPointer<NSOverride> cur(new NSOverride);
+ if (!cur.isNull()) {
char kw[ULOC_KEYWORD_AND_VALUES_CAPACITY];
uprv_strcpy(kw,"numbers=");
nsName.extract(0,len,kw+8,ULOC_KEYWORD_AND_VALUES_CAPACITY-8,US_INV);
Locale ovrLoc(locale.getLanguage(),locale.getCountry(),locale.getVariant(),kw);
- nf = NumberFormat::createInstance(ovrLoc,status);
-
- // no matter what the locale's default number format looked like, we want
- // to modify it so that it doesn't use thousands separators, doesn't always
- // show the decimal point, and recognizes integers only when parsing
-
- if (U_SUCCESS(status)) {
- nf->setGroupingUsed(FALSE);
- DecimalFormat* decfmt = dynamic_cast<DecimalFormat*>(nf);
- if (decfmt != NULL) {
- decfmt->setDecimalSeparatorAlwaysShown(FALSE);
+ cur->hash = nsNameHash;
+ cur->next = overrideList;
+ SharedObject::copyPtr(
+ createSharedNumberFormat(ovrLoc, status), cur->snf);
+ if (U_FAILURE(status)) {
+ if (overrideList) {
+ overrideList->free();
}
- nf->setParseIntegerOnly(TRUE);
- nf->setMinimumFractionDigits(0); // To prevent "Jan 1.00, 1997.00"
-
- cur->nf = nf;
- cur->hash = nsNameHash;
- cur->next = fOverrideList;
- fOverrideList = cur;
+ return;
}
- else {
- // clean up before returning
- if (cur != NULL) {
- uprv_free(cur);
- }
- return;
- }
-
+ snf = cur->snf;
+ overrideList = cur.orphan();
} else {
status = U_MEMORY_ALLOCATION_ERROR;
+ if (overrideList) {
+ overrideList->free();
+ }
return;
}
}
@@ -1187,7 +1350,7 @@ SimpleDateFormat::processOverrideString(const Locale &locale, const UnicodeStrin
case kOvrStrDate:
case kOvrStrBoth: {
for ( int8_t i=0 ; i<kDateFieldsCount; i++ ) {
- fNumberFormatters[kDateFields[i]] = nf;
+ SharedObject::copyPtr(snf, fSharedNumberFormatters[kDateFields[i]]);
}
if (type==kOvrStrDate) {
break;
@@ -1195,7 +1358,7 @@ SimpleDateFormat::processOverrideString(const Locale &locale, const UnicodeStrin
}
case kOvrStrTime : {
for ( int8_t i=0 ; i<kTimeFieldsCount; i++ ) {
- fNumberFormatters[kTimeFields[i]] = nf;
+ SharedObject::copyPtr(snf, fSharedNumberFormatters[kTimeFields[i]]);
}
break;
}
@@ -1206,15 +1369,19 @@ SimpleDateFormat::processOverrideString(const Locale &locale, const UnicodeStrin
DateFormatSymbols::getPatternCharIndex(ovrField.charAt(0));
if (patternCharIndex == UDAT_FIELD_COUNT) {
status = U_INVALID_FORMAT_ERROR;
+ if (overrideList) {
+ overrideList->free();
+ }
return;
}
-
- // Set the number formatter in the table
- fNumberFormatters[patternCharIndex] = nf;
+ SharedObject::copyPtr(snf, fSharedNumberFormatters[patternCharIndex]);
}
start = delimiterPosition + 1;
}
+ if (overrideList) {
+ overrideList->free();
+ }
}
//---------------------------------------------------------------------
@@ -1226,6 +1393,7 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
int32_t fieldNum,
FieldPositionHandler& handler,
Calendar& cal,
+ SimpleDateFormatMutableNFs &mutableNFs,
UErrorCode& status) const
{
if (U_FAILURE(status)) {
@@ -1254,12 +1422,20 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
}
UCalendarDateFields field = fgPatternIndexToCalendarField[patternCharIndex];
- int32_t value = (patternCharIndex != UDAT_RELATED_YEAR_FIELD)? cal.get(field, status): cal.getRelatedYear(status);
+ int32_t value = 0;
+ // Don't get value unless it is useful
+ if (field < UCAL_FIELD_COUNT) {
+ value = (patternCharIndex != UDAT_RELATED_YEAR_FIELD)? cal.get(field, status): cal.getRelatedYear(status);
+ }
if (U_FAILURE(status)) {
return;
}
- currentNumberFormat = getNumberFormatByIndex(patternCharIndex);
+ currentNumberFormat = mutableNFs.get(getNumberFormatByIndex(patternCharIndex));
+ if (currentNumberFormat == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
UnicodeString hebr("hebr", 4, US_INV);
switch (patternCharIndex) {
@@ -1463,10 +1639,24 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
}
break;
- // for and "a" symbol, write out the whole AM/PM string
+ // for "a" symbol, write out the whole AM/PM string
case UDAT_AM_PM_FIELD:
- _appendSymbol(appendTo, value, fSymbols->fAmPms,
- fSymbols->fAmPmsCount);
+ if (count < 5) {
+ _appendSymbol(appendTo, value, fSymbols->fAmPms,
+ fSymbols->fAmPmsCount);
+ } else {
+ _appendSymbol(appendTo, value, fSymbols->fNarrowAmPms,
+ fSymbols->fNarrowAmPmsCount);
+ }
+ break;
+
+ // if we see pattern character for UDAT_TIME_SEPARATOR_FIELD (none currently defined),
+ // write out the time separator string. Leave support in for future definition.
+ case UDAT_TIME_SEPARATOR_FIELD:
+ {
+ UnicodeString separator;
+ appendTo += fSymbols->getTimeSeparatorString(separator);
+ }
break;
// for "h" and "hh", write out the hour, adjusting noon and midnight to show up
@@ -1486,7 +1676,8 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
case UDAT_TIMEZONE_ISO_FIELD: // 'X'
case UDAT_TIMEZONE_ISO_LOCAL_FIELD: // 'x'
{
- UnicodeString zoneString;
+ UChar zsbuf[64];
+ UnicodeString zoneString(zsbuf, 0, UPRV_LENGTHOF(zsbuf));
const TimeZone& tz = cal.getTimeZone();
UDate date = cal.getTime(status);
if (U_SUCCESS(status)) {
@@ -1654,116 +1845,70 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
//----------------------------------------------------------------------
void SimpleDateFormat::adoptNumberFormat(NumberFormat *formatToAdopt) {
- formatToAdopt->setParseIntegerOnly(TRUE);
- if (fNumberFormat && fNumberFormat != formatToAdopt){
- delete fNumberFormat;
- }
+ fixNumberFormatForDates(*formatToAdopt);
+ delete fNumberFormat;
fNumberFormat = formatToAdopt;
-
- if (fNumberFormatters) {
- for (int32_t i = 0; i < UDAT_FIELD_COUNT; i++) {
- if (fNumberFormatters[i] == formatToAdopt) {
- fNumberFormatters[i] = NULL;
- }
- }
- uprv_free(fNumberFormatters);
- fNumberFormatters = NULL;
- }
- while (fOverrideList) {
- NSOverride *cur = fOverrideList;
- fOverrideList = cur->next;
- if (cur->nf != formatToAdopt) { // only delete those not duplicate
- delete cur->nf;
- uprv_free(cur);
- } else {
- cur->nf = NULL;
- uprv_free(cur);
- }
+ // We successfully set the default number format. Now delete the overrides
+ // (can't fail).
+ if (fSharedNumberFormatters) {
+ freeSharedNumberFormatters(fSharedNumberFormatters);
+ fSharedNumberFormatters = NULL;
}
}
void SimpleDateFormat::adoptNumberFormat(const UnicodeString& fields, NumberFormat *formatToAdopt, UErrorCode &status){
- // if it has not been initialized yet, initialize
- if (fNumberFormatters == NULL) {
- fNumberFormatters = (NumberFormat**)uprv_malloc(UDAT_FIELD_COUNT * sizeof(NumberFormat*));
- if (fNumberFormatters) {
- for (int32_t i = 0; i < UDAT_FIELD_COUNT; i++) {
- fNumberFormatters[i] = fNumberFormat;
- }
- } else {
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
+ fixNumberFormatForDates(*formatToAdopt);
+ LocalPointer<NumberFormat> fmt(formatToAdopt);
+ if (U_FAILURE(status)) {
+ return;
}
-
- // See if the numbering format is in the override list, if not, then add it.
- NSOverride *cur = fOverrideList;
- UBool found = FALSE;
- while (cur && !found) {
- if ( cur->nf == formatToAdopt ) {
- found = TRUE;
- }
- cur = cur->next;
- }
-
- if (!found) {
- cur = (NSOverride *)uprv_malloc(sizeof(NSOverride));
- if (cur) {
- // no matter what the locale's default number format looked like, we want
- // to modify it so that it doesn't use thousands separators, doesn't always
- // show the decimal point, and recognizes integers only when parsing
- formatToAdopt->setGroupingUsed(FALSE);
- DecimalFormat* decfmt = dynamic_cast<DecimalFormat*>(formatToAdopt);
- if (decfmt != NULL) {
- decfmt->setDecimalSeparatorAlwaysShown(FALSE);
- }
- formatToAdopt->setParseIntegerOnly(TRUE);
- formatToAdopt->setMinimumFractionDigits(0); // To prevent "Jan 1.00, 1997.00"
-
- cur->nf = formatToAdopt;
- cur->hash = -1; // set duplicate here (before we set it with NumberSystem Hash, here we cannot get nor use it)
- cur->next = fOverrideList;
- fOverrideList = cur;
- } else {
+
+ // We must ensure fSharedNumberFormatters is allocated.
+ if (fSharedNumberFormatters == NULL) {
+ fSharedNumberFormatters = allocSharedNumberFormatters();
+ if (fSharedNumberFormatters == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
}
-
+ const SharedNumberFormat *newFormat = createSharedNumberFormat(fmt.orphan());
+ if (newFormat == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
for (int i=0; i<fields.length(); i++) {
UChar field = fields.charAt(i);
// if the pattern character is unrecognized, signal an error and bail out
UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(field);
if (patternCharIndex == UDAT_FIELD_COUNT) {
status = U_INVALID_FORMAT_ERROR;
+ newFormat->deleteIfZeroRefCount();
return;
}
// Set the number formatter in the table
- fNumberFormatters[patternCharIndex] = formatToAdopt;
+ SharedObject::copyPtr(
+ newFormat, fSharedNumberFormatters[patternCharIndex]);
}
+ newFormat->deleteIfZeroRefCount();
}
const NumberFormat *
SimpleDateFormat::getNumberFormatForField(UChar field) const {
UDateFormatField index = DateFormatSymbols::getPatternCharIndex(field);
- return getNumberFormatByIndex(index);
-}
-
-NumberFormat *
-SimpleDateFormat::getNumberFormatByIndex(UDateFormatField index) const {
- if (fNumberFormatters != NULL) {
- return fNumberFormatters[index];
- } else {
- return fNumberFormat;
+ if (index == UDAT_FIELD_COUNT) {
+ return NULL;
}
+ return getNumberFormatByIndex(index);
}
//----------------------------------------------------------------------
void
-SimpleDateFormat::zeroPaddingNumber(NumberFormat *currentNumberFormat,UnicodeString &appendTo,
- int32_t value, int32_t minDigits, int32_t maxDigits) const
+SimpleDateFormat::zeroPaddingNumber(
+ NumberFormat *currentNumberFormat,
+ UnicodeString &appendTo,
+ int32_t value, int32_t minDigits, int32_t maxDigits) const
{
if (currentNumberFormat!=NULL) {
FieldPosition pos(0);
@@ -1834,6 +1979,7 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
int32_t saveHebrewMonth = -1;
int32_t count = 0;
UTimeZoneFormatTimeType tzTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
+ SimpleDateFormatMutableNFs mutableNFs;
// For parsing abutting numeric fields. 'abutPat' is the
// offset into 'pattern' of the first of 2 or more abutting
@@ -1881,7 +2027,7 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
UChar ch = fPattern.charAt(i);
// Handle alphabetic field characters.
- if (!inQuote && ((ch >= 0x41 && ch <= 0x5A) || (ch >= 0x61 && ch <= 0x7A))) { // [A-Za-z]
+ if (!inQuote && isSyntaxChar(ch)) {
int32_t fieldPat = i;
// Count the length of this field specifier
@@ -1927,7 +2073,7 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
}
pos = subParse(text, pos, ch, count,
- TRUE, FALSE, ambiguousYear, saveHebrewMonth, *workCal, i, numericLeapMonthFormatter, &tzTimeType);
+ TRUE, FALSE, ambiguousYear, saveHebrewMonth, *workCal, i, numericLeapMonthFormatter, &tzTimeType, mutableNFs);
// If the parse fails anywhere in the run, back up to the
// start of the run and retry.
@@ -1942,7 +2088,7 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
// fields.
else if (ch != 0x6C) { // pattern char 'l' (SMALL LETTER L) just gets ignored
int32_t s = subParse(text, pos, ch, count,
- FALSE, TRUE, ambiguousYear, saveHebrewMonth, *workCal, i, numericLeapMonthFormatter, &tzTimeType);
+ FALSE, TRUE, ambiguousYear, saveHebrewMonth, *workCal, i, numericLeapMonthFormatter, &tzTimeType, mutableNFs);
if (s == -pos-1) {
// era not present, in special cases allow this to continue
@@ -1979,7 +2125,7 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
abutPat = -1; // End of any abutting fields
- if (! matchLiterals(fPattern, i, text, pos, getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status), getBooleanAttribute(UDAT_PARSE_PARTIAL_MATCH, status), isLenient())) {
+ if (! matchLiterals(fPattern, i, text, pos, getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status), getBooleanAttribute(UDAT_PARSE_PARTIAL_LITERAL_MATCH, status), isLenient())) {
status = U_PARSE_ERROR;
goto ExitParse;
}
@@ -2180,11 +2326,10 @@ ExitParse:
//----------------------------------------------------------------------
-static UBool
-newBestMatchWithOptionalDot(const UnicodeString &lcaseText,
- const UnicodeString &data,
- UnicodeString &bestMatchName,
- int32_t &bestMatchLength);
+static int32_t
+matchStringWithOptionalDot(const UnicodeString &text,
+ int32_t index,
+ const UnicodeString &data);
int32_t SimpleDateFormat::matchQuarterString(const UnicodeString& text,
int32_t start,
@@ -2203,54 +2348,17 @@ int32_t SimpleDateFormat::matchQuarterString(const UnicodeString& text,
int32_t bestMatchLength = 0, bestMatch = -1;
UnicodeString bestMatchName;
- // {sfb} kludge to support case-insensitive comparison
- // {markus 2002oct11} do not just use caseCompareBetween because we do not know
- // the length of the match after case folding
- // {alan 20040607} don't case change the whole string, since the length
- // can change
- // TODO we need a case-insensitive startsWith function
- UnicodeString lcaseText;
- text.extract(start, INT32_MAX, lcaseText);
- lcaseText.foldCase();
-
- for (; i < count; ++i)
- {
- // Always compare if we have no match yet; otherwise only compare
- // against potentially better matches (longer strings).
-
- if (newBestMatchWithOptionalDot(lcaseText, data[i], bestMatchName, bestMatchLength)) {
+ for (; i < count; ++i) {
+ int32_t matchLength = 0;
+ if ((matchLength = matchStringWithOptionalDot(text, start, data[i])) > bestMatchLength) {
+ bestMatchLength = matchLength;
bestMatch = i;
}
}
- if (bestMatch >= 0)
- {
- cal.set(field, bestMatch * 3);
-
- // Once we have a match, we have to determine the length of the
- // original source string. This will usually be == the length of
- // the case folded string, but it may differ (e.g. sharp s).
- // Most of the time, the length will be the same as the length
- // of the string from the locale data. Sometimes it will be
- // different, in which case we will have to figure it out by
- // adding a character at a time, until we have a match. We do
- // this all in one loop, where we try 'len' first (at index
- // i==0).
- int32_t len = bestMatchName.length(); // 99+% of the time
- int32_t n = text.length() - start;
- for (i=0; i<=n; ++i) {
- int32_t j=i;
- if (i == 0) {
- j = len;
- } else if (i == len) {
- continue; // already tried this when i was 0
- }
- text.extract(start, j, lcaseText);
- lcaseText.foldCase();
- if (bestMatchName == lcaseText) {
- return start + j;
- }
- }
+ if (bestMatch >= 0) {
+ cal.set(field, bestMatch * 3);
+ return start + bestMatchLength;
}
return -start;
@@ -2268,12 +2376,12 @@ UBool SimpleDateFormat::matchLiterals(const UnicodeString &pattern,
UBool inQuote = FALSE;
UnicodeString literal;
int32_t i = patternOffset;
-
+
// scan pattern looking for contiguous literal characters
for ( ; i < pattern.length(); i += 1) {
UChar ch = pattern.charAt(i);
- if (!inQuote && ((ch >= 0x41 && ch <= 0x5A) || (ch >= 0x61 && ch <= 0x7A))) { // unquoted [A-Za-z]
+ if (!inQuote && isSyntaxChar(ch)) {
break;
}
@@ -2424,24 +2532,11 @@ int32_t SimpleDateFormat::matchString(const UnicodeString& text,
UnicodeString bestMatchName;
int32_t isLeapMonth = 0;
- // {sfb} kludge to support case-insensitive comparison
- // {markus 2002oct11} do not just use caseCompareBetween because we do not know
- // the length of the match after case folding
- // {alan 20040607} don't case change the whole string, since the length
- // can change
- // TODO we need a case-insensitive startsWith function
- UnicodeString lcaseText;
- text.extract(start, INT32_MAX, lcaseText);
- lcaseText.foldCase();
-
- for (; i < count; ++i)
- {
- // Always compare if we have no match yet; otherwise only compare
- // against potentially better matches (longer strings).
-
- if (newBestMatchWithOptionalDot(lcaseText, data[i], bestMatchName, bestMatchLength)) {
+ for (; i < count; ++i) {
+ int32_t matchLen = 0;
+ if ((matchLen = matchStringWithOptionalDot(text, start, data[i])) > bestMatchLength) {
bestMatch = i;
- isLeapMonth = 0;
+ bestMatchLength = matchLen;
}
if (monthPattern != NULL) {
@@ -2450,88 +2545,59 @@ int32_t SimpleDateFormat::matchString(const UnicodeString& text,
Formattable monthName((const UnicodeString&)(data[i]));
MessageFormat::format(*monthPattern, &monthName, 1, leapMonthName, status);
if (U_SUCCESS(status)) {
- if (newBestMatchWithOptionalDot(lcaseText, leapMonthName, bestMatchName, bestMatchLength)) {
+ if ((matchLen = matchStringWithOptionalDot(text, start, leapMonthName)) > bestMatchLength) {
bestMatch = i;
+ bestMatchLength = matchLen;
isLeapMonth = 1;
}
}
}
}
- if (bestMatch >= 0)
- {
- // Adjustment for Hebrew Calendar month Adar II
- if (!strcmp(cal.getType(),"hebrew") && field==UCAL_MONTH && bestMatch==13) {
- cal.set(field,6);
- }
- else {
- if (field == UCAL_YEAR) {
- bestMatch++; // only get here for cyclic year names, which match 1-based years 1-60
- }
- cal.set(field, bestMatch);
- }
- if (monthPattern != NULL) {
- cal.set(UCAL_IS_LEAP_MONTH, isLeapMonth);
- }
-
- // Once we have a match, we have to determine the length of the
- // original source string. This will usually be == the length of
- // the case folded string, but it may differ (e.g. sharp s).
- // Most of the time, the length will be the same as the length
- // of the string from the locale data. Sometimes it will be
- // different, in which case we will have to figure it out by
- // adding a character at a time, until we have a match. We do
- // this all in one loop, where we try 'len' first (at index
- // i==0).
- int32_t len = bestMatchName.length(); // 99+% of the time
- int32_t n = text.length() - start;
- for (i=0; i<=n; ++i) {
- int32_t j=i;
- if (i == 0) {
- j = len;
- } else if (i == len) {
- continue; // already tried this when i was 0
+ if (bestMatch >= 0) {
+ if (field < UCAL_FIELD_COUNT) {
+ // Adjustment for Hebrew Calendar month Adar II
+ if (!strcmp(cal.getType(),"hebrew") && field==UCAL_MONTH && bestMatch==13) {
+ cal.set(field,6);
+ } else {
+ if (field == UCAL_YEAR) {
+ bestMatch++; // only get here for cyclic year names, which match 1-based years 1-60
+ }
+ cal.set(field, bestMatch);
}
- text.extract(start, j, lcaseText);
- lcaseText.foldCase();
- if (bestMatchName == lcaseText) {
- return start + j;
+ if (monthPattern != NULL) {
+ cal.set(UCAL_IS_LEAP_MONTH, isLeapMonth);
}
}
+
+ return start + bestMatchLength;
}
return -start;
}
-static UBool
-newBestMatchWithOptionalDot(const UnicodeString &lcaseText,
- const UnicodeString &data,
- UnicodeString &bestMatchName,
- int32_t &bestMatchLength) {
- UnicodeString lcase;
- lcase.fastCopyFrom(data).foldCase();
- int32_t length = lcase.length();
- if (length <= bestMatchLength) {
- // data cannot provide a better match.
- return FALSE;
- }
+static int32_t
+matchStringWithOptionalDot(const UnicodeString &text,
+ int32_t index,
+ const UnicodeString &data) {
+ UErrorCode sts = U_ZERO_ERROR;
+ int32_t matchLenText = 0;
+ int32_t matchLenData = 0;
- if (lcaseText.compareBetween(0, length, lcase, 0, length) == 0) {
- // normal match
- bestMatchName = lcase;
- bestMatchLength = length;
- return TRUE;
- }
- if (lcase.charAt(--length) == 0x2e) {
- if (lcaseText.compareBetween(0, length, lcase, 0, length) == 0) {
- // The input text matches the data except for data's trailing dot.
- bestMatchName = lcase;
- bestMatchName.truncate(length);
- bestMatchLength = length;
- return TRUE;
- }
+ u_caseInsensitivePrefixMatch(text.getBuffer() + index, text.length() - index,
+ data.getBuffer(), data.length(),
+ 0 /* default case option */,
+ &matchLenText, &matchLenData,
+ &sts);
+ U_ASSERT (U_SUCCESS(sts));
+
+ if (matchLenData == data.length() /* normal match */
+ || (data.charAt(data.length() - 1) == 0x2e
+ && matchLenData == data.length() - 1 /* match without trailing dot */)) {
+ return matchLenText;
}
- return FALSE;
+
+ return 0;
}
//----------------------------------------------------------------------
@@ -2548,7 +2614,7 @@ SimpleDateFormat::set2DigitYearStart(UDate d, UErrorCode& status)
*/
int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UChar ch, int32_t count,
UBool obeyCount, UBool allowNegative, UBool ambiguousYear[], int32_t& saveHebrewMonth, Calendar& cal,
- int32_t patLoc, MessageFormat * numericLeapMonthFormatter, UTimeZoneFormatTimeType *tzTimeType) const
+ int32_t patLoc, MessageFormat * numericLeapMonthFormatter, UTimeZoneFormatTimeType *tzTimeType, SimpleDateFormatMutableNFs &mutableNFs) const
{
Formattable number;
int32_t value = 0;
@@ -2569,8 +2635,11 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
return -start;
}
- currentNumberFormat = getNumberFormatByIndex(patternCharIndex);
- UCalendarDateFields field = fgPatternIndexToCalendarField[patternCharIndex];
+ currentNumberFormat = mutableNFs.get(getNumberFormatByIndex(patternCharIndex));
+ if (currentNumberFormat == NULL) {
+ return -start;
+ }
+ UCalendarDateFields field = fgPatternIndexToCalendarField[patternCharIndex]; // UCAL_FIELD_COUNT if irrelevant
UnicodeString hebr("hebr", 4, US_INV);
if (numericLeapMonthFormatter != NULL) {
@@ -2981,7 +3050,24 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
break;
case UDAT_AM_PM_FIELD:
- return matchString(text, start, UCAL_AM_PM, fSymbols->fAmPms, fSymbols->fAmPmsCount, NULL, cal);
+ {
+ // optionally try both wide/abbrev and narrow forms
+ int32_t newStart = 0;
+ // try wide/abbrev
+ if( getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count < 5 ) {
+ if ((newStart = matchString(text, start, UCAL_AM_PM, fSymbols->fAmPms, fSymbols->fAmPmsCount, NULL, cal)) > 0) {
+ return newStart;
+ }
+ }
+ // try narrow
+ if( getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count >= 5 ) {
+ if ((newStart = matchString(text, start, UCAL_AM_PM, fSymbols->fNarrowAmPms, fSymbols->fNarrowAmPmsCount, NULL, cal)) > 0) {
+ return newStart;
+ }
+ }
+ // no matches for given options
+ return -start;
+ }
case UDAT_HOUR1_FIELD:
// [We computed 'value' above.]
@@ -3177,6 +3263,30 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
}
return -start;
}
+ // currently no pattern character is defined for UDAT_TIME_SEPARATOR_FIELD
+ // so we should not get here. Leave support in for future definition.
+ case UDAT_TIME_SEPARATOR_FIELD: //
+ {
+ static const UChar def_sep = DateFormatSymbols::DEFAULT_TIME_SEPARATOR;
+ static const UChar alt_sep = DateFormatSymbols::ALTERNATE_TIME_SEPARATOR;
+
+ // Try matching a time separator.
+ int32_t count = 1;
+ UnicodeString data[3];
+ fSymbols->getTimeSeparatorString(data[0]);
+
+ // Add the default, if different from the locale.
+ if (data[0].compare(&def_sep, 1) != 0) {
+ data[count++].setTo(def_sep);
+ }
+
+ // If lenient, add also the alternate, if different from the locale.
+ if (isLenient() && data[0].compare(&alt_sep, 1) != 0) {
+ data[count++].setTo(alt_sep);
+ }
+
+ return matchString(text, start, UCAL_FIELD_COUNT /* => nothing to set */, data, count, NULL, cal);
+ }
default:
// Handle "generic" fields
@@ -3316,42 +3426,42 @@ void SimpleDateFormat::translatePattern(const UnicodeString& originalPattern,
const UnicodeString& to,
UErrorCode& status)
{
- // run through the pattern and convert any pattern symbols from the version
- // in "from" to the corresponding character ion "to". This code takes
- // quoted strings into account (it doesn't try to translate them), and it signals
- // an error if a particular "pattern character" doesn't appear in "from".
- // Depending on the values of "from" and "to" this can convert from generic
- // to localized patterns or localized to generic.
- if (U_FAILURE(status))
- return;
-
- translatedPattern.remove();
- UBool inQuote = FALSE;
- for (int32_t i = 0; i < originalPattern.length(); ++i) {
- UChar c = originalPattern[i];
- if (inQuote) {
- if (c == QUOTE)
- inQuote = FALSE;
- }
- else {
- if (c == QUOTE)
- inQuote = TRUE;
- else if ((c >= 0x0061 /*'a'*/ && c <= 0x007A) /*'z'*/
- || (c >= 0x0041 /*'A'*/ && c <= 0x005A /*'Z'*/)) {
- int32_t ci = from.indexOf(c);
- if (ci == -1) {
- status = U_INVALID_FORMAT_ERROR;
- return;
+ // run through the pattern and convert any pattern symbols from the version
+ // in "from" to the corresponding character ion "to". This code takes
+ // quoted strings into account (it doesn't try to translate them), and it signals
+ // an error if a particular "pattern character" doesn't appear in "from".
+ // Depending on the values of "from" and "to" this can convert from generic
+ // to localized patterns or localized to generic.
+ if (U_FAILURE(status)) {
+ return;
}
- c = to[ci];
- }
+
+ translatedPattern.remove();
+ UBool inQuote = FALSE;
+ for (int32_t i = 0; i < originalPattern.length(); ++i) {
+ UChar c = originalPattern[i];
+ if (inQuote) {
+ if (c == QUOTE) {
+ inQuote = FALSE;
+ }
+ } else {
+ if (c == QUOTE) {
+ inQuote = TRUE;
+ } else if (isSyntaxChar(c)) {
+ int32_t ci = from.indexOf(c);
+ if (ci == -1) {
+ status = U_INVALID_FORMAT_ERROR;
+ return;
+ }
+ c = to[ci];
+ }
+ }
+ translatedPattern += c;
+ }
+ if (inQuote) {
+ status = U_INVALID_FORMAT_ERROR;
+ return;
}
- translatedPattern += c;
- }
- if (inQuote) {
- status = U_INVALID_FORMAT_ERROR;
- return;
- }
}
//----------------------------------------------------------------------
@@ -3447,10 +3557,16 @@ SimpleDateFormat::setTimeZoneFormat(const TimeZoneFormat& newTimeZoneFormat)
void SimpleDateFormat::adoptCalendar(Calendar* calendarToAdopt)
{
UErrorCode status = U_ZERO_ERROR;
+ Locale calLocale(fLocale);
+ calLocale.setKeywordValue("calendar", calendarToAdopt->getType(), status);
+ DateFormatSymbols *newSymbols =
+ DateFormatSymbols::createForLocale(calLocale, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
DateFormat::adoptCalendar(calendarToAdopt);
delete fSymbols;
- fSymbols=NULL;
- initializeSymbols(fLocale, fCalendar, status); // we need new symbols
+ fSymbols = newSymbols;
initializeDefaultCentury(); // we need a new century (possibly)
}
@@ -3502,9 +3618,9 @@ SimpleDateFormat::isFieldUnitIgnored(const UnicodeString& pattern,
for (int32_t i = 0; i < pattern.length(); ++i) {
ch = pattern[i];
if (ch != prevCh && count > 0) {
- level = fgPatternCharToLevel[prevCh - PATTERN_CHAR_BASE];
+ level = getLevelFromChar(prevCh);
// the larger the level, the smaller the field unit.
- if ( fieldLevel <= level ) {
+ if (fieldLevel <= level) {
return FALSE;
}
count = 0;
@@ -3516,18 +3632,17 @@ SimpleDateFormat::isFieldUnitIgnored(const UnicodeString& pattern,
inQuote = ! inQuote;
}
}
- else if ( ! inQuote && ((ch >= 0x0061 /*'a'*/ && ch <= 0x007A /*'z'*/)
- || (ch >= 0x0041 /*'A'*/ && ch <= 0x005A /*'Z'*/))) {
+ else if (!inQuote && isSyntaxChar(ch)) {
prevCh = ch;
++count;
}
}
- if ( count > 0 ) {
+ if (count > 0) {
// last item
- level = fgPatternCharToLevel[prevCh - PATTERN_CHAR_BASE];
- if ( fieldLevel <= level ) {
- return FALSE;
- }
+ level = getLevelFromChar(prevCh);
+ if (fieldLevel <= level) {
+ return FALSE;
+ }
}
return TRUE;
}
« no previous file with comments | « source/i18n/smallintformatter.cpp ('k') | source/i18n/timezone.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698