]> granicus.if.org Git - icu/commitdiff
ICU-8807 Add internal changes for use in unicode tools. Adds internal API, but doesn...
authorMark Davis <mark@macchiato.com>
Thu, 8 Sep 2011 22:28:40 +0000 (22:28 +0000)
committerMark Davis <mark@macchiato.com>
Thu, 8 Sep 2011 22:28:40 +0000 (22:28 +0000)
X-SVN-Rev: 30638

12 files changed:
.gitattributes
icu4j/main/classes/core/src/com/ibm/icu/impl/ImplicitCEGenerator.java
icu4j/main/classes/core/src/com/ibm/icu/impl/UnicodeRegex.java
icu4j/main/classes/core/src/com/ibm/icu/text/UnicodeSet.java
icu4j/main/tests/translit/src/com/ibm/icu/dev/test/translit/TestAll.java
icu4j/main/tests/translit/src/com/ibm/icu/dev/test/translit/TestUnicodeProperty.java [new file with mode: 0644]
icu4j/main/tests/translit/src/com/ibm/icu/dev/test/util/ICUPropertyFactory.java
icu4j/main/tests/translit/src/com/ibm/icu/dev/test/util/IcuUnicodeNormalizerFactory.java [new file with mode: 0644]
icu4j/main/tests/translit/src/com/ibm/icu/dev/test/util/UnicodeMap.java
icu4j/main/tests/translit/src/com/ibm/icu/dev/test/util/UnicodeProperty.java
icu4j/main/tests/translit/src/com/ibm/icu/dev/test/util/UnicodePropertySymbolTable.java [new file with mode: 0644]
icu4j/main/tests/translit/src/com/ibm/icu/dev/test/util/UnicodeTransform.java [new file with mode: 0644]

index 3f7ff05349be7dd6bbd8c2f885ab127165db7358..84b3e770060f073a9a557b0f3640d61e5fee830a 100644 (file)
@@ -714,6 +714,10 @@ icu4j/main/tests/translit/.externalToolBuilders/copy-translit-test-data.launch -
 icu4j/main/tests/translit/.settings/org.eclipse.core.resources.prefs -text
 icu4j/main/tests/translit/.settings/org.eclipse.jdt.core.prefs -text
 icu4j/main/tests/translit/.settings/org.eclipse.jdt.ui.prefs -text
+icu4j/main/tests/translit/src/com/ibm/icu/dev/test/translit/TestUnicodeProperty.java -text
+icu4j/main/tests/translit/src/com/ibm/icu/dev/test/util/IcuUnicodeNormalizerFactory.java -text
+icu4j/main/tests/translit/src/com/ibm/icu/dev/test/util/UnicodePropertySymbolTable.java -text
+icu4j/main/tests/translit/src/com/ibm/icu/dev/test/util/UnicodeTransform.java -text
 icu4j/main/tests/translit/translit-tests-build.launch -text
 icu4j/manifest.stub -text
 icu4j/tools/build/.settings/org.eclipse.core.resources.prefs -text
index 41bd01e424b684b4d1786ce1b8ee77ebf6242919..63e5691ea8205cb9ee786e851a79d29465d34556 100644 (file)
@@ -1,6 +1,6 @@
 /**
  *******************************************************************************
- * Copyright (C) 2004-2010, International Business Machines Corporation and         *
+ * Copyright (C) 2004-2011, International Business Machines Corporation and         *
  * others. All Rights Reserved.                                                *
  *******************************************************************************
  */
@@ -46,7 +46,7 @@ public class ImplicitCEGenerator {
     // 4E00;<CJK Ideograph, First>;Lo;0;L;;;;;N;;;;;
     // 9FCB;<CJK Ideograph, Last>;Lo;0;L;;;;;N;;;;;
     CJK_BASE = 0x4E00,
-    CJK_LIMIT = 0x9FCB+1,
+    CJK_LIMIT = 0x9FCC+1,
 
     CJK_COMPAT_USED_BASE = 0xFA0E,
     CJK_COMPAT_USED_LIMIT = 0xFA2F+1,
index 925ad5a1e4b673ddc1ad69efe83c7a0770586a38..252be8d981560eebb01c28a01ca6abffd0dd2b5f 100644 (file)
@@ -1,6 +1,6 @@
 /*
  ********************************************************************************
- * Copyright (C) 2009-2010, Google, International Business Machines Corporation *
+ * Copyright (C) 2009-2011, Google, International Business Machines Corporation *
  * and others. All Rights Reserved.                                             *
  ********************************************************************************
  */
@@ -24,6 +24,7 @@ import java.util.TreeMap;
 import java.util.regex.Pattern;
 
 import com.ibm.icu.text.StringTransform;
+import com.ibm.icu.text.SymbolTable;
 import com.ibm.icu.text.UnicodeSet;
 import com.ibm.icu.util.Freezable;
 
@@ -37,6 +38,26 @@ public class UnicodeRegex implements Cloneable, Freezable<UnicodeRegex>, StringT
     // Note: we don't currently have any state, but intend to in the future,
     // particularly for the regex style supported.
 
+    private SymbolTable symbolTable;
+    private ParsePosition parsePosition = new ParsePosition(0);
+
+    /**
+     * Set the symbol table for internal processing
+     * @internal
+     */
+    public SymbolTable getSymbolTable() {
+        return symbolTable;
+    }
+
+    /**
+     * Get the symbol table for internal processing
+     * @internal
+     */
+    public UnicodeRegex setSymbolTable(SymbolTable symbolTable) {
+        this.symbolTable = symbolTable;
+        return this;
+    }
+
     /**
      * Adds full Unicode property support, with the latest version of Unicode,
      * to Java Regex, bringing it up to Level 1 (see
@@ -185,12 +206,12 @@ public class UnicodeRegex implements Cloneable, Freezable<UnicodeRegex>, StringT
         // brute force replacement; do twice to allow for different order
         // later on can optimize
         for (int i = 0; i < 2; ++i) {
-            for (Iterator<String> it = variables.keySet().iterator(); it.hasNext();) {
-                String variable = it.next();
+            for (String variable : variables.keySet()) {
                 String definition = variables.get(variable);
-                for (Iterator<String> it2 = variables.keySet().iterator(); it2.hasNext();) {
-                    String variable2 = it2.next();
-                    if (variable.equals(variable2)) continue;
+                for (String variable2 : variables.keySet()) {
+                    if (variable.equals(variable2)) {
+                        continue;
+                    }
                     String definition2 = variables.get(variable2);
                     String altered2 = definition2.replace(variable, definition);
                     if (!altered2.equals(definition2)) {
@@ -303,7 +324,7 @@ public class UnicodeRegex implements Cloneable, Freezable<UnicodeRegex>, StringT
     private int processSet(String regex, int i, StringBuilder result, UnicodeSet temp, ParsePosition pos) {
         try {
             pos.setIndex(i);
-            UnicodeSet x = temp.clear().applyPattern(regex, pos, null, 0);
+            UnicodeSet x = temp.clear().applyPattern(regex, pos, symbolTable, 0);
             x.complement().complement(); // hack to fix toPattern
             result.append(x.toPattern(false));
             i = pos.getIndex() - 1; // allow for the loop increment
@@ -335,8 +356,7 @@ public class UnicodeRegex implements Cloneable, Freezable<UnicodeRegex>, StringT
         String variable = null;
         StringBuffer definition = new StringBuffer();
         int count = 0;
-        for (Iterator<String> it = lines.iterator(); it.hasNext();) {
-            String line = it.next();
+        for (String line : lines) {
             ++count;
             // remove initial bom, comments
             if (line.length() == 0) continue;
index 5a9dd609c9a28a418d4edb713e76b2174cd010ff..6654e5cd398c399033dfaab465c77eec6cb63b09 100644 (file)
@@ -285,6 +285,8 @@ public class UnicodeSet extends UnicodeFilter implements Iterable<String>, Compa
      * @provisional This API might change or be removed in a future release.
      */
     public static final UnicodeSet ALL_CODE_POINTS = new UnicodeSet(0, 0x10FFFF).freeze();
+    
+    private static XSymbolTable XSYMBOL_TABLE = null; // for overriding the the function processing
 
     private static final int LOW = 0x000000; // LOW <= all valid values. ZERO for codepoints
     private static final int HIGH = 0x110000; // HIGH > all valid values. 10000 for code units.
@@ -3282,7 +3284,7 @@ public class UnicodeSet extends UnicodeFilter implements Iterable<String>, Compa
     public UnicodeSet applyPropertyAlias(String propertyAlias, String valueAlias) {
         return applyPropertyAlias(propertyAlias, valueAlias, null);
     }
-
+    
     /**
      * Modifies this set to contain those code points which have the
      * given value for the given property.  Prior contents of this
@@ -3306,6 +3308,12 @@ public class UnicodeSet extends UnicodeFilter implements Iterable<String>, Compa
                 && ((XSymbolTable)symbols).applyPropertyAlias(propertyAlias, valueAlias, this)) {
             return this;
         }
+        
+        if (XSYMBOL_TABLE != null) {
+            if (XSYMBOL_TABLE.applyPropertyAlias(propertyAlias, valueAlias, this)) {
+                return this;
+            }
+        }
 
         if (valueAlias.length() > 0) {
             p = UCharacter.getPropertyEnum(propertyAlias);
@@ -4540,5 +4548,30 @@ public class UnicodeSet extends UnicodeFilter implements Iterable<String>, Compa
          */
         CONDITION_COUNT
     }
+
+    /**
+     * Get the default symbol table. Null means ordinary processing. For internal use only.
+     * @return
+     * @internal
+     */
+    public static XSymbolTable getDefaultXSymbolTable() {
+        return XSYMBOL_TABLE;
+    }
+
+    /**
+     * Set the default symbol table. Null means ordinary processing. For internal use only. Will affect all subsequent parsing
+     * of UnicodeSets.
+ * <p>
+ * WARNING: If this function is used with a {@link UnicodeProperty}, and the
+ * Unassigned characters (gc=Cn) are different than in ICU other than in ICU, you MUST call
+ * {@code UnicodeProperty.ResetCacheProperties} afterwards. If you then call {@code UnicodeSet.setDefaultXSymbolTable}
+ * with null to clear the value, you MUST also call {@code UnicodeProperty.ResetCacheProperties}.
+ * 
+     * @param xSymbolTable the new default symbol table.
+     * @internal
+     */
+    public static void setDefaultXSymbolTable(XSymbolTable xSymbolTable) {
+        XSYMBOL_TABLE = xSymbolTable;
+    }
 }
 //eof
index cb8b2c410dd83d40d5b4ec6f3bd4f5b9c059e748..0742a162cd96568b093e920ce0292458f570349c 100644 (file)
@@ -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.                                                *
  *******************************************************************************
  */
@@ -28,7 +28,8 @@ public class TestAll extends TestGroup {
                 "TransliteratorTest",
                 "RegexUtilitiesTest",
                 "UnicodeMapTest",
-                "ThreadTest"
+                "ThreadTest",
+                "TestUnicodeProperty"
         });
     }
 
diff --git a/icu4j/main/tests/translit/src/com/ibm/icu/dev/test/translit/TestUnicodeProperty.java b/icu4j/main/tests/translit/src/com/ibm/icu/dev/test/translit/TestUnicodeProperty.java
new file mode 100644 (file)
index 0000000..7859711
--- /dev/null
@@ -0,0 +1 @@
+/*\r *******************************************************************************\r * Copyright (C) 2011, International Business Machines Corporation and         *\r * others. All Rights Reserved.                                                *\r *******************************************************************************\r */\rpackage com.ibm.icu.dev.test.translit;\r\rimport java.util.List;\r\rimport com.ibm.icu.dev.test.TestFmwk;\rimport com.ibm.icu.dev.test.util.ICUPropertyFactory;\rimport com.ibm.icu.dev.test.util.UnicodeProperty;\rimport com.ibm.icu.dev.test.util.UnicodeProperty.Factory;\rimport com.ibm.icu.dev.test.util.UnicodePropertySymbolTable;\rimport com.ibm.icu.text.UnicodeSet;\r\r/**\r * @author markdavis\r *\r */\rpublic class TestUnicodeProperty extends TestFmwk{\r    public static void main(String[] args) {\r        new TestUnicodeProperty().run(args);\r    }\r    static final UnicodeSet casedLetter = new UnicodeSet("[:gc=cased letter:]");\r    static final UnicodeSet letter = new UnicodeSet("[:gc=L:]");\r\r\r    public void TestBasic() {\r        Factory factory = ICUPropertyFactory.make();\r        UnicodeProperty property = factory.getProperty("gc");\r        List values = property.getAvailableValues();\r        assertTrue("Values contain GC values", values.contains("Unassigned"));\r        final UnicodeSet lu = property.getSet("Lu");\r        if (!assertTrue("Gc=L contains 'A'", lu.contains('A'))) {\r            errln("Contents:\t" + lu.complement().complement().toPattern(false));\r        }\r    }\r\r    public void TestSymbolTable() {\r        Factory factory = ICUPropertyFactory.make();\r        UnicodePropertySymbolTable upst = new UnicodePropertySymbolTable(factory);\r        UnicodeSet.setDefaultXSymbolTable(upst);\r        try {\r            final UnicodeSet luSet = new UnicodeSet("[:gc=L:]");\r            assertTrue("Gc=L contains 'A'", luSet.contains('A'));\r            assertTrue("Gc=L contains 'Z'", luSet.contains('Z'));\r            assertFalse("Gc=L contains 'a'", luSet.contains('1'));\r            UnicodeSet casedLetter2 = new UnicodeSet("[:gc=cased letter:]");\r            assertEquals("gc=lc are equal", casedLetter, casedLetter2);\r        } finally {\r            // restore the world\r            UnicodeSet.setDefaultXSymbolTable(null);\r        }\r    }\r\r    public void TestSymbolTable2() {\r        Factory factory = new MyUnicodePropertyFactory();\r        UnicodePropertySymbolTable upst = new UnicodePropertySymbolTable(factory);\r        UnicodeSet.setDefaultXSymbolTable(upst);\r        try {\r            final UnicodeSet luSet = new UnicodeSet("[:gc=L:]");\r            assertFalse("Gc=L contains 'A'", luSet.contains('A'));\r            if (!assertTrue("Gc=L contains 'Z'", luSet.contains('Z'))) {\r                errln("Contents:\t" + luSet.complement().complement().toPattern(false));\r            }\r            assertFalse("Gc=L contains 'a'", luSet.contains('1'));\r            UnicodeSet casedLetter2 = new UnicodeSet("[:gc=cased letter:]");\r            assertNotEquals("gc=lc should not be equal", casedLetter, casedLetter2);\r        } finally {\r            // restore the world\r            UnicodeSet.setDefaultXSymbolTable(null);\r        }\r    }\r\r\r    /**\r     * For testing, override to set A-M to Cn.\r     */\r    static class MyUnicodeGCProperty extends UnicodeProperty.SimpleProperty {\r        UnicodeProperty icuProperty = ICUPropertyFactory.make().getProperty("Gc");\r        {\r            setName(icuProperty.getName());\r            setType(icuProperty.getType());\r        }\r        @Override\r        protected String _getValue(int codepoint) {\r            if (codepoint >= 'A' && codepoint <= 'M') {\r                return "Unassigned";\r            } else {\r                return icuProperty.getValue(codepoint);\r            }\r        }\r        @Override\r        protected List _getValueAliases(String valueAlias, List result) {\r            return icuProperty.getValueAliases(valueAlias, result);\r        }\r        @Override\r        public List _getNameAliases(List result) {\r            return icuProperty.getNameAliases();\r        }\r    }\r\r    /**\r     * For testing, override to set A-Z to Cn.\r     */\r    static class MyUnicodePropertyFactory extends ICUPropertyFactory {\r        private MyUnicodePropertyFactory() {\r            add(new MyUnicodeGCProperty());\r        }\r    }\r\r    static class MyUnicodePropertySymbolTable extends UnicodePropertySymbolTable {\r        public MyUnicodePropertySymbolTable(Factory factory) {\r            super(factory);\r        }\r    }\r}\r
\ No newline at end of file
index 266d49cd8b398b1a80e5fcde7cd7a35793614be3..bb2d86f4bf4ded3d03ab8dd398f9d1ceca22dea3 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *******************************************************************************
- * Copyright (C) 2002-2010, International Business Machines Corporation and    *
+ * Copyright (C) 2002-2011, International Business Machines Corporation and    *
  * others. All Rights Reserved.                                                *
  *******************************************************************************
  */
@@ -437,7 +437,7 @@ public class ICUPropertyFactory extends UnicodeProperty.Factory {
 //        NFKD = UProperty.STRING_LIMIT+3
         ;
 
-    private ICUPropertyFactory() {
+    protected ICUPropertyFactory() {
         Collection c = getInternalAvailablePropertyAliases(new ArrayList());
         Iterator it = c.iterator();
         while (it.hasNext()) {
diff --git a/icu4j/main/tests/translit/src/com/ibm/icu/dev/test/util/IcuUnicodeNormalizerFactory.java b/icu4j/main/tests/translit/src/com/ibm/icu/dev/test/util/IcuUnicodeNormalizerFactory.java
new file mode 100644 (file)
index 0000000..dc803bf
--- /dev/null
@@ -0,0 +1 @@
+/*\r *******************************************************************************\r * Copyright (C) 2011, International Business Machines Corporation and         *\r * others. All Rights Reserved.                                                *\r *******************************************************************************\r */\rpackage com.ibm.icu.dev.test.util;\r\rimport com.ibm.icu.dev.test.util.UnicodeTransform.Type;\rimport com.ibm.icu.lang.UCharacter;\rimport com.ibm.icu.text.Normalizer2;\rimport com.ibm.icu.text.Normalizer2.Mode;\r\r/**\r * @author markdavis\r *\r */\rpublic class IcuUnicodeNormalizerFactory implements UnicodeTransform.Factory {\r\r    public UnicodeTransform getInstance(Type type) {\r        switch (type) {\r        case NFC: case NFKC:\r            return new IcuUnicodeNormalizer(Normalizer2.getInstance(null, type.toString(), Mode.COMPOSE));\r        case NFD: case NFKD:\r            return new IcuUnicodeNormalizer(Normalizer2.getInstance(null, type == Type.NFD ? "NFC" : "NFKC", Mode.DECOMPOSE));\r        case CASEFOLD:\r            return new CaseFolder();\r        default:\r            throw new IllegalArgumentException();\r        }\r    }\r\r    private static class CaseFolder extends UnicodeTransform {\r        @Override\r        public String transform(String source) {\r            return UCharacter.foldCase(source.toString(), true);\r        }\r    }\r\r    private static class IcuUnicodeNormalizer extends UnicodeTransform {\r        private Normalizer2 normalizer;\r\r        private IcuUnicodeNormalizer(Normalizer2 normalizer) {\r            this.normalizer = normalizer;\r        }\r\r        public String transform(String src) {\r            return normalizer.normalize(src);\r        }\r\r        public boolean isTransformed(String s) {\r            return normalizer.isNormalized(s);\r        }\r    }\r}\r
\ No newline at end of file
index cd18571702eb21f0d240713b240bc6c7e87bfb0c..97238ef67b3bdef1b3672297cfd41bfe8497a2dc 100644 (file)
@@ -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.                                                *
  *******************************************************************************
  */
@@ -277,7 +277,7 @@ public final class UnicodeMap<T> implements Cloneable, Freezable, StringTransfor
             throw new UnsupportedOperationException("Attempt to modify locked object");
         }
         if (errorOnReset && values[baseIndex] != null) {
-            throw new IllegalArgumentException("Attempt to reset value for " + Utility.hex(codepoint)
+            throw new UnsupportedOperationException("Attempt to reset value for " + Utility.hex(codepoint)
                     + " when that is disallowed. Old: " + values[baseIndex] + "; New: " + value);
         }
 
index d3f9a18af7784ef3dd60c04599dc7a8d9f5cc9df..89ddd946e261c1dc806f5520a365615f261f5cdd 100644 (file)
@@ -10,19 +10,25 @@ import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.text.ParsePosition;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.TreeMap;
 import java.util.regex.Pattern;
 
+import com.ibm.icu.dev.test.util.BagFormatter;
+import com.ibm.icu.dev.test.util.UnicodeLabel;
+import com.ibm.icu.dev.test.util.UnicodeMap;
 import com.ibm.icu.dev.test.util.CollectionUtilities.InverseMatcher;
 import com.ibm.icu.dev.test.util.CollectionUtilities.ObjectMatcher;
 import com.ibm.icu.impl.Utility;
 import com.ibm.icu.text.SymbolTable;
+import com.ibm.icu.text.Transform;
 import com.ibm.icu.text.UFormat;
 import com.ibm.icu.text.UTF16;
 import com.ibm.icu.text.UnicodeMatcher;
@@ -31,17 +37,87 @@ import com.ibm.icu.text.UnicodeSetIterator;
 
 public abstract class UnicodeProperty extends UnicodeLabel {
 
-    public static final UnicodeSet UNASSIGNED = new UnicodeSet("[:gc=unassigned:]").freeze();
+    public static final UnicodeSet NONCHARACTERS = new UnicodeSet("[:noncharactercodepoint:]").freeze();
     public static final UnicodeSet PRIVATE_USE = new UnicodeSet("[:gc=privateuse:]").freeze();
     public static final UnicodeSet SURROGATE = new UnicodeSet("[:gc=surrogate:]").freeze();
-    public static final UnicodeSet SPECIALS = new UnicodeSet(UNASSIGNED).addAll(PRIVATE_USE).addAll(SURROGATE).freeze();
-    public static final int SAMPLE_UNASSIGNED = UNASSIGNED.charAt(0);
-    public static final int SAMPLE_PRIVATE_USE = 0xE000;
-    public static final int SAMPLE_SURROGATE = 0xD800;
-    public static final UnicodeSet STUFF_TO_TEST = new UnicodeSet(SPECIALS).complement()
-    .add(SAMPLE_UNASSIGNED).add(SAMPLE_PRIVATE_USE).add(SAMPLE_SURROGATE).freeze();
-    public static final UnicodeSet STUFF_TO_TEST_WITH_UNASSIGNED = new UnicodeSet("[:any:]").freeze();
 
+    public static final UnicodeSet HIGH_SURROGATES = new UnicodeSet("[\\uD800-\\uDB7F]").freeze();
+    public static final int SAMPLE_HIGH_SURROGATE = HIGH_SURROGATES.charAt(0);
+    public static final UnicodeSet HIGH_PRIVATE_USE_SURROGATES = new UnicodeSet("[\\uDB80-\\uDBFF]").freeze();
+    public static final int SAMPLE_HIGH_PRIVATE_USE_SURROGATE = HIGH_PRIVATE_USE_SURROGATES.charAt(0);
+    public static final UnicodeSet LOW_SURROGATES = new UnicodeSet("[\\uDC00-\\uDFFF]").freeze();
+    public static final int SAMPLE_LOW_SURROGATE = LOW_SURROGATES.charAt(0);
+
+    public static final UnicodeSet PRIVATE_USE_AREA = new UnicodeSet("[\\uE000-\\uF8FF]").freeze();
+    public static final int SAMPLE_PRIVATE_USE_AREA = PRIVATE_USE_AREA.charAt(0);
+    public static final UnicodeSet PRIVATE_USE_AREA_A = new UnicodeSet("[\\U000F0000-\\U000FFFFD]").freeze();
+    public static final int SAMPLE_PRIVATE_USE_AREA_A = PRIVATE_USE_AREA_A.charAt(0);
+    public static final UnicodeSet PRIVATE_USE_AREA_B = new UnicodeSet("[\\U00100000-\\U0010FFFD]").freeze();
+    public static final int SAMPLE_PRIVATE_USE_AREA_B = PRIVATE_USE_AREA_B.charAt(0);
+
+    // The following are special. They are used for performance, but must be changed if the version of Unicode for the UnicodeProperty changes.
+    private static UnicodeSet UNASSIGNED;
+    private static int SAMPLE_UNASSIGNED;
+    private static UnicodeSet SPECIALS;
+    private static UnicodeSet STUFF_TO_TEST;
+    private static UnicodeSet STUFF_TO_TEST_WITH_UNASSIGNED;
+
+    public static synchronized UnicodeSet getUNASSIGNED() {
+        if (UNASSIGNED == null) {
+            UNASSIGNED = new UnicodeSet("[:gc=unassigned:]").freeze();
+        }
+        return UNASSIGNED;
+    }
+
+    public static synchronized int getSAMPLE_UNASSIGNED() {
+        if (SAMPLE_UNASSIGNED == 0) {
+            SAMPLE_UNASSIGNED = getUNASSIGNED().charAt(0);
+        }
+        return SAMPLE_UNASSIGNED;
+    }
+
+    public static synchronized UnicodeSet getSPECIALS() {
+        if (SPECIALS == null) {
+            SPECIALS = new UnicodeSet(getUNASSIGNED()).addAll(PRIVATE_USE).addAll(SURROGATE).freeze();
+        }
+        return SPECIALS;
+    }
+
+    public static synchronized UnicodeSet getSTUFF_TO_TEST() {
+        if (STUFF_TO_TEST == null) {
+            STUFF_TO_TEST = new UnicodeSet(getSPECIALS()).complement()
+            .addAll(NONCHARACTERS)
+            .add(getSAMPLE_UNASSIGNED())
+            .add(SAMPLE_HIGH_SURROGATE)
+            .add(SAMPLE_HIGH_PRIVATE_USE_SURROGATE)
+            .add(SAMPLE_LOW_SURROGATE)
+            .add(SAMPLE_PRIVATE_USE_AREA)
+            .add(SAMPLE_PRIVATE_USE_AREA_A)
+            .add(SAMPLE_PRIVATE_USE_AREA_B)
+            .freeze();
+        }
+        return STUFF_TO_TEST;
+    }
+
+    public static synchronized UnicodeSet getSTUFF_TO_TEST_WITH_UNASSIGNED() {
+        if (STUFF_TO_TEST_WITH_UNASSIGNED == null) {
+            STUFF_TO_TEST_WITH_UNASSIGNED = new UnicodeSet(getSTUFF_TO_TEST()).addAll(getUNASSIGNED()).freeze();
+        }
+        return STUFF_TO_TEST_WITH_UNASSIGNED;
+    }
+
+    /**
+     * Reset the cache properties. Must be done if the version of Unicode is different than the ICU one, AND any UnicodeProperty has already been instantiated.
+     * TODO make this a bit more robust.
+     * @internal
+     */
+    public static synchronized void ResetCacheProperties() {
+        UNASSIGNED = null;
+        SAMPLE_UNASSIGNED = 0;
+        SPECIALS = null;
+        STUFF_TO_TEST = null;
+        STUFF_TO_TEST_WITH_UNASSIGNED = null;
+    }
 
     public static boolean DEBUG = false;
 
@@ -57,7 +133,7 @@ public abstract class UnicodeProperty extends UnicodeLabel {
 
     private Map valueToFirstValueAlias = null;
 
-    private boolean hasUniformUnassigned = false;
+    private boolean hasUniformUnassigned = true;
 
     /*
      * Name: Unicode_1_Name Name: ISO_Comment Name: Name Name: Unicode_1_Name
@@ -238,7 +314,7 @@ public abstract class UnicodeProperty extends UnicodeLabel {
             return maxFirstValueAliasWidth;
         return maxValueWidth;
     }
-    
+
     public final UnicodeSet getSet(String propertyValue) {
         return getSet(propertyValue, null);
     }
@@ -247,6 +323,8 @@ public abstract class UnicodeProperty extends UnicodeLabel {
         return getSet(matcher, null);
     }
 
+    /** Adds the property value set to the result. Clear the result first if you don't want to keep the original contents.
+     */
     public final UnicodeSet getSet(String propertyValue, UnicodeSet result) {
         return getSet(new SimpleMatcher(propertyValue,
                 isType(STRING_OR_MISC_MASK) ? null : PROPERTY_COMPARATOR),
@@ -257,7 +335,7 @@ public abstract class UnicodeProperty extends UnicodeLabel {
 
     public static final String UNUSED = "??";
 
-    public final UnicodeSet getSet(PatternMatcher matcher, UnicodeSet result) {
+    public UnicodeSet getSet(PatternMatcher matcher, UnicodeSet result) {
         if (result == null)
             result = new UnicodeSet();
         boolean uniformUnassigned = hasUniformUnassigned();
@@ -422,7 +500,7 @@ public abstract class UnicodeProperty extends UnicodeLabel {
     }
 
     private static UnicodeSetIterator getStuffToTest(boolean uniformUnassigned) {
-        return new UnicodeSetIterator(uniformUnassigned ? STUFF_TO_TEST : STUFF_TO_TEST_WITH_UNASSIGNED);
+        return new UnicodeSetIterator(uniformUnassigned ? getSTUFF_TO_TEST() : getSTUFF_TO_TEST_WITH_UNASSIGNED());
     }
 
     /**
@@ -654,7 +732,9 @@ public abstract class UnicodeProperty extends UnicodeLabel {
         Map propertyCache = new HashMap(1);
 
         public final Factory add(UnicodeProperty sp) {
-            canonicalNames.put(sp.getName(), sp);
+            String name2 = sp.getName();
+            canonicalNames.put(name2, sp);
+            skeletonNames.put(toSkeleton(name2), sp);
             List c = sp.getNameAliases(new ArrayList(1));
             Iterator it = c.iterator();
             while (it.hasNext()) {
@@ -1178,7 +1258,7 @@ public abstract class UnicodeProperty extends UnicodeLabel {
     }
 
     public static abstract class SimpleProperty extends BaseProperty {
-        List values;
+        LinkedHashSet values;
 
         public UnicodeProperty addName(String alias) {
             propertyAliases.add(alias);
@@ -1209,7 +1289,7 @@ public abstract class UnicodeProperty extends UnicodeLabel {
         }
 
         public SimpleProperty setValues(List valueAliases) {
-            this.values = new ArrayList(valueAliases);
+            this.values = new LinkedHashSet(valueAliases);
             for (Iterator it = this.values.iterator(); it.hasNext();) {
                 _addToValues((String) it.next(), null);
             }
@@ -1233,7 +1313,7 @@ public abstract class UnicodeProperty extends UnicodeLabel {
 
         private void _addToValues(String item, String alias) {
             if (values == null)
-                values = new ArrayList(1);
+                values = new LinkedHashSet();
             if (toValueAliases == null)
                 _fixValueAliases();
             addUnique(item, values);
@@ -1328,32 +1408,57 @@ public abstract class UnicodeProperty extends UnicodeLabel {
 
 
     public static UnicodeSet addUntested(UnicodeSet result, boolean uniformUnassigned) {
-        if (!uniformUnassigned) return result;
-
-        if (result.contains(UnicodeProperty.SAMPLE_UNASSIGNED)) {
-            result.addAll(UnicodeProperty.UNASSIGNED);
+        if (uniformUnassigned && result.contains(UnicodeProperty.getSAMPLE_UNASSIGNED())) {
+            result.addAll(UnicodeProperty.getUNASSIGNED());
+        }
+        
+        if (result.contains(UnicodeProperty.SAMPLE_HIGH_SURROGATE)) {
+            result.addAll(UnicodeProperty.HIGH_SURROGATES);
         }
-        if (result.contains(UnicodeProperty.SAMPLE_PRIVATE_USE)) {
-            result.addAll(UnicodeProperty.PRIVATE_USE);
+        if (result.contains(UnicodeProperty.SAMPLE_HIGH_PRIVATE_USE_SURROGATE)) {
+            result.addAll(UnicodeProperty.HIGH_PRIVATE_USE_SURROGATES);
         }
-        if (result.contains(UnicodeProperty.SAMPLE_SURROGATE)) {
-            result.addAll(UnicodeProperty.SURROGATE);
+        if (result.contains(UnicodeProperty.SAMPLE_LOW_SURROGATE)) {
+            result.addAll(UnicodeProperty.LOW_SURROGATES);
         }
+        
+        if (result.contains(UnicodeProperty.SAMPLE_PRIVATE_USE_AREA)) {
+            result.addAll(UnicodeProperty.PRIVATE_USE_AREA);
+        }
+        if (result.contains(UnicodeProperty.SAMPLE_PRIVATE_USE_AREA_A)) {
+            result.addAll(UnicodeProperty.PRIVATE_USE_AREA_A);
+        }
+        if (result.contains(UnicodeProperty.SAMPLE_PRIVATE_USE_AREA_B)) {
+            result.addAll(UnicodeProperty.PRIVATE_USE_AREA_B);
+        }
+
         return result;
     }
 
     public static UnicodeMap addUntested(UnicodeMap result, boolean uniformUnassigned) {
-        if (!uniformUnassigned) return result;
-
         Object temp;
-        if (null != (temp = result.get(UnicodeProperty.SAMPLE_UNASSIGNED))) {
-            result.putAll(UnicodeProperty.UNASSIGNED, temp);
+        if (uniformUnassigned && null != (temp = result.get(UnicodeProperty.getSAMPLE_UNASSIGNED()))) {
+            result.putAll(UnicodeProperty.getUNASSIGNED(), temp);
+        }
+
+        if (null != (temp = result.get(UnicodeProperty.SAMPLE_HIGH_SURROGATE))) {
+            result.putAll(UnicodeProperty.HIGH_SURROGATES, temp);
         }
-        if (null != (temp = result.get(UnicodeProperty.SAMPLE_PRIVATE_USE))) {
-            result.putAll(UnicodeProperty.PRIVATE_USE, temp);
+        if (null != (temp = result.get(UnicodeProperty.SAMPLE_HIGH_PRIVATE_USE_SURROGATE))) {
+            result.putAll(UnicodeProperty.HIGH_PRIVATE_USE_SURROGATES, temp);
         }
-        if (null != (temp = result.get(UnicodeProperty.SAMPLE_SURROGATE))) {
-            result.putAll(UnicodeProperty.SURROGATE, temp);
+        if (null != (temp = result.get(UnicodeProperty.SAMPLE_LOW_SURROGATE))) {
+            result.putAll(UnicodeProperty.LOW_SURROGATES, temp);
+        }
+
+        if (null != (temp = result.get(UnicodeProperty.SAMPLE_PRIVATE_USE_AREA))) {
+            result.putAll(UnicodeProperty.PRIVATE_USE_AREA, temp);
+        }
+        if (null != (temp = result.get(UnicodeProperty.SAMPLE_PRIVATE_USE_AREA_A))) {
+            result.putAll(UnicodeProperty.PRIVATE_USE_AREA_A, temp);
+        }
+        if (null != (temp = result.get(UnicodeProperty.SAMPLE_PRIVATE_USE_AREA_B))) {
+            result.putAll(UnicodeProperty.PRIVATE_USE_AREA_B, temp);
         }
         return result;
     }
@@ -1363,7 +1468,7 @@ public abstract class UnicodeProperty extends UnicodeLabel {
         if (isType(STRING_OR_MISC_MASK)) {
             return equals(cp, value);
         }
-        String defaultValue = getValue(SAMPLE_UNASSIGNED);
+        String defaultValue = getValue(getSAMPLE_UNASSIGNED());
         return defaultValue == null ? value == null : defaultValue.equals(value);   
     }
 
@@ -1374,5 +1479,53 @@ public abstract class UnicodeProperty extends UnicodeLabel {
         this.hasUniformUnassigned = hasUniformUnassigned;
         return this;
     }
+    
+    public static class UnicodeSetProperty extends BaseProperty {
+        protected UnicodeSet unicodeSet;
+        private static final String[] YESNO_ARRAY = new String[]{"Yes", "No"};
+        private static final List YESNO = Arrays.asList(YESNO_ARRAY);
+
+        public UnicodeSetProperty set(UnicodeSet set) {
+            unicodeSet = set.freeze();
+            return this;
+        }
+
+        public UnicodeSetProperty set(String string) {
+            // TODO Auto-generated method stub
+            return set(new UnicodeSet(string).freeze());
+        }
+
+        protected String _getValue(int codepoint) {
+            return YESNO_ARRAY[unicodeSet.contains(codepoint) ? 0 : 1];
+        }
+
+        protected List _getAvailableValues(List result) {
+            return YESNO;
+        }
+    }
+    
+    private static class StringTransformProperty extends SimpleProperty {
+        Transform<String,String> transform;
+
+        public StringTransformProperty(Transform<String,String> transform, boolean hasUniformUnassigned) {
+            this.transform = transform;
+            setUniformUnassigned(hasUniformUnassigned);
+        }
+        protected String _getValue(int codepoint) {
+            return transform.transform(UTF16.valueOf(codepoint));
+        }
+    }
+
+    private static class CodepointTransformProperty extends SimpleProperty {
+        Transform<Integer,String> transform;
+
+        public CodepointTransformProperty(Transform<Integer,String> transform, boolean hasUniformUnassigned) {
+            this.transform = transform;
+            setUniformUnassigned(hasUniformUnassigned);
+        }
+        protected String _getValue(int codepoint) {
+            return transform.transform(codepoint);
+        }
+    }
 }
 
diff --git a/icu4j/main/tests/translit/src/com/ibm/icu/dev/test/util/UnicodePropertySymbolTable.java b/icu4j/main/tests/translit/src/com/ibm/icu/dev/test/util/UnicodePropertySymbolTable.java
new file mode 100644 (file)
index 0000000..5e39d38
--- /dev/null
@@ -0,0 +1 @@
+/*\r *******************************************************************************\r * Copyright (C) 1996-2011, Google, International Business Machines Corporation and    *\r * others. All Rights Reserved.                                                *\r *******************************************************************************\r */\rpackage com.ibm.icu.dev.test.util;\r\rimport java.util.Comparator;\rimport java.util.HashMap;\rimport java.util.List;\rimport java.util.Locale;\rimport java.util.Set;\r\rimport com.ibm.icu.dev.test.util.UnicodeProperty.PatternMatcher;\rimport com.ibm.icu.impl.UnicodeRegex;\rimport com.ibm.icu.text.UTF16;\rimport com.ibm.icu.text.UnicodeSet;\r\r/**\r * Allows for overriding the parsing of UnicodeSet property patterns.\r * <p>\r * WARNING: If this UnicodePropertySymbolTable is used with {@code UnicodeSet.setDefaultXSymbolTable}, and the\r * Unassigned characters (gc=Cn) are different than in ICU other than in ICU, you MUST call\r * {@code UnicodeProperty.ResetCacheProperties} afterwards. If you then call {@code UnicodeSet.setDefaultXSymbolTable}\r * with null to clear the value, you MUST also call {@code UnicodeProperty.ResetCacheProperties}.\r * \r * @author markdavis\r */\rpublic class UnicodePropertySymbolTable extends UnicodeSet.XSymbolTable {\r    UnicodeRegex unicodeRegex;\r    final UnicodeProperty.Factory factory;\r\r    public UnicodePropertySymbolTable(UnicodeProperty.Factory factory) {\r      unicodeRegex = new UnicodeRegex().setSymbolTable(this);\r      this.factory = factory;\r    }\r\r\r    //    public boolean applyPropertyAlias0(String propertyName,\r    //            String propertyValue, UnicodeSet result) {\r    //      if (!propertyName.contains("*")) {\r    //        return applyPropertyAlias(propertyName, propertyValue, result);\r    //      }\r    //      String[] propertyNames = propertyName.split("[*]");\r    //      for (int i = propertyNames.length - 1; i >= 0; ++i) {\r    //        String pname = propertyNames[i];\r    //        \r    //      }\r    //      return null;\r    //    }\r\r    public boolean applyPropertyAlias(String propertyName,\r            String propertyValue, UnicodeSet result) {\r      boolean status = false;\r      boolean invert = false;\r      int posNotEqual = propertyName.indexOf('\u2260');\r      int posColon = propertyName.indexOf(':');\r      if (posNotEqual >= 0 || posColon >= 0) {\r          if (posNotEqual < 0) posNotEqual = propertyName.length();\r          if (posColon < 0) posColon = propertyName.length();\r          int opPos = posNotEqual < posColon ? posNotEqual : posColon;\r          propertyValue = propertyValue.length() == 0 ? propertyName.substring(opPos+1) \r                  : propertyName.substring(opPos+1) + "=" + propertyValue;\r          propertyName = propertyName.substring(0,opPos);\r          if (posNotEqual < posColon) {\r              invert = true;\r          }\r      }\r      if (propertyName.endsWith("!")) {\r        propertyName = propertyName.substring(0, propertyName.length() - 1);\r        invert = !invert;\r      }\r      propertyValue = propertyValue.trim();\r      if (propertyValue.length() != 0) {\r        status = applyPropertyAlias0(propertyName, propertyValue, result);\r      } else {\r        try {\r          status = applyPropertyAlias0("gc", propertyName, result);\r        } catch (Exception e) {};\r        if (!status) {\r          try {\r            status = applyPropertyAlias0("sc", propertyName, result);\r          } catch (Exception e) {};\r          if (!status) {\r            try {\r              status = applyPropertyAlias0(propertyName, "Yes", result);\r            } catch (Exception e) {};\r            if (!status) {\r              status = applyPropertyAlias0(propertyName, "", result);\r            }\r          }\r        }\r      }\r      if (status && invert) {\r        result.complement();\r      }\r      return status;\r    }\r\r    static final HashMap<String,String[]> GC_REMAP = new HashMap();\r    {\r        GC_REMAP.put("c", "Cc Cf Cn Co Cs".split(" "));\r        GC_REMAP.put("other", GC_REMAP.get("c"));\r        \r        GC_REMAP.put("l", "Ll Lm Lo Lt Lu".split(" "));\r        GC_REMAP.put("letter", GC_REMAP.get("l"));\r        \r        GC_REMAP.put("lc", "Ll Lt Lu".split(" "));\r        GC_REMAP.put("casedletter", GC_REMAP.get("lc"));\r        \r        GC_REMAP.put("m", "Mc Me Mn".split(" "));\r        GC_REMAP.put("mark", GC_REMAP.get("m"));\r        \r        GC_REMAP.put("n", "Nd Nl No".split(" "));\r        GC_REMAP.put("number", GC_REMAP.get("n"));\r        \r        GC_REMAP.put("p", "Pc Pd Pe Pf Pi Po Ps".split(" "));\r        GC_REMAP.put("punctuation", GC_REMAP.get("p"));\r        GC_REMAP.put("punct", GC_REMAP.get("p"));\r        \r        GC_REMAP.put("s", "Sc Sk Sm So".split(" "));\r        GC_REMAP.put("symbol", GC_REMAP.get("s"));\r        \r        GC_REMAP.put("z", "Zl Zp Zs".split(" "));\r        GC_REMAP.put("separator", GC_REMAP.get("z"));\r    }\r    \r    public boolean applyPropertyAlias0(String propertyName,\r            String propertyValue, UnicodeSet result) {\r      result.clear();\r      UnicodeProperty prop = factory.getProperty(propertyName);\r      String canonicalName = prop.getName();\r      boolean isAge = UnicodeProperty.equalNames("Age", canonicalName);\r\r      // Hack for special GC values\r      if (canonicalName.equals("General_Category")) {\r          String[] parts = GC_REMAP.get(UnicodeProperty.toSkeleton(propertyValue));\r          if (parts != null) {\r              for (String part : parts) {\r                  prop.getSet(part, result);\r              }\r              return true;\r          }\r      }\r\r      PatternMatcher patternMatcher = null;\r      if (propertyValue.length() > 1 && propertyValue.startsWith("/") && propertyValue.endsWith("/")) {\r        String fixedRegex = unicodeRegex.transform(propertyValue.substring(1, propertyValue.length() - 1));\r        patternMatcher = new UnicodeProperty.RegexMatcher().set(fixedRegex);\r      }\r      UnicodeProperty otherProperty = null;\r      boolean testCp = false;\r      if (propertyValue.length() > 1 && propertyValue.startsWith("@") && propertyValue.endsWith("@")) {\r        String otherPropName = propertyValue.substring(1, propertyValue.length() - 1).trim();\r        if ("cp".equalsIgnoreCase(otherPropName)) {\r          testCp = true;\r        } else {\r          otherProperty = factory.getProperty(otherPropName);\r        }\r      }\r      if (prop != null) {\r        UnicodeSet set;\r        if (testCp) {\r          set = new UnicodeSet();\r          for (int i = 0; i <= 0x10FFFF; ++i) {\r            if (UnicodeProperty.equals(i, prop.getValue(i))) {\r              set.add(i);\r            }\r          }\r        } else if (otherProperty != null) {\r          set = new UnicodeSet();\r          for (int i = 0; i <= 0x10FFFF; ++i) {\r            String v1 = prop.getValue(i);\r            String v2 = otherProperty.getValue(i);\r            if (UnicodeProperty.equals(v1, v2)) {\r              set.add(i);\r            }\r          }\r        } else if (patternMatcher == null) {\r          if (!isValid(prop, propertyValue)) {\r            throw new IllegalArgumentException("The value '" + propertyValue + "' is illegal. Values for " + propertyName\r                    + " must be in "\r                    + prop.getAvailableValues() + " or in " + prop.getValueAliases());\r          }\r          if (isAge) {\r            set = prop.getSet(new ComparisonMatcher(propertyValue, Relation.geq));\r          } else {\r            set = prop.getSet(propertyValue);\r          }\r        } else if (isAge) {\r          set = new UnicodeSet();\r          List<String> values = prop.getAvailableValues();\r          for (String value : values) {\r            if (patternMatcher.matches(value)) {\r              for (String other : values) {\r                if (other.compareTo(value) <= 0) {\r                  set.addAll(prop.getSet(other));\r                }\r              }\r            }\r          }\r        } else {\r          set = prop.getSet(patternMatcher);\r        }\r        result.addAll(set);\r        return true;\r      }\r      throw new IllegalArgumentException("Illegal property: " + propertyName);\r    }\r\r    \r\r    private boolean isValid(UnicodeProperty prop, String propertyValue) {\r//      if (prop.getName().equals("General_Category")) {\r//        if (propertyValue)\r//      }\r      return prop.isValidValue(propertyValue);\r    }\r\r    public enum Relation {less, leq, equal, geq, greater}\r\r    public static class ComparisonMatcher implements PatternMatcher {\r        Relation relation;\r        static Comparator comparator = new UTF16.StringComparator(true, false,0);\r\r        String pattern;\r\r        public ComparisonMatcher(String pattern, Relation comparator) {\r          this.relation = comparator;\r          this.pattern = pattern;\r        }\r\r        public boolean matches(Object value) {\r          int comp = comparator.compare(pattern, value.toString());\r          switch (relation) {\r          case less: return comp < 0;\r          case leq: return comp <= 0;\r          default: return comp == 0;\r          case geq: return comp >= 0;\r          case greater: return comp > 0;\r          }\r        }\r\r        public PatternMatcher set(String pattern) {\r          this.pattern = pattern;\r          return this;\r        }\r      }\r  }
\ No newline at end of file
diff --git a/icu4j/main/tests/translit/src/com/ibm/icu/dev/test/util/UnicodeTransform.java b/icu4j/main/tests/translit/src/com/ibm/icu/dev/test/util/UnicodeTransform.java
new file mode 100644 (file)
index 0000000..69359ec
--- /dev/null
@@ -0,0 +1 @@
+/*\r *******************************************************************************\r * Copyright (C) 2011, Google, International Business Machines Corporation and         *\r * others. All Rights Reserved.                                                *\r *******************************************************************************\r */\rpackage com.ibm.icu.dev.test.util;\r\rimport com.ibm.icu.text.Transform;\rimport com.ibm.icu.text.UTF16;\r\r/**\r * Simple wrapping for normalizer that allows for both the standard ICU normalizer, and one built directly from the UCD.\r */\rpublic abstract class UnicodeTransform implements Transform<String,String> {\r    public enum Type {\r        NFD, NFC, NFKD, NFKC, CASEFOLD\r    }\r    \r    public interface Factory {\r        public UnicodeTransform getInstance(Type type);\r    }\r    \r    private static Factory factory = new IcuUnicodeNormalizerFactory();\r    \r    public static synchronized Factory getFactory() {\r        return factory;\r    }\r\r    public static synchronized void setFactory(Factory factory) {\r        UnicodeTransform.factory = factory;\r    }\r\r    public static synchronized UnicodeTransform getInstance(Type type) {\r        return factory.getInstance(type);\r    }\r    \r    public abstract String transform(String source);\r    \r    /**\r     * Can be overridden for performance.\r     */\r    public boolean isTransformed(String source) {\r        return source.equals(transform(source));\r    }\r    /**\r     * Can be overridden for performance.\r     */\r    public String transform(int source) {\r        return transform(UTF16.valueOf(source));\r    }\r    /**\r     * Can be overridden for performance.\r     */\r    public boolean isTransformed(int source) {\r        return isTransformed(UTF16.valueOf(source));\r    }\r}\r\r
\ No newline at end of file