/******************************************************************************* * 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.IMapWriter; import org.rascalmpl.value.ITuple; import org.rascalmpl.value.IValue; import org.rascalmpl.value.impl.util.collections.ShareableValuesHashMap; import org.rascalmpl.value.type.Type; import org.rascalmpl.value.type.TypeFactory; // TODO Add checking. /** * Implementation of IMapWriter. * * @author Arnold Lankamp */ /*package*/ class MapWriter implements IMapWriter{ protected Type keyType; protected Type valueType; protected Type mapType; protected final ShareableValuesHashMap data; protected IMap constructedMap; protected final boolean inferred; protected boolean inferredTypeinvalidated; /*package*/ MapWriter(){ super(); this.mapType = null; this.keyType = TypeFactory.getInstance().voidType(); this.valueType = TypeFactory.getInstance().voidType(); this.inferred = true; data = new ShareableValuesHashMap(); constructedMap = null; } /*package*/ MapWriter(Type mapType) { super(); if(mapType.isFixedWidth() && mapType.getArity() >= 2) { mapType = TypeFactory.getInstance().mapTypeFromTuple(mapType); } this.mapType = mapType; this.keyType = mapType.getKeyType(); this.valueType = mapType.getValueType(); this.inferred = false; data = new ShareableValuesHashMap(); constructedMap = null; } /*package*/ MapWriter(Type mapType, ShareableValuesHashMap data){ super(); this.mapType = mapType; this.keyType = mapType.getKeyType(); this.valueType = mapType.getValueType(); this.data = data; this.inferred = false; constructedMap = null; } @Override public void put(IValue key, IValue value){ checkMutation(); updateTypes(key,value); IValue replaced = data.put(key, value); if (replaced != null) { inferredTypeinvalidated = true; } } private void updateTypes(IValue key, IValue value) { if (inferred) { keyType = keyType.lub(key.getType()); valueType = valueType.lub(value.getType()); } } @Override public void putAll(IMap map){ checkMutation(); Iterator<Entry<IValue, IValue>> entryIterator = map.entryIterator(); while(entryIterator.hasNext()){ Entry<IValue, IValue> entry = entryIterator.next(); IValue key = entry.getKey(); IValue value = entry.getValue(); updateTypes(key,value); data.put(key, value); } } @Override public void putAll(java.util.Map<IValue, IValue> map){ checkMutation(); Iterator<Entry<IValue, IValue>> entryIterator = map.entrySet().iterator(); while(entryIterator.hasNext()){ Entry<IValue, IValue> entry = entryIterator.next(); IValue key = entry.getKey(); IValue value = entry.getValue(); updateTypes(key,value); data.put(key,value); } } @Override public void insert(IValue... values){ checkMutation(); for(int i = values.length - 1; i >= 0; i--){ IValue value = values[i]; if(!(value instanceof ITuple)) throw new IllegalArgumentException("Argument must be of ITuple type."); ITuple tuple = (ITuple) value; if(tuple.arity() != 2) throw new IllegalArgumentException("Tuple must have an arity of 2."); IValue key = tuple.get(0); IValue value2 = tuple.get(1); updateTypes(key,value2); put(key, value2); } } @Override public void insertAll(Iterable<? extends IValue> collection){ checkMutation(); Iterator<? extends IValue> collectionIterator = collection.iterator(); while(collectionIterator.hasNext()){ IValue value = collectionIterator.next(); if(!(value instanceof ITuple)) throw new IllegalArgumentException("Argument must be of ITuple type."); ITuple tuple = (ITuple) value; if(tuple.arity() != 2) throw new IllegalArgumentException("Tuple must have an arity of 2."); IValue key = tuple.get(0); IValue value2 = tuple.get(1); updateTypes(key,value2); put(key, value2); } } protected void checkMutation() { if (constructedMap != null) throw new UnsupportedOperationException( "Mutation of a finalized map is not supported."); } @Override public IMap done(){ if(constructedMap == null) { if (mapType == null) { mapType = TypeFactory.getInstance().mapType(keyType, valueType); } if (data.isEmpty()) { Type voidType = TypeFactory.getInstance().voidType(); Type voidMapType = TypeFactory.getInstance().mapType(voidType, mapType.getKeyLabel(), voidType, mapType.getValueLabel()); constructedMap = Map.newMap(voidMapType, data); } else { if (inferred && inferredTypeinvalidated) { Type voidType = TypeFactory.getInstance().voidType(); keyType = voidType; valueType = voidType; for (Iterator<Entry<IValue, IValue>> it = data.entryIterator(); it.hasNext(); ) { final Entry<IValue, IValue> currentEntry = it.next(); keyType = keyType.lub(currentEntry.getKey().getType()); valueType = valueType.lub(currentEntry.getValue().getType()); mapType = TypeFactory.getInstance().mapType(keyType, mapType.getKeyLabel(), valueType, mapType.getValueLabel()); } } constructedMap = Map.newMap(mapType, data); } } return constructedMap; } }