]> gitweb.fperrin.net Git - Dictionary.git/blobdiff - jars/icu4j-4_2_1-src/src/com/ibm/icu/dev/test/util/CollectionUtilities.java
go
[Dictionary.git] / jars / icu4j-4_2_1-src / src / com / ibm / icu / dev / test / util / CollectionUtilities.java
old mode 100755 (executable)
new mode 100644 (file)
index 5b4e765..e58fcfa
-//##header\r
-/*\r
- *******************************************************************************\r
- * Copyright (C) 1996-2009, International Business Machines Corporation and    *\r
- * others. All Rights Reserved.                                                *\r
- *******************************************************************************\r
- */\r
-package com.ibm.icu.dev.test.util;\r
-\r
-import java.util.Collection;\r
-import java.util.Comparator;\r
-import java.util.HashMap;\r
-import java.util.Iterator;\r
-import java.util.Map;\r
-import java.util.SortedSet;\r
-\r
-//#if defined(FOUNDATION10) || defined(J2SE13)\r
-//#else\r
-import java.util.regex.Matcher;\r
-//#endif\r
-\r
-import com.ibm.icu.text.Transliterator;\r
-import com.ibm.icu.text.UTF16;\r
-import com.ibm.icu.text.UnicodeSet;\r
-import com.ibm.icu.text.UnicodeSetIterator;\r
-\r
-/**\r
- * Utilities that ought to be on collections, but aren't\r
- */\r
-public final class CollectionUtilities {\r
-    \r
-    public static String join(Object[] array, String separator) {\r
-        StringBuffer result = new StringBuffer();\r
-        for (int i = 0; i < array.length; ++i) {\r
-            if (i != 0) result.append(separator);\r
-            result.append(array[i]);\r
-        }\r
-        return result.toString();\r
-    }\r
-\r
-    public static String join(Collection collection, String separator) {\r
-        StringBuffer result = new StringBuffer();\r
-        boolean first = true;\r
-        for (Iterator it = collection.iterator(); it.hasNext();) {\r
-            if (first) first = false;\r
-            else result.append(separator);\r
-            result.append(it.next());\r
-        }\r
-        return result.toString();\r
-    }\r
-\r
-    /**\r
-     * Utility like Arrays.asList()\r
-     */\r
-    public static Map asMap(Object[][] source, Map target, boolean reverse) {\r
-        int from = 0, to = 1;\r
-        if (reverse) {\r
-            from = 1; to = 0;\r
-        }\r
-        for (int i = 0; i < source.length; ++i) {\r
-            target.put(source[i][from], source[i][to]);\r
-        }\r
-        return target;\r
-    }\r
-    \r
-    public static Collection addAll(Iterator source, Collection target) {\r
-        while (source.hasNext()) {\r
-            target.add(source.next());\r
-        }\r
-        return target; // for chaining\r
-    }\r
-    \r
-    public static int size(Iterator source) {\r
-        int result = 0;\r
-        while (source.hasNext()) {\r
-            source.next();\r
-            ++result;\r
-        }\r
-        return result;\r
-    }\r
-    \r
-\r
-    public static Map asMap(Object[][] source) {\r
-        return asMap(source, new HashMap(), false);\r
-    }\r
-    \r
-    /**\r
-     * Utility that ought to be on Map\r
-     */\r
-    public static Map removeAll(Map m, Collection itemsToRemove) {\r
-        for (Iterator it = itemsToRemove.iterator(); it.hasNext();) {\r
-            Object item = it.next();\r
-            m.remove(item);\r
-        }\r
-        return m;\r
-    }\r
-    \r
-    public Object getFirst(Collection c) {\r
-        Iterator it = c.iterator();\r
-        if (!it.hasNext()) return null;\r
-        return it.next();\r
-    }\r
-    \r
-    public static Object getBest(Collection c, Comparator comp, int direction) {\r
-        Iterator it = c.iterator();\r
-        if (!it.hasNext()) return null;\r
-        Object bestSoFar = it.next();\r
-        if (direction < 0) {\r
-            while (it.hasNext()) {\r
-                Object item = it.next();\r
-                int compValue = comp.compare(item, bestSoFar);\r
-                if (compValue < 0) {\r
-                    bestSoFar = item;\r
-                }\r
-            }\r
-        } else {\r
-            while (it.hasNext()) {\r
-                Object item = it.next();\r
-                int compValue = comp.compare(item, bestSoFar);\r
-                if (compValue > 0) {\r
-                    bestSoFar = item;\r
-                }\r
-            }\r
-        }\r
-        return bestSoFar;\r
-    }\r
-    \r
-    public interface ObjectMatcher {\r
-        /**\r
-         * Must handle null, never throw exception\r
-         */\r
-        boolean matches(Object o);\r
-    }\r
-    \r
-    public static class InverseMatcher implements ObjectMatcher {\r
-        ObjectMatcher other;\r
-        public ObjectMatcher set(ObjectMatcher toInverse) {\r
-            other = toInverse;\r
-            return this;\r
-        }\r
-        public boolean matches(Object value) {\r
-            return !other.matches(value);\r
-        }\r
-    }\r
-\r
-    public static Collection removeAll(Collection c, ObjectMatcher f) {\r
-        for (Iterator it = c.iterator(); it.hasNext();) {\r
-            Object item = it.next();\r
-            if (f.matches(item)) it.remove();\r
-        }\r
-        return c;\r
-    }\r
-    \r
-    public static Collection retainAll(Collection c, ObjectMatcher f) {\r
-        for (Iterator it = c.iterator(); it.hasNext();) {\r
-            Object item = it.next();\r
-            if (!f.matches(item)) it.remove();\r
-        }\r
-        return c;\r
-    }\r
-    \r
-    public static boolean containsSome(Collection a, Collection b) {\r
-        // fast paths\r
-        if (a.size() == 0 || b.size() == 0) return false;\r
-        if (a == b) return true; // must test after size test.\r
-\r
-        if (a instanceof SortedSet && b instanceof SortedSet) {\r
-            SortedSet aa = (SortedSet) a;\r
-            SortedSet bb = (SortedSet) b;\r
-            aa.containsAll(null);\r
-            Comparator bbc = bb.comparator();\r
-            Comparator aac = aa.comparator();\r
-            if (bbc == null) {\r
-                if (aac == null) {\r
-                    Iterator ai = aa.iterator();\r
-                    Iterator bi = bb.iterator();\r
-                    Comparable ao = (Comparable) ai.next(); // these are ok, since the sizes are != 0\r
-                    Comparable bo = (Comparable) bi.next();\r
-                    while (true) {\r
-                        int rel = ao.compareTo(bo);\r
-                        if (rel < 0) {\r
-                            if (!ai.hasNext()) return false;\r
-                            ao = (Comparable) ai.next();\r
-                        } else if (rel > 0) {\r
-                            if (!bi.hasNext()) return false;\r
-                            bo = (Comparable) bi.next();\r
-                        } else {\r
-                                return true;  \r
-                        }\r
-                    }\r
-                }\r
-            } else if (bbc.equals(a)) {\r
-                Iterator ai = aa.iterator();\r
-                Iterator bi = bb.iterator();\r
-                Object ao = ai.next(); // these are ok, since the sizes are != 0\r
-                Object bo = bi.next();\r
-                while (true) {\r
-                    int rel = aac.compare(ao, bo);\r
-                    if (rel < 0) {\r
-                        if (!ai.hasNext()) return false;\r
-                        ao = ai.next();\r
-                    } else if (rel > 0)  {\r
-                        if (!bi.hasNext()) return false;\r
-                        bo = bi.next();\r
-                    } else {\r
-                        return true;  \r
-                    }\r
-                }\r
-            }           \r
-        }\r
-        for (Iterator it = a.iterator(); it.hasNext();) {\r
-            if (b.contains(it.next())) return true;\r
-        }\r
-        return false;\r
-    }\r
-    \r
-    public static boolean containsAll(Collection a, Collection b) {\r
-        // fast paths\r
-        if (a == b) return true;\r
-        if (b.size() == 0) return true;\r
-        if (a.size() == 0) return false;\r
-\r
-        if (a instanceof SortedSet && b instanceof SortedSet) {\r
-            SortedSet aa = (SortedSet) a;\r
-            SortedSet bb = (SortedSet) b;\r
-            Comparator bbc = bb.comparator();\r
-            Comparator aac = aa.comparator();\r
-            if (bbc == null) {\r
-                if (aac == null) {\r
-                    Iterator ai = aa.iterator();\r
-                    Iterator bi = bb.iterator();\r
-                    Comparable ao = (Comparable) ai.next(); // these are ok, since the sizes are != 0\r
-                    Comparable bo = (Comparable) bi.next();\r
-                    while (true) {\r
-                        int rel = ao.compareTo(bo);\r
-                        if (rel == 0) {\r
-                            if (!bi.hasNext()) return true;\r
-                            if (!ai.hasNext()) return false;\r
-                            bo = (Comparable) bi.next();\r
-                            ao = (Comparable) ai.next();\r
-                        } else if (rel < 0) {\r
-                            if (!ai.hasNext()) return false;\r
-                            ao = (Comparable) ai.next();\r
-                        } else {\r
-                            return false;  \r
-                        }\r
-                    }\r
-                }\r
-            } else if (bbc.equals(a)) {\r
-                Iterator ai = aa.iterator();\r
-                Iterator bi = bb.iterator();\r
-                Object ao = ai.next(); // these are ok, since the sizes are != 0\r
-                Object bo = bi.next();\r
-                while (true) {\r
-                    int rel = aac.compare(ao, bo);\r
-                    if (rel == 0) {\r
-                        if (!bi.hasNext()) return true;\r
-                        if (!ai.hasNext()) return false;\r
-                        bo = bi.next();\r
-                        ao = ai.next();\r
-                    } else if (rel < 0) {\r
-                        if (!ai.hasNext()) return false;\r
-                        ao = ai.next();\r
-                    } else {\r
-                        return false;  \r
-                    }\r
-                }\r
-            }           \r
-        }\r
-        return a.containsAll(b);\r
-    }\r
-    \r
-    public static boolean containsNone(Collection a, Collection b) {\r
-        return !containsSome(a, b);\r
-    }\r
-    \r
-    /**\r
-     * Used for results of getContainmentRelation\r
-     */\r
-    public static final int\r
-        ALL_EMPTY = 0,\r
-        NOT_A_SUPERSET_B = 1,\r
-        NOT_A_DISJOINT_B = 2,\r
-        NOT_A_SUBSET_B = 4,\r
-        NOT_A_EQUALS_B = NOT_A_SUBSET_B | NOT_A_SUPERSET_B,\r
-        A_PROPER_SUBSET_OF_B = NOT_A_DISJOINT_B | NOT_A_SUPERSET_B,\r
-        A_PROPER_SUPERSET_B = NOT_A_SUBSET_B | NOT_A_DISJOINT_B,\r
-        A_PROPER_OVERLAPS_B = NOT_A_SUBSET_B | NOT_A_DISJOINT_B | NOT_A_SUPERSET_B;\r
-    \r
-    /**\r
-     * Assesses all the possible containment relations between collections A and B with one call.<br>\r
-     * Returns an int with bits set, according to a "Venn Diagram" view of A vs B.<br>\r
-     * NOT_A_SUPERSET_B: a - b != {}<br>\r
-     * NOT_A_DISJOINT_B: a * b != {}  // * is intersects<br>\r
-     * NOT_A_SUBSET_B: b - a != {}<br>\r
-     * Thus the bits can be used to get the following relations:<br>\r
-     * for A_SUPERSET_B, use (x & CollectionUtilities.NOT_A_SUPERSET_B) == 0<br>\r
-     * for A_SUBSET_B, use (x & CollectionUtilities.NOT_A_SUBSET_B) == 0<br>\r
-     * for A_EQUALS_B, use (x & CollectionUtilities.NOT_A_EQUALS_B) == 0<br>\r
-     * for A_DISJOINT_B, use (x & CollectionUtilities.NOT_A_DISJOINT_B) == 0<br>\r
-     * for A_OVERLAPS_B, use (x & CollectionUtilities.NOT_A_DISJOINT_B) != 0<br>\r
-     */\r
-     public static int getContainmentRelation(Collection a, Collection b) {\r
-        if (a.size() == 0) {\r
-            return (b.size() == 0) ? ALL_EMPTY : NOT_A_SUPERSET_B;\r
-        } else if (b.size() == 0) {\r
-            return NOT_A_SUBSET_B;\r
-        }\r
-        int result = 0;\r
-        // WARNING: one might think that the following can be short-circuited, by looking at\r
-        // the sizes of a and b. However, this would fail in general, where a different comparator is being\r
-        // used in the two collections. Unfortunately, there is no failsafe way to test for that.\r
-        for (Iterator it = a.iterator(); result != 6 && it.hasNext();) {\r
-            result |= (b.contains(it.next())) ? NOT_A_DISJOINT_B : NOT_A_SUBSET_B;\r
-        }\r
-        for (Iterator it = b.iterator(); (result & 3) != 3 && it.hasNext();) {\r
-            result |= (a.contains(it.next())) ? NOT_A_DISJOINT_B : NOT_A_SUPERSET_B;\r
-        }\r
-        return result;\r
-    }\r
-\r
-    public static String remove(String source, UnicodeSet removals) {\r
-        StringBuffer result = new StringBuffer();\r
-        int cp;\r
-        for (int i = 0; i < source.length(); i += UTF16.getCharCount(cp)) {\r
-            cp = UTF16.charAt(source, i);\r
-            if (!removals.contains(cp)) UTF16.append(result, cp);\r
-        }\r
-        return result.toString();\r
-    }\r
-\r
-//#if defined(FOUNDATION10) || defined(J2SE13)\r
-//#else\r
-     /**\r
-      * Does one string contain another, starting at a specific offset?\r
-      * @param text\r
-      * @param offset\r
-      * @param other\r
-      * @return\r
-      */\r
-        public static int matchesAt(CharSequence text, int offset, CharSequence other) {\r
-            int len = other.length();\r
-            int i = 0;\r
-            int j = offset;\r
-            for (; i < len; ++i, ++j) {\r
-                char pc = other.charAt(i);\r
-                char tc = text.charAt(j);\r
-                if (pc != tc) return -1;\r
-            }\r
-            return i;\r
-        }\r
-\r
-        /**\r
-         * Returns the ending offset found by matching characters with testSet, until a position is found that doen't match\r
-         * @param string\r
-         * @param offset\r
-         * @param testSet\r
-         * @return\r
-         */\r
-        public int span(CharSequence string, int offset, UnicodeSet testSet) {\r
-            while (true) {\r
-                int newOffset = testSet.matchesAt(string, offset);\r
-                if (newOffset < 0) return offset;\r
-            }\r
-        }\r
-\r
-        /**\r
-         * Returns the ending offset found by matching characters with testSet, until a position is found that does match\r
-         * @param string\r
-         * @param offset\r
-         * @param testSet\r
-         * @return\r
-         */\r
-        public int spanNot(CharSequence string, int offset, UnicodeSet testSet) {\r
-            while (true) {\r
-                int newOffset = testSet.matchesAt(string, offset);\r
-                if (newOffset >= 0) return offset;\r
-                ++offset; // try next character position\r
-                // we don't have to worry about surrogates for this.\r
-            }\r
-        }\r
-//#endif\r
-\r
-    public static String prettyPrint(UnicodeSet uset, boolean compressRanges, UnicodeSet toQuote, Transliterator quoter, \r
-            Comparator ordering, Comparator spaceComparator) {\r
-        PrettyPrinter pp = new PrettyPrinter().setCompressRanges(compressRanges);\r
-        if (toQuote != null) pp.setToQuote(toQuote);\r
-        if (ordering != null) pp.setOrdering(ordering);\r
-        if (spaceComparator != null) pp.setSpaceComparator(spaceComparator);\r
-        return pp.toPattern(uset);\r
-    }\r
-    \r
-    public static class MultiComparator implements Comparator {\r
-        private Comparator[] comparators;\r
-    \r
-        public MultiComparator (Comparator[] comparators) {\r
-            this.comparators = comparators;\r
-        }\r
-    \r
-        /* Lexigraphic compare. Returns the first difference\r
-         * @return zero if equal. Otherwise +/- (i+1) \r
-         * where i is the index of the first comparator finding a difference\r
-         * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)\r
-         */\r
-        public int compare(Object arg0, Object arg1) {\r
-            for (int i = 0; i < comparators.length; ++i) {\r
-                int result = comparators[i].compare(arg0, arg1);\r
-                if (result == 0) continue;\r
-                if (result > 0) return i+1;\r
-                return -(i+1);\r
-            }\r
-            return 0;\r
-        }\r
-    }\r
-\r
-    /**\r
-     * Modifies Unicode set to flatten the strings. Eg [abc{da}] => [abcd]\r
-     * Returns the set for chaining.\r
-     * @param exemplar1\r
-     * @return\r
-     */\r
-    public static UnicodeSet flatten(UnicodeSet exemplar1) {\r
-        UnicodeSet result = new UnicodeSet();\r
-        boolean gotString = false;\r
-        for (UnicodeSetIterator it = new UnicodeSetIterator(exemplar1); it.nextRange();) {\r
-            if (it.codepoint == UnicodeSetIterator.IS_STRING) {\r
-                result.addAll(it.string);\r
-                gotString = true;\r
-            } else {\r
-                result.add(it.codepoint, it.codepointEnd);\r
-            }\r
-        }\r
-        if (gotString) exemplar1.set(result);\r
-        return exemplar1;\r
-    }\r
-\r
-    /**\r
-     * For producing filtered iterators\r
-     */\r
-    public static abstract class FilteredIterator implements Iterator {\r
-        private Iterator baseIterator;\r
-        private static final Object EMPTY = new Object();\r
-        private static final Object DONE = new Object();\r
-        private Object nextObject = EMPTY;\r
-        public FilteredIterator set(Iterator baseIterator) {\r
-            this.baseIterator = baseIterator;\r
-            return this;\r
-        }\r
-        public void remove() {\r
-            throw new UnsupportedOperationException("Doesn't support removal");\r
-        }\r
-        public Object next() {\r
-            Object result = nextObject;\r
-            nextObject = EMPTY;\r
-            return result;\r
-        }       \r
-        public boolean hasNext() {\r
-            if (nextObject == DONE) return false;\r
-            if (nextObject != EMPTY) return true;\r
-            while (baseIterator.hasNext()) {\r
-                nextObject = baseIterator.next();\r
-                if (isIncluded(nextObject)) {\r
-                    return true;\r
-                }\r
-            }\r
-            nextObject = DONE;\r
-            return false;\r
-        }\r
-        abstract public boolean isIncluded(Object item);\r
-    }\r
-    \r
-    public static class PrefixIterator extends FilteredIterator {\r
-        private String prefix;\r
-        public PrefixIterator set(Iterator baseIterator, String prefix) {\r
-            super.set(baseIterator);\r
-            this.prefix = prefix;\r
-            return this;\r
-        }\r
-        public boolean isIncluded(Object item) {\r
-            return ((String)item).startsWith(prefix);\r
-        }\r
-    }\r
-    \r
-//#if defined(FOUNDATION10) || defined(J2SE13)\r
-//#else\r
-    public static class RegexIterator extends FilteredIterator {\r
-        private Matcher matcher;\r
-        public RegexIterator set(Iterator baseIterator, Matcher matcher) {\r
-            super.set(baseIterator);\r
-            this.matcher = matcher;\r
-            return this;\r
-        }\r
-        public boolean isIncluded(Object item) {\r
-            return matcher.reset((String)item).matches();\r
-        }\r
-    }\r
-//#endif\r
-}\r
+//##header J2SE15
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2009, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+package com.ibm.icu.dev.test.util;
+
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.SortedSet;
+
+//#if defined(FOUNDATION10) || defined(J2SE13)
+//#else
+import java.util.regex.Matcher;
+//#endif
+
+import com.ibm.icu.text.Transliterator;
+import com.ibm.icu.text.UTF16;
+import com.ibm.icu.text.UnicodeSet;
+import com.ibm.icu.text.UnicodeSetIterator;
+
+/**
+ * Utilities that ought to be on collections, but aren't
+ */
+public final class CollectionUtilities {
+    
+    public static String join(Object[] array, String separator) {
+        StringBuffer result = new StringBuffer();
+        for (int i = 0; i < array.length; ++i) {
+            if (i != 0) result.append(separator);
+            result.append(array[i]);
+        }
+        return result.toString();
+    }
+
+    public static String join(Collection collection, String separator) {
+        StringBuffer result = new StringBuffer();
+        boolean first = true;
+        for (Iterator it = collection.iterator(); it.hasNext();) {
+            if (first) first = false;
+            else result.append(separator);
+            result.append(it.next());
+        }
+        return result.toString();
+    }
+
+    /**
+     * Utility like Arrays.asList()
+     */
+    public static Map asMap(Object[][] source, Map target, boolean reverse) {
+        int from = 0, to = 1;
+        if (reverse) {
+            from = 1; to = 0;
+        }
+        for (int i = 0; i < source.length; ++i) {
+            target.put(source[i][from], source[i][to]);
+        }
+        return target;
+    }
+    
+    public static Collection addAll(Iterator source, Collection target) {
+        while (source.hasNext()) {
+            target.add(source.next());
+        }
+        return target; // for chaining
+    }
+    
+    public static int size(Iterator source) {
+        int result = 0;
+        while (source.hasNext()) {
+            source.next();
+            ++result;
+        }
+        return result;
+    }
+    
+
+    public static Map asMap(Object[][] source) {
+        return asMap(source, new HashMap(), false);
+    }
+    
+    /**
+     * Utility that ought to be on Map
+     */
+    public static Map removeAll(Map m, Collection itemsToRemove) {
+        for (Iterator it = itemsToRemove.iterator(); it.hasNext();) {
+            Object item = it.next();
+            m.remove(item);
+        }
+        return m;
+    }
+    
+    public Object getFirst(Collection c) {
+        Iterator it = c.iterator();
+        if (!it.hasNext()) return null;
+        return it.next();
+    }
+    
+    public static Object getBest(Collection c, Comparator comp, int direction) {
+        Iterator it = c.iterator();
+        if (!it.hasNext()) return null;
+        Object bestSoFar = it.next();
+        if (direction < 0) {
+            while (it.hasNext()) {
+                Object item = it.next();
+                int compValue = comp.compare(item, bestSoFar);
+                if (compValue < 0) {
+                    bestSoFar = item;
+                }
+            }
+        } else {
+            while (it.hasNext()) {
+                Object item = it.next();
+                int compValue = comp.compare(item, bestSoFar);
+                if (compValue > 0) {
+                    bestSoFar = item;
+                }
+            }
+        }
+        return bestSoFar;
+    }
+    
+    public interface ObjectMatcher {
+        /**
+         * Must handle null, never throw exception
+         */
+        boolean matches(Object o);
+    }
+    
+    public static class InverseMatcher implements ObjectMatcher {
+        ObjectMatcher other;
+        public ObjectMatcher set(ObjectMatcher toInverse) {
+            other = toInverse;
+            return this;
+        }
+        public boolean matches(Object value) {
+            return !other.matches(value);
+        }
+    }
+
+    public static Collection removeAll(Collection c, ObjectMatcher f) {
+        for (Iterator it = c.iterator(); it.hasNext();) {
+            Object item = it.next();
+            if (f.matches(item)) it.remove();
+        }
+        return c;
+    }
+    
+    public static Collection retainAll(Collection c, ObjectMatcher f) {
+        for (Iterator it = c.iterator(); it.hasNext();) {
+            Object item = it.next();
+            if (!f.matches(item)) it.remove();
+        }
+        return c;
+    }
+    
+    public static boolean containsSome(Collection a, Collection b) {
+        // fast paths
+        if (a.size() == 0 || b.size() == 0) return false;
+        if (a == b) return true; // must test after size test.
+
+        if (a instanceof SortedSet && b instanceof SortedSet) {
+            SortedSet aa = (SortedSet) a;
+            SortedSet bb = (SortedSet) b;
+            aa.containsAll(null);
+            Comparator bbc = bb.comparator();
+            Comparator aac = aa.comparator();
+            if (bbc == null) {
+                if (aac == null) {
+                    Iterator ai = aa.iterator();
+                    Iterator bi = bb.iterator();
+                    Comparable ao = (Comparable) ai.next(); // these are ok, since the sizes are != 0
+                    Comparable bo = (Comparable) bi.next();
+                    while (true) {
+                        int rel = ao.compareTo(bo);
+                        if (rel < 0) {
+                            if (!ai.hasNext()) return false;
+                            ao = (Comparable) ai.next();
+                        } else if (rel > 0) {
+                            if (!bi.hasNext()) return false;
+                            bo = (Comparable) bi.next();
+                        } else {
+                                return true;  
+                        }
+                    }
+                }
+            } else if (bbc.equals(a)) {
+                Iterator ai = aa.iterator();
+                Iterator bi = bb.iterator();
+                Object ao = ai.next(); // these are ok, since the sizes are != 0
+                Object bo = bi.next();
+                while (true) {
+                    int rel = aac.compare(ao, bo);
+                    if (rel < 0) {
+                        if (!ai.hasNext()) return false;
+                        ao = ai.next();
+                    } else if (rel > 0)  {
+                        if (!bi.hasNext()) return false;
+                        bo = bi.next();
+                    } else {
+                        return true;  
+                    }
+                }
+            }           
+        }
+        for (Iterator it = a.iterator(); it.hasNext();) {
+            if (b.contains(it.next())) return true;
+        }
+        return false;
+    }
+    
+    public static boolean containsAll(Collection a, Collection b) {
+        // fast paths
+        if (a == b) return true;
+        if (b.size() == 0) return true;
+        if (a.size() == 0) return false;
+
+        if (a instanceof SortedSet && b instanceof SortedSet) {
+            SortedSet aa = (SortedSet) a;
+            SortedSet bb = (SortedSet) b;
+            Comparator bbc = bb.comparator();
+            Comparator aac = aa.comparator();
+            if (bbc == null) {
+                if (aac == null) {
+                    Iterator ai = aa.iterator();
+                    Iterator bi = bb.iterator();
+                    Comparable ao = (Comparable) ai.next(); // these are ok, since the sizes are != 0
+                    Comparable bo = (Comparable) bi.next();
+                    while (true) {
+                        int rel = ao.compareTo(bo);
+                        if (rel == 0) {
+                            if (!bi.hasNext()) return true;
+                            if (!ai.hasNext()) return false;
+                            bo = (Comparable) bi.next();
+                            ao = (Comparable) ai.next();
+                        } else if (rel < 0) {
+                            if (!ai.hasNext()) return false;
+                            ao = (Comparable) ai.next();
+                        } else {
+                            return false;  
+                        }
+                    }
+                }
+            } else if (bbc.equals(a)) {
+                Iterator ai = aa.iterator();
+                Iterator bi = bb.iterator();
+                Object ao = ai.next(); // these are ok, since the sizes are != 0
+                Object bo = bi.next();
+                while (true) {
+                    int rel = aac.compare(ao, bo);
+                    if (rel == 0) {
+                        if (!bi.hasNext()) return true;
+                        if (!ai.hasNext()) return false;
+                        bo = bi.next();
+                        ao = ai.next();
+                    } else if (rel < 0) {
+                        if (!ai.hasNext()) return false;
+                        ao = ai.next();
+                    } else {
+                        return false;  
+                    }
+                }
+            }           
+        }
+        return a.containsAll(b);
+    }
+    
+    public static boolean containsNone(Collection a, Collection b) {
+        return !containsSome(a, b);
+    }
+    
+    /**
+     * Used for results of getContainmentRelation
+     */
+    public static final int
+        ALL_EMPTY = 0,
+        NOT_A_SUPERSET_B = 1,
+        NOT_A_DISJOINT_B = 2,
+        NOT_A_SUBSET_B = 4,
+        NOT_A_EQUALS_B = NOT_A_SUBSET_B | NOT_A_SUPERSET_B,
+        A_PROPER_SUBSET_OF_B = NOT_A_DISJOINT_B | NOT_A_SUPERSET_B,
+        A_PROPER_SUPERSET_B = NOT_A_SUBSET_B | NOT_A_DISJOINT_B,
+        A_PROPER_OVERLAPS_B = NOT_A_SUBSET_B | NOT_A_DISJOINT_B | NOT_A_SUPERSET_B;
+    
+    /**
+     * Assesses all the possible containment relations between collections A and B with one call.<br>
+     * Returns an int with bits set, according to a "Venn Diagram" view of A vs B.<br>
+     * NOT_A_SUPERSET_B: a - b != {}<br>
+     * NOT_A_DISJOINT_B: a * b != {}  // * is intersects<br>
+     * NOT_A_SUBSET_B: b - a != {}<br>
+     * Thus the bits can be used to get the following relations:<br>
+     * for A_SUPERSET_B, use (x & CollectionUtilities.NOT_A_SUPERSET_B) == 0<br>
+     * for A_SUBSET_B, use (x & CollectionUtilities.NOT_A_SUBSET_B) == 0<br>
+     * for A_EQUALS_B, use (x & CollectionUtilities.NOT_A_EQUALS_B) == 0<br>
+     * for A_DISJOINT_B, use (x & CollectionUtilities.NOT_A_DISJOINT_B) == 0<br>
+     * for A_OVERLAPS_B, use (x & CollectionUtilities.NOT_A_DISJOINT_B) != 0<br>
+     */
+     public static int getContainmentRelation(Collection a, Collection b) {
+        if (a.size() == 0) {
+            return (b.size() == 0) ? ALL_EMPTY : NOT_A_SUPERSET_B;
+        } else if (b.size() == 0) {
+            return NOT_A_SUBSET_B;
+        }
+        int result = 0;
+        // WARNING: one might think that the following can be short-circuited, by looking at
+        // the sizes of a and b. However, this would fail in general, where a different comparator is being
+        // used in the two collections. Unfortunately, there is no failsafe way to test for that.
+        for (Iterator it = a.iterator(); result != 6 && it.hasNext();) {
+            result |= (b.contains(it.next())) ? NOT_A_DISJOINT_B : NOT_A_SUBSET_B;
+        }
+        for (Iterator it = b.iterator(); (result & 3) != 3 && it.hasNext();) {
+            result |= (a.contains(it.next())) ? NOT_A_DISJOINT_B : NOT_A_SUPERSET_B;
+        }
+        return result;
+    }
+
+    public static String remove(String source, UnicodeSet removals) {
+        StringBuffer result = new StringBuffer();
+        int cp;
+        for (int i = 0; i < source.length(); i += UTF16.getCharCount(cp)) {
+            cp = UTF16.charAt(source, i);
+            if (!removals.contains(cp)) UTF16.append(result, cp);
+        }
+        return result.toString();
+    }
+
+//#if defined(FOUNDATION10) || defined(J2SE13)
+//#else
+     /**
+      * Does one string contain another, starting at a specific offset?
+      * @param text
+      * @param offset
+      * @param other
+      * @return
+      */
+        public static int matchesAt(CharSequence text, int offset, CharSequence other) {
+            int len = other.length();
+            int i = 0;
+            int j = offset;
+            for (; i < len; ++i, ++j) {
+                char pc = other.charAt(i);
+                char tc = text.charAt(j);
+                if (pc != tc) return -1;
+            }
+            return i;
+        }
+
+        /**
+         * Returns the ending offset found by matching characters with testSet, until a position is found that doen't match
+         * @param string
+         * @param offset
+         * @param testSet
+         * @return
+         */
+        public int span(CharSequence string, int offset, UnicodeSet testSet) {
+            while (true) {
+                int newOffset = testSet.matchesAt(string, offset);
+                if (newOffset < 0) return offset;
+            }
+        }
+
+        /**
+         * Returns the ending offset found by matching characters with testSet, until a position is found that does match
+         * @param string
+         * @param offset
+         * @param testSet
+         * @return
+         */
+        public int spanNot(CharSequence string, int offset, UnicodeSet testSet) {
+            while (true) {
+                int newOffset = testSet.matchesAt(string, offset);
+                if (newOffset >= 0) return offset;
+                ++offset; // try next character position
+                // we don't have to worry about surrogates for this.
+            }
+        }
+//#endif
+
+    public static String prettyPrint(UnicodeSet uset, boolean compressRanges, UnicodeSet toQuote, Transliterator quoter, 
+            Comparator ordering, Comparator spaceComparator) {
+        PrettyPrinter pp = new PrettyPrinter().setCompressRanges(compressRanges);
+        if (toQuote != null) pp.setToQuote(toQuote);
+        if (ordering != null) pp.setOrdering(ordering);
+        if (spaceComparator != null) pp.setSpaceComparator(spaceComparator);
+        return pp.toPattern(uset);
+    }
+    
+    public static class MultiComparator implements Comparator {
+        private Comparator[] comparators;
+    
+        public MultiComparator (Comparator[] comparators) {
+            this.comparators = comparators;
+        }
+    
+        /* Lexigraphic compare. Returns the first difference
+         * @return zero if equal. Otherwise +/- (i+1) 
+         * where i is the index of the first comparator finding a difference
+         * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
+         */
+        public int compare(Object arg0, Object arg1) {
+            for (int i = 0; i < comparators.length; ++i) {
+                int result = comparators[i].compare(arg0, arg1);
+                if (result == 0) continue;
+                if (result > 0) return i+1;
+                return -(i+1);
+            }
+            return 0;
+        }
+    }
+
+    /**
+     * Modifies Unicode set to flatten the strings. Eg [abc{da}] => [abcd]
+     * Returns the set for chaining.
+     * @param exemplar1
+     * @return
+     */
+    public static UnicodeSet flatten(UnicodeSet exemplar1) {
+        UnicodeSet result = new UnicodeSet();
+        boolean gotString = false;
+        for (UnicodeSetIterator it = new UnicodeSetIterator(exemplar1); it.nextRange();) {
+            if (it.codepoint == UnicodeSetIterator.IS_STRING) {
+                result.addAll(it.string);
+                gotString = true;
+            } else {
+                result.add(it.codepoint, it.codepointEnd);
+            }
+        }
+        if (gotString) exemplar1.set(result);
+        return exemplar1;
+    }
+
+    /**
+     * For producing filtered iterators
+     */
+    public static abstract class FilteredIterator implements Iterator {
+        private Iterator baseIterator;
+        private static final Object EMPTY = new Object();
+        private static final Object DONE = new Object();
+        private Object nextObject = EMPTY;
+        public FilteredIterator set(Iterator baseIterator) {
+            this.baseIterator = baseIterator;
+            return this;
+        }
+        public void remove() {
+            throw new UnsupportedOperationException("Doesn't support removal");
+        }
+        public Object next() {
+            Object result = nextObject;
+            nextObject = EMPTY;
+            return result;
+        }       
+        public boolean hasNext() {
+            if (nextObject == DONE) return false;
+            if (nextObject != EMPTY) return true;
+            while (baseIterator.hasNext()) {
+                nextObject = baseIterator.next();
+                if (isIncluded(nextObject)) {
+                    return true;
+                }
+            }
+            nextObject = DONE;
+            return false;
+        }
+        abstract public boolean isIncluded(Object item);
+    }
+    
+    public static class PrefixIterator extends FilteredIterator {
+        private String prefix;
+        public PrefixIterator set(Iterator baseIterator, String prefix) {
+            super.set(baseIterator);
+            this.prefix = prefix;
+            return this;
+        }
+        public boolean isIncluded(Object item) {
+            return ((String)item).startsWith(prefix);
+        }
+    }
+    
+//#if defined(FOUNDATION10) || defined(J2SE13)
+//#else
+    public static class RegexIterator extends FilteredIterator {
+        private Matcher matcher;
+        public RegexIterator set(Iterator baseIterator, Matcher matcher) {
+            super.set(baseIterator);
+            this.matcher = matcher;
+            return this;
+        }
+        public boolean isIncluded(Object item) {
+            return matcher.reset((String)item).matches();
+        }
+    }
+//#endif
+}