/******************************************************************************* * This file is part of logisim-evolution. * * logisim-evolution 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. * * logisim-evolution 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 logisim-evolution. If not, see <http://www.gnu.org/licenses/>. * * Original code by Carl Burch (http://www.cburch.com), 2011. * Subsequent modifications by : * + Haute École Spécialisée Bernoise * http://www.bfh.ch * + Haute École du paysage, d'ingénierie et d'architecture de Genève * http://hepia.hesge.ch/ * + Haute École d'Ingénierie et de Gestion du Canton de Vaud * http://www.heig-vd.ch/ * The project is currently maintained by : * + REDS Institute - HEIG-VD * Yverdon-les-Bains, Switzerland * http://reds.heig-vd.ch *******************************************************************************/ package com.cburch.logisim.circuit; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Set; import com.cburch.logisim.comp.Component; import com.cburch.logisim.comp.EndData; import com.cburch.logisim.data.BitWidth; import com.cburch.logisim.data.Location; class CircuitPoints { private static class LocationData { BitWidth width = BitWidth.UNKNOWN; ArrayList<Component> components = new ArrayList<Component>(4); ArrayList<EndData> ends = new ArrayList<EndData>(4); // these lists are parallel - ends corresponding to wires are null } private HashMap<Location, LocationData> map = new HashMap<Location, LocationData>(); private HashMap<Location, WidthIncompatibilityData> incompatibilityData = new HashMap<Location, WidthIncompatibilityData>(); public CircuitPoints() { } // // update methods // void add(Component comp) { if (comp instanceof Wire) { Wire w = (Wire) comp; addSub(w.getEnd0(), w, null); addSub(w.getEnd1(), w, null); } else { for (EndData endData : comp.getEnds()) { if (endData != null) { addSub(endData.getLocation(), comp, endData); } } } } void add(Component comp, EndData endData) { if (endData != null) addSub(endData.getLocation(), comp, endData); } private void addSub(Location loc, Component comp, EndData endData) { LocationData locData = map.get(loc); if (locData == null) { locData = new LocationData(); map.put(loc, locData); } locData.components.add(comp); locData.ends.add(endData); computeIncompatibilityData(loc, locData); } private void computeIncompatibilityData(Location loc, LocationData locData) { WidthIncompatibilityData error = null; if (locData != null) { BitWidth width = BitWidth.UNKNOWN; for (EndData endData : locData.ends) { if (endData != null) { BitWidth endWidth = endData.getWidth(); if (width == BitWidth.UNKNOWN) { width = endWidth; } else if (width != endWidth && endWidth != BitWidth.UNKNOWN) { if (error == null) { error = new WidthIncompatibilityData(); error.add(loc, width); } error.add(loc, endWidth); } } } locData.width = width; } if (error == null) { incompatibilityData.remove(loc); } else { incompatibilityData.put(loc, error); } } private Collection<? extends Component> find(Location loc, boolean isWire) { LocationData locData = map.get(loc); if (locData == null) return Collections.emptySet(); // first see how many elements we have; we can handle some simple // cases without creating any new lists ArrayList<Component> list = locData.components; int retSize = 0; Component retValue = null; for (Component o : list) { if ((o instanceof Wire) == isWire) { retValue = o; retSize++; } } if (retSize == list.size()) return list; if (retSize == 0) return Collections.emptySet(); if (retSize == 1) return Collections.singleton(retValue); // otherwise we have to create our own list Component[] ret = new Component[retSize]; int retPos = 0; for (Component o : list) { if ((o instanceof Wire) == isWire) { ret[retPos] = o; retPos++; } } return Arrays.asList(ret); } int getComponentCount(Location loc) { LocationData locData = map.get(loc); return locData == null ? 0 : locData.components.size(); } Collection<? extends Component> getComponents(Location loc) { LocationData locData = map.get(loc); if (locData == null) return Collections.emptySet(); else return locData.components; } Component getExclusive(Location loc) { LocationData locData = map.get(loc); if (locData == null) return null; int i = -1; for (EndData endData : locData.ends) { i++; if (endData != null && endData.isExclusive()) { return locData.components.get(i); } } return null; } Collection<? extends Component> getNonWires(Location loc) { return find(loc, false); } Collection<? extends Component> getSplitCauses(Location loc) { return getComponents(loc); } // // access methods // Set<Location> getSplitLocations() { return map.keySet(); } BitWidth getWidth(Location loc) { LocationData locData = map.get(loc); return locData == null ? BitWidth.UNKNOWN : locData.width; } Collection<WidthIncompatibilityData> getWidthIncompatibilityData() { return incompatibilityData.values(); } Collection<Wire> getWires(Location loc) { @SuppressWarnings("unchecked") Collection<Wire> ret = (Collection<Wire>) find(loc, true); return ret; } boolean hasConflict(Component comp) { if (comp instanceof Wire) { return false; } else { for (EndData endData : comp.getEnds()) { if (endData != null && endData.isExclusive() && getExclusive(endData.getLocation()) != null) { return true; } } return false; } } void remove(Component comp) { if (comp instanceof Wire) { Wire w = (Wire) comp; removeSub(w.getEnd0(), w); removeSub(w.getEnd1(), w); } else { for (EndData endData : comp.getEnds()) { if (endData != null) { removeSub(endData.getLocation(), comp); } } } } void remove(Component comp, EndData endData) { if (endData != null) removeSub(endData.getLocation(), comp); } private void removeSub(Location loc, Component comp) { LocationData locData = map.get(loc); if (locData == null) return; int index = locData.components.indexOf(comp); if (index < 0) return; if (locData.components.size() == 1) { map.remove(loc); incompatibilityData.remove(loc); } else { locData.components.remove(index); locData.ends.remove(index); computeIncompatibilityData(loc, locData); } } }