// © 2017 and later: Unicode, Inc. and others. // License & terms of use: http://www.unicode.org/copyright.html#License package com.ibm.icu.impl.locale; import java.io.BufferedReader; import java.io.File; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; import java.nio.charset.Charset; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.ibm.icu.util.ICUException; import com.ibm.icu.util.ICUUncheckedIOException; /** * Stub class to make migration easier until we get either Guava or a higher level of Java. */ public class XCldrStub { public static class Multimap { private final Map> map; private final Class> setClass; @SuppressWarnings("unchecked") private Multimap(Map> map, Class setClass) { this.map = map; this.setClass = (Class>) (setClass != null ? setClass : HashSet.class); } public Multimap putAll(K key, V... values) { if (values.length != 0) { createSetIfMissing(key).addAll(Arrays.asList(values)); } return this; } public void putAll(K key, Collection values) { if (!values.isEmpty()) { createSetIfMissing(key).addAll(values); } } public void putAll(Collection keys, V value) { for (K key : keys) { put(key, value); } } public void putAll(Multimap source) { for (Entry> entry : source.map.entrySet()) { putAll(entry.getKey(), entry.getValue()); } } public void put(K key, V value) { createSetIfMissing(key).add(value); } private Set createSetIfMissing(K key) { Set old = map.get(key); if (old == null) { map.put(key, old = getInstance()); } return old; } private Set getInstance() { try { return setClass.newInstance(); } catch (Exception e) { throw new ICUException(e); } } public Set get(K key) { Set result = map.get(key); return result; // == null ? Collections.emptySet() : result; } public Set keySet() { return map.keySet(); } public Map> asMap() { return map; } public Set values() { Collection> values = map.values(); if (values.size() == 0) { return Collections.emptySet(); } Set result = getInstance(); for ( Set valueSet : values) { result.addAll(valueSet); } return result; } public int size() { return map.size(); } public Iterable> entries() { return new MultimapIterator(map); } @Override public boolean equals(Object obj) { return this == obj || (obj != null && obj.getClass() == this.getClass() && map.equals(((Multimap) obj).map)); } @Override public int hashCode() { return map.hashCode(); } } public static class Multimaps { public static > R invertFrom(Multimap source, R target) { for (Entry> entry : source.asMap().entrySet()) { target.putAll(entry.getValue(), entry.getKey()); } return target; } public static > R invertFrom(Map source, R target) { for (Entry entry : source.entrySet()) { target.put(entry.getValue(), entry.getKey()); } return target; } /** * Warning, not functionally the same as Guava; only for use in invertFrom. */ public static Map forMap(Map map) { return map; } } private static class MultimapIterator implements Iterator>, Iterable> { private final Iterator>> it1; private Iterator it2 = null; private final ReusableEntry entry = new ReusableEntry(); private MultimapIterator(Map> map) { it1 = map.entrySet().iterator(); } @Override public boolean hasNext() { return it1.hasNext() || it2 != null && it2.hasNext(); } @Override public Entry next() { if (it2 != null && it2.hasNext()) { entry.value = it2.next(); } else { Entry> e = it1.next(); entry.key = e.getKey(); it2 = e.getValue().iterator(); } return entry; } @Override public Iterator> iterator() { return this; } @Override public void remove() { throw new UnsupportedOperationException(); } } private static class ReusableEntry implements Entry { K key; V value; @Override public K getKey() { return key; } @Override public V getValue() { return value; } @Override public V setValue(V value) { throw new UnsupportedOperationException(); } } public static class HashMultimap extends Multimap { private HashMultimap() { super(new HashMap>(), HashSet.class); } public static HashMultimap create() { return new HashMultimap(); } } public static class TreeMultimap extends Multimap { private TreeMultimap() { super(new TreeMap>(), TreeSet.class); } public static TreeMultimap create() { return new TreeMultimap(); } } public static class LinkedHashMultimap extends Multimap { private LinkedHashMultimap() { super(new LinkedHashMap>(), LinkedHashSet.class); } public static LinkedHashMultimap create() { return new LinkedHashMultimap(); } } // public static class Counter implements Iterable{ // private Map data; // @Override // public Iterator iterator() { // return data.keySet().iterator(); // } // public long get(T s) { // Long result = data.get(s); // return result != null ? result : 0L; // } // public void add(T item, int count) { // Long result = data.get(item); // data.put(item, result == null ? count : result + count); // } // } public static String join(T[] source, String separator) { StringBuilder result = new StringBuilder(); for (int i = 0; i < source.length; ++i) { if (i != 0) result.append(separator); result.append(source[i]); } return result.toString(); } public static String join(Iterable source, String separator) { StringBuilder result = new StringBuilder(); boolean first = true; for (T item : source) { if (!first) result.append(separator); else first = false; result.append(item.toString()); } return result.toString(); } public static class CollectionUtilities { public static > String join(U source, String separator) { return XCldrStub.join(source, separator); } } public static class Joiner { private final String separator; private Joiner(String separator) { this.separator = separator; } public static final Joiner on(String separator) { return new Joiner(separator); } public String join(T[] source) { return XCldrStub.join(source, separator); } public String join(Iterable source) { return XCldrStub.join(source, separator); } } public static class Splitter { Pattern pattern; boolean trimResults = false; public Splitter(char c) { this(Pattern.compile("\\Q" + c + "\\E")); } public Splitter(Pattern p) { pattern = p; } public static Splitter on(char c) { return new Splitter(c); } public static Splitter on(Pattern p) { return new Splitter(p); } public List splitToList(String input) { String[] items = pattern.split(input); if (trimResults) { for (int i = 0; i < items.length; ++i) { items[i] = items[i].trim(); } } return Arrays.asList(items); } public Splitter trimResults() { trimResults = true; return this; } public Iterable split(String input) { return splitToList(input); } } public static class ImmutableSet { public static Set copyOf(Set values) { return Collections.unmodifiableSet(new LinkedHashSet(values)); // copy set for safety, preserve order } } public static class ImmutableMap { public static Map copyOf(Map values) { return Collections.unmodifiableMap(new LinkedHashMap(values)); // copy set for safety, preserve order } } public static class ImmutableMultimap { public static Multimap copyOf(Multimap values) { LinkedHashMap> temp = new LinkedHashMap>(); // semi-deep copy, preserve order for (Entry> entry : values.asMap().entrySet()) { Set value = entry.getValue(); temp.put(entry.getKey(), value.size() == 1 ? Collections.singleton(value.iterator().next()) : Collections.unmodifiableSet(new LinkedHashSet(value))); } return new Multimap(Collections.unmodifiableMap(temp), null); } } public static class FileUtilities { public static final Charset UTF8 = Charset.forName("utf-8"); public static BufferedReader openFile(Class class1, String file) { return openFile(class1, file, UTF8); } public static BufferedReader openFile(Class class1, String file, Charset charset) { // URL path = null; // String externalForm = null; try { final InputStream resourceAsStream = class1.getResourceAsStream(file); if (charset == null) { charset = UTF8; } InputStreamReader reader = new InputStreamReader(resourceAsStream, charset); BufferedReader bufferedReader = new BufferedReader(reader, 1024 * 64); return bufferedReader; } catch (Exception e) { String className = class1 == null ? null : class1.getCanonicalName(); String canonicalName = null; try { String relativeFileName = getRelativeFileName(class1, "../util/"); canonicalName = new File(relativeFileName).getCanonicalPath(); } catch (Exception e1) { throw new ICUUncheckedIOException("Couldn't open file: " + file + "; relative to class: " + className, e); } throw new ICUUncheckedIOException("Couldn't open file " + file + "; in path " + canonicalName + "; relative to class: " + className, e); } } public static String getRelativeFileName(Class class1, String filename) { URL resource = class1 == null ? FileUtilities.class.getResource(filename) : class1.getResource(filename); String resourceString = resource.toString(); if (resourceString.startsWith("file:")) { return resourceString.substring(5); } else if (resourceString.startsWith("jar:file:")) { return resourceString.substring(9); } else { throw new ICUUncheckedIOException("File not found: " + resourceString); } } } static public class RegexUtilities { public static int findMismatch(Matcher m, CharSequence s) { int i; for (i = 1; i < s.length(); ++i) { boolean matches = m.reset(s.subSequence(0, i)).matches(); if (!matches && !m.hitEnd()) { break; } } return i - 1; } public static String showMismatch(Matcher m, CharSequence s) { int failPoint = findMismatch(m, s); String show = s.subSequence(0, failPoint) + "☹" + s.subSequence(failPoint, s.length()); return show; } } public interface Predicate { /** * Evaluates this predicate on the given argument. * * @param t the input argument * @return {@code true} if the input argument matches the predicate, * otherwise {@code false} */ boolean test(T t); } }