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}