MemoryLocationMap.java

package dev.civl.mc.library.mem;

import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import dev.civl.sarl.IF.expr.SymbolicExpression;

/**
 * <p>
 * A map specifically designed for values of $mem type:
 * </p>
 * 
 * <p>
 * This map maps four keys: variable ID, heap ID, malloc ID and scope value to a
 * value set template. The four keys will not all be significant at same time:
 * <ol>
 * <li>if variable ID is positive, only variable ID and scope value are
 * significant</li>
 * <li>otherwise, only heap ID, mallocID and scope value are significant.</li>
 * </ol>
 * The heap ID is the ID of a lexical malloc statement. The malloc ID is the ID
 * of a runtime instance of a lexical malloc statement.
 * 
 * </p>
 * 
 * @author ziqing
 *
 */
public class MemoryLocationMap {

	private class TwoInt {
		private int[] int2;

		private TwoInt(int i, int j) {
			int2 = new int[]{i, j};
		}

		@Override
		public boolean equals(Object obj) {
			if (obj instanceof TwoInt) {
				TwoInt other = (TwoInt) obj;

				return Arrays.equals(int2, other.int2);
			}
			return false;
		}

		@Override
		public int hashCode() {
			return Arrays.hashCode(int2);
		}
	}

	/**
	 * The entry of this map:
	 * 
	 * @author ziqing
	 *
	 */
	public class MemLocMapEntry {

		private int vid, heapID, mallocID;

		private SymbolicExpression scope, vst;

		private MemLocMapEntry(int vid, int heapID, int mallocID,
				SymbolicExpression scopeVal,
				SymbolicExpression valueSetTemplate) {
			this.vid = vid;
			this.heapID = heapID;
			this.mallocID = mallocID;
			this.scope = scopeVal;
			this.vst = valueSetTemplate;
		}

		public int vid() {
			return vid;
		}
		public int heapID() {
			return heapID;
		}
		public int mallocID() {
			return mallocID;
		}
		public SymbolicExpression scopeValue() {
			return scope;
		}
		public SymbolicExpression valueSetTemplate() {
			return vst;
		}
	}

	Map<Integer, Map<SymbolicExpression, SymbolicExpression>> variableTable;

	Map<TwoInt, Map<SymbolicExpression, SymbolicExpression>> heapTable;

	public MemoryLocationMap() {
		this.variableTable = new HashMap<>();
		this.heapTable = new HashMap<>();
	}

	/**
	 * 
	 * the get operation. For meanings of parameters, see
	 * {@link MemoryLocationMap}
	 */
	public SymbolicExpression get(int vid, int heapID, int mallocID,
			SymbolicExpression scope) {
		Map<SymbolicExpression, SymbolicExpression> subMap;

		if (vid == 0)
			subMap = heapTable.get(new TwoInt(heapID, mallocID));
		else {
			assert vid > 0;
			subMap = variableTable.get(vid);
		}
		return subMap == null ? null : subMap.get(scope);
	}

	/**
	 * 
	 * the put operation. For meanings of parameters, see
	 * {@link MemoryLocationMap}
	 */
	public void put(int vid, int heapID, int mallocID, SymbolicExpression scope,
			SymbolicExpression value) {

		if (vid == 0) {
			TwoInt key = new TwoInt(heapID, mallocID);
			Map<SymbolicExpression, SymbolicExpression> subMap = heapTable
					.get(key);

			if (subMap == null)
				subMap = new HashMap<>();
			subMap.put(scope, value);
			heapTable.put(key, subMap);
		} else {
			assert vid > 0;
			Map<SymbolicExpression, SymbolicExpression> subMap = variableTable
					.get(vid);

			if (subMap == null)
				subMap = new HashMap<>();
			subMap.put(scope, value);
			variableTable.put(vid, subMap);
		}
	}

	/**
	 * 
	 * the entrySet method.
	 */
	public Iterable<MemLocMapEntry> entrySet() {
		List<MemLocMapEntry> results = new LinkedList<>();

		for (Entry<Integer, Map<SymbolicExpression, SymbolicExpression>> entry : variableTable
				.entrySet()) {
			int vid = entry.getKey();

			for (Entry<SymbolicExpression, SymbolicExpression> subEntry : entry
					.getValue().entrySet())
				results.add(new MemLocMapEntry(vid, -1, -1, subEntry.getKey(),
						subEntry.getValue()));
		}
		for (Entry<TwoInt, Map<SymbolicExpression, SymbolicExpression>> entry : heapTable
				.entrySet()) {
			TwoInt heap = entry.getKey();

			for (Entry<SymbolicExpression, SymbolicExpression> subEntry : entry
					.getValue().entrySet())
				results.add(new MemLocMapEntry(0, heap.int2[0], heap.int2[1],
						subEntry.getKey(), subEntry.getValue()));
		}
		return results;
	}

	public int size() {
		return this.heapTable.size() + this.variableTable.size();
	}
}