1 /**
2  *******************************************************************************
3  * Copyright (C) 1996-2001, International Business Machines Corporation and    *
4  * others. All Rights Reserved.                                                *
5  *******************************************************************************
6  *
7  * $Revision$
8  *
9  *******************************************************************************
10  */
11 
12 package org.unicode.cldr.util;
13 
14 import java.util.Collection;
15 import java.util.Comparator;
16 import java.util.Iterator;
17 import java.util.LinkedHashMap;
18 import java.util.LinkedHashSet;
19 import java.util.Map;
20 import java.util.Set;
21 import java.util.TreeMap;
22 import java.util.TreeSet;
23 
24 import com.ibm.icu.impl.Row;
25 import com.ibm.icu.impl.Row.R2;
26 
27 public class Counter<T> implements Iterable<T>, Comparable<Counter<T>> {
28     Map<T, RWLong> map;
29     Comparator<T> comparator;
30 
Counter()31     public Counter() {
32         this(null);
33     }
34 
Counter(boolean naturalOrdering)35     public Counter(boolean naturalOrdering) {
36         this(naturalOrdering ? new CldrUtility.ComparableComparator() : null);
37     }
38 
Counter(Comparator<T> comparator)39     public Counter(Comparator<T> comparator) {
40         if (comparator != null) {
41             this.comparator = comparator;
42             map = new TreeMap<>(comparator);
43         } else {
44             map = new LinkedHashMap<>();
45         }
46     }
47 
48     static private final class RWLong implements Comparable<RWLong> {
49         // the uniqueCount ensures that two different RWIntegers will always be different
50         static int uniqueCount;
51         public long value;
52         private final int forceUnique;
53         public long time;
54         {
55             synchronized (RWLong.class) { // make thread-safe
56                 forceUnique = uniqueCount++;
57             }
58         }
59 
60         @Override
compareTo(RWLong that)61         public int compareTo(RWLong that) {
62             if (that.value < value) return -1;
63             if (that.value > value) return 1;
64             if (this == that) return 0;
65             synchronized (this) { // make thread-safe
66                 if (that.forceUnique < forceUnique) return -1;
67             }
68             return 1; // the forceUnique values must be different, so this is the only remaining case
69         }
70 
71         @Override
toString()72         public String toString() {
73             return String.valueOf(value);
74         }
75 
76     }
77 
add(T obj, long countValue)78     public Counter<T> add(T obj, long countValue) {
79         RWLong count = map.get(obj);
80         if (count == null) map.put(obj, count = new RWLong());
81         count.value += countValue;
82         count.time = 0;
83         return this;
84     }
85 
add(T obj, long countValue, long time)86     public Counter<T> add(T obj, long countValue, long time) {
87         RWLong count = map.get(obj);
88         if (count == null) map.put(obj, count = new RWLong());
89         count.value += countValue;
90         count.time = time;
91         return this;
92     }
93 
add(T obj, long countValue, boolean boo)94     public Counter<T> add(T obj, long countValue, boolean boo) {
95         RWLong count = map.get(obj);
96         if (count == null) map.put(obj, count = new RWLong());
97         count.value = countValue;
98         count.time = 0;
99         return this;
100     }
101 
getCount(T obj)102     public long getCount(T obj) {
103         return get(obj);
104     }
105 
get(T obj)106     public long get(T obj) {
107         RWLong count = map.get(obj);
108         return count == null ? 0 : count.value;
109     }
110 
111     /**
112      * Get the time, or 0
113      * @param obj
114      * @return the time, or 0 as a fallback
115      */
getTime(T obj)116     public final long getTime(T obj) {
117         RWLong count = map.get(obj);
118         return count == null ? 0 : count.time;
119     }
120 
clear()121     public Counter<T> clear() {
122         map.clear();
123         return this;
124     }
125 
getTotal()126     public long getTotal() {
127         long count = 0;
128         for (T item : map.keySet()) {
129             count += map.get(item).value;
130         }
131         return count;
132     }
133 
getItemCount()134     public int getItemCount() {
135         return size();
136     }
137 
138     private static class Entry<T> {
139         RWLong count;
140         T value;
141         int uniqueness;
142 
Entry(RWLong count, T value, int uniqueness)143         public Entry(RWLong count, T value, int uniqueness) {
144             this.count = count;
145             this.value = value;
146             this.uniqueness = uniqueness;
147         }
148     }
149 
150     private static class EntryComparator<T> implements Comparator<Entry<T>> {
151         int countOrdering;
152         Comparator<T> byValue;
153 
EntryComparator(boolean ascending, Comparator<T> byValue)154         public EntryComparator(boolean ascending, Comparator<T> byValue) {
155             countOrdering = ascending ? 1 : -1;
156             this.byValue = byValue;
157         }
158 
159         @Override
compare(Entry<T> o1, Entry<T> o2)160         public int compare(Entry<T> o1, Entry<T> o2) {
161             if (o1.count.value < o2.count.value) return -countOrdering;
162             if (o1.count.value > o2.count.value) return countOrdering;
163             if (byValue != null) {
164                 return byValue.compare(o1.value, o2.value);
165             }
166             return o1.uniqueness - o2.uniqueness;
167         }
168     }
169 
getKeysetSortedByCount(boolean ascending)170     public Set<T> getKeysetSortedByCount(boolean ascending) {
171         return getKeysetSortedByCount(ascending, null);
172     }
173 
getKeysetSortedByCount(boolean ascending, Comparator<T> byValue)174     public Set<T> getKeysetSortedByCount(boolean ascending, Comparator<T> byValue) {
175         Set<Entry<T>> count_key = new TreeSet<>(new EntryComparator<>(ascending, byValue));
176         int counter = 0;
177         for (T key : map.keySet()) {
178             count_key.add(new Entry<>(map.get(key), key, counter++));
179         }
180         Set<T> result = new LinkedHashSet<>();
181         for (Entry<T> entry : count_key) {
182             result.add(entry.value);
183         }
184         return result;
185     }
186 
getEntrySetSortedByCount(boolean ascending, Comparator<T> byValue)187     public Set<Row.R2<Long, T>> getEntrySetSortedByCount(boolean ascending, Comparator<T> byValue) {
188         Set<Entry<T>> count_key = new TreeSet<>(new EntryComparator<>(ascending, byValue));
189         int counter = 0;
190         for (T key : map.keySet()) {
191             count_key.add(new Entry<>(map.get(key), key, counter++));
192         }
193         Set<R2<Long, T>> result = new LinkedHashSet<>();
194         for (Entry<T> entry : count_key) {
195             result.add(Row.of(entry.count.value, entry.value));
196         }
197         return result;
198     }
199 
getKeysetSortedByKey()200     public Set<T> getKeysetSortedByKey() {
201         Set<T> s = new TreeSet<>(comparator);
202         s.addAll(map.keySet());
203         return s;
204     }
205 
206     // public Map<T,RWInteger> getKeyToKey() {
207     // Map<T,RWInteger> result = new HashMap<T,RWInteger>();
208     // Iterator<T> it = map.keySet().iterator();
209     // while (it.hasNext()) {
210     // Object key = it.next();
211     // result.put(key, key);
212     // }
213     // return result;
214     // }
215 
keySet()216     public Set<T> keySet() {
217         return map.keySet();
218     }
219 
220     @Override
iterator()221     public Iterator<T> iterator() {
222         return map.keySet().iterator();
223     }
224 
getMap()225     public Map<T, RWLong> getMap() {
226         return map; // older code was protecting map, but not the integer values.
227     }
228 
size()229     public int size() {
230         return map.size();
231     }
232 
233     @Override
toString()234     public String toString() {
235         return map.toString();
236     }
237 
addAll(Collection<T> keys, int delta)238     public Counter<T> addAll(Collection<T> keys, int delta) {
239         for (T key : keys) {
240             long time = getTime(key);
241             add(key, delta, time);
242         }
243         return this;
244     }
245 
addAll(Counter<T> keys)246     public Counter<T> addAll(Counter<T> keys) {
247         for (T key : keys) {
248             long time = getTime(key);
249             add(key, keys.getCount(key), time);
250         }
251         return this;
252     }
253 
254     @Override
compareTo(Counter<T> o)255     public int compareTo(Counter<T> o) {
256         Iterator<T> i = map.keySet().iterator();
257         Iterator<T> j = o.map.keySet().iterator();
258         while (true) {
259             boolean goti = i.hasNext();
260             boolean gotj = j.hasNext();
261             if (!goti || !gotj) {
262                 return goti ? 1 : gotj ? -1 : 0;
263             }
264             T ii = i.next();
265             T jj = i.next();
266             int result = ((Comparable<T>) ii).compareTo(jj);
267             if (result != 0) {
268                 return result;
269             }
270             final long iv = map.get(ii).value;
271             final long jv = o.map.get(jj).value;
272             if (iv != jv) return iv < jv ? -1 : 0;
273         }
274     }
275 
increment(T key)276     public Counter<T> increment(T key) {
277         return add(key, 1, getTime(key));
278     }
279 
containsKey(T key)280     public boolean containsKey(T key) {
281         return map.containsKey(key);
282     }
283 
284     @Override
equals(Object o)285     public boolean equals(Object o) {
286         return map.equals(o);
287     }
288 
289     @Override
hashCode()290     public int hashCode() {
291         return map.hashCode();
292     }
293 
isEmpty()294     public boolean isEmpty() {
295         return map.isEmpty();
296     }
297 
remove(T key)298     public Counter<T> remove(T key) {
299         map.remove(key);
300         return this;
301     }
302 
303     // public RWLong put(T key, RWLong value) {
304     // return map.put(key, value);
305     // }
306     //
307     // public void putAll(Map<? extends T, ? extends RWLong> t) {
308     // map.putAll(t);
309     // }
310     //
311     // public Set<java.util.Map.Entry<T, Long>> entrySet() {
312     // return map.entrySet();
313     // }
314     //
315     // public Collection<RWLong> values() {
316     // return map.values();
317     // }
318 
319 }