AbstractLinkedMap.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.apache.commons.collections4.map;

  18. import java.util.ConcurrentModificationException;
  19. import java.util.Iterator;
  20. import java.util.Map;
  21. import java.util.NoSuchElementException;
  22. import java.util.Objects;

  23. import org.apache.commons.collections4.OrderedIterator;
  24. import org.apache.commons.collections4.OrderedMap;
  25. import org.apache.commons.collections4.OrderedMapIterator;
  26. import org.apache.commons.collections4.ResettableIterator;
  27. import org.apache.commons.collections4.iterators.EmptyOrderedIterator;
  28. import org.apache.commons.collections4.iterators.EmptyOrderedMapIterator;

  29. /**
  30.  * An abstract implementation of a hash-based map that links entries to create an
  31.  * ordered map and which provides numerous points for subclasses to override.
  32.  * <p>
  33.  * This class implements all the features necessary for a subclass linked
  34.  * hash-based map. Key-value entries are stored in instances of the
  35.  * {@code LinkEntry} class which can be overridden and replaced.
  36.  * The iterators can similarly be replaced, without the need to replace the KeySet,
  37.  * EntrySet and Values view classes.
  38.  * </p>
  39.  * <p>
  40.  * Overridable methods are provided to change the default hashing behavior, and
  41.  * to change how entries are added to and removed from the map. Hopefully, all you
  42.  * need for unusual subclasses is here.
  43.  * </p>
  44.  * <p>
  45.  * This implementation maintains order by original insertion, but subclasses
  46.  * may work differently. The {@code OrderedMap} interface is implemented
  47.  * to provide access to bidirectional iteration and extra convenience methods.
  48.  * </p>
  49.  * <p>
  50.  * The {@code orderedMapIterator()} method provides direct access to a
  51.  * bidirectional iterator. The iterators from the other views can also be cast
  52.  * to {@code OrderedIterator} if required.
  53.  * </p>
  54.  * <p>
  55.  * All the available iterators can be reset back to the start by casting to
  56.  * {@code ResettableIterator} and calling {@code reset()}.
  57.  * </p>
  58.  * <p>
  59.  * The implementation is also designed to be subclassed, with lots of useful
  60.  * methods exposed.
  61.  * </p>
  62.  *
  63.  * @param <K> the type of the keys in this map
  64.  * @param <V> the type of the values in this map
  65.  * @since 3.0
  66.  */
  67. public abstract class AbstractLinkedMap<K, V> extends AbstractHashedMap<K, V> implements OrderedMap<K, V> {

  68.     /**
  69.      * EntrySet iterator.
  70.      *
  71.      * @param <K> the key type.
  72.      * @param <V> the value type.
  73.      */
  74.     protected static class EntrySetIterator<K, V> extends LinkIterator<K, V> implements
  75.             OrderedIterator<Map.Entry<K, V>>, ResettableIterator<Map.Entry<K, V>> {

  76.         /**
  77.          * Constructs a new instance.
  78.          *
  79.          * @param parent The parent AbstractLinkedMap.
  80.          */
  81.         protected EntrySetIterator(final AbstractLinkedMap<K, V> parent) {
  82.             super(parent);
  83.         }

  84.         @Override
  85.         public Map.Entry<K, V> next() {
  86.             return super.nextEntry();
  87.         }

  88.         @Override
  89.         public Map.Entry<K, V> previous() {
  90.             return super.previousEntry();
  91.         }
  92.     }

  93.     /**
  94.      * KeySet iterator.
  95.      *
  96.      * @param <K> the key type.
  97.      */
  98.     protected static class KeySetIterator<K> extends LinkIterator<K, Object> implements
  99.             OrderedIterator<K>, ResettableIterator<K> {

  100.         /**
  101.          * Constructs a new instance.
  102.          *
  103.          * @param parent The parent AbstractLinkedMap.
  104.          */
  105.         @SuppressWarnings("unchecked")
  106.         protected KeySetIterator(final AbstractLinkedMap<K, ?> parent) {
  107.             super((AbstractLinkedMap<K, Object>) parent);
  108.         }

  109.         @Override
  110.         public K next() {
  111.             return super.nextEntry().getKey();
  112.         }

  113.         @Override
  114.         public K previous() {
  115.             return super.previousEntry().getKey();
  116.         }
  117.     }

  118.     /**
  119.      * LinkEntry that stores the data.
  120.      * <p>
  121.      * If you subclass {@code AbstractLinkedMap} but not {@code LinkEntry}
  122.      * then you will not be able to access the protected fields.
  123.      * The {@code entryXxx()} methods on {@code AbstractLinkedMap} exist
  124.      * to provide the necessary access.
  125.      * </p>
  126.      *
  127.      * @param <K> the key type.
  128.      * @param <V> the value type.
  129.      */
  130.     protected static class LinkEntry<K, V> extends HashEntry<K, V> {
  131.         /** The entry before this one in the order */
  132.         protected LinkEntry<K, V> before;
  133.         /** The entry after this one in the order */
  134.         protected LinkEntry<K, V> after;

  135.         /**
  136.          * Constructs a new entry.
  137.          *
  138.          * @param next  the next entry in the hash bucket sequence
  139.          * @param hashCode  the hash code
  140.          * @param key  the key
  141.          * @param value  the value
  142.          */
  143.         protected LinkEntry(final HashEntry<K, V> next, final int hashCode, final Object key, final V value) {
  144.             super(next, hashCode, key, value);
  145.         }
  146.     }

  147.     /**
  148.      * Base Iterator that iterates in link order.
  149.      *
  150.      * @param <K> the key type.
  151.      * @param <V> the value type.
  152.      */
  153.     protected abstract static class LinkIterator<K, V> {

  154.         /** The parent map */
  155.         protected final AbstractLinkedMap<K, V> parent;

  156.         /** The current (last returned) entry */
  157.         protected LinkEntry<K, V> last;

  158.         /** The next entry */
  159.         protected LinkEntry<K, V> next;

  160.         /** The modification count expected */
  161.         protected int expectedModCount;

  162.         /**
  163.          * Constructs a new instance.
  164.          *
  165.          * @param parent The parent AbstractLinkedMap.
  166.          */
  167.         protected LinkIterator(final AbstractLinkedMap<K, V> parent) {
  168.             this.parent = Objects.requireNonNull(parent);
  169.             this.next = parent.header.after;
  170.             this.expectedModCount = parent.modCount;
  171.         }

  172.         /**
  173.          * Gets the current entry.
  174.          *
  175.          * @return the current entry.
  176.          */
  177.         protected LinkEntry<K, V> currentEntry() {
  178.             return last;
  179.         }

  180.         /**
  181.          * Tests whether there is another entry.
  182.          *
  183.          * @return whether there is another entry.
  184.          */
  185.         public boolean hasNext() {
  186.             return next != parent.header;
  187.         }

  188.         /**
  189.          * Tests whether there is a previous entry.
  190.          *
  191.          * @return whether there is a previous entry.
  192.          */
  193.         public boolean hasPrevious() {
  194.             return next.before != parent.header;
  195.         }

  196.         /**
  197.          * Gets the next entry.
  198.          *
  199.          * @return the next entry.
  200.          */
  201.         protected LinkEntry<K, V> nextEntry() {
  202.             if (parent.modCount != expectedModCount) {
  203.                 throw new ConcurrentModificationException();
  204.             }
  205.             if (next == parent.header)  {
  206.                 throw new NoSuchElementException(NO_NEXT_ENTRY);
  207.             }
  208.             last = next;
  209.             next = next.after;
  210.             return last;
  211.         }

  212.         /**
  213.          * Gets the previous entry.
  214.          *
  215.          * @return the previous entry.
  216.          */
  217.         protected LinkEntry<K, V> previousEntry() {
  218.             if (parent.modCount != expectedModCount) {
  219.                 throw new ConcurrentModificationException();
  220.             }
  221.             final LinkEntry<K, V> previous = next.before;
  222.             if (previous == parent.header)  {
  223.                 throw new NoSuchElementException(NO_PREVIOUS_ENTRY);
  224.             }
  225.             next = previous;
  226.             last = previous;
  227.             return last;
  228.         }

  229.         /**
  230.          * Removes the current entry.
  231.          */
  232.         public void remove() {
  233.             if (last == null) {
  234.                 throw new IllegalStateException(REMOVE_INVALID);
  235.             }
  236.             if (parent.modCount != expectedModCount) {
  237.                 throw new ConcurrentModificationException();
  238.             }
  239.             parent.remove(last.getKey());
  240.             last = null;
  241.             expectedModCount = parent.modCount;
  242.         }

  243.         /**
  244.          * Resets the state to the end.
  245.          */
  246.         public void reset() {
  247.             last = null;
  248.             next = parent.header.after;
  249.         }

  250.         @Override
  251.         public String toString() {
  252.             if (last != null) {
  253.                 return "Iterator[" + last.getKey() + "=" + last.getValue() + "]";
  254.             }
  255.             return "Iterator[]";
  256.         }
  257.     }

  258.     /**
  259.      * MapIterator implementation.
  260.      *
  261.      * @param <K> the key type.
  262.      * @param <V> the value type.
  263.      */
  264.     protected static class LinkMapIterator<K, V> extends LinkIterator<K, V> implements
  265.             OrderedMapIterator<K, V>, ResettableIterator<K> {

  266.         /**
  267.          * Constructs a new instance.
  268.          *
  269.          * @param parent The parent AbstractLinkedMap.
  270.          */
  271.         protected LinkMapIterator(final AbstractLinkedMap<K, V> parent) {
  272.             super(parent);
  273.         }

  274.         @Override
  275.         public K getKey() {
  276.             final LinkEntry<K, V> current = currentEntry();
  277.             if (current == null) {
  278.                 throw new IllegalStateException(GETKEY_INVALID);
  279.             }
  280.             return current.getKey();
  281.         }

  282.         @Override
  283.         public V getValue() {
  284.             final LinkEntry<K, V> current = currentEntry();
  285.             if (current == null) {
  286.                 throw new IllegalStateException(GETVALUE_INVALID);
  287.             }
  288.             return current.getValue();
  289.         }

  290.         @Override
  291.         public K next() {
  292.             return super.nextEntry().getKey();
  293.         }

  294.         @Override
  295.         public K previous() {
  296.             return super.previousEntry().getKey();
  297.         }

  298.         @Override
  299.         public V setValue(final V value) {
  300.             final LinkEntry<K, V> current = currentEntry();
  301.             if (current == null) {
  302.                 throw new IllegalStateException(SETVALUE_INVALID);
  303.             }
  304.             return current.setValue(value);
  305.         }
  306.     }

  307.     /**
  308.      * Values iterator.
  309.      *
  310.      * @param <V> the value type.
  311.      */
  312.     protected static class ValuesIterator<V> extends LinkIterator<Object, V> implements
  313.             OrderedIterator<V>, ResettableIterator<V> {

  314.         /**
  315.          * Constructs a new instance.
  316.          *
  317.          * @param parent The parent AbstractLinkedMap.
  318.          */
  319.         @SuppressWarnings("unchecked")
  320.         protected ValuesIterator(final AbstractLinkedMap<?, V> parent) {
  321.             super((AbstractLinkedMap<Object, V>) parent);
  322.         }

  323.         @Override
  324.         public V next() {
  325.             return super.nextEntry().getValue();
  326.         }

  327.         @Override
  328.         public V previous() {
  329.             return super.previousEntry().getValue();
  330.         }
  331.     }

  332.     /** Header in the linked list */
  333.     transient LinkEntry<K, V> header;

  334.     /**
  335.      * Constructor only used in deserialization, do not use otherwise.
  336.      */
  337.     protected AbstractLinkedMap() {
  338.     }

  339.     /**
  340.      * Constructs a new, empty map with the specified initial capacity.
  341.      *
  342.      * @param initialCapacity  the initial capacity
  343.      * @throws IllegalArgumentException if the initial capacity is negative
  344.      */
  345.     protected AbstractLinkedMap(final int initialCapacity) {
  346.         super(initialCapacity);
  347.     }

  348.     /**
  349.      * Constructs a new, empty map with the specified initial capacity and
  350.      * load factor.
  351.      *
  352.      * @param initialCapacity  the initial capacity
  353.      * @param loadFactor  the load factor
  354.      * @throws IllegalArgumentException if the initial capacity is negative
  355.      * @throws IllegalArgumentException if the load factor is less than zero
  356.      */
  357.     protected AbstractLinkedMap(final int initialCapacity, final float loadFactor) {
  358.         super(initialCapacity, loadFactor);
  359.     }

  360.     /**
  361.      * Constructor which performs no validation on the passed in parameters.
  362.      *
  363.      * @param initialCapacity  the initial capacity, must be a power of two
  364.      * @param loadFactor  the load factor, must be &gt; 0.0f and generally &lt; 1.0f
  365.      * @param threshold  the threshold, must be sensible
  366.      */
  367.     protected AbstractLinkedMap(final int initialCapacity, final float loadFactor, final int threshold) {
  368.         super(initialCapacity, loadFactor, threshold);
  369.     }

  370.     /**
  371.      * Constructor copying elements from another map.
  372.      *
  373.      * @param map  the map to copy
  374.      * @throws NullPointerException if the map is null
  375.      */
  376.     protected AbstractLinkedMap(final Map<? extends K, ? extends V> map) {
  377.         super(map);
  378.     }

  379.     /**
  380.      * Adds an entry into this map, maintaining insertion order.
  381.      * <p>
  382.      * This implementation adds the entry to the data storage table and
  383.      * to the end of the linked list.
  384.      * </p>
  385.      *
  386.      * @param entry  the entry to add
  387.      * @param hashIndex  the index into the data array to store at
  388.      */
  389.     @Override
  390.     protected void addEntry(final HashEntry<K, V> entry, final int hashIndex) {
  391.         final LinkEntry<K, V> link = (LinkEntry<K, V>) entry;
  392.         link.after  = header;
  393.         link.before = header.before;
  394.         header.before.after = link;
  395.         header.before = link;
  396.         data[hashIndex] = link;
  397.     }

  398.     /**
  399.      * Clears the map, resetting the size to zero and nullifying references
  400.      * to avoid garbage collection issues.
  401.      */
  402.     @Override
  403.     public void clear() {
  404.         // override to reset the linked list
  405.         super.clear();
  406.         header.before = header.after = header;
  407.     }

  408.     /**
  409.      * Checks whether the map contains the specified value.
  410.      *
  411.      * @param value  the value to search for
  412.      * @return true if the map contains the value
  413.      */
  414.     @Override
  415.     public boolean containsValue(final Object value) {
  416.         // override uses faster iterator
  417.         if (value == null) {
  418.             for (LinkEntry<K, V> entry = header.after; entry != header; entry = entry.after) {
  419.                 if (entry.getValue() == null) {
  420.                     return true;
  421.                 }
  422.             }
  423.         } else {
  424.             for (LinkEntry<K, V> entry = header.after; entry != header; entry = entry.after) {
  425.                 if (isEqualValue(value, entry.getValue())) {
  426.                     return true;
  427.                 }
  428.             }
  429.         }
  430.         return false;
  431.     }

  432.     /**
  433.      * Creates an entry to store the data.
  434.      * <p>
  435.      * This implementation creates a new LinkEntry instance.
  436.      * </p>
  437.      *
  438.      * @param next  the next entry in sequence
  439.      * @param hashCode  the hash code to use
  440.      * @param key  the key to store
  441.      * @param value  the value to store
  442.      * @return the newly created entry
  443.      */
  444.     @Override
  445.     protected LinkEntry<K, V> createEntry(final HashEntry<K, V> next, final int hashCode, final K key, final V value) {
  446.         return new LinkEntry<>(next, hashCode, convertKey(key), value);
  447.     }

  448.     /**
  449.      * Creates an entry set iterator.
  450.      * Subclasses can override this to return iterators with different properties.
  451.      *
  452.      * @return the entrySet iterator
  453.      */
  454.     @Override
  455.     protected Iterator<Map.Entry<K, V>> createEntrySetIterator() {
  456.         if (isEmpty()) {
  457.             return EmptyOrderedIterator.<Map.Entry<K, V>>emptyOrderedIterator();
  458.         }
  459.         return new EntrySetIterator<>(this);
  460.     }

  461.     /**
  462.      * Creates a key set iterator.
  463.      * Subclasses can override this to return iterators with different properties.
  464.      *
  465.      * @return the keySet iterator
  466.      */
  467.     @Override
  468.     protected Iterator<K> createKeySetIterator() {
  469.         if (isEmpty()) {
  470.             return EmptyOrderedIterator.<K>emptyOrderedIterator();
  471.         }
  472.         return new KeySetIterator<>(this);
  473.     }

  474.     /**
  475.      * Creates a values iterator.
  476.      * Subclasses can override this to return iterators with different properties.
  477.      *
  478.      * @return the values iterator
  479.      */
  480.     @Override
  481.     protected Iterator<V> createValuesIterator() {
  482.         if (isEmpty()) {
  483.             return EmptyOrderedIterator.<V>emptyOrderedIterator();
  484.         }
  485.         return new ValuesIterator<>(this);
  486.     }

  487.     /**
  488.      * Gets the {@code after} field from a {@code LinkEntry}.
  489.      * Used in subclasses that have no visibility of the field.
  490.      *
  491.      * @param entry  the entry to query, must not be null
  492.      * @return the {@code after} field of the entry
  493.      * @throws NullPointerException if the entry is null
  494.      * @since 3.1
  495.      */
  496.     protected LinkEntry<K, V> entryAfter(final LinkEntry<K, V> entry) {
  497.         return entry.after;
  498.     }

  499.     /**
  500.      * Gets the {@code before} field from a {@code LinkEntry}.
  501.      * Used in subclasses that have no visibility of the field.
  502.      *
  503.      * @param entry  the entry to query, must not be null
  504.      * @return the {@code before} field of the entry
  505.      * @throws NullPointerException if the entry is null
  506.      * @since 3.1
  507.      */
  508.     protected LinkEntry<K, V> entryBefore(final LinkEntry<K, V> entry) {
  509.         return entry.before;
  510.     }

  511.     /**
  512.      * Gets the first key in the map, which is the first inserted.
  513.      *
  514.      * @return the eldest key
  515.      */
  516.     @Override
  517.     public K firstKey() {
  518.         if (size == 0) {
  519.             throw new NoSuchElementException("Map is empty");
  520.         }
  521.         return header.after.getKey();
  522.     }

  523.     /**
  524.      * Gets the key at the specified index.
  525.      *
  526.      * @param index  the index to retrieve
  527.      * @return the key at the specified index
  528.      * @throws IndexOutOfBoundsException if the index is invalid
  529.      */
  530.     protected LinkEntry<K, V> getEntry(final int index) {
  531.         if (index < 0) {
  532.             throw new IndexOutOfBoundsException("Index " + index + " is less than zero");
  533.         }
  534.         if (index >= size) {
  535.             throw new IndexOutOfBoundsException("Index " + index + " is invalid for size " + size);
  536.         }
  537.         LinkEntry<K, V> entry;
  538.         if (index < size / 2) {
  539.             // Search forwards
  540.             entry = header.after;
  541.             for (int currentIndex = 0; currentIndex < index; currentIndex++) {
  542.                 entry = entry.after;
  543.             }
  544.         } else {
  545.             // Search backwards
  546.             entry = header;
  547.             for (int currentIndex = size; currentIndex > index; currentIndex--) {
  548.                 entry = entry.before;
  549.             }
  550.         }
  551.         return entry;
  552.     }

  553.     @Override
  554.     protected LinkEntry<K, V> getEntry(final Object key) {
  555.         return (LinkEntry<K, V>) super.getEntry(key);
  556.     }

  557.     /**
  558.      * Initialize this subclass during construction.
  559.      * <p>
  560.      * Note: As from v3.2 this method calls
  561.      * {@link #createEntry(HashEntry, int, Object, Object)} to create
  562.      * the map entry object.
  563.      * </p>
  564.      */
  565.     @Override
  566.     protected void init() {
  567.         header = createEntry(null, -1, null, null);
  568.         header.before = header.after = header;
  569.     }

  570.     /**
  571.      * Gets the last key in the map, which is the most recently inserted.
  572.      *
  573.      * @return the most recently inserted key
  574.      */
  575.     @Override
  576.     public K lastKey() {
  577.         if (size == 0) {
  578.             throw new NoSuchElementException("Map is empty");
  579.         }
  580.         return header.before.getKey();
  581.     }

  582.     /**
  583.      * {@inheritDoc}
  584.      */
  585.     @Override
  586.     public OrderedMapIterator<K, V> mapIterator() {
  587.         if (size == 0) {
  588.             return EmptyOrderedMapIterator.<K, V>emptyOrderedMapIterator();
  589.         }
  590.         return new LinkMapIterator<>(this);
  591.     }

  592.     /**
  593.      * Gets the next key in sequence.
  594.      *
  595.      * @param key  the key to get after
  596.      * @return the next key
  597.      */
  598.     @Override
  599.     public K nextKey(final Object key) {
  600.         final LinkEntry<K, V> entry = getEntry(key);
  601.         return entry == null || entry.after == header ? null : entry.after.getKey();
  602.     }

  603.     /**
  604.      * Gets the previous key in sequence.
  605.      *
  606.      * @param key  the key to get before
  607.      * @return the previous key
  608.      */
  609.     @Override
  610.     public K previousKey(final Object key) {
  611.         final LinkEntry<K, V> entry = getEntry(key);
  612.         return entry == null || entry.before == header ? null : entry.before.getKey();
  613.     }

  614.     /**
  615.      * Removes an entry from the map and the linked list.
  616.      * <p>
  617.      * This implementation removes the entry from the linked list chain, then
  618.      * calls the superclass implementation.
  619.      * </p>
  620.      *
  621.      * @param entry  the entry to remove
  622.      * @param hashIndex  the index into the data structure
  623.      * @param previous  the previous entry in the chain
  624.      */
  625.     @Override
  626.     protected void removeEntry(final HashEntry<K, V> entry, final int hashIndex, final HashEntry<K, V> previous) {
  627.         final LinkEntry<K, V> link = (LinkEntry<K, V>) entry;
  628.         link.before.after = link.after;
  629.         link.after.before = link.before;
  630.         link.after = null;
  631.         link.before = null;
  632.         super.removeEntry(entry, hashIndex, previous);
  633.     }

  634. }