1 16 package org.apache.commons.collections.map; 17 18 import java.util.AbstractCollection ; 19 import java.util.AbstractSet ; 20 import java.util.ArrayList ; 21 import java.util.Collection ; 22 import java.util.Iterator ; 23 import java.util.Map ; 24 import java.util.NoSuchElementException ; 25 import java.util.Set ; 26 27 import org.apache.commons.collections.KeyValue; 28 29 102 public final class StaticBucketMap implements Map { 103 104 105 private static final int DEFAULT_BUCKETS = 255; 106 107 private Node[] buckets; 108 109 private Lock[] locks; 110 111 114 public StaticBucketMap() { 115 this(DEFAULT_BUCKETS); 116 } 117 118 128 public StaticBucketMap(int numBuckets) { 129 int size = Math.max(17, numBuckets); 130 131 if (size % 2 == 0) { 133 size--; 134 } 135 136 buckets = new Node[size]; 137 locks = new Lock[size]; 138 139 for (int i = 0; i < size; i++) { 140 locks[i] = new Lock(); 141 } 142 } 143 144 158 private final int getHash(Object key) { 159 if (key == null) { 160 return 0; 161 } 162 int hash = key.hashCode(); 163 hash += ~(hash << 15); 164 hash ^= (hash >>> 10); 165 hash += (hash << 3); 166 hash ^= (hash >>> 6); 167 hash += ~(hash << 11); 168 hash ^= (hash >>> 16); 169 hash %= buckets.length; 170 return (hash < 0) ? hash * -1 : hash; 171 } 172 173 179 public int size() { 180 int cnt = 0; 181 182 for (int i = 0; i < buckets.length; i++) { 183 cnt += locks[i].size; 184 } 185 return cnt; 186 } 187 188 193 public boolean isEmpty() { 194 return (size() == 0); 195 } 196 197 203 public Object get(final Object key) { 204 int hash = getHash(key); 205 206 synchronized (locks[hash]) { 207 Node n = buckets[hash]; 208 209 while (n != null) { 210 if (n.key == key || (n.key != null && n.key.equals(key))) { 211 return n.value; 212 } 213 214 n = n.next; 215 } 216 } 217 return null; 218 } 219 220 226 public boolean containsKey(final Object key) { 227 int hash = getHash(key); 228 229 synchronized (locks[hash]) { 230 Node n = buckets[hash]; 231 232 while (n != null) { 233 if (n.key == null || (n.key != null && n.key.equals(key))) { 234 return true; 235 } 236 237 n = n.next; 238 } 239 } 240 return false; 241 } 242 243 249 public boolean containsValue(final Object value) { 250 for (int i = 0; i < buckets.length; i++) { 251 synchronized (locks[i]) { 252 Node n = buckets[i]; 253 254 while (n != null) { 255 if (n.value == value || (n.value != null && n.value.equals(value))) { 256 return true; 257 } 258 259 n = n.next; 260 } 261 } 262 } 263 return false; 264 } 265 266 274 public Object put(final Object key, final Object value) { 275 int hash = getHash(key); 276 277 synchronized (locks[hash]) { 278 Node n = buckets[hash]; 279 280 if (n == null) { 281 n = new Node(); 282 n.key = key; 283 n.value = value; 284 buckets[hash] = n; 285 locks[hash].size++; 286 return null; 287 } 288 289 for (Node next = n; next != null; next = next.next) { 293 n = next; 294 295 if (n.key == key || (n.key != null && n.key.equals(key))) { 296 Object returnVal = n.value; 297 n.value = value; 298 return returnVal; 299 } 300 } 301 302 Node newNode = new Node(); 305 newNode.key = key; 306 newNode.value = value; 307 n.next = newNode; 308 locks[hash].size++; 309 } 310 return null; 311 } 312 313 319 public Object remove(Object key) { 320 int hash = getHash(key); 321 322 synchronized (locks[hash]) { 323 Node n = buckets[hash]; 324 Node prev = null; 325 326 while (n != null) { 327 if (n.key == key || (n.key != null && n.key.equals(key))) { 328 if (null == prev) { 330 buckets[hash] = n.next; 332 } else { 333 prev.next = n.next; 335 } 336 locks[hash].size--; 337 return n.value; 338 } 339 340 prev = n; 341 n = n.next; 342 } 343 } 344 return null; 345 } 346 347 353 public Set keySet() { 354 return new KeySet(); 355 } 356 357 362 public Collection values() { 363 return new Values(); 364 } 365 366 371 public Set entrySet() { 372 return new EntrySet(); 373 } 374 375 382 public void putAll(Map map) { 383 Iterator i = map.keySet().iterator(); 384 385 while (i.hasNext()) { 386 Object key = i.next(); 387 put(key, map.get(key)); 388 } 389 } 390 391 394 public void clear() { 395 for (int i = 0; i < buckets.length; i++) { 396 Lock lock = locks[i]; 397 synchronized (lock) { 398 buckets[i] = null; 399 lock.size = 0; 400 } 401 } 402 } 403 404 410 public boolean equals(Object obj) { 411 if (obj == this) { 412 return true; 413 } 414 if (obj instanceof Map == false) { 415 return false; 416 } 417 Map other = (Map ) obj; 418 return entrySet().equals(other.entrySet()); 419 } 420 421 426 public int hashCode() { 427 int hashCode = 0; 428 429 for (int i = 0; i < buckets.length; i++) { 430 synchronized (locks[i]) { 431 Node n = buckets[i]; 432 433 while (n != null) { 434 hashCode += n.hashCode(); 435 n = n.next; 436 } 437 } 438 } 439 return hashCode; 440 } 441 442 446 private static final class Node implements Map.Entry , KeyValue { 447 protected Object key; 448 protected Object value; 449 protected Node next; 450 451 public Object getKey() { 452 return key; 453 } 454 455 public Object getValue() { 456 return value; 457 } 458 459 public int hashCode() { 460 return ((key == null ? 0 : key.hashCode()) ^ 461 (value == null ? 0 : value.hashCode())); 462 } 463 464 public boolean equals(Object obj) { 465 if (obj == this) { 466 return true; 467 } 468 if (obj instanceof Map.Entry == false) { 469 return false; 470 } 471 472 Map.Entry e2 = (Map.Entry ) obj; 473 return ( 474 (key == null ? e2.getKey() == null : key.equals(e2.getKey())) && 475 (value == null ? e2.getValue() == null : value.equals(e2.getValue()))); 476 } 477 478 public Object setValue(Object obj) { 479 Object retVal = value; 480 value = obj; 481 return retVal; 482 } 483 } 484 485 486 489 private final static class Lock { 490 public int size; 491 } 492 493 494 private class EntryIterator implements Iterator { 496 497 private ArrayList current = new ArrayList (); 498 private int bucket; 499 private Map.Entry last; 500 501 502 public boolean hasNext() { 503 if (current.size() > 0) return true; 504 while (bucket < buckets.length) { 505 synchronized (locks[bucket]) { 506 Node n = buckets[bucket]; 507 while (n != null) { 508 current.add(n); 509 n = n.next; 510 } 511 bucket++; 512 if (current.size() > 0) return true; 513 } 514 } 515 return false; 516 } 517 518 protected Map.Entry nextEntry() { 519 if (!hasNext()) throw new NoSuchElementException (); 520 last = (Map.Entry )current.remove(current.size() - 1); 521 return last; 522 } 523 524 public Object next() { 525 return nextEntry(); 526 } 527 528 public void remove() { 529 if (last == null) throw new IllegalStateException (); 530 StaticBucketMap.this.remove(last.getKey()); 531 last = null; 532 } 533 534 } 535 536 private class ValueIterator extends EntryIterator { 537 538 public Object next() { 539 return nextEntry().getValue(); 540 } 541 542 } 543 544 private class KeyIterator extends EntryIterator { 545 546 public Object next() { 547 return nextEntry().getKey(); 548 } 549 550 } 551 552 private class EntrySet extends AbstractSet { 553 554 public int size() { 555 return StaticBucketMap.this.size(); 556 } 557 558 public void clear() { 559 StaticBucketMap.this.clear(); 560 } 561 562 public Iterator iterator() { 563 return new EntryIterator(); 564 } 565 566 public boolean contains(Object obj) { 567 Map.Entry entry = (Map.Entry ) obj; 568 int hash = getHash(entry.getKey()); 569 synchronized (locks[hash]) { 570 for (Node n = buckets[hash]; n != null; n = n.next) { 571 if (n.equals(entry)) return true; 572 } 573 } 574 return false; 575 } 576 577 public boolean remove(Object obj) { 578 if (obj instanceof Map.Entry == false) { 579 return false; 580 } 581 Map.Entry entry = (Map.Entry ) obj; 582 int hash = getHash(entry.getKey()); 583 synchronized (locks[hash]) { 584 for (Node n = buckets[hash]; n != null; n = n.next) { 585 if (n.equals(entry)) { 586 StaticBucketMap.this.remove(n.getKey()); 587 return true; 588 } 589 } 590 } 591 return false; 592 } 593 594 } 595 596 597 private class KeySet extends AbstractSet { 598 599 public int size() { 600 return StaticBucketMap.this.size(); 601 } 602 603 public void clear() { 604 StaticBucketMap.this.clear(); 605 } 606 607 public Iterator iterator() { 608 return new KeyIterator(); 609 } 610 611 public boolean contains(Object obj) { 612 return StaticBucketMap.this.containsKey(obj); 613 } 614 615 public boolean remove(Object obj) { 616 int hash = getHash(obj); 617 synchronized (locks[hash]) { 618 for (Node n = buckets[hash]; n != null; n = n.next) { 619 Object k = n.getKey(); 620 if ((k == obj) || ((k != null) && k.equals(obj))) { 621 StaticBucketMap.this.remove(k); 622 return true; 623 } 624 } 625 } 626 return false; 627 628 } 629 630 } 631 632 633 private class Values extends AbstractCollection { 634 635 public int size() { 636 return StaticBucketMap.this.size(); 637 } 638 639 public void clear() { 640 StaticBucketMap.this.clear(); 641 } 642 643 public Iterator iterator() { 644 return new ValueIterator(); 645 } 646 647 } 648 649 650 684 public void atomic(Runnable r) { 685 if (r == null) throw new NullPointerException (); 686 atomic(r, 0); 687 } 688 689 private void atomic(Runnable r, int bucket) { 690 if (bucket >= buckets.length) { 691 r.run(); 692 return; 693 } 694 synchronized (locks[bucket]) { 695 atomic(r, bucket + 1); 696 } 697 } 698 699 } 700 | Popular Tags |