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 }