1 16 package org.apache.commons.collections.bag; 17 18 import java.io.IOException ; 19 import java.io.ObjectInputStream ; 20 import java.io.ObjectOutputStream ; 21 import java.lang.reflect.Array ; 22 import java.util.Collection ; 23 import java.util.ConcurrentModificationException ; 24 import java.util.Iterator ; 25 import java.util.Map ; 26 import java.util.Set ; 27 28 import org.apache.commons.collections.Bag; 29 import org.apache.commons.collections.set.UnmodifiableSet; 30 31 47 public abstract class AbstractMapBag implements Bag { 48 49 50 private transient Map map; 51 52 private int size; 53 54 private transient int modCount; 55 56 private transient Set uniqueSet; 57 58 62 protected AbstractMapBag() { 63 super(); 64 } 65 66 72 protected AbstractMapBag(Map map) { 73 super(); 74 this.map = map; 75 } 76 77 83 protected Map getMap() { 84 return map; 85 } 86 87 93 public int size() { 94 return size; 95 } 96 97 102 public boolean isEmpty() { 103 return map.isEmpty(); 104 } 105 106 113 public int getCount(Object object) { 114 MutableInteger count = (MutableInteger) map.get(object); 115 if (count != null) { 116 return count.value; 117 } 118 return 0; 119 } 120 121 129 public boolean contains(Object object) { 130 return map.containsKey(object); 131 } 132 133 139 public boolean containsAll(Collection coll) { 140 if (coll instanceof Bag) { 141 return containsAll((Bag) coll); 142 } 143 return containsAll(new HashBag(coll)); 144 } 145 146 153 boolean containsAll(Bag other) { 154 boolean result = true; 155 Iterator it = other.uniqueSet().iterator(); 156 while (it.hasNext()) { 157 Object current = it.next(); 158 boolean contains = getCount(current) >= other.getCount(current); 159 result = result && contains; 160 } 161 return result; 162 } 163 164 171 public Iterator iterator() { 172 return new BagIterator(this); 173 } 174 175 178 static class BagIterator implements Iterator { 179 private AbstractMapBag parent; 180 private Iterator entryIterator; 181 private Map.Entry current; 182 private int itemCount; 183 private final int mods; 184 private boolean canRemove; 185 186 191 public BagIterator(AbstractMapBag parent) { 192 this.parent = parent; 193 this.entryIterator = parent.map.entrySet().iterator(); 194 this.current = null; 195 this.mods = parent.modCount; 196 this.canRemove = false; 197 } 198 199 public boolean hasNext() { 200 return (itemCount > 0 || entryIterator.hasNext()); 201 } 202 203 public Object next() { 204 if (parent.modCount != mods) { 205 throw new ConcurrentModificationException (); 206 } 207 if (itemCount == 0) { 208 current = (Map.Entry ) entryIterator.next(); 209 itemCount = ((MutableInteger) current.getValue()).value; 210 } 211 canRemove = true; 212 itemCount--; 213 return current.getKey(); 214 } 215 216 public void remove() { 217 if (parent.modCount != mods) { 218 throw new ConcurrentModificationException (); 219 } 220 if (canRemove == false) { 221 throw new IllegalStateException (); 222 } 223 MutableInteger mut = (MutableInteger) current.getValue(); 224 if (mut.value > 0) { 225 mut.value--; 226 parent.size--; 227 } else { 228 entryIterator.remove(); 229 } 230 canRemove = false; 231 } 232 } 233 234 241 public boolean add(Object object) { 242 return add(object, 1); 243 } 244 245 252 public boolean add(Object object, int nCopies) { 253 modCount++; 254 if (nCopies > 0) { 255 MutableInteger mut = (MutableInteger) map.get(object); 256 size += nCopies; 257 if (mut == null) { 258 map.put(object, new MutableInteger(nCopies)); 259 return true; 260 } else { 261 mut.value += nCopies; 262 return false; 263 } 264 } else { 265 return false; 266 } 267 } 268 269 275 public boolean addAll(Collection coll) { 276 boolean changed = false; 277 Iterator i = coll.iterator(); 278 while (i.hasNext()) { 279 boolean added = add(i.next()); 280 changed = changed || added; 281 } 282 return changed; 283 } 284 285 289 public void clear() { 290 modCount++; 291 map.clear(); 292 size = 0; 293 } 294 295 301 public boolean remove(Object object) { 302 MutableInteger mut = (MutableInteger) map.get(object); 303 if (mut == null) { 304 return false; 305 } 306 modCount++; 307 map.remove(object); 308 size -= mut.value; 309 return true; 310 } 311 312 319 public boolean remove(Object object, int nCopies) { 320 MutableInteger mut = (MutableInteger) map.get(object); 321 if (mut == null) { 322 return false; 323 } 324 if (nCopies <= 0) { 325 return false; 326 } 327 modCount++; 328 if (nCopies < mut.value) { 329 mut.value -= nCopies; 330 size -= nCopies; 331 } else { 332 map.remove(object); 333 size -= mut.value; 334 } 335 return true; 336 } 337 338 344 public boolean removeAll(Collection coll) { 345 boolean result = false; 346 if (coll != null) { 347 Iterator i = coll.iterator(); 348 while (i.hasNext()) { 349 boolean changed = remove(i.next(), 1); 350 result = result || changed; 351 } 352 } 353 return result; 354 } 355 356 363 public boolean retainAll(Collection coll) { 364 if (coll instanceof Bag) { 365 return retainAll((Bag) coll); 366 } 367 return retainAll(new HashBag(coll)); 368 } 369 370 378 boolean retainAll(Bag other) { 379 boolean result = false; 380 Bag excess = new HashBag(); 381 Iterator i = uniqueSet().iterator(); 382 while (i.hasNext()) { 383 Object current = i.next(); 384 int myCount = getCount(current); 385 int otherCount = other.getCount(current); 386 if (1 <= otherCount && otherCount <= myCount) { 387 excess.add(current, myCount - otherCount); 388 } else { 389 excess.add(current, myCount); 390 } 391 } 392 if (!excess.isEmpty()) { 393 result = removeAll(excess); 394 } 395 return result; 396 } 397 398 402 protected static class MutableInteger { 403 404 protected int value; 405 406 410 MutableInteger(int value) { 411 this.value = value; 412 } 413 414 public boolean equals(Object obj) { 415 if (obj instanceof MutableInteger == false) { 416 return false; 417 } 418 return ((MutableInteger) obj).value == value; 419 } 420 421 public int hashCode() { 422 return value; 423 } 424 } 425 426 432 public Object [] toArray() { 433 Object [] result = new Object [size()]; 434 int i = 0; 435 Iterator it = map.keySet().iterator(); 436 while (it.hasNext()) { 437 Object current = it.next(); 438 for (int index = getCount(current); index > 0; index--) { 439 result[i++] = current; 440 } 441 } 442 return result; 443 } 444 445 451 public Object [] toArray(Object [] array) { 452 int size = size(); 453 if (array.length < size) { 454 array = (Object []) Array.newInstance(array.getClass().getComponentType(), size); 455 } 456 457 int i = 0; 458 Iterator it = map.keySet().iterator(); 459 while (it.hasNext()) { 460 Object current = it.next(); 461 for (int index = getCount(current); index > 0; index--) { 462 array[i++] = current; 463 } 464 } 465 if (array.length > size) { 466 array[size] = null; 467 } 468 return array; 469 } 470 471 476 public Set uniqueSet() { 477 if (uniqueSet == null) { 478 uniqueSet = UnmodifiableSet.decorate(map.keySet()); 479 } 480 return uniqueSet; 481 } 482 483 489 protected void doWriteObject(ObjectOutputStream out) throws IOException { 490 out.writeInt(map.size()); 491 for (Iterator it = map.entrySet().iterator(); it.hasNext();) { 492 Map.Entry entry = (Map.Entry ) it.next(); 493 out.writeObject(entry.getKey()); 494 out.writeInt(((MutableInteger) entry.getValue()).value); 495 } 496 } 497 498 505 protected void doReadObject(Map map, ObjectInputStream in) throws IOException , ClassNotFoundException { 506 this.map = map; 507 int entrySize = in.readInt(); 508 for (int i = 0; i < entrySize; i++) { 509 Object obj = in.readObject(); 510 int count = in.readInt(); 511 map.put(obj, new MutableInteger(count)); 512 size += count; 513 } 514 } 515 516 525 public boolean equals(Object object) { 526 if (object == this) { 527 return true; 528 } 529 if (object instanceof Bag == false) { 530 return false; 531 } 532 Bag other = (Bag) object; 533 if (other.size() != size()) { 534 return false; 535 } 536 for (Iterator it = map.keySet().iterator(); it.hasNext();) { 537 Object element = it.next(); 538 if (other.getCount(element) != getCount(element)) { 539 return false; 540 } 541 } 542 return true; 543 } 544 545 554 public int hashCode() { 555 int total = 0; 556 for (Iterator it = map.entrySet().iterator(); it.hasNext();) { 557 Map.Entry entry = (Map.Entry ) it.next(); 558 Object element = entry.getKey(); 559 MutableInteger count = (MutableInteger) entry.getValue(); 560 total += (element == null ? 0 : element.hashCode()) ^ count.value; 561 } 562 return total; 563 } 564 565 570 public String toString() { 571 if (size() == 0) { 572 return "[]"; 573 } 574 StringBuffer buf = new StringBuffer (); 575 buf.append('['); 576 Iterator it = uniqueSet().iterator(); 577 while (it.hasNext()) { 578 Object current = it.next(); 579 int count = getCount(current); 580 buf.append(count); 581 buf.append(':'); 582 buf.append(current); 583 if (it.hasNext()) { 584 buf.append(','); 585 } 586 } 587 buf.append(']'); 588 return buf.toString(); 589 } 590 591 } 592 | Popular Tags |