• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // © 2017 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 package com.ibm.icu.impl.locale;
4 
5 import java.io.BufferedReader;
6 import java.io.File;
7 import java.io.InputStream;
8 import java.io.InputStreamReader;
9 import java.net.URL;
10 import java.nio.charset.Charset;
11 import java.util.Arrays;
12 import java.util.Collection;
13 import java.util.Collections;
14 import java.util.HashMap;
15 import java.util.HashSet;
16 import java.util.Iterator;
17 import java.util.LinkedHashMap;
18 import java.util.LinkedHashSet;
19 import java.util.List;
20 import java.util.Map;
21 import java.util.Map.Entry;
22 import java.util.Set;
23 import java.util.TreeMap;
24 import java.util.TreeSet;
25 import java.util.regex.Matcher;
26 import java.util.regex.Pattern;
27 
28 import com.ibm.icu.util.ICUException;
29 import com.ibm.icu.util.ICUUncheckedIOException;
30 
31 /**
32  * Stub class to make migration easier until we get either Guava or a higher level of Java.
33  */
34 public class XCldrStub {
35 
36     public static class Multimap<K, V> {
37         private final Map<K,Set<V>> map;
38         private final Class<Set<V>> setClass;
39 
40         @SuppressWarnings("unchecked")
Multimap(Map<K,Set<V>> map, Class<?> setClass)41         private Multimap(Map<K,Set<V>> map, Class<?> setClass) {
42             this.map = map;
43             this.setClass = (Class<Set<V>>) (setClass != null
44                     ? setClass
45                             : HashSet.class);
46         }
47         @SafeVarargs
48         @SuppressWarnings("varargs")    // Not supported by Eclipse, but we need this for javac
putAll(K key, V... values)49         public final Multimap<K, V> putAll(K key, V... values) {
50             if (values.length != 0) {
51                 createSetIfMissing(key).addAll(Arrays.asList(values));
52             }
53             return this;
54         }
putAll(K key, Collection<V> values)55         public void putAll(K key, Collection<V> values) {
56             if (!values.isEmpty()) {
57                 createSetIfMissing(key).addAll(values);
58             }
59         }
putAll(Collection<K> keys, V value)60         public void putAll(Collection<K> keys, V value) {
61             for (K key : keys) {
62                 put(key, value);
63             }
64         }
putAll(Multimap<K, V> source)65         public void putAll(Multimap<K, V> source) {
66             for (Entry<K, Set<V>> entry : source.map.entrySet()) {
67                 putAll(entry.getKey(), entry.getValue());
68             }
69         }
put(K key, V value)70         public void put(K key, V value) {
71             createSetIfMissing(key).add(value);
72         }
createSetIfMissing(K key)73         private Set<V> createSetIfMissing(K key) {
74             Set<V> old = map.get(key);
75             if (old == null) {
76                 map.put(key, old = getInstance());
77             }
78             return old;
79         }
getInstance()80         private Set<V> getInstance() {
81             try {
82                 return setClass.newInstance();
83             } catch (Exception e) {
84                 throw new ICUException(e);
85             }
86         }
get(K key)87         public Set<V> get(K key) {
88             Set<V> result = map.get(key);
89             return result; //  == null ? Collections.<V>emptySet() : result;
90         }
keySet()91         public Set<K> keySet() {
92             return map.keySet();
93         }
asMap()94         public Map<K, Set<V>> asMap() {
95             return map;
96         }
values()97         public Set<V> values() {
98             Collection<Set<V>> values = map.values();
99             if (values.size() == 0) {
100                 return Collections.<V>emptySet();
101             }
102             Set<V> result = getInstance();
103             for ( Set<V> valueSet : values) {
104                 result.addAll(valueSet);
105             }
106             return result;
107         }
size()108         public int size() {
109             return map.size();
110         }
entries()111         public Iterable<Entry<K, V>> entries() {
112             return new MultimapIterator<>(map);
113         }
114         @Override
equals(Object obj)115         public boolean equals(Object obj) {
116             return this == obj ||
117                     (obj != null
118                     && obj.getClass() == this.getClass()
119                     && map.equals(((Multimap<?,?>) obj).map));
120         }
121 
122         @Override
hashCode()123         public int hashCode() {
124             return map.hashCode();
125         }
126     }
127 
128     public static class Multimaps {
invertFrom(Multimap<V, K> source, R target)129         public static <K, V, R extends Multimap<K, V>> R invertFrom(Multimap<V, K> source, R target) {
130             for (Entry<V, Set<K>> entry : source.asMap().entrySet()) {
131                 target.putAll(entry.getValue(), entry.getKey());
132             }
133             return target;
134         }
invertFrom(Map<V, K> source, R target)135         public static <K, V, R extends Multimap<K, V>> R invertFrom(Map<V, K> source, R target) {
136             for (Entry<V, K> entry : source.entrySet()) {
137                 target.put(entry.getValue(), entry.getKey());
138             }
139             return target;
140         }
141         /**
142          * Warning, not functionally the same as Guava; only for use in invertFrom.
143          */
forMap(Map<K,V> map)144         public static <K, V> Map<K,V> forMap(Map<K,V> map) {
145             return map;
146         }
147     }
148 
149     private static class MultimapIterator<K,V> implements Iterator<Entry<K,V>>, Iterable<Entry<K,V>> {
150         private final Iterator<Entry<K, Set<V>>> it1;
151         private Iterator<V> it2 = null;
152         private final ReusableEntry<K,V> entry = new ReusableEntry<>();
153 
MultimapIterator(Map<K,Set<V>> map)154         private MultimapIterator(Map<K,Set<V>> map) {
155             it1 = map.entrySet().iterator();
156         }
157         @Override
hasNext()158         public boolean hasNext() {
159             return it1.hasNext() || it2 != null && it2.hasNext();
160         }
161         @Override
next()162         public Entry<K, V> next() {
163             if (it2 != null && it2.hasNext()) {
164                 entry.value = it2.next();
165             } else {
166                 Entry<K, Set<V>> e = it1.next();
167                 entry.key = e.getKey();
168                 it2 = e.getValue().iterator();
169             }
170             return entry;
171         }
172         @Override
iterator()173         public Iterator<Entry<K, V>> iterator() {
174             return this;
175         }
176         @Override
remove()177         public void remove() {
178             throw new UnsupportedOperationException();
179         }
180     }
181 
182     private static class ReusableEntry<K,V> implements Entry<K,V> {
183         K key;
184         V value;
185         @Override
getKey()186         public K getKey() {
187             return key;
188         }
189         @Override
getValue()190         public V getValue() {
191             return value;
192         }
193         @Override
setValue(V value)194         public V setValue(V value) {
195             throw new UnsupportedOperationException();
196         }
197     }
198 
199     public static class HashMultimap<K, V> extends Multimap<K, V> {
HashMultimap()200         private HashMultimap() {
201             super(new HashMap<K, Set<V>>(), HashSet.class);
202         }
create()203         public static <K, V> HashMultimap<K, V> create() {
204             return new HashMultimap<>();
205         }
206     }
207 
208     public static class TreeMultimap<K, V> extends Multimap<K, V> {
TreeMultimap()209         private TreeMultimap() {
210             super(new TreeMap<K, Set<V>>(), TreeSet.class);
211         }
create()212         public static <K, V> TreeMultimap<K, V> create() {
213             return new TreeMultimap<>();
214         }
215     }
216 
217     public static class LinkedHashMultimap<K, V> extends Multimap<K, V> {
LinkedHashMultimap()218         private LinkedHashMultimap() {
219             super(new LinkedHashMap<K, Set<V>>(), LinkedHashSet.class);
220         }
create()221         public static <K, V> LinkedHashMultimap<K, V> create() {
222             return new LinkedHashMultimap<>();
223         }
224     }
225 
226 
227     //    public static class Counter<T> implements Iterable<T>{
228     //        private Map<T,Long> data;
229     //        @Override
230     //        public Iterator<T> iterator() {
231     //            return data.keySet().iterator();
232     //        }
233     //        public long get(T s) {
234     //            Long result = data.get(s);
235     //            return result != null ? result : 0L;
236     //        }
237     //        public void add(T item, int count) {
238     //            Long result = data.get(item);
239     //            data.put(item, result == null ? count : result + count);
240     //        }
241     //    }
242 
join(T[] source, String separator)243     public static <T> String join(T[] source, String separator) {
244         StringBuilder result = new StringBuilder();
245         for (int i = 0; i < source.length; ++i) {
246             if (i != 0) result.append(separator);
247             result.append(source[i]);
248         }
249         return result.toString();
250     }
251 
join(Iterable<T> source, String separator)252     public static <T> String join(Iterable<T> source, String separator) {
253         StringBuilder result = new StringBuilder();
254         boolean first = true;
255         for (T item : source) {
256             if (!first) result.append(separator);
257             else first = false;
258             result.append(item.toString());
259         }
260         return result.toString();
261     }
262 
263     public static class CollectionUtilities {
join(U source, String separator)264         public static <T, U extends Iterable<T>> String join(U source, String separator) {
265             return XCldrStub.join(source, separator);
266         }
267     }
268 
269     public static class Joiner {
270         private final String separator;
Joiner(String separator)271         private Joiner(String separator) {
272             this.separator = separator;
273         }
on(String separator)274         public static final Joiner on(String separator) {
275             return new Joiner(separator);
276         }
join(T[] source)277         public <T> String join(T[] source) {
278             return XCldrStub.join(source, separator);
279         }
join(Iterable<T> source)280         public <T> String join(Iterable<T> source) {
281             return XCldrStub.join(source, separator);
282         }
283     }
284 
285     public static class Splitter {
286         Pattern pattern;
287         boolean trimResults = false;
Splitter(char c)288         public Splitter(char c) {
289             this(Pattern.compile("\\Q" + c + "\\E"));
290         }
Splitter(Pattern p)291         public Splitter(Pattern p) {
292             pattern = p;
293         }
on(char c)294         public static Splitter on(char c) {
295             return new Splitter(c);
296         }
on(Pattern p)297         public static Splitter on(Pattern p) {
298             return new Splitter(p);
299         }
splitToList(String input)300         public List<String> splitToList(String input) {
301             String[] items = pattern.split(input);
302             if (trimResults) {
303                 for (int i = 0; i < items.length; ++i) {
304                     items[i] = items[i].trim();
305                 }
306             }
307             return Arrays.asList(items);
308         }
trimResults()309         public Splitter trimResults() {
310             trimResults = true;
311             return this;
312         }
split(String input)313         public Iterable<String> split(String input) {
314             return splitToList(input);
315         }
316     }
317 
318     public static class ImmutableSet {
copyOf(Set<T> values)319         public static <T> Set<T> copyOf(Set<T> values) {
320             return Collections.unmodifiableSet(new LinkedHashSet<>(values)); // copy set for safety, preserve order
321         }
322     }
323     public static class ImmutableMap {
copyOf(Map<K,V> values)324         public static <K,V> Map<K,V> copyOf(Map<K,V> values) {
325             return Collections.unmodifiableMap(new LinkedHashMap<>(values)); // copy set for safety, preserve order
326         }
327     }
328     public static class ImmutableMultimap {
copyOf(Multimap<K,V> values)329         public static <K,V> Multimap<K,V> copyOf(Multimap<K,V> values) {
330             LinkedHashMap<K, Set<V>> temp = new LinkedHashMap<>(); // semi-deep copy, preserve order
331             for (Entry<K, Set<V>> entry : values.asMap().entrySet()) {
332                 Set<V> value = entry.getValue();
333                 temp.put(entry.getKey(), value.size() == 1
334                         ? Collections.singleton(value.iterator().next())
335                                 : Collections.unmodifiableSet(new LinkedHashSet<>(value)));
336             }
337             return new Multimap<>(Collections.unmodifiableMap(temp), null);
338         }
339     }
340 
341     public static class FileUtilities {
342         public static final Charset UTF8 = Charset.forName("utf-8");
343 
openFile(Class<?> class1, String file)344         public static BufferedReader openFile(Class<?> class1, String file) {
345             return openFile(class1, file, UTF8);
346         }
347 
openFile(Class<?> class1, String file, Charset charset)348         public static BufferedReader openFile(Class<?> class1, String file, Charset charset) {
349             // URL path = null;
350             // String externalForm = null;
351             try {
352                 final InputStream resourceAsStream = class1.getResourceAsStream(file);
353                 if (charset == null) {
354                     charset = UTF8;
355                 }
356                 InputStreamReader reader = new InputStreamReader(resourceAsStream, charset);
357                 BufferedReader bufferedReader = new BufferedReader(reader, 1024 * 64);
358                 return bufferedReader;
359             } catch (Exception e) {
360                 String className = class1 == null ? null : class1.getCanonicalName();
361                 String canonicalName = null;
362                 try {
363                     String relativeFileName = getRelativeFileName(class1, "../util/");
364                     canonicalName = new File(relativeFileName).getCanonicalPath();
365                 } catch (Exception e1) {
366                     throw new ICUUncheckedIOException("Couldn't open file: " + file + "; relative to class: "
367                             + className, e);
368                 }
369                 throw new ICUUncheckedIOException("Couldn't open file " + file + "; in path " + canonicalName + "; relative to class: "
370                         + className, e);
371             }
372         }
getRelativeFileName(Class<?> class1, String filename)373         public static String getRelativeFileName(Class<?> class1, String filename) {
374             URL resource = class1 == null ?
375                     FileUtilities.class.getResource(filename) : class1.getResource(filename);
376                     String resourceString = resource.toString();
377                     if (resourceString.startsWith("file:")) {
378                         return resourceString.substring(5);
379                     } else if (resourceString.startsWith("jar:file:")) {
380                         return resourceString.substring(9);
381                     } else {
382                         throw new ICUUncheckedIOException("File not found: " + resourceString);
383                     }
384         }
385     }
386 
387     static public class RegexUtilities {
findMismatch(Matcher m, CharSequence s)388         public static int findMismatch(Matcher m, CharSequence s) {
389             int i;
390             for (i = 1; i < s.length(); ++i) {
391                 boolean matches = m.reset(s.subSequence(0, i)).matches();
392                 if (!matches && !m.hitEnd()) {
393                     break;
394                 }
395             }
396             return i - 1;
397         }
showMismatch(Matcher m, CharSequence s)398         public static String showMismatch(Matcher m, CharSequence s) {
399             int failPoint = findMismatch(m, s);
400             String show = s.subSequence(0, failPoint) + "☹" + s.subSequence(failPoint, s.length());
401             return show;
402         }
403     }
404 
405     public interface Predicate<T> {
406         /**
407          * Evaluates this predicate on the given argument.
408          *
409          * @param t the input argument
410          * @return {@code true} if the input argument matches the predicate,
411          * otherwise {@code false}
412          */
test(T t)413         boolean test(T t);
414     }
415 }
416