/******************************************************************************* * Copyright (c) 2009, 2012 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 * Anya Helene Bagge - labels *******************************************************************************/ package org.rascalmpl.value.impl.fast; import java.util.Iterator; import java.util.Map.Entry; import org.rascalmpl.value.IMap; import org.rascalmpl.value.IValue; import org.rascalmpl.value.impl.AbstractValue; import org.rascalmpl.value.impl.util.collections.ShareableValuesHashMap; import org.rascalmpl.value.type.Type; import org.rascalmpl.value.type.TypeFactory; import org.rascalmpl.value.visitors.IValueVisitor; /** * Implementation of IMap. * * @author Arnold Lankamp */ /*package*/ class Map extends AbstractValue implements IMap { protected final static TypeFactory typeFactory = TypeFactory.getInstance(); protected final Type mapType; protected final ShareableValuesHashMap data; /*package*/ static IMap newMap(Type mapType, ShareableValuesHashMap data) { return new Map(mapType, data); } private Map(Type mapType, ShareableValuesHashMap data) { super(); this.mapType = mapType; this.data = data; } public Type getType(){ return mapType; } public Type getKeyType(){ return mapType.getKeyType(); } public Type getValueType(){ return mapType.getValueType(); } public int size(){ return data.size(); } public int arity(){ return size(); } public boolean isEmpty(){ return data.isEmpty(); } public IValue get(IValue key){ return data.get(key); } public Iterator<IValue> iterator(){ return data.keysIterator(); } public Iterator<Entry<IValue, IValue>> entryIterator(){ return data.entryIterator(); } public Iterator<IValue> valueIterator(){ return data.valuesIterator(); } public <T, E extends Throwable> T accept(IValueVisitor<T,E> v) throws E{ return v.visitMap(this); } public boolean containsKey(IValue key){ return data.contains(key); } public boolean containsValue(IValue value){ Iterator<IValue> valuesIterator = data.valuesIterator(); while(valuesIterator.hasNext()){ if(valuesIterator.next().isEqual(value)) return true; } return false; } public boolean isSubMap(IMap other) { Map otherMap = (Map) other; Iterator<IValue> keysIterator = iterator(); while (keysIterator.hasNext()) { IValue key = keysIterator.next(); if (!otherMap.data.contains(key)) { return false; } if (!otherMap.data.get(key).isEqual(data.get(key))) { return false; } } return true; } public IMap put(IValue key, IValue value){ ShareableValuesHashMap newData = new ShareableValuesHashMap(data); IValue replaced = newData.put(key, value); if (replaced != null) { /* * we might have to narrow dynamic type of value range */ Type voidType = TypeFactory.getInstance().voidType(); Type newMapType = mapType; Type newKeyType = voidType; Type newValueType = voidType; for (Iterator<Entry<IValue, IValue>> it = newData.entryIterator(); it.hasNext(); ) { final Entry<IValue, IValue> currentEntry = it.next(); newKeyType = newKeyType.lub(currentEntry.getKey().getType()); newValueType = newValueType.lub(currentEntry.getValue().getType()); if(newKeyType != mapType.getKeyType() || newValueType != mapType.getValueType()) { newMapType = TypeFactory.getInstance().mapType(newKeyType, mapType.getKeyLabel(), newValueType, mapType.getValueLabel()); } } return new MapWriter(newMapType, newData).done(); } else { Type newMapType = mapType; Type newKeyType = mapType.getKeyType().lub(key.getType()); Type newValueType = mapType.getValueType().lub(value.getType()); if(newKeyType != mapType.getKeyType() || newValueType != mapType.getValueType()) { newMapType = TypeFactory.getInstance().mapType(newKeyType, mapType.getKeyLabel(), newValueType, mapType.getValueLabel()); } return new MapWriter(newMapType, newData).done(); } } public IMap common(IMap other){ ShareableValuesHashMap commonData = new ShareableValuesHashMap(); Iterator<Entry<IValue, IValue>> entryIterator; IMap theOtherMap; if(other.size() <= size()){ entryIterator = other.entryIterator(); theOtherMap = this; }else{ entryIterator = entryIterator(); theOtherMap = other; } Type newKeyType = TypeFactory.getInstance().voidType(); Type newValueType = TypeFactory.getInstance().voidType(); while(entryIterator.hasNext()){ Entry<IValue, IValue> entry = entryIterator.next(); IValue key = entry.getKey(); IValue value = entry.getValue(); if(value.isEqual(theOtherMap.get(key))){ newKeyType = newKeyType.lub(key.getType()); newValueType = newValueType.lub(value.getType()); commonData.put(key, value); } } Type lub = mapType.lub(other.getType()); return new MapWriter(TypeFactory.getInstance().mapType(newKeyType, lub.getKeyLabel(), newValueType, lub.getValueLabel()), commonData).done(); } public IMap compose(IMap other){ ShareableValuesHashMap newData = new ShareableValuesHashMap(); Map otherMap = (Map) other; Iterator<Entry<IValue, IValue>> entryIterator = entryIterator(); while(entryIterator.hasNext()){ Entry<IValue,IValue> entry = entryIterator.next(); IValue value = otherMap.get(entry.getValue()); if(value != null){ newData.put(entry.getKey(), value); } } Type newMapType; if(mapType.hasFieldNames() && otherMap.mapType.hasFieldNames()) { newMapType = TypeFactory.getInstance().mapType(mapType.getKeyType(), mapType.getKeyLabel(), otherMap.mapType.getValueType(), otherMap.mapType.getValueLabel()); } else { newMapType = TypeFactory.getInstance().mapType(mapType.getKeyType(), otherMap.mapType.getValueType()); } return new MapWriter(newMapType, newData).done(); } public IMap join(IMap other){ ShareableValuesHashMap newData; Iterator<Entry<IValue, IValue>> entryIterator; Map otherMap = (Map) other; newData = new ShareableValuesHashMap(data); entryIterator = otherMap.entryIterator(); while(entryIterator.hasNext()){ Entry<IValue, IValue> entry = entryIterator.next(); newData.put(entry.getKey(), entry.getValue()); } return new MapWriter(mapType.lub(otherMap.mapType), newData).done(); } public IMap remove(IMap other){ ShareableValuesHashMap newData = new ShareableValuesHashMap(data); Iterator<IValue> keysIterator = other.iterator(); while(keysIterator.hasNext()){ newData.remove(keysIterator.next()); } Type newKeyType = TypeFactory.getInstance().voidType(); Type newValueType = TypeFactory.getInstance().voidType(); Iterator<Entry<IValue, IValue>> entryIterator = newData.entryIterator(); while(entryIterator.hasNext()) { Entry<IValue, IValue> el = entryIterator.next(); newKeyType = newKeyType.lub(el.getKey().getType()); newValueType = newValueType.lub(el.getValue().getType()); } return new MapWriter(TypeFactory.getInstance().mapType(newKeyType, mapType.getKeyLabel(), newValueType, mapType.getValueLabel()), newData).done(); } public int hashCode(){ return data.hashCode(); } public boolean equals(Object o){ if(o == this) return true; if(o == null) return false; if(o.getClass() == getClass()){ Map otherMap = (Map) o; if (getType() != otherMap.getType()) return false; return data.equals(otherMap.data); } return false; } public boolean isEqual(IValue value){ if(value == this) return true; if(value == null) return false; if(value instanceof Map){ Map otherMap = (Map) value; return data.isEqual(otherMap.data); } return false; } @Override public IMap removeKey(IValue key) { ShareableValuesHashMap newData = new ShareableValuesHashMap(data); IValue replaced = newData.remove(key); if (replaced != null) { /* * we might have to narrow dynamic type of value range */ Type voidType = TypeFactory.getInstance().voidType(); Type newMapType = mapType; Type newKeyType = voidType; Type newValueType = voidType; for (Iterator<Entry<IValue, IValue>> it = newData.entryIterator(); it.hasNext();) { final Entry<IValue, IValue> currentEntry = it.next(); newKeyType = newKeyType.lub(currentEntry.getKey().getType()); newValueType = newValueType.lub(currentEntry.getValue().getType()); if (newKeyType != mapType.getKeyType() || newValueType != mapType.getValueType()) { newMapType = TypeFactory.getInstance().mapType(newKeyType, mapType.getKeyLabel(), newValueType, mapType.getValueLabel()); } } return new MapWriter(newMapType, newData).done(); } else { return this; } } }