1 3 package jodd.util.collection; 4 5 import jodd.mutable.MutableInteger; 6 7 import java.lang.reflect.Array ; 8 import java.util.*; 9 10 13 public class HashBag implements Bag { 14 15 protected transient Map map; protected int size; private transient int modCount; 19 public HashBag() { 20 super(); 21 map = new HashMap(); 22 } 23 24 public HashBag(Collection coll) { 25 this(); 26 addAll(coll); 27 } 28 29 33 public int size() { 34 return size; 35 } 36 37 40 public boolean isEmpty() { 41 return map.isEmpty(); 42 } 43 44 47 public int getCount(Object object) { 48 MutableInteger count = (MutableInteger) map.get(object); 49 if (count != null) { 50 return count.value; 51 } 52 return 0; 53 } 54 55 57 62 public boolean contains(Object object) { 63 return map.containsKey(object); 64 } 65 66 71 public boolean containsAll(Collection coll) { 72 if (coll instanceof Bag) { 73 return containsAll((Bag) coll); 74 } 75 return containsAll(new HashBag(coll)); 76 } 77 78 84 boolean containsAll(Bag other) { 85 boolean result = true; 86 Iterator it = other.uniqueSet().iterator(); 87 while (it.hasNext()) { 88 Object current = it.next(); 89 boolean contains = getCount(current) >= other.getCount(current); 90 result = result && contains; 91 } 92 return result; 93 } 94 95 97 101 public Iterator iterator() { 102 return new BagIterator(this); 103 } 104 105 108 static class BagIterator implements Iterator { 109 private HashBag parent; 110 private Iterator entryIterator; 111 private Map.Entry current; 112 private int itemCount; 113 private final int mods; 114 private boolean canRemove; 115 116 BagIterator(HashBag parent) { 117 this.parent = parent; 118 this.entryIterator = parent.map.entrySet().iterator(); 119 this.current = null; 120 this.mods = parent.modCount; 121 this.canRemove = false; 122 } 123 124 public boolean hasNext() { 125 return (itemCount > 0 || entryIterator.hasNext()); 126 } 127 128 public Object next() { 129 if (parent.modCount != mods) { 130 throw new ConcurrentModificationException(); 131 } 132 if (itemCount == 0) { 133 current = (Map.Entry) entryIterator.next(); 134 itemCount = ((MutableInteger) current.getValue()).value; 135 } 136 canRemove = true; 137 itemCount--; 138 return current.getKey(); 139 } 140 141 public void remove() { 142 if (parent.modCount != mods) { 143 throw new ConcurrentModificationException(); 144 } 145 if (canRemove == false) { 146 throw new IllegalStateException (); 147 } 148 MutableInteger mut = (MutableInteger) current.getValue(); 149 if (mut.value > 1) { 150 mut.value--; 151 } else { 152 entryIterator.remove(); 153 } 154 parent.size--; 155 canRemove = false; 156 } 157 } 158 159 165 public boolean add(Object object) { 166 return add(object, 1); 167 } 168 169 174 public boolean add(Object object, int copies) { 175 if (copies <= 0) { 176 throw new IllegalArgumentException ("Invalid number of bag element copies (" + copies + ")"); 177 } 178 modCount++; 179 MutableInteger mut = (MutableInteger) map.get(object); 180 size += copies; 181 if (mut == null) { 182 map.put(object, new MutableInteger(copies)); 183 return true; 184 } else { 185 mut.value += copies; 186 return false; 187 } 188 } 189 190 195 public boolean addAll(Collection coll) { 196 boolean changed = false; 197 Iterator i = coll.iterator(); 198 while (i.hasNext()) { 199 boolean added = add(i.next()); 200 changed = changed || added; 201 } 202 return changed; 203 } 204 205 207 210 public void clear() { 211 if (size == 0) { 212 return; 213 } 214 modCount++; 215 map.clear(); 216 size = 0; 217 } 218 219 224 public boolean remove(Object object) { 225 MutableInteger mut = (MutableInteger) map.get(object); 226 if (mut == null) { 227 return false; 228 } 229 modCount++; 230 map.remove(object); 231 size -= mut.value; 232 return true; 233 } 234 235 240 public boolean remove(Object object, int copies) { 241 if (copies <= 0) { 242 throw new IllegalArgumentException ("Invalid number of bag element copies (" + copies + ")"); 243 } 244 MutableInteger mut = (MutableInteger) map.get(object); 245 if (mut == null) { 246 return false; 247 } 248 modCount++; 249 if (copies < mut.value) { 250 mut.value -= copies; 251 size -= copies; 252 } else { 253 map.remove(object); 254 size -= mut.value; 255 } 256 return true; 257 } 258 259 263 public boolean removeAll(Collection coll) { 264 boolean result = false; 265 if (coll != null) { 266 Iterator i = coll.iterator(); 267 while (i.hasNext()) { 268 boolean changed = remove(i.next(), 1); 269 result = result || changed; 270 } 271 } 272 return result; 273 } 274 275 276 278 284 public boolean retainAll(Collection coll) { 285 if (coll instanceof Bag) { 286 return retainAll((Bag) coll); 287 } 288 return retainAll(new HashBag(coll)); 289 } 290 291 297 boolean retainAll(Bag other) { 298 boolean result = false; 299 Bag excess = new HashBag(); 300 Iterator it = map.keySet().iterator(); 301 while (it.hasNext()) { 302 Object current = it.next(); 303 int myCount = getCount(current); 304 int otherCount = other.getCount(current); 305 if (1 <= otherCount && otherCount <= myCount) { 306 excess.add(current, myCount - otherCount); 307 } else { 308 excess.add(current, myCount); 309 } 310 } 311 if (!excess.isEmpty()) { 312 result = removeAll(excess); 313 } 314 return result; 315 } 316 317 318 319 321 public Set uniqueSet() { 322 return map.keySet(); 323 } 324 325 328 public Object [] toArray() { 329 Object [] result = new Object [size()]; 330 int i = 0; 331 Iterator it = map.keySet().iterator(); 332 while (it.hasNext()) { 333 Object current = it.next(); 334 for (int index = getCount(current); index > 0; index--) { 335 result[i++] = current; 336 } 337 } 338 return result; 339 } 340 341 344 public Object [] toArray(Object [] array) { 345 int size = size(); 346 if (array.length < size) { 347 array = (Object []) Array.newInstance(array.getClass().getComponentType(), size); 348 } 349 350 int i = 0; 351 Iterator it = map.keySet().iterator(); 352 while (it.hasNext()) { 353 Object current = it.next(); 354 for (int index = getCount(current); index > 0; index--) { 355 array[i++] = current; 356 } 357 } 358 while (array.length > size) { 359 array[size] = null; 360 size++; 361 } 362 return array; 363 } 364 365 367 374 public boolean equals(Object object) { 375 if (object == this) { 376 return true; 377 } 378 if (object instanceof Bag == false) { 379 return false; 380 } 381 Bag other = (Bag) object; 382 if (other.size() != size()) { 383 return false; 384 } 385 Iterator it = map.keySet().iterator(); 386 while (it.hasNext()) { 387 Object element = it.next(); 388 if (other.getCount(element) != getCount(element)) { 389 return false; 390 } 391 } 392 return true; 393 } 394 395 402 public int hashCode() { 403 int total = 0; 404 for (Iterator it = map.entrySet().iterator(); it.hasNext();) { 405 Map.Entry entry = (Map.Entry) it.next(); 406 Object element = entry.getKey(); 407 MutableInteger count = (MutableInteger) entry.getValue(); 408 total += (element == null ? 0 : element.hashCode()) ^ count.value; 409 } 410 return total; 411 } 412 413 416 public String toString() { 417 if (size() == 0) { 418 return "[]"; 419 } 420 StringBuffer buf = new StringBuffer (); 421 buf.append('['); 422 Iterator it = uniqueSet().iterator(); 423 while (it.hasNext()) { 424 Object current = it.next(); 425 int count = getCount(current); 426 buf.append(count); 427 buf.append(':'); 428 buf.append(current); 429 if (it.hasNext()) { 430 buf.append(','); 431 } 432 } 433 buf.append(']'); 434 return buf.toString(); 435 } 436 437 } 438 | Popular Tags |