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

org.cometd.util.ImmutableHashMap Maven / Gradle / Ivy

package org.cometd.util;

import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;


/* ------------------------------------------------------------ */
/** Immutable Hash Map.
 * 

FixedHashMap is a hash {@link Map} implementation that provides both * mutable and immutable APIs to the same data structure. The immutable * API applies to deep structures of FixedHashMaps of FixedHashMaps. *

*

The implementation uses a fixed size array of hash entries whose keys * and hashes are retained when removed from the map, which is optimal * for pooled maps that will frequently contain the same key over and over. *

*

FixedMap keys cannot be null. FixedMap values may be null, but * null values are treated exactly as if the entry is not added to the * map. Setting a value to null is equivalent to removing the entry *

*

The {@link #getEntry(Object))} may be used to obtain references * to Map.Entry instances that will not change for a given key and thus * may be used for direct access to the related value. *

*

This map is not thread safe and multiple threads should not access * the map without some synchronization

. * * @param The key type * @param The key value */ public class ImmutableHashMap extends AbstractMap implements Map { private final DualEntry[] _entries; private final Mutable _mutable; private final ImmutableEntrySet _immutableSet; private final MutableEntrySet _mutableSet; private int _size; /* ------------------------------------------------------------ */ public ImmutableHashMap() { this(16); } /* ------------------------------------------------------------ */ public ImmutableHashMap(int nominalSize) { int capacity = 1; while (capacity < nominalSize) capacity <<= 1; _entries=new DualEntry[capacity]; _mutable=new Mutable(); _immutableSet = new ImmutableEntrySet(); _mutableSet = new MutableEntrySet(); } /* ------------------------------------------------------------ */ /** Get the immutable API to this map. * @return an Immutable map backed by this map. */ public Mutable asMutable() { return _mutable; } /* ------------------------------------------------------------ */ /** Get an entry reference. * The first [nominalSize] entries added are guaranteed never to * be deleted from the map, so the references may be used as repeated * quick lookups of the same key. * @param key * @return */ public Map.Entry getEntry(K key) { if (key == null) throw new IllegalArgumentException(); final int hash = key.hashCode(); final int index=hash & (_entries.length-1); for (DualEntry e = _entries[index]; e != null; e = e._next) { if (e._hash == hash && key.equals(e._key)) return e; } return null; } /* ------------------------------------------------------------ */ /** Called if the map is about to be changed. * @param key The key to be changed, or null if multiple keys. * @throws UnsupportedOperationException If change is not allowed/ */ protected void onChange(K key) throws UnsupportedOperationException { } /* ------------------------------------------------------------ */ @Override public Set> entrySet() { return _immutableSet; } /* ------------------------------------------------------------ */ @Override public boolean containsKey(Object key) { return _mutable.containsKey(key); } /* ------------------------------------------------------------ */ @Override public V get(Object key) { if (key == null) throw new IllegalArgumentException(); final int hash = key.hashCode(); final int index=hash & (_entries.length-1); for (DualEntry e = _entries[index]; e != null; e = e._next) { if (e._hash == hash && key.equals(e._key)) return e.getValue(); } return null; } /* ------------------------------------------------------------ */ @Override public int size() { return _size; } /* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */ public class Mutable extends AbstractMap implements Map { public ImmutableHashMap asImmutable() { return ImmutableHashMap.this; } /* ------------------------------------------------------------ */ @Override public Set> entrySet() { return _mutableSet; } /* ------------------------------------------------------------ */ @Override public boolean containsKey(Object key) { if (key == null) throw new IllegalArgumentException(); final int hash = key.hashCode(); final int index=hash & (_entries.length-1); for (DualEntry e = _entries[index]; e != null; e = e._next) { if (e._hash == hash && key.equals(e._key)) return true; } return false; } /* ------------------------------------------------------------ */ @Override public V get(Object key) { if (key == null) throw new IllegalArgumentException(); final int hash = key.hashCode(); final int index=hash & (_entries.length-1); for (DualEntry e = _entries[index]; e != null; e = e._next) { if (e._hash == hash && key.equals(e._key)) return e._mutable.getValue(); } return null; } /* ------------------------------------------------------------ */ /** Get an entry reference. * The first [nominalSize] entries added are guarenteed never to * be deleted from the map, so the references may be used as repeated * quick lookups of the same key. * @param key * @return */ public Map.Entry getEntry(K key) { if (key == null) throw new IllegalArgumentException(); final int hash = key.hashCode(); final int index=hash & (_entries.length-1); for (DualEntry e = _entries[index]; e != null; e = e._next) { if (e._hash == hash && key.equals(e._key)) return e._mutable; } return null; } /* ------------------------------------------------------------ */ @Override public V put(K key, V value) { if (key == null) throw new IllegalArgumentException(); onChange(key); final int hash = key.hashCode(); final int index=hash & (_entries.length-1); DualEntry last = null; for (DualEntry e = _entries[index]; e != null; e = e._next) { if (e._hash == hash && key.equals(e._key)) { V old=e._mutable.setValue(value); return old; } last=e; } DualEntry e = new DualEntry(ImmutableHashMap.this,hash,key,value); if (last==null) _entries[index]=e; else last._next=e; return null; } /* ------------------------------------------------------------ */ @Override public void clear() { onChange(null); for (int i=_entries.length; i-->0;) { int depth=0; for (DualEntry e = _entries[i]; e != null; e = e._next) { e._mutable.setValue(null); if (++depth>_entries.length) { e._next=null; break; } } } _size=0; } /* ------------------------------------------------------------ */ @Override public V remove(Object key) { if (key == null) throw new IllegalArgumentException(); onChange((K)key); final int hash = key.hashCode(); final int index=hash & (_entries.length-1); for (DualEntry e = _entries[index]; e != null; e = e._next) { if (e._hash == hash && key.equals(e._key)) { V old=e._mutable.setValue(null); return old; } } return null; } /* ------------------------------------------------------------ */ @Override public int size() { return _size; } } /* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */ class MutableEntrySet extends AbstractSet> { @Override public Iterator> iterator() { return new MutableEntryIterator(); } @Override public int size() { return _size; } } /* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */ class ImmutableEntrySet extends AbstractSet> { @Override public Iterator> iterator() { return new ImmutableEntryIterator(); } @Override public int size() { return _size; } } /* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */ static class DualEntry implements Map.Entry { private final ImmutableHashMap _map; private final K _key; private final int _hash; private V _value; private DualEntry _next; public K getKey() { return _key; } public V getValue() { if (_value instanceof ImmutableHashMap.Mutable) return (V)((ImmutableHashMap.Mutable)_value).asImmutable(); else if (_value instanceof Map) return (V)Collections.unmodifiableMap((Map)_value); return _value; } public V setValue(V value) { throw new UnsupportedOperationException(); } private Map.Entry _mutable = new Map.Entry() { public K getKey() { return _key; } public V getValue() { if (_value instanceof ImmutableHashMap) return (V)((ImmutableHashMap)_value).asMutable(); return _value; } public V setValue(V value) { _map.onChange(_key); V old = _value; _value = value; if (old!=null && _value==null) _map._size--; else if (old==null && _value!=null) _map._size++; return old; } }; DualEntry(ImmutableHashMap map,int hash, K k, V v) { _map=map; _value = v; if (_value!=null) _map._size++; _key = k; _hash = hash; } } /* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */ class EntryIterator { protected int _index=0; protected DualEntry _entry; protected DualEntry _last; EntryIterator() { while(_entry==null && _index<_entries.length) { _entry=_entries[_index++]; while(_entry!=null && _entry._value==null) { _entry=_entry._next; } } } public boolean hasNext() { return _entry!=null; } protected DualEntry nextEntry() { if (_entry==null) throw new NoSuchElementException(); DualEntry entry=_entry; _entry=_entry._next; while(_entry!=null && _entry._value==null) { _entry=_entry._next; } while(_entry==null && _index<_entries.length) { _entry=_entries[_index++]; while(_entry!=null && _entry._value==null) { _entry=_entry._next; } } _last=entry; return entry; } } /* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */ class ImmutableEntryIterator extends EntryIterator implements Iterator> { ImmutableEntryIterator() {} public Map.Entry next() { return nextEntry(); } public void remove() { throw new UnsupportedOperationException(); } } /* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */ class MutableEntryIterator extends EntryIterator implements Iterator> { MutableEntryIterator() {} public Map.Entry next() { return nextEntry()._mutable; } public void remove() { if (_last==null) throw new NoSuchElementException(); _last._mutable.setValue(null); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy