1 /** 2 ******************************************************************************* 3 * Copyright (C) 1996-2001, International Business Machines Corporation and * 4 * others. All Rights Reserved. * 5 ******************************************************************************* 6 * 7 * $Revision: 13987 $ 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<T, RWLong>(comparator); 43 } else { 44 map = new LinkedHashMap<T, RWLong>(); 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 compareTo(RWLong that)60 public int compareTo(RWLong that) { 61 if (that.value < value) return -1; 62 if (that.value > value) return 1; 63 if (this == that) return 0; 64 synchronized (this) { // make thread-safe 65 if (that.forceUnique < forceUnique) return -1; 66 } 67 return 1; // the forceUnique values must be different, so this is the only remaining case 68 } 69 toString()70 public String toString() { 71 return String.valueOf(value); 72 } 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 * @param obj 112 * @return the time, or 0 as a fallback 113 */ getTime(T obj)114 public final long getTime(T obj) { 115 RWLong count = map.get(obj); 116 return count == null ? 0 : count.time; 117 } 118 clear()119 public Counter<T> clear() { 120 map.clear(); 121 return this; 122 } 123 getTotal()124 public long getTotal() { 125 long count = 0; 126 for (T item : map.keySet()) { 127 count += map.get(item).value; 128 } 129 return count; 130 } 131 getItemCount()132 public int getItemCount() { 133 return size(); 134 } 135 136 private static class Entry<T> { 137 RWLong count; 138 T value; 139 int uniqueness; 140 Entry(RWLong count, T value, int uniqueness)141 public Entry(RWLong count, T value, int uniqueness) { 142 this.count = count; 143 this.value = value; 144 this.uniqueness = uniqueness; 145 } 146 } 147 148 private static class EntryComparator<T> implements Comparator<Entry<T>> { 149 int countOrdering; 150 Comparator<T> byValue; 151 EntryComparator(boolean ascending, Comparator<T> byValue)152 public EntryComparator(boolean ascending, Comparator<T> byValue) { 153 countOrdering = ascending ? 1 : -1; 154 this.byValue = byValue; 155 } 156 compare(Entry<T> o1, Entry<T> o2)157 public int compare(Entry<T> o1, Entry<T> o2) { 158 if (o1.count.value < o2.count.value) return -countOrdering; 159 if (o1.count.value > o2.count.value) return countOrdering; 160 if (byValue != null) { 161 return byValue.compare(o1.value, o2.value); 162 } 163 return o1.uniqueness - o2.uniqueness; 164 } 165 } 166 getKeysetSortedByCount(boolean ascending)167 public Set<T> getKeysetSortedByCount(boolean ascending) { 168 return getKeysetSortedByCount(ascending, null); 169 } 170 getKeysetSortedByCount(boolean ascending, Comparator<T> byValue)171 public Set<T> getKeysetSortedByCount(boolean ascending, Comparator<T> byValue) { 172 Set<Entry<T>> count_key = new TreeSet<Entry<T>>(new EntryComparator<T>(ascending, byValue)); 173 int counter = 0; 174 for (T key : map.keySet()) { 175 count_key.add(new Entry<T>(map.get(key), key, counter++)); 176 } 177 Set<T> result = new LinkedHashSet<T>(); 178 for (Entry<T> entry : count_key) { 179 result.add(entry.value); 180 } 181 return result; 182 } 183 getEntrySetSortedByCount(boolean ascending, Comparator<T> byValue)184 public Set<Row.R2<Long, T>> getEntrySetSortedByCount(boolean ascending, Comparator<T> byValue) { 185 Set<Entry<T>> count_key = new TreeSet<Entry<T>>(new EntryComparator<T>(ascending, byValue)); 186 int counter = 0; 187 for (T key : map.keySet()) { 188 count_key.add(new Entry<T>(map.get(key), key, counter++)); 189 } 190 Set<R2<Long, T>> result = new LinkedHashSet<Row.R2<Long, T>>(); 191 for (Entry<T> entry : count_key) { 192 result.add(Row.of(entry.count.value, entry.value)); 193 } 194 return result; 195 } 196 getKeysetSortedByKey()197 public Set<T> getKeysetSortedByKey() { 198 Set<T> s = new TreeSet<T>(comparator); 199 s.addAll(map.keySet()); 200 return s; 201 } 202 203 // public Map<T,RWInteger> getKeyToKey() { 204 // Map<T,RWInteger> result = new HashMap<T,RWInteger>(); 205 // Iterator<T> it = map.keySet().iterator(); 206 // while (it.hasNext()) { 207 // Object key = it.next(); 208 // result.put(key, key); 209 // } 210 // return result; 211 // } 212 keySet()213 public Set<T> keySet() { 214 return map.keySet(); 215 } 216 iterator()217 public Iterator<T> iterator() { 218 return map.keySet().iterator(); 219 } 220 getMap()221 public Map<T, RWLong> getMap() { 222 return map; // older code was protecting map, but not the integer values. 223 } 224 size()225 public int size() { 226 return map.size(); 227 } 228 toString()229 public String toString() { 230 return map.toString(); 231 } 232 addAll(Collection<T> keys, int delta)233 public Counter<T> addAll(Collection<T> keys, int delta) { 234 for (T key : keys) { 235 long time = getTime(key); 236 add(key, delta, time); 237 } 238 return this; 239 } 240 addAll(Counter<T> keys)241 public Counter<T> addAll(Counter<T> keys) { 242 for (T key : keys) { 243 long time = getTime(key); 244 add(key, keys.getCount(key), time); 245 } 246 return this; 247 } 248 compareTo(Counter<T> o)249 public int compareTo(Counter<T> o) { 250 Iterator<T> i = map.keySet().iterator(); 251 Iterator<T> j = o.map.keySet().iterator(); 252 while (true) { 253 boolean goti = i.hasNext(); 254 boolean gotj = j.hasNext(); 255 if (!goti || !gotj) { 256 return goti ? 1 : gotj ? -1 : 0; 257 } 258 T ii = i.next(); 259 T jj = i.next(); 260 int result = ((Comparable<T>) ii).compareTo(jj); 261 if (result != 0) { 262 return result; 263 } 264 final long iv = map.get(ii).value; 265 final long jv = o.map.get(jj).value; 266 if (iv != jv) return iv < jv ? -1 : 0; 267 } 268 } 269 increment(T key)270 public Counter<T> increment(T key) { 271 return add(key, 1, getTime(key)); 272 } 273 containsKey(T key)274 public boolean containsKey(T key) { 275 return map.containsKey(key); 276 } 277 equals(Object o)278 public boolean equals(Object o) { 279 return map.equals(o); 280 } 281 hashCode()282 public int hashCode() { 283 return map.hashCode(); 284 } 285 isEmpty()286 public boolean isEmpty() { 287 return map.isEmpty(); 288 } 289 remove(T key)290 public Counter<T> remove(T key) { 291 map.remove(key); 292 return this; 293 } 294 295 // public RWLong put(T key, RWLong value) { 296 // return map.put(key, value); 297 // } 298 // 299 // public void putAll(Map<? extends T, ? extends RWLong> t) { 300 // map.putAll(t); 301 // } 302 // 303 // public Set<java.util.Map.Entry<T, Long>> entrySet() { 304 // return map.entrySet(); 305 // } 306 // 307 // public Collection<RWLong> values() { 308 // return map.values(); 309 // } 310 311 }