| /** |
| ******************************************************************************* |
| * Copyright (C) 1996-2010, International Business Machines Corporation and * |
| * others. All Rights Reserved. * |
| ******************************************************************************* |
| * |
| * $Date: 2009-08-07 15:01:31 -0700 (Fri, 07 Aug 2009) $ |
| * $Revision: 4231 $ |
| * |
| ******************************************************************************* |
| */ |
| |
| package com.ibm.icu.dev.test.collator; |
| |
| |
| import java.util.Collection; |
| import java.util.Comparator; |
| import java.util.Iterator; |
| import java.util.LinkedHashMap; |
| import java.util.LinkedHashSet; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.TreeMap; |
| import java.util.TreeSet; |
| |
| public class Counter<T> implements Iterable<T>, Comparable<Counter<T>> { |
| Map<T,RWLong> map; |
| Comparator<T> comparator; |
| |
| public Counter() { |
| this(null); |
| } |
| |
| public Counter(Comparator<T> comparator) { |
| if (comparator != null) { |
| this.comparator = comparator; |
| map = new TreeMap<T, RWLong>(comparator); |
| } else { |
| map = new LinkedHashMap<T, RWLong>(); |
| } |
| } |
| |
| static private final class RWLong implements Comparable<RWLong> { |
| // the uniqueCount ensures that two different RWIntegers will always be different |
| static int uniqueCount; |
| public long value; |
| private final int forceUnique; |
| { |
| synchronized (RWLong.class) { // make thread-safe |
| forceUnique = uniqueCount++; |
| } |
| } |
| |
| public int compareTo(RWLong that) { |
| if (that.value < value) return -1; |
| if (that.value > value) return 1; |
| if (this == that) return 0; |
| synchronized (this) { // make thread-safe |
| if (that.forceUnique < forceUnique) return -1; |
| } |
| return 1; // the forceUnique values must be different, so this is the only remaining case |
| } |
| public String toString() { |
| return String.valueOf(value); |
| } |
| } |
| |
| public Counter<T> add(T obj, long countValue) { |
| RWLong count = map.get(obj); |
| if (count == null) map.put(obj, count = new RWLong()); |
| count.value += countValue; |
| return this; |
| } |
| |
| public long getCount(T obj) { |
| return get(obj); |
| } |
| |
| public long get(T obj) { |
| RWLong count = map.get(obj); |
| return count == null ? 0 : count.value; |
| } |
| |
| public Counter<T> clear() { |
| map.clear(); |
| return this; |
| } |
| |
| public long getTotal() { |
| long count = 0; |
| for (T item : map.keySet()) { |
| count += map.get(item).value; |
| } |
| return count; |
| } |
| |
| public int getItemCount() { |
| return size(); |
| } |
| |
| private static class Entry<T> { |
| RWLong count; |
| T value; |
| int uniqueness; |
| public Entry(RWLong count, T value, int uniqueness) { |
| this.count = count; |
| this.value = value; |
| this.uniqueness = uniqueness; |
| } |
| } |
| |
| private static class EntryComparator<T> implements Comparator<Entry<T>>{ |
| int countOrdering; |
| Comparator<T> byValue; |
| |
| public EntryComparator(boolean ascending, Comparator<T> byValue) { |
| countOrdering = ascending ? 1 : -1; |
| this.byValue = byValue; |
| } |
| public int compare(Entry<T> o1, Entry<T> o2) { |
| if (o1.count.value < o2.count.value) return -countOrdering; |
| if (o1.count.value > o2.count.value) return countOrdering; |
| if (byValue != null) { |
| return byValue.compare(o1.value, o2.value); |
| } |
| return o1.uniqueness - o2.uniqueness; |
| } |
| } |
| |
| public Set<T> getKeysetSortedByCount(boolean ascending) { |
| return getKeysetSortedByCount(ascending, null); |
| } |
| |
| public Set<T> getKeysetSortedByCount(boolean ascending, Comparator<T> byValue) { |
| Set<Entry<T>> count_key = new TreeSet<Entry<T>>(new EntryComparator<T>(ascending, byValue)); |
| int counter = 0; |
| for (T key : map.keySet()) { |
| count_key.add(new Entry<T>(map.get(key), key, counter++)); |
| } |
| Set<T> result = new LinkedHashSet<T>(); |
| for (Entry<T> entry : count_key) { |
| result.add(entry.value); |
| } |
| return result; |
| } |
| |
| public Set<T> getKeysetSortedByKey() { |
| Set<T> s = new TreeSet<T>(comparator); |
| s.addAll(map.keySet()); |
| return s; |
| } |
| |
| //public Map<T,RWInteger> getKeyToKey() { |
| //Map<T,RWInteger> result = new HashMap<T,RWInteger>(); |
| //Iterator<T> it = map.keySet().iterator(); |
| //while (it.hasNext()) { |
| //Object key = it.next(); |
| //result.put(key, key); |
| //} |
| //return result; |
| //} |
| |
| public Set<T> keySet() { |
| return map.keySet(); |
| } |
| |
| public Iterator<T> iterator() { |
| return map.keySet().iterator(); |
| } |
| |
| public Map<T, RWLong> getMap() { |
| return map; // older code was protecting map, but not the integer values. |
| } |
| |
| public int size() { |
| return map.size(); |
| } |
| |
| public String toString() { |
| return map.toString(); |
| } |
| |
| public Counter<T> addAll(Collection<T> keys, int delta) { |
| for (T key : keys) { |
| add(key, delta); |
| } |
| return this; |
| } |
| |
| public Counter<T> addAll(Counter<T> keys) { |
| for (T key : keys) { |
| add(key, keys.getCount(key)); |
| } |
| return this; |
| } |
| |
| public int compareTo(Counter<T> o) { |
| Iterator<T> i = map.keySet().iterator(); |
| Iterator<T> j = o.map.keySet().iterator(); |
| while (true) { |
| boolean goti = i.hasNext(); |
| boolean gotj = j.hasNext(); |
| if (!goti || !gotj) { |
| return goti ? 1 : gotj ? -1 : 0; |
| } |
| T ii = i.next(); |
| T jj = i.next(); |
| int result = ((Comparable<T>)ii).compareTo(jj); |
| if (result != 0) { |
| return result; |
| } |
| final long iv = map.get(ii).value; |
| final long jv = o.map.get(jj).value; |
| if (iv != jv) return iv < jv ? -1 : 0; |
| } |
| } |
| |
| public Counter<T> increment(T key) { |
| return add(key, 1); |
| } |
| |
| public boolean containsKey(T key) { |
| return map.containsKey(key); |
| } |
| |
| public boolean equals(Object o) { |
| return map.equals(o); |
| } |
| |
| public int hashCode() { |
| return map.hashCode(); |
| } |
| |
| public boolean isEmpty() { |
| return map.isEmpty(); |
| } |
| |
| public Counter<T> remove(T key) { |
| map.remove(key); |
| return this; |
| } |
| |
| //public RWLong put(T key, RWLong value) { |
| // return map.put(key, value); |
| //} |
| // |
| //public void putAll(Map<? extends T, ? extends RWLong> t) { |
| // map.putAll(t); |
| //} |
| // |
| //public Set<java.util.Map.Entry<T, Long>> entrySet() { |
| // return map.entrySet(); |
| //} |
| // |
| //public Collection<RWLong> values() { |
| // return map.values(); |
| //} |
| |
| } |