net.sf.javagimmicks.collections.bidimap.DualBidiMap Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gimmicks Show documentation
Show all versions of gimmicks Show documentation
Utility classes, APIs and tools for Java
package net.sf.javagimmicks.collections.bidimap;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* A default implementation of {@link BidiMap} that internally works with two
* convenient {@link Map} (one for each "direction").
*/
public class DualBidiMap extends AbstractMap implements BidiMap
{
protected final Map _forwardMap;
protected final Map _reverseMap;
/**
* Creates a new instance for the given forward and reverse {@link Map}
*
* @param forwardMap
* the forward {@link Map} used to map keys to values
* @param reverseMap
* the reverse {@link Map} used to map values to keys
*/
public DualBidiMap(final Map forwardMap, final Map reverseMap)
{
_forwardMap = forwardMap;
_reverseMap = reverseMap;
}
@Override
public Set> entrySet()
{
return new DualBidiEntrySet(getForwardMap().entrySet());
}
@Override
public V put(final K key, final V value)
{
checkKey(key);
checkValue(value);
final V oldValue = getForwardMap().put(key, value);
postProcessPut(key, value, oldValue);
return oldValue;
}
@Override
public V remove(final Object key)
{
final V value = getForwardMap().remove(key);
getReverseMap().remove(value);
return value;
}
@Override
public BidiMap inverseBidiMap()
{
return new InverseDualBidiMap(getReverseMap(), getForwardMap());
}
@Override
public V get(final Object key)
{
return getForwardMap().get(key);
}
@Override
public K getKey(final V value)
{
return getReverseMap().get(value);
}
protected Map getForwardMap()
{
return _forwardMap;
}
protected Map getReverseMap()
{
return _reverseMap;
}
protected void postProcessPut(final K key, final V newValue, final V oldValue)
{
final Map reverseMap = getReverseMap();
// Put the new value to the reverse map
final K oldKey = reverseMap.put(newValue, key);
// Update to forward map might have invalidated a key in the reverse map
if (oldValue != null)
{
reverseMap.remove(oldValue);
}
// Update to reverse map might have invalidated a key in the forward map
if (oldKey != null)
{
getForwardMap().remove(oldKey);
}
}
protected static void checkKey(final K value)
{
if (value == null)
{
throw new IllegalArgumentException("Null keys not allowed in BidiMaps!");
}
}
protected static void checkValue(final V value)
{
if (value == null)
{
throw new IllegalArgumentException("Null values not allowed in BidiMaps!");
}
}
protected class DualBidiEntry implements Entry
{
protected final Entry _internalEntry;
protected DualBidiEntry(final Entry internalEntry)
{
this._internalEntry = internalEntry;
}
@Override
public K getKey()
{
return _internalEntry.getKey();
}
@Override
public V getValue()
{
return _internalEntry.getValue();
}
@Override
public V setValue(final V value)
{
final V oldValue = _internalEntry.setValue(value);
// Attention!
// This might invalidate the Iterator that created this entry
// But there is no workaround possible - it's the bidirectional nature
postProcessPut(getKey(), value, oldValue);
return oldValue;
}
}
protected class DualBidiEntryIterator implements Iterator>
{
protected final Iterator> _internalIterator;
protected Entry _lastEntry;
protected DualBidiEntryIterator(final Iterator> internalIterator)
{
this._internalIterator = internalIterator;
}
@Override
public boolean hasNext()
{
return _internalIterator.hasNext();
}
@Override
public Entry next()
{
_lastEntry = _internalIterator.next();
return new DualBidiEntry(_lastEntry);
}
@Override
public void remove()
{
_internalIterator.remove();
_reverseMap.remove(_lastEntry.getValue());
}
}
protected class DualBidiEntrySet extends AbstractSet>
{
private final Set> internalEntrySet;
protected DualBidiEntrySet(final Set> internalEntrySet)
{
this.internalEntrySet = internalEntrySet;
}
@Override
public Iterator> iterator()
{
return new DualBidiEntryIterator(internalEntrySet.iterator());
}
@Override
public int size()
{
return internalEntrySet.size();
}
}
protected class InverseDualBidiMap extends DualBidiMap
{
protected InverseDualBidiMap(final Map reverseMap, final Map forwardMap)
{
super(reverseMap, forwardMap);
}
@Override
public BidiMap inverseBidiMap()
{
return DualBidiMap.this;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy