Clover coverage report - PLT Utilities Test Coverage (plt-20120304-r5436)
Coverage timestamp: Sat Mar 3 2012 22:01:56 CST
file stats: LOC: 240   Methods: 31
NCLOC: 161   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
HashMultiset.java 12.5% 16.2% 19.4% 15.9%
coverage coverage
 1    /*BEGIN_COPYRIGHT_BLOCK*
 2   
 3    PLT Utilities BSD License
 4   
 5    Copyright (c) 2007-2010 JavaPLT group at Rice University
 6    All rights reserved.
 7   
 8    Developed by: Java Programming Languages Team
 9    Rice University
 10    http://www.cs.rice.edu/~javaplt/
 11   
 12    Redistribution and use in source and binary forms, with or without modification, are permitted
 13    provided that the following conditions are met:
 14   
 15    - Redistributions of source code must retain the above copyright notice, this list of conditions
 16    and the following disclaimer.
 17    - Redistributions in binary form must reproduce the above copyright notice, this list of
 18    conditions and the following disclaimer in the documentation and/or other materials provided
 19    with the distribution.
 20    - Neither the name of the JavaPLT group, Rice University, nor the names of the library's
 21    contributors may be used to endorse or promote products derived from this software without
 22    specific prior written permission.
 23   
 24    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
 25    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 26    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND
 27    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 28    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 29    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
 30    IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 31    OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 32   
 33    *END_COPYRIGHT_BLOCK*/
 34   
 35    package edu.rice.cs.plt.collect;
 36   
 37    import java.util.Collection;
 38    import java.util.AbstractCollection;
 39    import java.util.Map;
 40    import java.util.HashMap;
 41    import java.util.Iterator;
 42    import java.io.Serializable;
 43    import edu.rice.cs.plt.iter.IterUtil;
 44    import edu.rice.cs.plt.tuple.Option;
 45   
 46    /**
 47    * A {@link HashMap}-based implementation of {@link Multiset}. Values in the set
 48    * must be valid as keys in a {@code HashMap}. Care is taken so that most operations
 49    * are either performed in constant time or time linear to the number of <em>unique</em>
 50    * elements in the multiset (as opposed to time linear in the size of the multiset, which
 51    * may be significantly larger).
 52    */
 53    public class HashMultiset<T> extends AbstractCollection<T> implements Multiset<T>, Serializable {
 54   
 55    private HashMap<T, Integer> _counts;
 56    private int _size;
 57   
 58    /** Create an empty {@code HashMultiset} */
 59  569 public HashMultiset() { _counts = new HashMap<T, Integer>(); }
 60   
 61    /** Create a {@code HashMultiset} containing all the elements of {@code coll} */
 62  0 public HashMultiset(Collection<? extends T> coll) {
 63  0 this();
 64  0 addAll(coll);
 65    }
 66   
 67  0 public int size() { return _size; }
 68  0 public int size(int bound) { return _size < bound ? _size : bound; }
 69  0 public boolean isInfinite() { return false; }
 70  0 public boolean hasFixedSize() { return false; }
 71  0 public boolean isStatic() { return false; }
 72  0 @Override public boolean isEmpty() { return _size == 0; }
 73   
 74  1152 @Override public boolean contains(Object obj) { return _counts.containsKey(obj); }
 75   
 76  0 @Override public boolean containsAll(Collection<?> c) {
 77  0 for (Object obj : asMultiset(c).asSet()) { if (!contains(obj)) { return false; } }
 78  0 return true;
 79    }
 80   
 81  0 public boolean isSupersetOf(Multiset<?> m) {
 82  0 for (Object elt : m.asSet()) {
 83  0 if (m.count(elt) > count(elt)) { return false; }
 84    }
 85  0 return true;
 86    }
 87   
 88  1152 public int count(Object value) {
 89  577 if (_counts.containsKey(value)) { return _counts.get(value); }
 90  575 else { return 0; }
 91    }
 92   
 93    /**
 94    * Produce a set view of the multiset. Removing a value from the set is the equivalent
 95    * of invoking {@link #removeAllInstances} for that value. Adding to the set is not supported.
 96    */
 97  0 public PredicateSet<T> asSet() { return CollectUtil.asPredicateSet(_counts.keySet()); }
 98   
 99  0 public Iterator<T> iterator() {
 100  0 final Iterator<Map.Entry<T, Integer>> entries = _counts.entrySet().iterator();
 101  0 return new Iterator<T>() {
 102    private Map.Entry<T, Integer> _current = null;
 103    private int _currentCount = 0;
 104    private boolean _removed = false;
 105   
 106  0 public boolean hasNext() { return _currentCount > 0 || entries.hasNext(); }
 107   
 108  0 public T next() {
 109  0 if (_currentCount == 0) {
 110  0 _current = entries.next();
 111  0 _currentCount = _current.getValue();
 112    }
 113  0 _removed = false;
 114  0 _currentCount--;
 115  0 return _current.getKey();
 116    }
 117   
 118  0 public void remove() {
 119  0 if (_current == null || _removed) { throw new IllegalStateException(); }
 120    else {
 121  0 _removed = true;
 122  0 _size--;
 123  0 int oldCount = _current.getValue();
 124  0 if (oldCount == 1) { entries.remove(); }
 125  0 else { _current.setValue(oldCount - 1); }
 126    }
 127    }
 128   
 129    };
 130    }
 131   
 132  576 @Override public boolean add(T val) {
 133  576 _counts.put(val, count(val) + 1);
 134  576 _size++;
 135  576 return true;
 136    }
 137   
 138  0 public boolean add(T val, int instances) {
 139  0 _counts.put(val, count(val) + instances);
 140  0 _size += instances;
 141  0 return true;
 142    }
 143   
 144  0 @Override public boolean addAll(Collection<? extends T> coll) {
 145  0 boolean result = false;
 146  0 Multiset<? extends T> collMultiset = asMultiset(coll);
 147  0 for (T entry : collMultiset.asSet()) {
 148  0 result |= add(entry, collMultiset.count(entry));
 149    }
 150  0 return result;
 151    }
 152   
 153  576 @Override public boolean remove(Object obj) {
 154  576 Option<T> cast = CollectUtil.castIfContains(this, obj);
 155  576 if (cast.isSome()) { doRemove(cast.unwrap(), 1); return true; }
 156  0 else { return false; }
 157    }
 158   
 159  0 public boolean remove(Object obj, int instances) {
 160  0 Option<T> cast = CollectUtil.castIfContains(this, obj);
 161  0 if (cast.isSome()) { doRemove(cast.unwrap(), instances); return true; }
 162  0 else { return false; }
 163    }
 164   
 165  0 public boolean removeAllInstances(Object obj) {
 166  0 Option<T> cast = CollectUtil.castIfContains(this, obj);
 167  0 if (cast.isSome()) { doRemove(cast.unwrap(), count(obj)); return true; }
 168  0 else { return false; }
 169    }
 170   
 171  576 private void doRemove(T key, int instances) {
 172  576 int newCount = count(key) - instances;
 173  576 if (newCount <= 0) {
 174  575 int actualInstances = _counts.remove(key);
 175  575 _size -= actualInstances;
 176    }
 177    else {
 178  1 _counts.put(key, newCount);
 179  1 _size -= instances;
 180    }
 181    }
 182   
 183  0 @Override public boolean removeAll(Collection<?> coll) {
 184  0 boolean result = false;
 185  0 Multiset<?> collMultiset = asMultiset(coll);
 186  0 for (Object obj : collMultiset.asSet()) { result |= remove(obj, collMultiset.count(obj)); }
 187  0 return result;
 188    }
 189   
 190  0 @Override public boolean retainAll(Collection<?> coll) {
 191  0 boolean result = false;
 192  0 Multiset<?> collMultiset = asMultiset(coll);
 193  0 Iterator<Map.Entry<T, Integer>> iter = _counts.entrySet().iterator();
 194  0 while (iter.hasNext()) {
 195  0 Map.Entry<T, Integer> entry = iter.next();
 196  0 if (collMultiset.contains(entry.getKey())) {
 197  0 int newCount = collMultiset.count(entry.getKey());
 198  0 if (entry.getValue() > newCount) {
 199  0 _size -= (entry.getValue() - newCount);
 200  0 entry.setValue(newCount);
 201  0 result = true;
 202    }
 203    }
 204  0 else { _size -= entry.getValue(); iter.remove(); result = true; }
 205    }
 206  0 return result;
 207    }
 208   
 209  0 @Override public void clear() { _counts.clear(); }
 210   
 211  0 public String toString() { return IterUtil.toString(this); }
 212   
 213  0 public boolean equals(Object obj) {
 214  0 if (this == obj) { return true; }
 215  0 else if (!(obj instanceof Multiset<?>)) { return false; }
 216    else {
 217  0 Multiset<?> cast = (Multiset<?>) obj;
 218  0 if (_size == cast.size()) {
 219  0 for (Object elt : cast.asSet()) {
 220  0 if (count(elt) != cast.count(elt)) { return false; }
 221    }
 222  0 return true;
 223    }
 224  0 else { return false; }
 225    }
 226    }
 227   
 228  0 public int hashCode() {
 229  0 int result = 0;
 230  0 for (T elt : asSet()) { result += (elt == null ? 1 : elt.hashCode()) * count(elt); }
 231  0 return result;
 232    }
 233   
 234    /** Convert {@code coll} to a multiset by casting or, where necessary, allocation */
 235  0 private <S> Multiset<S> asMultiset(Collection<S> coll) {
 236  0 if (coll instanceof Multiset<?>) { return (Multiset<S>) coll; }
 237  0 else { return new HashMultiset<S>(coll); }
 238    }
 239   
 240    }