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