ICU-8291 Merge some important fixes done after 4.4 back to maint-4-4. #7201 (r28825), #7480 (r27945), #7690 (r28106) and #7880 (r28493).
X-SVN-Rev: 29415
diff --git a/main/classes/core/src/com/ibm/icu/impl/DateNumberFormat.java b/main/classes/core/src/com/ibm/icu/impl/DateNumberFormat.java
index a6e2b82..e2abb77 100644
--- a/main/classes/core/src/com/ibm/icu/impl/DateNumberFormat.java
+++ b/main/classes/core/src/com/ibm/icu/impl/DateNumberFormat.java
@@ -1,6 +1,6 @@
/*
*******************************************************************************
-* Copyright (C) 2007-2009, International Business Machines
+* Copyright (C) 2007-2011, International Business Machines
* Corporation and others. All Rights Reserved.
*******************************************************************************
*/
@@ -36,7 +36,7 @@
private int maxIntDigits;
private int minIntDigits;
-
+
public DateNumberFormat(ULocale loc, char zeroDigitIn) {
initialize(loc,zeroDigitIn);
}
@@ -152,6 +152,8 @@
/*
* Note: This method only parse integer numbers which can be represented by long
*/
+ private static final long PARSE_THRESHOLD = 922337203685477579L; // (Long.MAX_VALUE / 10) - 1
+
public Number parse(String text, ParsePosition parsePosition) {
long num = 0;
boolean sawNumber = false;
@@ -170,7 +172,7 @@
if (digit < 0 || 9 < digit) {
digit = UCharacter.digit(ch);
}
- if (0 <= digit && digit <= 9) {
+ if (0 <= digit && digit <= 9 && num < PARSE_THRESHOLD) {
sawNumber = true;
num = num * 10 + digit;
} else {
diff --git a/main/classes/core/src/com/ibm/icu/impl/OlsonTimeZone.java b/main/classes/core/src/com/ibm/icu/impl/OlsonTimeZone.java
index c2d3b38..71e2b52 100644
--- a/main/classes/core/src/com/ibm/icu/impl/OlsonTimeZone.java
+++ b/main/classes/core/src/com/ibm/icu/impl/OlsonTimeZone.java
@@ -1,6 +1,6 @@
/*
*******************************************************************************
- * Copyright (C) 2005-2010, International Business Machines Corporation and *
+ * Copyright (C) 2005-2011, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
@@ -477,26 +477,30 @@
// Post-32bit transition data is optional
}
- transitionTimes64 = new long[transitionCount];
- int idx = 0;
- if (transPre32 != null) {
- for (int i = 0; i < transPre32.length / 2; i++, idx++) {
- transitionTimes64[idx] =
- (((long)transPre32[i * 2]) & 0x00000000FFFFFFFFL) << 32
- | (((long)transPre32[i * 2 + 1]) & 0x00000000FFFFFFFFL);
+ if (transitionCount > 0) {
+ transitionTimes64 = new long[transitionCount];
+ int idx = 0;
+ if (transPre32 != null) {
+ for (int i = 0; i < transPre32.length / 2; i++, idx++) {
+ transitionTimes64[idx] =
+ (((long)transPre32[i * 2]) & 0x00000000FFFFFFFFL) << 32
+ | (((long)transPre32[i * 2 + 1]) & 0x00000000FFFFFFFFL);
+ }
}
- }
- if (trans32 != null) {
- for (int i = 0; i < trans32.length; i++, idx++) {
- transitionTimes64[idx] = (long)trans32[i];
+ if (trans32 != null) {
+ for (int i = 0; i < trans32.length; i++, idx++) {
+ transitionTimes64[idx] = (long)trans32[i];
+ }
}
- }
- if (transPost32 != null) {
- for (int i = 0; i < transPost32.length / 2; i++, idx++) {
- transitionTimes64[idx] =
- (((long)transPost32[i * 2]) & 0x00000000FFFFFFFFL) << 32
- | (((long)transPost32[i * 2 + 1]) & 0x00000000FFFFFFFFL);
+ if (transPost32 != null) {
+ for (int i = 0; i < transPost32.length / 2; i++, idx++) {
+ transitionTimes64[idx] =
+ (((long)transPost32[i * 2]) & 0x00000000FFFFFFFFL) << 32
+ | (((long)transPost32[i * 2 + 1]) & 0x00000000FFFFFFFFL);
+ }
}
+ } else {
+ transitionTimes64 = null;
}
// Type offsets list must be of even size, with size >= 2
@@ -508,13 +512,14 @@
typeCount = typeOffsets.length / 2;
// Type map data must be of the same size as the transition count
- typeMapData = null;
if (transitionCount > 0) {
r = res.get("typeMap");
typeMapData = r.getBinary(null);
if (typeMapData.length != transitionCount) {
throw new IllegalArgumentException("Invalid Format");
}
+ } else {
+ typeMapData = null;
}
// Process final rule and data, if any
@@ -727,6 +732,18 @@
} else {
buf.append("null");
}
+ buf.append(",typeMapData=");
+ if (typeMapData != null) {
+ buf.append('[');
+ for (int i = 0; i < typeMapData.length; ++i) {
+ if (i > 0) {
+ buf.append(',');
+ }
+ buf.append(Byte.toString(typeMapData[i]));
+ }
+ } else {
+ buf.append("null");
+ }
buf.append(",finalStartYear=" + finalStartYear);
buf.append(",finalStartMillis=" + finalStartMillis);
buf.append(",finalZone=" + finalZone);
@@ -754,14 +771,14 @@
* Offset from GMT in seconds for each type.
* Length is equal to typeCount
*/
- private int[] typeOffsets; // alias into res; do not delete
+ private int[] typeOffsets;
/**
* Type description data, consisting of transitionCount uint8_t
* type indices (from 0..typeCount-1).
* Length is equal to transitionCount
*/
- private byte[] typeMapData; // alias into res; do not delete
+ private byte[] typeMapData;
/**
* For year >= finalStartYear, the finalZone will be used.
@@ -819,15 +836,19 @@
Double.doubleToLongBits(finalStartMillis)+
(finalZone == null ? 0 : finalZone.hashCode()) +
super.hashCode());
- for(int i=0; i<transitionTimes64.length; i++){
- ret+=transitionTimes64[i]^(transitionTimes64[i]>>>8);
+ if (transitionTimes64 != null) {
+ for(int i=0; i<transitionTimes64.length; i++){
+ ret+=transitionTimes64[i]^(transitionTimes64[i]>>>8);
+ }
}
for(int i=0; i<typeOffsets.length; i++){
ret+=typeOffsets[i]^(typeOffsets[i]>>>8);
}
- for(int i=0; i<typeMapData.length; i++){
- ret+=typeMapData[i] & 0xFF;
- }
+ if (typeMapData != null) {
+ for(int i=0; i<typeMapData.length; i++){
+ ret+=typeMapData[i] & 0xFF;
+ }
+ }
return ret;
}
diff --git a/main/classes/core/src/com/ibm/icu/util/VersionInfo.java b/main/classes/core/src/com/ibm/icu/util/VersionInfo.java
index 8f200aa..681fa84 100644
--- a/main/classes/core/src/com/ibm/icu/util/VersionInfo.java
+++ b/main/classes/core/src/com/ibm/icu/util/VersionInfo.java
@@ -7,7 +7,7 @@
package com.ibm.icu.util;
-import java.util.HashMap;
+import java.util.concurrent.ConcurrentHashMap;
/**
* Class to store version numbers of the form major.minor.milli.micro.
@@ -238,7 +238,10 @@
VersionInfo result = MAP_.get(key);
if (result == null) {
result = new VersionInfo(version);
- MAP_.put(key, result);
+ VersionInfo tmpvi = MAP_.putIfAbsent(key, result);
+ if (tmpvi != null) {
+ result = tmpvi;
+ }
}
return result;
}
@@ -429,7 +432,7 @@
/**
* Map of singletons
*/
- private static final HashMap<Integer, VersionInfo> MAP_ = new HashMap<Integer, VersionInfo>();
+ private static final ConcurrentHashMap<Integer, VersionInfo> MAP_ = new ConcurrentHashMap<Integer, VersionInfo>();
/**
* Last byte mask
*/
diff --git a/main/classes/translit/src/com/ibm/icu/text/BreakTransliterator.java b/main/classes/translit/src/com/ibm/icu/text/BreakTransliterator.java
index b0950eb..bec670f 100644
--- a/main/classes/translit/src/com/ibm/icu/text/BreakTransliterator.java
+++ b/main/classes/translit/src/com/ibm/icu/text/BreakTransliterator.java
@@ -1,6 +1,6 @@
/*
*******************************************************************************
- * Copyright (C) 1996-2010, International Business Machines Corporation and *
+ * Copyright (C) 1996-2011, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
@@ -70,7 +70,7 @@
| (1<<Character.NON_SPACING_MARK)
| (1<<Character.ENCLOSING_MARK)
;
- protected void handleTransliterate(Replaceable text, Position pos, boolean incremental) {
+ protected synchronized void handleTransliterate(Replaceable text, Position pos, boolean incremental) {
boundaryCount = 0;
int boundary = 0;
getBreakIterator(); // Lazy-create it if necessary
diff --git a/main/classes/translit/src/com/ibm/icu/text/CaseFoldTransliterator.java b/main/classes/translit/src/com/ibm/icu/text/CaseFoldTransliterator.java
index 3750522..34e0aad 100644
--- a/main/classes/translit/src/com/ibm/icu/text/CaseFoldTransliterator.java
+++ b/main/classes/translit/src/com/ibm/icu/text/CaseFoldTransliterator.java
@@ -1,8 +1,8 @@
/*
- *******************************************************************************
- * Copyright (C) 2009, Google, International Business Machines Corporation *
- * and others. All Rights Reserved. *
- *******************************************************************************
+ ********************************************************************************
+ * Copyright (C) 2009-2011, Google, International Business Machines Corporation *
+ * and others. All Rights Reserved. *
+ ********************************************************************************
*/
package com.ibm.icu.text;
@@ -58,7 +58,7 @@
/**
* Implements {@link Transliterator#handleTransliterate}.
*/
- protected void handleTransliterate(Replaceable text,
+ protected synchronized void handleTransliterate(Replaceable text,
Position offsets, boolean isIncremental) {
if(csp==null) {
return;
diff --git a/main/classes/translit/src/com/ibm/icu/text/LowercaseTransliterator.java b/main/classes/translit/src/com/ibm/icu/text/LowercaseTransliterator.java
index 18a2fef..26c55dc 100644
--- a/main/classes/translit/src/com/ibm/icu/text/LowercaseTransliterator.java
+++ b/main/classes/translit/src/com/ibm/icu/text/LowercaseTransliterator.java
@@ -1,6 +1,6 @@
/*
*******************************************************************************
- * Copyright (C) 1996-2010, International Business Machines Corporation and *
+ * Copyright (C) 1996-2011, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
@@ -65,7 +65,7 @@
/**
* Implements {@link Transliterator#handleTransliterate}.
*/
- protected void handleTransliterate(Replaceable text,
+ protected synchronized void handleTransliterate(Replaceable text,
Position offsets, boolean isIncremental) {
if(csp==null) {
return;
diff --git a/main/classes/translit/src/com/ibm/icu/text/NameUnicodeTransliterator.java b/main/classes/translit/src/com/ibm/icu/text/NameUnicodeTransliterator.java
index 1c2621a..7465a02 100644
--- a/main/classes/translit/src/com/ibm/icu/text/NameUnicodeTransliterator.java
+++ b/main/classes/translit/src/com/ibm/icu/text/NameUnicodeTransliterator.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 1996-2010, International Business Machines Corporation and
+ * Copyright (C) 1996-2011, International Business Machines Corporation and
* others. All Rights Reserved.
*/
package com.ibm.icu.text;
@@ -14,9 +14,6 @@
*/
class NameUnicodeTransliterator extends Transliterator {
- char openDelimiter;
- char closeDelimiter;
-
static final String _ID = "Name-Any";
static final String OPEN_PAT = "\\N~{~";
diff --git a/main/classes/translit/src/com/ibm/icu/text/RuleBasedTransliterator.java b/main/classes/translit/src/com/ibm/icu/text/RuleBasedTransliterator.java
index ed2fc9f..415732d 100644
--- a/main/classes/translit/src/com/ibm/icu/text/RuleBasedTransliterator.java
+++ b/main/classes/translit/src/com/ibm/icu/text/RuleBasedTransliterator.java
@@ -1,6 +1,6 @@
/*
*******************************************************************************
- * Copyright (C) 1996-2009, International Business Machines Corporation and *
+ * Copyright (C) 1996-2011, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
@@ -328,7 +328,7 @@
* @internal
* @deprecated This API is ICU internal only.
*/
- protected synchronized void handleTransliterate(Replaceable text,
+ protected void handleTransliterate(Replaceable text,
Position index, boolean incremental) {
/* We keep start and limit fixed the entire time,
* relative to the text -- limit may move numerically if text is
@@ -354,16 +354,18 @@
* number of characters n, unless n is so large that 16n exceeds a
* uint32_t.
*/
- int loopCount = 0;
- int loopLimit = (index.limit - index.start) << 4;
- if (loopLimit < 0) {
- loopLimit = 0x7FFFFFFF;
- }
+ synchronized(data) {
+ int loopCount = 0;
+ int loopLimit = (index.limit - index.start) << 4;
+ if (loopLimit < 0) {
+ loopLimit = 0x7FFFFFFF;
+ }
- while (index.start < index.limit &&
- loopCount <= loopLimit &&
- data.ruleSet.transliterate(text, index, incremental)) {
- ++loopCount;
+ while (index.start < index.limit &&
+ loopCount <= loopLimit &&
+ data.ruleSet.transliterate(text, index, incremental)) {
+ ++loopCount;
+ }
}
}
diff --git a/main/classes/translit/src/com/ibm/icu/text/TitlecaseTransliterator.java b/main/classes/translit/src/com/ibm/icu/text/TitlecaseTransliterator.java
index f231f20..dae5cf3 100644
--- a/main/classes/translit/src/com/ibm/icu/text/TitlecaseTransliterator.java
+++ b/main/classes/translit/src/com/ibm/icu/text/TitlecaseTransliterator.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 1996-2010, International Business Machines Corporation and
+ * Copyright (C) 1996-2011, International Business Machines Corporation and
* others. All Rights Reserved.
*
*/
@@ -63,7 +63,7 @@
/**
* Implements {@link Transliterator#handleTransliterate}.
*/
- protected void handleTransliterate(Replaceable text,
+ protected synchronized void handleTransliterate(Replaceable text,
Position offsets, boolean isIncremental) {
// TODO reimplement, see ustrcase.c
// using a real word break iterator
diff --git a/main/classes/translit/src/com/ibm/icu/text/UppercaseTransliterator.java b/main/classes/translit/src/com/ibm/icu/text/UppercaseTransliterator.java
index 1417811..8e2ed63 100644
--- a/main/classes/translit/src/com/ibm/icu/text/UppercaseTransliterator.java
+++ b/main/classes/translit/src/com/ibm/icu/text/UppercaseTransliterator.java
@@ -1,6 +1,6 @@
/*
*******************************************************************************
- * Copyright (C) 1996-2010, International Business Machines Corporation and *
+ * Copyright (C) 1996-2011, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
@@ -61,7 +61,7 @@
/**
* Implements {@link Transliterator#handleTransliterate}.
*/
- protected void handleTransliterate(Replaceable text,
+ protected synchronized void handleTransliterate(Replaceable text,
Position offsets, boolean isIncremental) {
if(csp==null) {
return;
diff --git a/main/tests/core/src/com/ibm/icu/dev/test/format/DateFormatTest.java b/main/tests/core/src/com/ibm/icu/dev/test/format/DateFormatTest.java
index b5cdcea..1946403 100644
--- a/main/tests/core/src/com/ibm/icu/dev/test/format/DateFormatTest.java
+++ b/main/tests/core/src/com/ibm/icu/dev/test/format/DateFormatTest.java
@@ -1,6 +1,6 @@
/*
*******************************************************************************
- * Copyright (C) 2001-2010, International Business Machines Corporation and *
+ * Copyright (C) 2001-2011, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
@@ -3701,4 +3701,20 @@
};
expect(DATA, new Locale("en", "", ""));
}
+
+ /*
+ * Test case for very long contiguous numeric patterns (ticket#7480)
+ */
+ public void TestLongContiguousNumericPattern() {
+ String DATA[] = {
+ "yyyy-MM-dd HH:mm:ss.SSS",
+
+ "yyyyMMddHHmmssSSSSSS", "fp", "2010-04-16 12:23:34.456",
+ "20100416122334456000", "2010-04-16 12:23:34.456",
+
+ "yyyyyyMMddHHHHmmmmssssSSSSSS", "fp", "2010-04-16 12:23:34.456",
+ "0020100416001200230034456000", "2010-04-16 12:23:34.456",
+ };
+ expect(DATA, new Locale("en", "", ""));
+ }
}
diff --git a/main/tests/core/src/com/ibm/icu/dev/test/timezone/TimeZoneTest.java b/main/tests/core/src/com/ibm/icu/dev/test/timezone/TimeZoneTest.java
index 514a4e1..8edf9aa 100644
--- a/main/tests/core/src/com/ibm/icu/dev/test/timezone/TimeZoneTest.java
+++ b/main/tests/core/src/com/ibm/icu/dev/test/timezone/TimeZoneTest.java
@@ -1,6 +1,6 @@
/**
*******************************************************************************
- * Copyright (C) 2000-2010, International Business Machines Corporation and *
+ * Copyright (C) 2000-2011, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
@@ -1622,6 +1622,27 @@
logln("Note: Errors could be the result of changes to zoneStrings locale data");
}
}
+
+ /*
+ * Test case for hashCode problem reported by ticket#7690 OlsonTimeZone.hashCode() throws NPE.
+ */
+ public void TestHashCode() {
+ String[] ids = TimeZone.getAvailableIDs();
+
+ for (String id: ids) {
+ TimeZone tz1 = TimeZone.getTimeZone(id);
+ TimeZone tz2 = TimeZone.getTimeZone(id);
+
+ // hash code are same for the same time zone
+ if (tz1.hashCode() != tz2.hashCode()) {
+ errln("Fail: Two time zone instances for " + id + " have different hash values.");
+ }
+ // string representation should be also same
+ if (!tz1.toString().equals(tz2.toString())) {
+ errln("Fail: Two time zone instances for " + id + " have different toString() values.");
+ }
+ }
+ }
}
//eof
diff --git a/main/tests/core/src/com/ibm/icu/dev/test/util/VersionInfoTest.java b/main/tests/core/src/com/ibm/icu/dev/test/util/VersionInfoTest.java
index 7a30723..5b9c611 100644
--- a/main/tests/core/src/com/ibm/icu/dev/test/util/VersionInfoTest.java
+++ b/main/tests/core/src/com/ibm/icu/dev/test/util/VersionInfoTest.java
@@ -1,6 +1,6 @@
/*
*******************************************************************************
-* Copyright (C) 1996-2009, International Business Machines Corporation and *
+* Copyright (C) 1996-2011, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
@@ -342,4 +342,56 @@
"2.1.255.0",
"3.1.255.100"
};
+
+ /*
+ * Test case for multi-threading problem reported by ticket#7880
+ */
+ public void TestMultiThread() {
+ final int numThreads = 20;
+ GetInstanceWorker[] workers = new GetInstanceWorker[numThreads];
+ VersionInfo[][] results = new VersionInfo[numThreads][255];
+
+ // Create workers
+ for (int i = 0; i < workers.length; i++) {
+ workers[i] = new GetInstanceWorker(i, results[i]);
+ }
+
+ // Start workers
+ for (int i = 0; i < workers.length; i++) {
+ workers[i].start();
+ }
+
+ // Wait for the completion
+ for (int i = 0; i < workers.length; i++) {
+ try {
+ workers[i].join();
+ } catch (InterruptedException e) {
+ errln("A problem in thread execution. " + e.getMessage());
+ }
+ }
+
+ // Check if singleton for each
+ for (int i = 1; i < results.length; i++) {
+ for (int j = 0; j < results[0].length; j++) {
+ if (results[0][j] != results[i][j]) {
+ errln("Different instance at index " + j + " Thread#" + i);
+ }
+ }
+ }
+ }
+
+ private class GetInstanceWorker extends Thread {
+ private VersionInfo[] results;
+
+ GetInstanceWorker(int serialNumber, VersionInfo[] results) {
+ super("GetInstnaceWorker#" + serialNumber);
+ this.results = results;
+ }
+
+ public void run() {
+ for (int i = 0; i < results.length; i++) {
+ results[i] = VersionInfo.getInstance(i);
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/main/tests/translit/src/com/ibm/icu/dev/test/translit/TestAll.java b/main/tests/translit/src/com/ibm/icu/dev/test/translit/TestAll.java
index 8301230..b32e48d 100644
--- a/main/tests/translit/src/com/ibm/icu/dev/test/translit/TestAll.java
+++ b/main/tests/translit/src/com/ibm/icu/dev/test/translit/TestAll.java
@@ -1,6 +1,6 @@
/*
*******************************************************************************
- * Copyright (C) 1996-2009, International Business Machines Corporation and *
+ * Copyright (C) 1996-2011, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
@@ -28,6 +28,7 @@
"TransliteratorTest",
"RegexUtilitiesTest",
"UnicodeMapTest",
+ "ThreadTest"
});
}
diff --git a/main/tests/translit/src/com/ibm/icu/dev/test/translit/ThreadTest.java b/main/tests/translit/src/com/ibm/icu/dev/test/translit/ThreadTest.java
new file mode 100644
index 0000000..6d15f20
--- /dev/null
+++ b/main/tests/translit/src/com/ibm/icu/dev/test/translit/ThreadTest.java
@@ -0,0 +1,66 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 2010-2011, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ *******************************************************************************
+ */
+package com.ibm.icu.dev.test.translit;
+
+import java.util.ArrayList;
+import com.ibm.icu.dev.test.TestFmwk;
+import com.ibm.icu.text.Transliterator;
+
+// Test for ICU Ticket #7201. With threading bugs in RuleBasedTransliterator, this
+// test would reliably crash.
+
+public class ThreadTest extends TransliteratorTest {
+ public static void main(String[] args) throws Exception {
+ new ThreadTest().run(args);
+ }
+
+ private ArrayList<Worker> threads = new ArrayList<Worker>();
+ private int iterationCount = 100000;
+
+ public void TestThreads() {
+ if (getInclusion() >= 9) {
+ // Exhaustive test. Run longer.
+ iterationCount = 1000000;
+ }
+
+ for (int i = 0; i < 8; i++) {
+ Worker thread = new Worker();
+ threads.add(thread);
+ thread.start();
+ }
+ long expectedCount = 0;
+ for (Worker thread: threads) {
+ try {
+ thread.join();
+ if (expectedCount == 0) {
+ expectedCount = thread.count;
+ } else {
+ if (expectedCount != thread.count) {
+ errln("Threads gave differing results.");
+ }
+ }
+ } catch (InterruptedException e) {
+ errln(e.toString());
+ }
+ }
+ }
+
+ private static final String [] WORDS = {"edgar", "allen", "poe"};
+
+ private class Worker extends Thread {
+ public long count = 0;
+ public void run() {
+ Transliterator tx = Transliterator.getInstance("Latin-Thai");
+ for (int loop = 0; loop < iterationCount; loop++) {
+ for (String s : WORDS) {
+ count += tx.transliterate(s).length();
+ }
+ }
+ }
+ }
+
+}