gt: 			if(otherValue != thisValue 
context: /*******************************************************************************
  * Copyright (c) 2009 Centrum Wiskunde en Informatica (CWI)
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  *    Arnold Lankamp - interfaces and implementation
  *******************************************************************************/
  package org.eclipse.imp.pdb.facts.impl.util.collections;
  
  import java.util.Collection;
  import java.util.Iterator;
  import java.util.Map;
  import java.util.Set;
  
  import org.eclipse.imp.pdb.facts.IValue;
  import org.eclipse.imp.pdb.facts.util.ShareableHashSet;
  
  /**
   * A specialized version of the ShareableHashMap, specifically meant for storing values.
   * 
   * @author Arnold Lankamp
   */
  public final class ShareableValuesHashMap implements Map<IValue, IValue>{
  	private final static int INITIAL_LOG_SIZE = 4;
  
  	private int modSize;
  	private int hashMask;
  	
  	private Entry<IValue, IValue>[] data; // protected for easier access in inner class
  	
  	private int threshold;
  	
  	private int load;
  	
  	private int currentHashCode;
  	
  	@SuppressWarnings("unchecked")
  	public ShareableValuesHashMap(){
  		super();
  		
  		modSize = INITIAL_LOG_SIZE;
  		int tableSize = 1 << modSize;
  		hashMask = tableSize - 1;
  		data = (Entry<IValue, IValue>[]) new Entry[tableSize];
  		
  		threshold = tableSize;
  		
  		load = 0;
  		
  		currentHashCode = 0;
  	}
  	
  	public ShareableValuesHashMap(ShareableValuesHashMap shareableValuesHashMap){
  		super();
  		
  		modSize = shareableValuesHashMap.modSize;
  		int tableSize = 1 << modSize;
  		hashMask = tableSize - 1;
  		data = shareableValuesHashMap.data.clone();
  		
  		threshold = tableSize;
  		
  		load = shareableValuesHashMap.load;
  		
  		currentHashCode = shareableValuesHashMap.currentHashCode;
  	}
  	
  	@SuppressWarnings("unchecked")
  	public void clear(){
  		modSize = INITIAL_LOG_SIZE;
  		int tableSize = 1 << modSize;
  		hashMask = tableSize - 1;
  		data = (Entry<IValue, IValue>[]) new Entry[tableSize];
  		
  		threshold = tableSize;
  		
  		load = 0;
  		
  		currentHashCode = 0;
  	}
  	
  	@SuppressWarnings("unchecked")
  	private void rehash(){
  		modSize++;
  		int tableSize = 1 << modSize;
  		hashMask = tableSize - 1;
  		Entry<IValue, IValue>[] newData = (Entry<IValue, IValue>[]) new Entry[tableSize];
  
  		threshold = tableSize;
  		
  		Entry<IValue, IValue>[] oldData = data;
  		for(int i = oldData.length - 1; i >= 0; i--){
  			Entry<IValue, IValue> entry = oldData[i];
  			
  			if(entry != null){
  				// Determine the last unchanged entry chain.
  				Entry<IValue, IValue> lastUnchangedEntryChain = entry;
  				int newLastUnchangedEntryChainIndex = entry.hash & hashMask;
  				
  				Entry<IValue, IValue> e = entry.next;
  				while(e != null){
  					int newIndex = e.hash & hashMask;
  					if(newIndex != newLastUnchangedEntryChainIndex){
  						lastUnchangedEntryChain = e;
  						newLastUnchangedEntryChainIndex = newIndex;
  					}
  					
  					e = e.next;
  				}
  	
  				newData[newLastUnchangedEntryChainIndex] = lastUnchangedEntryChain;
  				
  				// Reconstruct the other entries (if necessary).
  				while(entry != lastUnchangedEntryChain){
  					int hash = entry.hash;
  					int position = hash & hashMask;
  					newData[position] = new Entry<>(hash, entry.key, entry.value, newData[position]);
  					
  					entry = entry.next;
  				}
  			}
  		}
  		
  		data = newData;
  	}
  	
  	private void ensureCapacity(){
  		if(load > threshold){
  			rehash();
  		}
  	}
  	
  	private void replaceValue(int position, Entry<IValue, IValue> entry, IValue newValue){
  		Entry<IValue, IValue> e = data[position];
  		
  		// Reconstruct the updated entry.
  		data[position] = new Entry<>(entry.hash, entry.key, newValue, entry.next);
  		
  		// Reconstruct the other entries (if necessary).
  		while(e != entry){
  			data[position] = new Entry<>(e.hash, e.key, e.value, data[position]);
  			
  			e = e.next;
  		}
  	}
  	
  	public IValue put(IValue key, IValue value){
  		ensureCapacity();
  		
  		int hash = key.hashCode();
  		int position = hash & hashMask;
  		
  		Entry<IValue, IValue> currentStartEntry = data[position];
  		// Check if the key is already in here.
  		if(currentStartEntry != null){
  			Entry<IValue, IValue> entry = currentStartEntry;
  			do{
  				if(hash == entry.hash && entry.key.isEqual(key)){ // Replace if present.
  					replaceValue(position, entry, value);
  					
  					return entry.value; // Return the old value.
  				}
  				
  				entry = entry.next;
  			}while(entry != null);
  		}
  		
  		data[position] = new Entry<>(hash, key, value, currentStartEntry); // Insert the new entry.
  		
  		load++;
  		
  		currentHashCode ^= hash; // Update the current hashcode of this map.
  		
  		return null;
  	}
  	
  	public IValue remove(Object object){
  		IValue key = (IValue) object;
  		
  		int hash = key.hashCode();
  		int position = hash & hashMask;
  		
  		Entry<IValue, IValue> currentStartEntry = data[position];
  		if(currentStartEntry != null){
  			Entry<IValue, IValue> entry = currentStartEntry;
  			do{
  				if(hash == entry.hash && entry.key.isEqual(key)){
  					Entry<IValue, IValue> e = data[position];
  					
  					data[position] = entry.next;
  					// Reconstruct the other entries (if necessary).
  					while(e != entry){
  						data[position] = new Entry<>(e.hash, e.key, e.value, data[position]);
  						
  						e = e.next;
  					}
  					
  					load--;
  					
  					currentHashCode ^= hash; // Update the current hashcode of this map.
  					
  					return entry.value; // Return the value.
  				}
  				
  				entry = entry.next;
  			}while(entry != null);
  		}
  		
  		return null; // Not found.
  	}
  	
  	public IValue get(Object object){
  		IValue key = (IValue) object;
  		
  		int hash = key.hashCode();
  		int position = hash & hashMask;
  		
  		Entry<IValue, IValue> entry = data[position];
  		while(entry != null){
  			if(hash == entry.hash && key.isEqual(entry.key)) return entry.value;
  			
  			entry = entry.next;
  		}
  		
  		return null;
  	}
  	
  	public boolean contains(IValue key){
  		return (get(key) != null);
  	}
  	
  	public int size(){
  		return load;
  	}
  	
  	public boolean isEmpty(){
  		return (load == 0);
  	}
  	
  	public Iterator<Map.Entry<IValue, IValue>> entryIterator(){
  		return new EntryIterator(data);
  	}
  	
  	public Iterator<IValue> keysIterator(){
  		return new KeysIterator(data);
  	}
  	
  	public Iterator<IValue> valuesIterator(){
  		return new ValuesIterator(data);
  	}
  	
  	@SuppressWarnings("unchecked")
  	public void putAll(Map<? extends IValue, ? extends IValue> otherMap){
  		Set<Map.Entry<IValue, IValue>> entrySet = (Set<Map.Entry<IValue, IValue>>) (Set<?>) otherMap.entrySet(); // Generics stink.
  		Iterator<Map.Entry<IValue, IValue>> entrySetIterator = entrySet.iterator();
  		while(entrySetIterator.hasNext()){
  			Map.Entry<IValue, IValue> next = entrySetIterator.next();
  			put(next.getKey(), next.getValue());
  		}
  	}
  	
  	public boolean containsKey(Object object){
  		IValue key = (IValue) object;
  		
  		int hash = key.hashCode();
  		int position = hash & hashMask;
  		
  		Entry<IValue, IValue> entry = data[position];
  		while(entry != null){
  			if(hash == entry.hash && key.isEqual(entry.key)) return true;
  			
  			entry = entry.next;
  		}
  		
  		return false;
  	}
  	
  	public boolean containsValue(Object object){
  		IValue value = (IValue) object;
  		
  		Iterator<IValue> valuesIterator = valuesIterator();
  		while(valuesIterator.hasNext()){
  			IValue nextValue = valuesIterator.next();
  			if(nextValue == value || (nextValue != null && nextValue.isEqual(value))){
  				return true;
  			}
  		}
  
  		return false;
  	}
  	
  	public Set<Map.Entry<IValue, IValue>> entrySet(){
  		ShareableHashSet<Map.Entry<IValue, IValue>> entrySet = new ShareableHashSet<>();
  		
  		Iterator<Map.Entry<IValue, IValue>> entriesIterator = entryIterator();
  		while(entriesIterator.hasNext()){
  			entrySet.add(entriesIterator.next());
  		}
  		
  		return entrySet;
  	}
  	
  	public Set<IValue> keySet(){
  		ShareableHashSet<IValue> keysSet = new ShareableHashSet<>();
  		
  		Iterator<IValue> keysIterator = keysIterator();
  		while(keysIterator.hasNext()){
  			keysSet.add(keysIterator.next());
  		}
  		
  		return keysSet;
  	}
  	
  	public Collection<IValue> values(){
  		ShareableHashSet<IValue> valuesSet = new ShareableHashSet<>();
  		
  		Iterator<IValue> valuesIterator = valuesIterator();
  		while(valuesIterator.hasNext()){
  			valuesSet.add(valuesIterator.next());
  		}
  		
  		return valuesSet;
  	}
  	
  	public String toString(){
  		StringBuilder buffer = new StringBuilder();
  		
  		buffer.append('{');
  		for(int i = 0; i < data.length; i++){
  			buffer.append('[');
  			Entry<IValue, IValue> e = data[i];
  			if(e != null){
  				buffer.append(e);
  				
  				e = e.next;
  				
  				while(e != null){
  					buffer.append(',');
  					buffer.append(e);
  					
  					e = e.next;
  				}
  			}
  			buffer.append(']');
  		}
  		buffer.append('}');
  		
  		return buffer.toString();
  	}
  	
  	public int hashCode(){
  		return currentHashCode;
  	}
  	
  	public boolean isEqual(ShareableValuesHashMap other){
  		if(other == null) {
  			return false;
  		}
  		if(other.currentHashCode != currentHashCode) { 
  			return false;
  		}
  		if(other.size() != size()) {
  			return false;
  		}
  		if(isEmpty()) {
  			return true; // No need to check if the maps are empty.
  		}
  		
  		Iterator<Map.Entry<IValue, IValue>> otherIterator = other.entryIterator();
  		while (otherIterator.hasNext()) {
  			Map.Entry<IValue, IValue> entry = otherIterator.next();
  			IValue otherValue = entry.getValue();
  			IValue thisValue = get(entry.getKey());
  			
  			if (thisValue == null) {
  				// Means the key from other is not present in this
  				return false; 
  			}
  			
  