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