All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.infinispan.commons.equivalence.EquivalentLinkedHashMap Maven / Gradle / Ivy

There is a newer version: 9.1.7.Final
Show newest version
package org.infinispan.commons.equivalence;

import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;

/**
 * Custom hash-based linked list map which accepts no null keys nor null values,
 * where equality and hash code calculations are done based on passed
 * {@link org.infinispan.commons.equivalence.Equivalence} function implementations for keys
 * and values, as opposed to relying on their own equals/hashCode/toString
 * implementations. This is handy when using key/values whose mentioned
 * methods cannot be overriden, i.e. arrays, and in situations where users
 * want to avoid using wrapper objects.
 *
 * In order to provide linked list behaviour, entries are linked with each
 * other in a predictable order.
 *
 * @author Galder Zamarreño
 * @since 6.0
 */
public class EquivalentLinkedHashMap extends EquivalentHashMap {

   private transient LinkedNode header;

   private final IterationOrder iterationOrder;

   public EquivalentLinkedHashMap(int initialCapacity, float loadFactor,
         IterationOrder iterationOrder,
         Equivalence keyEq, Equivalence valueEq) {
      super(initialCapacity, loadFactor, keyEq, valueEq);
      this.iterationOrder = iterationOrder;
      addFirstEntry();
   }

   private void addFirstEntry() {
      header = createLinkedNode();
      header.before = header;
      header.after = header;
   }

   @Override
   void addEntry(int index, K key, V value, int hash) {
      super.addEntry(index, key, value, hash);
      LinkedNode eldest = header.after;
      if (removeEldestEntry(eldest)) {
         remove(eldest.getKey());
      }
   }

   protected boolean removeEldestEntry(Map.Entry eldest) {
      return false;
   }

   @SuppressWarnings("unchecked")
   private  LinkedNode createLinkedNode() {
      return new LinkedNode(null, -1, null, null);
   }

   @Override
   Node createNode(K key, V value, int hash, Node node) {
      LinkedNode linkedNode = new LinkedNode(key, hash, value, node);
      linkedNode.addBefore(header);
      return linkedNode;
   }

   @Override
   public V get(Object key) {
      LinkedNode n = getNode(key);
      return n == null ? null : n.recordAccess(this);
   }

   @Override
   public V remove(Object key) {
      LinkedNode prevNode = removeNode(key);
      return prevNode == null ? null : prevNode.remove();
   }

   @Override
   public void clear() {
      super.clear();
      header.before = header;
      header.after = header;
   }

   private static final class LinkedNode extends Node {

      LinkedNode before;
      LinkedNode after;

      private LinkedNode(K key, int hash, V value, Node next) {
         super(key, hash, value, next);
      }

      private V remove() {
         before.after = after;
         after.before = before;
         return value;
      }

      private void addBefore(LinkedNode entry) {
         after  = entry;
         before = entry.before;
         before.after = this;
         after.before = this;
      }

      V recordAccess(EquivalentHashMap m) {
         EquivalentLinkedHashMap linkedMap = (EquivalentLinkedHashMap)m;
         if (linkedMap.iterationOrder == IterationOrder.ACCESS_ORDER) {
            linkedMap.modCount++;
            remove();
            addBefore(linkedMap.header);
         }
         return value;
      }

      @Override
      protected V setValue(V value, EquivalentHashMap map) {
         V retValue = super.setValue(value, map);
         recordAccess(map);
         return retValue;
      }
   }

   public enum IterationOrder {
      ACCESS_ORDER, INSERT_ORDER;

      public boolean toJdkAccessOrder() {
         return this == ACCESS_ORDER;
      }
   }

   /**
    * Exported Entry for iterators
    */
   private static class LinkedEntry extends MapEntry {
      LinkedNode before;
      LinkedNode after;

      LinkedEntry(K key, V val, LinkedNode before, LinkedNode after, EquivalentHashMap map) {
         super(key, val, map);
         this.before = before;
         this.after = after;
      }
   }

   private abstract class EquivalentLinkedHashIterator implements Iterator {
      final EquivalentHashMap map;
      LinkedEntry nextEntry;
      LinkedEntry lastReturned = null;

      protected EquivalentLinkedHashIterator(EquivalentHashMap map) {
         this.map = map;
         nextEntry = new LinkedEntry(
               header.after.key, header.after.value,
               header.after.before, header.after.after, map);
      }

      /**
       * The modCount value that the iterator believes that the backing
       * List should have.  If this expectation is violated, the iterator
       * has detected concurrent modification.
       */
      int expectedModCount = modCount;

      public boolean hasNext() {
         return !equals(nextEntry, header);
      }

      public void remove() {
         if (lastReturned == null)
            throw new IllegalStateException();
         if (modCount != expectedModCount)
            throw new ConcurrentModificationException();

         EquivalentLinkedHashMap.this.remove(lastReturned.key);
         lastReturned = null;
         expectedModCount = modCount;
      }

      LinkedEntry nextEntry() {
         if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
         if (equals(nextEntry, header))
            throw new NoSuchElementException();

         LinkedEntry e = nextEntry;
         lastReturned = nextEntry;
         nextEntry = new LinkedEntry(
               e.after.key, e.after.value,
               e.after.before, e.after.after, map);
         return e;
      }

      boolean equals(LinkedEntry entry, LinkedNode node) {
         return entry.key == node.key
               && entry.val == node.value
               && entry.before == node.before
               && entry.after == node.after;
      }
   }

   private class KeyIterator extends EquivalentLinkedHashIterator {

      protected KeyIterator(EquivalentHashMap map) {
         super(map);
      }

      public K next() {
         return nextEntry().getKey();
      }
   }

   private class ValueIterator extends EquivalentLinkedHashIterator {

      protected ValueIterator(EquivalentHashMap map) {
         super(map);
      }

      public V next() {
         return nextEntry().val;
      }
   }

   private class EntryIterator extends EquivalentLinkedHashIterator> {

      protected EntryIterator(EquivalentHashMap map) {
         super(map);
      }

      public Map.Entry next() {
         return nextEntry();
      }
   }

   Iterator newKeyIterator() {
      return new KeyIterator(this);
   }

   Iterator newValueIterator() {
      return new ValueIterator(this);
   }

   Iterator> newEntryIterator() {
      return new EntryIterator(this);
   }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy