-//##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
+}