1 16 package org.apache.commons.collections; 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 101 public final class StaticBucketMap implements Map { 102 103 private static final int DEFAULT_BUCKETS = 255; 104 private Node[] m_buckets; 105 private Lock[] m_locks; 106 107 110 public StaticBucketMap() 111 { 112 this( DEFAULT_BUCKETS ); 113 } 114 115 125 public StaticBucketMap( int numBuckets ) 126 { 127 int size = Math.max( 17, numBuckets ); 128 129 if( size % 2 == 0 ) 131 { 132 size--; 133 } 134 135 m_buckets = new Node[ size ]; 136 m_locks = new Lock[ size ]; 137 138 for( int i = 0; i < size; i++ ) 139 { 140 m_locks[ i ] = new Lock(); 141 } 142 } 143 144 157 private final int getHash( Object key ) 158 { 159 if( key == null ) return 0; 160 int hash = key.hashCode(); 161 hash += ~(hash << 15); 162 hash ^= (hash >>> 10); 163 hash += (hash << 3); 164 hash ^= (hash >>> 6); 165 hash += ~(hash << 11); 166 hash ^= (hash >>> 16); 167 hash %= m_buckets.length; 168 return ( hash < 0 ) ? hash * -1 : hash; 169 } 170 171 174 public Set keySet() 175 { 176 return new KeySet(); 177 } 178 179 182 public int size() 183 { 184 int cnt = 0; 185 186 for( int i = 0; i < m_buckets.length; i++ ) 187 { 188 cnt += m_locks[i].size; 189 } 190 191 return cnt; 192 } 193 194 197 public Object put( final Object key, final Object value ) 198 { 199 int hash = getHash( key ); 200 201 synchronized( m_locks[ hash ] ) 202 { 203 Node n = m_buckets[ hash ]; 204 205 if( n == null ) 206 { 207 n = new Node(); 208 n.key = key; 209 n.value = value; 210 m_buckets[ hash ] = n; 211 m_locks[hash].size++; 212 return null; 213 } 214 215 for( Node next = n; next != null; next = next.next ) 219 { 220 n = next; 221 222 if( n.key == key || ( n.key != null && n.key.equals( key ) ) ) 223 { 224 Object returnVal = n.value; 225 n.value = value; 226 return returnVal; 227 } 228 } 229 230 Node newNode = new Node(); 233 newNode.key = key; 234 newNode.value = value; 235 n.next = newNode; 236 m_locks[hash].size++; 237 } 238 239 return null; 240 } 241 242 245 public Object get( final Object key ) 246 { 247 int hash = getHash( key ); 248 249 synchronized( m_locks[ hash ] ) 250 { 251 Node n = m_buckets[ hash ]; 252 253 while( n != null ) 254 { 255 if( n.key == key || ( n.key != null && n.key.equals( key ) ) ) 256 { 257 return n.value; 258 } 259 260 n = n.next; 261 } 262 } 263 264 return null; 265 } 266 267 270 public boolean containsKey( final Object key ) 271 { 272 int hash = getHash( key ); 273 274 synchronized( m_locks[ hash ] ) 275 { 276 Node n = m_buckets[ hash ]; 277 278 while( n != null ) 279 { 280 if( n.key == null || ( n.key != null && n.key.equals( key ) ) ) 281 { 282 return true; 283 } 284 285 n = n.next; 286 } 287 } 288 289 return false; 290 } 291 292 295 public boolean containsValue( final Object value ) 296 { 297 for( int i = 0; i < m_buckets.length; i++ ) 298 { 299 synchronized( m_locks[ i ] ) 300 { 301 Node n = m_buckets[ i ]; 302 303 while( n != null ) 304 { 305 if( n.value == value || 306 (n.value != null && n.value.equals( value ) ) ) 307 { 308 return true; 309 } 310 311 n = n.next; 312 } 313 } 314 } 315 316 return false; 317 } 318 319 322 public Collection values() 323 { 324 return new Values(); 325 } 326 327 330 public Set entrySet() 331 { 332 return new EntrySet(); 333 } 334 335 338 public void putAll( Map other ) 339 { 340 Iterator i = other.keySet().iterator(); 341 342 while( i.hasNext() ) 343 { 344 Object key = i.next(); 345 put( key, other.get( key ) ); 346 } 347 } 348 349 352 public Object remove( Object key ) 353 { 354 int hash = getHash( key ); 355 356 synchronized( m_locks[ hash ] ) 357 { 358 Node n = m_buckets[ hash ]; 359 Node prev = null; 360 361 while( n != null ) 362 { 363 if( n.key == key || ( n.key != null && n.key.equals( key ) ) ) 364 { 365 if( null == prev ) 367 { 368 m_buckets[ hash ] = n.next; 370 } 371 else 372 { 373 prev.next = n.next; 375 } 376 m_locks[hash].size--; 377 return n.value; 378 } 379 380 prev = n; 381 n = n.next; 382 } 383 } 384 385 return null; 386 } 387 388 391 public final boolean isEmpty() 392 { 393 return size() == 0; 394 } 395 396 399 public final void clear() 400 { 401 for( int i = 0; i < m_buckets.length; i++ ) 402 { 403 Lock lock = m_locks[i]; 404 synchronized (lock) { 405 m_buckets[ i ] = null; 406 lock.size = 0; 407 } 408 } 409 } 410 411 414 public final boolean equals( Object obj ) 415 { 416 if( obj == null ) return false; 417 if( obj == this ) return true; 418 419 if( !( obj instanceof Map ) ) return false; 420 421 Map other = (Map )obj; 422 423 return entrySet().equals(other.entrySet()); 424 } 425 426 429 public final int hashCode() 430 { 431 int hashCode = 0; 432 433 for( int i = 0; i < m_buckets.length; i++ ) 434 { 435 synchronized( m_locks[ i ] ) 436 { 437 Node n = m_buckets[ i ]; 438 439 while( n != null ) 440 { 441 hashCode += n.hashCode(); 442 n = n.next; 443 } 444 } 445 } 446 return hashCode; 447 } 448 449 452 private static final class Node implements Map.Entry , KeyValue 453 { 454 protected Object key; 455 protected Object value; 456 protected Node next; 457 458 public Object getKey() 459 { 460 return key; 461 } 462 463 public Object getValue() 464 { 465 return value; 466 } 467 468 public int hashCode() 469 { 470 return ( ( key == null ? 0 : key.hashCode() ) ^ 471 ( value == null ? 0 : value.hashCode() ) ); 472 } 473 474 public boolean equals(Object o) { 475 if( o == null ) return false; 476 if( o == this ) return true; 477 478 if ( ! (o instanceof Map.Entry ) ) 479 return false; 480 481 Map.Entry e2 = (Map.Entry )o; 482 483 return ((key == null ? 484 e2.getKey() == null : key.equals(e2.getKey())) && 485 (value == null ? 486 e2.getValue() == null : value.equals(e2.getValue()))); 487 } 488 489 public Object setValue( Object val ) 490 { 491 Object retVal = value; 492 value = val; 493 return retVal; 494 } 495 } 496 497 private final static class Lock { 498 499 public int size; 500 501 } 502 503 504 private class EntryIterator implements Iterator { 505 506 private ArrayList current = new ArrayList (); 507 private int bucket; 508 private Map.Entry last; 509 510 511 public boolean hasNext() { 512 if (current.size() > 0) return true; 513 while (bucket < m_buckets.length) { 514 synchronized (m_locks[bucket]) { 515 Node n = m_buckets[bucket]; 516 while (n != null) { 517 current.add(n); 518 n = n.next; 519 } 520 bucket++; 521 if (current.size() > 0) return true; 522 } 523 } 524 return false; 525 } 526 527 protected Map.Entry nextEntry() { 528 if (!hasNext()) throw new NoSuchElementException (); 529 last = (Map.Entry )current.remove(current.size() - 1); 530 return last; 531 } 532 533 public Object next() { 534 return nextEntry(); 535 } 536 537 public void remove() { 538 if (last == null) throw new IllegalStateException (); 539 StaticBucketMap.this.remove(last.getKey()); 540 last = null; 541 } 542 543 } 544 545 private class ValueIterator extends EntryIterator { 546 547 public Object next() { 548 return nextEntry().getValue(); 549 } 550 551 } 552 553 private class KeyIterator extends EntryIterator { 554 555 public Object next() { 556 return nextEntry().getKey(); 557 } 558 559 } 560 561 private class EntrySet extends AbstractSet { 562 563 public int size() { 564 return StaticBucketMap.this.size(); 565 } 566 567 public void clear() { 568 StaticBucketMap.this.clear(); 569 } 570 571 public Iterator iterator() { 572 return new EntryIterator(); 573 } 574 575 public boolean contains(Object o) { 576 Map.Entry entry = (Map.Entry )o; 577 int hash = getHash(entry.getKey()); 578 synchronized (m_locks[hash]) { 579 for (Node n = m_buckets[hash]; n != null; n = n.next) { 580 if (n.equals(entry)) return true; 581 } 582 } 583 return false; 584 } 585 586 public boolean remove(Object obj) { 587 if (obj instanceof Map.Entry == false) { 588 return false; 589 } 590 Map.Entry entry = (Map.Entry ) obj; 591 int hash = getHash(entry.getKey()); 592 synchronized (m_locks[hash]) { 593 for (Node n = m_buckets[hash]; n != null; n = n.next) { 594 if (n.equals(entry)) { 595 StaticBucketMap.this.remove(n.getKey()); 596 return true; 597 } 598 } 599 } 600 return false; 601 } 602 603 } 604 605 606 private class KeySet extends AbstractSet { 607 608 public int size() { 609 return StaticBucketMap.this.size(); 610 } 611 612 public void clear() { 613 StaticBucketMap.this.clear(); 614 } 615 616 public Iterator iterator() { 617 return new KeyIterator(); 618 } 619 620 public boolean contains(Object o) { 621 return StaticBucketMap.this.containsKey(o); 622 } 623 624 public boolean remove(Object o) { 625 int hash = getHash(o); 626 synchronized (m_locks[hash]) { 627 for (Node n = m_buckets[hash]; n != null; n = n.next) { 628 Object k = n.getKey(); 629 if ((k == o) || ((k != null) && k.equals(o))) { 630 StaticBucketMap.this.remove(k); 631 return true; 632 } 633 } 634 } 635 return false; 636 637 } 638 639 } 640 641 642 private class Values extends AbstractCollection { 643 644 public int size() { 645 return StaticBucketMap.this.size(); 646 } 647 648 public void clear() { 649 StaticBucketMap.this.clear(); 650 } 651 652 public Iterator iterator() { 653 return new ValueIterator(); 654 } 655 656 } 657 658 659 693 public void atomic(Runnable r) { 694 if (r == null) throw new NullPointerException (); 695 atomic(r, 0); 696 } 697 698 private void atomic(Runnable r, int bucket) { 699 if (bucket >= m_buckets.length) { 700 r.run(); 701 return; 702 } 703 synchronized (m_locks[bucket]) { 704 atomic(r, bucket + 1); 705 } 706 } 707 708 709 } 710 | Popular Tags |