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