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