/* * #%~ * VDM Code Generator Runtime * %% * Copyright (C) 2008 - 2014 Overture * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program. If not, see * <http://www.gnu.org/licenses/gpl-3.0.html>. * #~% */ package org.overture.codegen.runtime; import java.util.LinkedList; import java.util.Set; public class MapUtil { public static VDMMap map() { return new VDMMap(); } public static Maplet[] toMaplets(Object map) { validateMap(map, "toMaplets"); VDMMap vdmMap = (VDMMap) map; Maplet[] maplets = new Maplet[vdmMap.size()]; int nextIndex = 0; for (Object key : vdmMap.keySet()) { Object val = vdmMap.get(key); maplets[nextIndex++] = new Maplet(key, val); } return maplets; } public static Object get(Object map, Object key) { validateMap(map, "map read"); VDMMap vdmMap = (VDMMap) map; Object value = vdmMap.get(key); if (value != null) { return value; } else { // The key may map to null if (vdmMap.containsKey(key)) { // The key is there return null; } else { throw new IllegalArgumentException("No such key in map: " + key); } } } @SuppressWarnings("unchecked") public static VDMSet dom(Object map) { validateMap(map, "map domain"); VDMMap vdmMap = (VDMMap) map; VDMSet set = SetUtil.set(); set.addAll(vdmMap.keySet()); return set; } @SuppressWarnings("unchecked") public static VDMSet rng(Object map) { validateMap(map, "map range"); VDMMap vdmMap = (VDMMap) map; VDMSet set = SetUtil.set(); set.addAll(vdmMap.values()); return set; } @SuppressWarnings("unchecked") public static VDMMap munion(Object left, Object right) { validateMaps(left, right, "map union"); VDMMap mapLeft = (VDMMap) left; VDMMap mapRight = (VDMMap) right; VDMMap result = map(); result.putAll(mapLeft); putAll(result, mapRight); return result; } @SuppressWarnings("unchecked") public static void mapAdd(Object map, Object maplet) { if (!(map instanceof VDMMap)) { throw new IllegalArgumentException("Expected " + map + " to be a " + VDMMap.class.getSimpleName()); } if (!(maplet instanceof Maplet)) { throw new IllegalArgumentException("Expected " + maplet + " to be a " + Maplet.class.getSimpleName()); } VDMMap vdmMap = (VDMMap) map; Maplet vdmMaplet = (Maplet) maplet; vdmMap.put(vdmMaplet.getLeft(), vdmMaplet.getRight()); } @SuppressWarnings("unchecked") public static VDMMap override(Object left, Object right) { validateMaps(left, right, "map override"); VDMMap mapLeft = (VDMMap) left; VDMMap mapRight = (VDMMap) right; VDMMap result = map(); result.putAll(mapLeft); result.putAll(mapRight); return result; } public static VDMMap merge(Object setOfMaps) { final String MAP_MERGE = "map merge"; SetUtil.validateSet(setOfMaps, MAP_MERGE); VDMSet vdmSetOfMaps = (VDMSet) setOfMaps; VDMMap result = map(); for (Object map : vdmSetOfMaps) { validateMap(map, MAP_MERGE); VDMMap vdmMap = (VDMMap) map; putAll(result, vdmMap); } return result; } @SuppressWarnings("unchecked") public static VDMMap domResTo(Object dom, Object map) { final String MAP_DOM_RESTRICT_TO = "map domain restrict to"; SetUtil.validateSet(dom, MAP_DOM_RESTRICT_TO); validateMap(map, MAP_DOM_RESTRICT_TO); VDMSet vdmDom = (VDMSet) dom; VDMMap vdmMap = (VDMMap) map; VDMMap result = map(); for (Object key : vdmDom) { if (vdmMap.containsKey(key)) { Object value = vdmMap.get(key); result.put(key, value); } } return result; } @SuppressWarnings("unchecked") public static VDMMap domResBy(Object dom, Object map) { final String MAP_DOM_RESTRICT_BY = "map domain restrict by"; SetUtil.validateSet(dom, MAP_DOM_RESTRICT_BY); validateMap(map, MAP_DOM_RESTRICT_BY); VDMSet vdmDom = (VDMSet) dom; VDMMap vdmMap = (VDMMap) map; VDMMap result = map(); for (Object key : vdmMap.keySet()) { if (!vdmDom.contains(key)) { Object value = vdmMap.get(key); result.put(key, value); } } return result; } @SuppressWarnings("unchecked") public static VDMMap rngResTo(Object map, Object rng) { final String MAP_RANGE_RESTRICT_TO = "map range restrict to"; validateMap(map, MAP_RANGE_RESTRICT_TO); SetUtil.validateSet(rng, MAP_RANGE_RESTRICT_TO); VDMMap vdmMap = (VDMMap) map; VDMSet vdmRng = (VDMSet) rng; VDMMap result = map(); @SuppressWarnings("rawtypes") Set dom = vdmMap.keySet(); for (Object key : dom) { Object value = vdmMap.get(key); if (vdmRng.contains(value)) { result.put(key, value); } } return result; } @SuppressWarnings("unchecked") public static VDMMap rngResBy(Object map, Object rng) { final String MAP_RANGE_RESTRICT_BY = "map range restrict by"; validateMap(map, MAP_RANGE_RESTRICT_BY); SetUtil.validateSet(rng, MAP_RANGE_RESTRICT_BY); VDMMap vdmMap = (VDMMap) map; VDMSet vdmRng = (VDMSet) rng; VDMMap result = map(); for (Object key : vdmMap.keySet()) { Object value = vdmMap.get(key); if (!vdmRng.contains(value)) { result.put(key, value); } } return result; } @SuppressWarnings("unchecked") public static VDMMap inverse(Object map) { validateMap(map, "map inverse"); VDMMap vdmMap = (VDMMap) map; VDMMap result = map(); if (vdmMap.size() == 0) { return result; } @SuppressWarnings("rawtypes") Set keysSet = vdmMap.keySet(); @SuppressWarnings("rawtypes") LinkedList keyList = new LinkedList(keysSet); Object firstKey = keyList.get(0); Object firstValue = vdmMap.get(firstKey); result.put(firstValue, firstKey); for (int i = 1; i < keyList.size(); i++) { Object nextKey = keyList.get(i); Object nextValue = vdmMap.get(nextKey); if (result.containsKey(nextKey)) { throw new IllegalArgumentException("Cannot invert non-injective map"); } else { result.put(nextValue, nextKey); } } return result; } @SuppressWarnings("unchecked") public static VDMMap map(Maplet... elements) { if (elements == null) { throw new IllegalArgumentException("Cannot instantiate map from null"); } VDMMap map = map(); if (elements.length == 0) { return map; } else { Maplet firstElement = elements[0]; map.put(firstElement.getLeft(), firstElement.getRight()); } for (int i = 1; i < elements.length; i++) { Maplet maplet = elements[i]; Object mapletKey = maplet.getLeft(); Object mapletValue = maplet.getRight(); if (map.containsKey(mapletKey)) { Object mapValue = map.get(mapletKey); if (differentValues(mapletValue, mapValue)) { throw new IllegalArgumentException("Duplicate keys that have different values are not allowed"); } } map.put(mapletKey, mapletValue); } return map; } @SuppressWarnings("unchecked") private static void putAll(VDMMap to, VDMMap from) { @SuppressWarnings("rawtypes") Set fromKeys = from.keySet(); for (Object fromKey : fromKeys) { Object fromVal = from.get(fromKey); if (to.containsKey(fromKey)) { Object toVal = to.get(fromKey); if (differentValues(toVal, fromVal)) { throw new IllegalAccessError("Duplicate keys that have different values are not allowed"); } } to.put(fromKey, fromVal); } } static void validateMap(Object arg, String operator) { if (!(arg instanceof VDMMap)) { throw new IllegalArgumentException(operator + " is only supported for " + VDMMap.class.getName() + ". Got " + arg); } } private static void validateMaps(Object left, Object right, String operator) { if (!(left instanceof VDMMap) || !(right instanceof VDMMap)) { throw new IllegalArgumentException(operator + " is only supported for " + VDMMap.class.getName() + ". Got " + left + " and " + right); } } private static boolean differentValues(Object leftVal, Object rightVal) { return leftVal == null && rightVal != null || leftVal != null && !leftVal.equals(rightVal); } }