1 16 package org.apache.commons.collections.map; 17 18 import java.util.ConcurrentModificationException ; 19 import java.util.Iterator ; 20 import java.util.Map ; 21 import java.util.NoSuchElementException ; 22 23 import org.apache.commons.collections.MapIterator; 24 import org.apache.commons.collections.OrderedIterator; 25 import org.apache.commons.collections.OrderedMap; 26 import org.apache.commons.collections.OrderedMapIterator; 27 import org.apache.commons.collections.ResettableIterator; 28 import org.apache.commons.collections.iterators.EmptyOrderedIterator; 29 import org.apache.commons.collections.iterators.EmptyOrderedMapIterator; 30 31 65 public class AbstractLinkedMap extends AbstractHashedMap implements OrderedMap { 66 67 68 protected transient LinkEntry header; 69 70 73 protected AbstractLinkedMap() { 74 super(); 75 } 76 77 84 protected AbstractLinkedMap(int initialCapacity, float loadFactor, int threshold) { 85 super(initialCapacity, loadFactor, threshold); 86 } 87 88 94 protected AbstractLinkedMap(int initialCapacity) { 95 super(initialCapacity); 96 } 97 98 107 protected AbstractLinkedMap(int initialCapacity, float loadFactor) { 108 super(initialCapacity, loadFactor); 109 } 110 111 117 protected AbstractLinkedMap(Map map) { 118 super(map); 119 } 120 121 124 protected void init() { 125 header = new LinkEntry(null, -1, null, null); 126 header.before = header.after = header; 127 } 128 129 136 public boolean containsValue(Object value) { 137 if (value == null) { 139 for (LinkEntry entry = header.after; entry != header; entry = entry.after) { 140 if (entry.getValue() == null) { 141 return true; 142 } 143 } 144 } else { 145 for (LinkEntry entry = header.after; entry != header; entry = entry.after) { 146 if (isEqualValue(value, entry.getValue())) { 147 return true; 148 } 149 } 150 } 151 return false; 152 } 153 154 158 public void clear() { 159 super.clear(); 161 header.before = header.after = header; 162 } 163 164 170 public Object firstKey() { 171 if (size == 0) { 172 throw new NoSuchElementException ("Map is empty"); 173 } 174 return header.after.getKey(); 175 } 176 177 182 public Object lastKey() { 183 if (size == 0) { 184 throw new NoSuchElementException ("Map is empty"); 185 } 186 return header.before.getKey(); 187 } 188 189 195 public Object nextKey(Object key) { 196 LinkEntry entry = (LinkEntry) getEntry(key); 197 return (entry == null || entry.after == header ? null : entry.after.getKey()); 198 } 199 200 206 public Object previousKey(Object key) { 207 LinkEntry entry = (LinkEntry) getEntry(key); 208 return (entry == null || entry.before == header ? null : entry.before.getKey()); 209 } 210 211 219 protected LinkEntry getEntry(int index) { 220 if (index < 0) { 221 throw new IndexOutOfBoundsException ("Index " + index + " is less than zero"); 222 } 223 if (index >= size) { 224 throw new IndexOutOfBoundsException ("Index " + index + " is invalid for size " + size); 225 } 226 LinkEntry entry; 227 if (index < (size / 2)) { 228 entry = header.after; 230 for (int currentIndex = 0; currentIndex < index; currentIndex++) { 231 entry = entry.after; 232 } 233 } else { 234 entry = header; 236 for (int currentIndex = size; currentIndex > index; currentIndex--) { 237 entry = entry.before; 238 } 239 } 240 return entry; 241 } 242 243 252 protected void addEntry(HashEntry entry, int hashIndex) { 253 LinkEntry link = (LinkEntry) entry; 254 link.after = header; 255 link.before = header.before; 256 header.before.after = link; 257 header.before = link; 258 data[hashIndex] = entry; 259 } 260 261 272 protected HashEntry createEntry(HashEntry next, int hashCode, Object key, Object value) { 273 return new LinkEntry(next, hashCode, key, value); 274 } 275 276 286 protected void removeEntry(HashEntry entry, int hashIndex, HashEntry previous) { 287 LinkEntry link = (LinkEntry) entry; 288 link.before.after = link.after; 289 link.after.before = link.before; 290 link.after = null; 291 link.before = null; 292 super.removeEntry(entry, hashIndex, previous); 293 } 294 295 305 protected LinkEntry entryBefore(LinkEntry entry) { 306 return entry.before; 307 } 308 309 318 protected LinkEntry entryAfter(LinkEntry entry) { 319 return entry.after; 320 } 321 322 333 public MapIterator mapIterator() { 334 if (size == 0) { 335 return EmptyOrderedMapIterator.INSTANCE; 336 } 337 return new LinkMapIterator(this); 338 } 339 340 350 public OrderedMapIterator orderedMapIterator() { 351 if (size == 0) { 352 return EmptyOrderedMapIterator.INSTANCE; 353 } 354 return new LinkMapIterator(this); 355 } 356 357 360 protected static class LinkMapIterator extends LinkIterator implements OrderedMapIterator { 361 362 protected LinkMapIterator(AbstractLinkedMap parent) { 363 super(parent); 364 } 365 366 public Object next() { 367 return super.nextEntry().getKey(); 368 } 369 370 public Object previous() { 371 return super.previousEntry().getKey(); 372 } 373 374 public Object getKey() { 375 HashEntry current = currentEntry(); 376 if (current == null) { 377 throw new IllegalStateException (AbstractHashedMap.GETKEY_INVALID); 378 } 379 return current.getKey(); 380 } 381 382 public Object getValue() { 383 HashEntry current = currentEntry(); 384 if (current == null) { 385 throw new IllegalStateException (AbstractHashedMap.GETVALUE_INVALID); 386 } 387 return current.getValue(); 388 } 389 390 public Object setValue(Object value) { 391 HashEntry current = currentEntry(); 392 if (current == null) { 393 throw new IllegalStateException (AbstractHashedMap.SETVALUE_INVALID); 394 } 395 return current.setValue(value); 396 } 397 } 398 399 406 protected Iterator createEntrySetIterator() { 407 if (size() == 0) { 408 return EmptyOrderedIterator.INSTANCE; 409 } 410 return new EntrySetIterator(this); 411 } 412 413 416 protected static class EntrySetIterator extends LinkIterator { 417 418 protected EntrySetIterator(AbstractLinkedMap parent) { 419 super(parent); 420 } 421 422 public Object next() { 423 return super.nextEntry(); 424 } 425 426 public Object previous() { 427 return super.previousEntry(); 428 } 429 } 430 431 438 protected Iterator createKeySetIterator() { 439 if (size() == 0) { 440 return EmptyOrderedIterator.INSTANCE; 441 } 442 return new KeySetIterator(this); 443 } 444 445 448 protected static class KeySetIterator extends EntrySetIterator { 449 450 protected KeySetIterator(AbstractLinkedMap parent) { 451 super(parent); 452 } 453 454 public Object next() { 455 return super.nextEntry().getKey(); 456 } 457 458 public Object previous() { 459 return super.previousEntry().getKey(); 460 } 461 } 462 463 470 protected Iterator createValuesIterator() { 471 if (size() == 0) { 472 return EmptyOrderedIterator.INSTANCE; 473 } 474 return new ValuesIterator(this); 475 } 476 477 480 protected static class ValuesIterator extends LinkIterator { 481 482 protected ValuesIterator(AbstractLinkedMap parent) { 483 super(parent); 484 } 485 486 public Object next() { 487 return super.nextEntry().getValue(); 488 } 489 490 public Object previous() { 491 return super.previousEntry().getValue(); 492 } 493 } 494 495 504 protected static class LinkEntry extends HashEntry { 505 506 protected LinkEntry before; 507 508 protected LinkEntry after; 509 510 518 protected LinkEntry(HashEntry next, int hashCode, Object key, Object value) { 519 super(next, hashCode, key, value); 520 } 521 } 522 523 526 protected static abstract class LinkIterator 527 implements OrderedIterator, ResettableIterator { 528 529 530 protected final AbstractLinkedMap parent; 531 532 protected LinkEntry last; 533 534 protected LinkEntry next; 535 536 protected int expectedModCount; 537 538 protected LinkIterator(AbstractLinkedMap parent) { 539 super(); 540 this.parent = parent; 541 this.next = parent.header.after; 542 this.expectedModCount = parent.modCount; 543 } 544 545 public boolean hasNext() { 546 return (next != parent.header); 547 } 548 549 public boolean hasPrevious() { 550 return (next.before != parent.header); 551 } 552 553 protected LinkEntry nextEntry() { 554 if (parent.modCount != expectedModCount) { 555 throw new ConcurrentModificationException (); 556 } 557 if (next == parent.header) { 558 throw new NoSuchElementException (AbstractHashedMap.NO_NEXT_ENTRY); 559 } 560 last = next; 561 next = next.after; 562 return last; 563 } 564 565 protected LinkEntry previousEntry() { 566 if (parent.modCount != expectedModCount) { 567 throw new ConcurrentModificationException (); 568 } 569 LinkEntry previous = next.before; 570 if (previous == parent.header) { 571 throw new NoSuchElementException (AbstractHashedMap.NO_PREVIOUS_ENTRY); 572 } 573 next = previous; 574 last = previous; 575 return last; 576 } 577 578 protected LinkEntry currentEntry() { 579 return last; 580 } 581 582 public void remove() { 583 if (last == null) { 584 throw new IllegalStateException (AbstractHashedMap.REMOVE_INVALID); 585 } 586 if (parent.modCount != expectedModCount) { 587 throw new ConcurrentModificationException (); 588 } 589 parent.remove(last.getKey()); 590 last = null; 591 expectedModCount = parent.modCount; 592 } 593 594 public void reset() { 595 last = null; 596 next = parent.header.after; 597 } 598 599 public String toString() { 600 if (last != null) { 601 return "Iterator[" + last.getKey() + "=" + last.getValue() + "]"; 602 } else { 603 return "Iterator[]"; 604 } 605 } 606 } 607 608 } 609 | Popular Tags |