/*
* Copyright (C) 2004 TiongHiang Lee
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Email: thlee@onemindsoft.org
*/
package org.onemind.commons.java.datastructure;
import java.util.HashMap;
/**
* A simple bi-directional map. It uses another map to store the inverse
* of this map. The key has to be unique in key space and the value need to
* be unique in the value space so that the value can be resolved to the key correctly.
* This class is not thread safe.
* @author TiongHiang Lee (thlee@onemindsoft.org)
* @version $Id: BiMap.java,v 1.1 2004/09/29 02:45:35 thlee Exp $ $Name: $
*/
public class BiMap extends HashMap
{
/** the inverse **/
private final BiMap _inverse;
/**
* Constructor
*/
public BiMap()
{
_inverse = new BiMap(this);
}
/**
* Constructor
* @param map the inverse
*/
private BiMap(BiMap inverse)
{
_inverse = inverse;
}
/**
* Get the inverse bimap
* @return the bimap
*/
public BiMap getInverse()
{
return _inverse;
}
/**
* {@inheritDoc}
*/
public void clear()
{
super.clear();
_inverse.clear();
}
/**
* {@inheritDoc}
*/
public Object put(Object key, Object value)
{
//some critical checks that ensure correctness
if (containsKey(key))
{
if (_inverse.containsKey(value))
{//make sure it is true
Object v = get(key);
boolean sameValue = (v == null) ? v == value : v.equals(value);
if (!sameValue)
{
throw new IllegalArgumentException("Value " + value + " exists in inverse");
} //else ok
} //else ok
} else
{
if (_inverse.containsKey(value))
{//will cause conflict
throw new IllegalArgumentException("Value " + value + " exists in inverse");
}
}
//pass the tests, do the things
remove(key);
_inverse.rawPut(value, key);
return rawPut(key, value);
}
/**
* Put the key value association with super.put()
* @param key the key
* @param value the value
*/
private Object rawPut(Object key, Object value)
{
return super.put(key, value);
}
/**
* Remove the key
* @param key the key
* @return the value by super.remove();
*/
private Object rawRemove(Object key)
{
return super.remove(key);
}
/**
* {@inheritDoc}
*/
public Object remove(Object key)
{
if (containsKey(key))
{
return _inverse.rawRemove(rawRemove(key));
} else
{
return null;
}
}
}