001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * https://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.collections4.map; 018 019import java.util.ConcurrentModificationException; 020import java.util.Iterator; 021import java.util.Map; 022import java.util.NoSuchElementException; 023import java.util.Objects; 024 025import org.apache.commons.collections4.OrderedIterator; 026import org.apache.commons.collections4.OrderedMap; 027import org.apache.commons.collections4.OrderedMapIterator; 028import org.apache.commons.collections4.ResettableIterator; 029import org.apache.commons.collections4.iterators.EmptyOrderedIterator; 030import org.apache.commons.collections4.iterators.EmptyOrderedMapIterator; 031 032/** 033 * An abstract implementation of a hash-based map that links entries to create an 034 * ordered map and which provides numerous points for subclasses to override. 035 * <p> 036 * This class implements all the features necessary for a subclass linked 037 * hash-based map. Key-value entries are stored in instances of the 038 * {@code LinkEntry} class which can be overridden and replaced. 039 * The iterators can similarly be replaced, without the need to replace the KeySet, 040 * EntrySet and Values view classes. 041 * </p> 042 * <p> 043 * Overridable methods are provided to change the default hashing behavior, and 044 * to change how entries are added to and removed from the map. Hopefully, all you 045 * need for unusual subclasses is here. 046 * </p> 047 * <p> 048 * This implementation maintains order by original insertion, but subclasses 049 * may work differently. The {@code OrderedMap} interface is implemented 050 * to provide access to bidirectional iteration and extra convenience methods. 051 * </p> 052 * <p> 053 * The {@code orderedMapIterator()} method provides direct access to a 054 * bidirectional iterator. The iterators from the other views can also be cast 055 * to {@code OrderedIterator} if required. 056 * </p> 057 * <p> 058 * All the available iterators can be reset back to the start by casting to 059 * {@code ResettableIterator} and calling {@code reset()}. 060 * </p> 061 * <p> 062 * The implementation is also designed to be subclassed, with lots of useful 063 * methods exposed. 064 * </p> 065 * 066 * @param <K> The type of the keys in this map 067 * @param <V> The type of the values in this map 068 * @since 3.0 069 */ 070public abstract class AbstractLinkedMap<K, V> extends AbstractHashedMap<K, V> implements OrderedMap<K, V> { 071 072 /** 073 * EntrySet iterator. 074 * 075 * @param <K> The key type. 076 * @param <V> The value type. 077 */ 078 protected static class EntrySetIterator<K, V> extends LinkIterator<K, V> implements 079 OrderedIterator<Map.Entry<K, V>>, ResettableIterator<Map.Entry<K, V>> { 080 081 /** 082 * Constructs a new instance. 083 * 084 * @param parent The parent AbstractLinkedMap. 085 */ 086 protected EntrySetIterator(final AbstractLinkedMap<K, V> parent) { 087 super(parent); 088 } 089 090 @Override 091 public Map.Entry<K, V> next() { 092 return super.nextEntry(); 093 } 094 095 @Override 096 public Map.Entry<K, V> previous() { 097 return super.previousEntry(); 098 } 099 } 100 101 /** 102 * KeySet iterator. 103 * 104 * @param <K> The key type. 105 */ 106 protected static class KeySetIterator<K> extends LinkIterator<K, Object> implements 107 OrderedIterator<K>, ResettableIterator<K> { 108 109 /** 110 * Constructs a new instance. 111 * 112 * @param parent The parent AbstractLinkedMap. 113 */ 114 @SuppressWarnings("unchecked") 115 protected KeySetIterator(final AbstractLinkedMap<K, ?> parent) { 116 super((AbstractLinkedMap<K, Object>) parent); 117 } 118 119 @Override 120 public K next() { 121 return super.nextEntry().getKey(); 122 } 123 124 @Override 125 public K previous() { 126 return super.previousEntry().getKey(); 127 } 128 } 129 130 /** 131 * LinkEntry that stores the data. 132 * <p> 133 * If you subclass {@code AbstractLinkedMap} but not {@code LinkEntry} 134 * then you will not be able to access the protected fields. 135 * The {@code entryXxx()} methods on {@code AbstractLinkedMap} exist 136 * to provide the necessary access. 137 * </p> 138 * 139 * @param <K> The key type. 140 * @param <V> The value type. 141 */ 142 protected static class LinkEntry<K, V> extends HashEntry<K, V> { 143 144 /** The entry before this one in the order */ 145 protected LinkEntry<K, V> before; 146 147 /** The entry after this one in the order */ 148 protected LinkEntry<K, V> after; 149 150 /** 151 * Constructs a new entry. 152 * 153 * @param next The next entry in the hash bucket sequence 154 * @param hashCode The hash code 155 * @param key The key 156 * @param value The value 157 */ 158 protected LinkEntry(final HashEntry<K, V> next, final int hashCode, final Object key, final V value) { 159 super(next, hashCode, key, value); 160 } 161 } 162 163 /** 164 * Base Iterator that iterates in link order. 165 * 166 * @param <K> The key type. 167 * @param <V> The value type. 168 */ 169 protected abstract static class LinkIterator<K, V> { 170 171 /** The parent map */ 172 protected final AbstractLinkedMap<K, V> parent; 173 174 /** The current (last returned) entry */ 175 protected LinkEntry<K, V> last; 176 177 /** The next entry */ 178 protected LinkEntry<K, V> next; 179 180 /** The modification count expected */ 181 protected int expectedModCount; 182 183 /** 184 * Constructs a new instance. 185 * 186 * @param parent The parent AbstractLinkedMap. 187 */ 188 protected LinkIterator(final AbstractLinkedMap<K, V> parent) { 189 this.parent = Objects.requireNonNull(parent, "parent"); 190 this.next = parent.header.after; 191 this.expectedModCount = parent.modCount; 192 } 193 194 /** 195 * Gets the current entry. 196 * 197 * @return The current entry. 198 */ 199 protected LinkEntry<K, V> currentEntry() { 200 return last; 201 } 202 203 /** 204 * Tests whether there is another entry. 205 * 206 * @return whether there is another entry. 207 */ 208 public boolean hasNext() { 209 return next != parent.header; 210 } 211 212 /** 213 * Tests whether there is a previous entry. 214 * 215 * @return whether there is a previous entry. 216 */ 217 public boolean hasPrevious() { 218 return next.before != parent.header; 219 } 220 221 /** 222 * Gets the next entry. 223 * 224 * @return The next entry. 225 */ 226 protected LinkEntry<K, V> nextEntry() { 227 if (parent.modCount != expectedModCount) { 228 throw new ConcurrentModificationException(); 229 } 230 if (next == parent.header) { 231 throw new NoSuchElementException(NO_NEXT_ENTRY); 232 } 233 last = next; 234 next = next.after; 235 return last; 236 } 237 238 /** 239 * Gets the previous entry. 240 * 241 * @return The previous entry. 242 */ 243 protected LinkEntry<K, V> previousEntry() { 244 if (parent.modCount != expectedModCount) { 245 throw new ConcurrentModificationException(); 246 } 247 final LinkEntry<K, V> previous = next.before; 248 if (previous == parent.header) { 249 throw new NoSuchElementException(NO_PREVIOUS_ENTRY); 250 } 251 next = previous; 252 last = previous; 253 return last; 254 } 255 256 /** 257 * Removes the current entry. 258 */ 259 public void remove() { 260 if (last == null) { 261 throw new IllegalStateException(REMOVE_INVALID); 262 } 263 if (parent.modCount != expectedModCount) { 264 throw new ConcurrentModificationException(); 265 } 266 parent.remove(last.getKey()); 267 last = null; 268 expectedModCount = parent.modCount; 269 } 270 271 /** 272 * Resets the state to the end. 273 */ 274 public void reset() { 275 last = null; 276 next = parent.header.after; 277 } 278 279 @Override 280 public String toString() { 281 if (last != null) { 282 return "Iterator[" + last.getKey() + "=" + last.getValue() + "]"; 283 } 284 return "Iterator[]"; 285 } 286 } 287 288 /** 289 * MapIterator implementation. 290 * 291 * @param <K> The key type. 292 * @param <V> The value type. 293 */ 294 protected static class LinkMapIterator<K, V> extends LinkIterator<K, V> implements 295 OrderedMapIterator<K, V>, ResettableIterator<K> { 296 297 /** 298 * Constructs a new instance. 299 * 300 * @param parent The parent AbstractLinkedMap. 301 */ 302 protected LinkMapIterator(final AbstractLinkedMap<K, V> parent) { 303 super(parent); 304 } 305 306 @Override 307 public K getKey() { 308 final LinkEntry<K, V> current = currentEntry(); 309 if (current == null) { 310 throw new IllegalStateException(GETKEY_INVALID); 311 } 312 return current.getKey(); 313 } 314 315 @Override 316 public V getValue() { 317 final LinkEntry<K, V> current = currentEntry(); 318 if (current == null) { 319 throw new IllegalStateException(GETVALUE_INVALID); 320 } 321 return current.getValue(); 322 } 323 324 @Override 325 public K next() { 326 return super.nextEntry().getKey(); 327 } 328 329 @Override 330 public K previous() { 331 return super.previousEntry().getKey(); 332 } 333 334 @Override 335 public V setValue(final V value) { 336 final LinkEntry<K, V> current = currentEntry(); 337 if (current == null) { 338 throw new IllegalStateException(SETVALUE_INVALID); 339 } 340 return current.setValue(value); 341 } 342 } 343 344 /** 345 * Values iterator. 346 * 347 * @param <V> The value type. 348 */ 349 protected static class ValuesIterator<V> extends LinkIterator<Object, V> implements 350 OrderedIterator<V>, ResettableIterator<V> { 351 352 /** 353 * Constructs a new instance. 354 * 355 * @param parent The parent AbstractLinkedMap. 356 */ 357 @SuppressWarnings("unchecked") 358 protected ValuesIterator(final AbstractLinkedMap<?, V> parent) { 359 super((AbstractLinkedMap<Object, V>) parent); 360 } 361 362 @Override 363 public V next() { 364 return super.nextEntry().getValue(); 365 } 366 367 @Override 368 public V previous() { 369 return super.previousEntry().getValue(); 370 } 371 } 372 373 /** Header in the linked list */ 374 transient LinkEntry<K, V> header; 375 376 /** 377 * Constructor only used in deserialization, do not use otherwise. 378 */ 379 protected AbstractLinkedMap() { 380 } 381 382 /** 383 * Constructs a new, empty map with the specified initial capacity. 384 * 385 * @param initialCapacity The initial capacity 386 * @throws IllegalArgumentException if the initial capacity is negative 387 */ 388 protected AbstractLinkedMap(final int initialCapacity) { 389 super(initialCapacity); 390 } 391 392 /** 393 * Constructs a new, empty map with the specified initial capacity and 394 * load factor. 395 * 396 * @param initialCapacity The initial capacity 397 * @param loadFactor The load factor 398 * @throws IllegalArgumentException if the initial capacity is negative 399 * @throws IllegalArgumentException if the load factor is less than zero 400 */ 401 protected AbstractLinkedMap(final int initialCapacity, final float loadFactor) { 402 super(initialCapacity, loadFactor); 403 } 404 405 /** 406 * Constructor which performs no validation on the passed in parameters. 407 * 408 * @param initialCapacity The initial capacity, must be a power of two 409 * @param loadFactor The load factor, must be > 0.0f and generally < 1.0f 410 * @param threshold The threshold, must be sensible 411 */ 412 protected AbstractLinkedMap(final int initialCapacity, final float loadFactor, final int threshold) { 413 super(initialCapacity, loadFactor, threshold); 414 } 415 416 /** 417 * Constructor copying elements from another map. 418 * 419 * @param map The map to copy 420 * @throws NullPointerException if the map is null 421 */ 422 protected AbstractLinkedMap(final Map<? extends K, ? extends V> map) { 423 super(map); 424 } 425 426 /** 427 * Adds an entry into this map, maintaining insertion order. 428 * <p> 429 * This implementation adds the entry to the data storage table and 430 * to the end of the linked list. 431 * </p> 432 * 433 * @param entry The entry to add 434 * @param hashIndex The index into the data array to store at 435 */ 436 @Override 437 protected void addEntry(final HashEntry<K, V> entry, final int hashIndex) { 438 final LinkEntry<K, V> link = (LinkEntry<K, V>) entry; 439 link.after = header; 440 link.before = header.before; 441 header.before.after = link; 442 header.before = link; 443 data[hashIndex] = link; 444 } 445 446 /** 447 * Clears the map, resetting the size to zero and nullifying references 448 * to avoid garbage collection issues. 449 */ 450 @Override 451 public void clear() { 452 // override to reset the linked list 453 super.clear(); 454 header.before = header.after = header; 455 } 456 457 /** 458 * Checks whether the map contains the specified value. 459 * 460 * @param value The value to search for 461 * @return true if the map contains the value 462 */ 463 @Override 464 public boolean containsValue(final Object value) { 465 // override uses faster iterator 466 if (value == null) { 467 for (LinkEntry<K, V> entry = header.after; entry != header; entry = entry.after) { 468 if (entry.getValue() == null) { 469 return true; 470 } 471 } 472 } else { 473 for (LinkEntry<K, V> entry = header.after; entry != header; entry = entry.after) { 474 if (isEqualValue(value, entry.getValue())) { 475 return true; 476 } 477 } 478 } 479 return false; 480 } 481 482 /** 483 * Creates an entry to store the data. 484 * <p> 485 * This implementation creates a new LinkEntry instance. 486 * </p> 487 * 488 * @param next The next entry in sequence 489 * @param hashCode The hash code to use 490 * @param key The key to store 491 * @param value The value to store 492 * @return The newly created entry 493 */ 494 @Override 495 protected LinkEntry<K, V> createEntry(final HashEntry<K, V> next, final int hashCode, final K key, final V value) { 496 return new LinkEntry<>(next, hashCode, convertKey(key), value); 497 } 498 499 /** 500 * Creates an entry set iterator. 501 * Subclasses can override this to return iterators with different properties. 502 * 503 * @return The entrySet iterator 504 */ 505 @Override 506 protected Iterator<Map.Entry<K, V>> createEntrySetIterator() { 507 if (isEmpty()) { 508 return EmptyOrderedIterator.<Map.Entry<K, V>>emptyOrderedIterator(); 509 } 510 return new EntrySetIterator<>(this); 511 } 512 513 /** 514 * Creates a key set iterator. 515 * Subclasses can override this to return iterators with different properties. 516 * 517 * @return The keySet iterator 518 */ 519 @Override 520 protected Iterator<K> createKeySetIterator() { 521 if (isEmpty()) { 522 return EmptyOrderedIterator.<K>emptyOrderedIterator(); 523 } 524 return new KeySetIterator<>(this); 525 } 526 527 /** 528 * Creates a values iterator. 529 * Subclasses can override this to return iterators with different properties. 530 * 531 * @return The values iterator 532 */ 533 @Override 534 protected Iterator<V> createValuesIterator() { 535 if (isEmpty()) { 536 return EmptyOrderedIterator.<V>emptyOrderedIterator(); 537 } 538 return new ValuesIterator<>(this); 539 } 540 541 /** 542 * Gets the {@code after} field from a {@code LinkEntry}. 543 * Used in subclasses that have no visibility of the field. 544 * 545 * @param entry The entry to query, must not be null 546 * @return The {@code after} field of the entry 547 * @throws NullPointerException if the entry is null 548 * @since 3.1 549 */ 550 protected LinkEntry<K, V> entryAfter(final LinkEntry<K, V> entry) { 551 return entry.after; 552 } 553 554 /** 555 * Gets the {@code before} field from a {@code LinkEntry}. 556 * Used in subclasses that have no visibility of the field. 557 * 558 * @param entry The entry to query, must not be null 559 * @return The {@code before} field of the entry 560 * @throws NullPointerException if the entry is null 561 * @since 3.1 562 */ 563 protected LinkEntry<K, V> entryBefore(final LinkEntry<K, V> entry) { 564 return entry.before; 565 } 566 567 /** 568 * Gets the first key in the map, which is the first inserted. 569 * 570 * @return The eldest key 571 */ 572 @Override 573 public K firstKey() { 574 if (size == 0) { 575 throw new NoSuchElementException("Map is empty"); 576 } 577 return header.after.getKey(); 578 } 579 580 /** 581 * Gets the key at the specified index. 582 * 583 * @param index The index to retrieve 584 * @return The key at the specified index 585 * @throws IndexOutOfBoundsException if the index is invalid 586 */ 587 protected LinkEntry<K, V> getEntry(final int index) { 588 if (index < 0) { 589 throw new IndexOutOfBoundsException("Index " + index + " is less than zero"); 590 } 591 if (index >= size) { 592 throw new IndexOutOfBoundsException("Index " + index + " is invalid for size " + size); 593 } 594 LinkEntry<K, V> entry; 595 if (index < size / 2) { 596 // Search forwards 597 entry = header.after; 598 for (int currentIndex = 0; currentIndex < index; currentIndex++) { 599 entry = entry.after; 600 } 601 } else { 602 // Search backwards 603 entry = header; 604 for (int currentIndex = size; currentIndex > index; currentIndex--) { 605 entry = entry.before; 606 } 607 } 608 return entry; 609 } 610 611 @Override 612 protected LinkEntry<K, V> getEntry(final Object key) { 613 return (LinkEntry<K, V>) super.getEntry(key); 614 } 615 616 /** 617 * Initialize this subclass during construction. 618 * <p> 619 * Note: As from v3.2 this method calls 620 * {@link #createEntry(HashEntry, int, Object, Object)} to create 621 * the map entry object. 622 * </p> 623 */ 624 @Override 625 protected void init() { 626 header = createEntry(null, -1, null, null); 627 header.before = header.after = header; 628 } 629 630 /** 631 * Gets the last key in the map, which is the most recently inserted. 632 * 633 * @return The most recently inserted key 634 */ 635 @Override 636 public K lastKey() { 637 if (size == 0) { 638 throw new NoSuchElementException("Map is empty"); 639 } 640 return header.before.getKey(); 641 } 642 643 /** 644 * {@inheritDoc} 645 */ 646 @Override 647 public OrderedMapIterator<K, V> mapIterator() { 648 if (size == 0) { 649 return EmptyOrderedMapIterator.<K, V>emptyOrderedMapIterator(); 650 } 651 return new LinkMapIterator<>(this); 652 } 653 654 /** 655 * Gets the next key in sequence. 656 * 657 * @param key The key to get after 658 * @return The next key 659 */ 660 @Override 661 public K nextKey(final Object key) { 662 final LinkEntry<K, V> entry = getEntry(key); 663 return entry == null || entry.after == header ? null : entry.after.getKey(); 664 } 665 666 /** 667 * Gets the previous key in sequence. 668 * 669 * @param key The key to get before 670 * @return The previous key 671 */ 672 @Override 673 public K previousKey(final Object key) { 674 final LinkEntry<K, V> entry = getEntry(key); 675 return entry == null || entry.before == header ? null : entry.before.getKey(); 676 } 677 678 /** 679 * Removes an entry from the map and the linked list. 680 * <p> 681 * This implementation removes the entry from the linked list chain, then 682 * calls the superclass implementation. 683 * </p> 684 * 685 * @param entry The entry to remove 686 * @param hashIndex The index into the data structure 687 * @param previous The previous entry in the chain 688 */ 689 @Override 690 protected void removeEntry(final HashEntry<K, V> entry, final int hashIndex, final HashEntry<K, V> previous) { 691 final LinkEntry<K, V> link = (LinkEntry<K, V>) entry; 692 link.before.after = link.after; 693 link.after.before = link.before; 694 link.after = null; 695 link.before = null; 696 super.removeEntry(entry, hashIndex, previous); 697 } 698 699}