/*******************************************************************************
* 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.io.PrintStream;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.cburch.logisim.comp.Component;
public class ReplacementMap {
final static Logger logger = LoggerFactory.getLogger(ReplacementMap.class);
private boolean frozen;
private HashMap<Component, HashSet<Component>> map;
private HashMap<Component, HashSet<Component>> inverse;
public ReplacementMap() {
this(new HashMap<Component, HashSet<Component>>(),
new HashMap<Component, HashSet<Component>>());
}
public ReplacementMap(Component oldComp, Component newComp) {
this(new HashMap<Component, HashSet<Component>>(),
new HashMap<Component, HashSet<Component>>());
HashSet<Component> oldSet = new HashSet<Component>(3);
oldSet.add(oldComp);
HashSet<Component> newSet = new HashSet<Component>(3);
newSet.add(newComp);
map.put(oldComp, newSet);
inverse.put(newComp, oldSet);
}
private ReplacementMap(HashMap<Component, HashSet<Component>> map,
HashMap<Component, HashSet<Component>> inverse) {
this.map = map;
this.inverse = inverse;
}
public void add(Component comp) {
if (frozen) {
throw new IllegalStateException("cannot change map after frozen");
}
inverse.put(comp, new HashSet<Component>(3));
}
void append(ReplacementMap next) {
for (Map.Entry<Component, HashSet<Component>> e : next.map.entrySet()) {
Component b = e.getKey();
HashSet<Component> cs = e.getValue(); // what b is replaced by
HashSet<Component> as = this.inverse.remove(b); // what was replaced
// to get b
if (as == null) { // b pre-existed replacements so
as = new HashSet<Component>(3); // we say it replaces itself.
as.add(b);
}
for (Component a : as) {
HashSet<Component> aDst = this.map.get(a);
if (aDst == null) { // should happen when b pre-existed only
aDst = new HashSet<Component>(cs.size());
this.map.put(a, aDst);
}
aDst.remove(b);
aDst.addAll(cs);
}
for (Component c : cs) {
HashSet<Component> cSrc = this.inverse.get(c); // should always
// be null
if (cSrc == null) {
cSrc = new HashSet<Component>(as.size());
this.inverse.put(c, cSrc);
}
cSrc.addAll(as);
}
}
for (Map.Entry<Component, HashSet<Component>> e : next.inverse
.entrySet()) {
Component c = e.getKey();
if (!inverse.containsKey(c)) {
HashSet<Component> bs = e.getValue();
if (!bs.isEmpty()) {
logger.error("Internal error: component replaced but not represented");
}
inverse.put(c, new HashSet<Component>(3));
}
}
}
void freeze() {
frozen = true;
}
public Collection<Component> get(Component prev) {
return map.get(prev);
}
public Collection<? extends Component> getAdditions() {
return inverse.keySet();
}
public Collection<Component> getComponentsReplacing(Component comp) {
return map.get(comp);
}
ReplacementMap getInverseMap() {
return new ReplacementMap(inverse, map);
}
public Collection<? extends Component> getRemovals() {
return map.keySet();
}
public Collection<Component> getReplacedComponents() {
return map.keySet();
}
public boolean isEmpty() {
return map.isEmpty() && inverse.isEmpty();
}
public void print(PrintStream out) {
boolean found = false;
for (Component c : getRemovals()) {
if (!found)
out.println(" removals:");
found = true;
out.println(" " + c.toString());
}
if (!found)
out.println(" removals: none");
found = false;
for (Component c : getAdditions()) {
if (!found)
out.println(" additions:");
found = true;
out.println(" " + c.toString());
}
if (!found)
out.println(" additions: none");
}
public void put(Component prev, Collection<? extends Component> next) {
if (frozen) {
throw new IllegalStateException("cannot change map after frozen");
}
HashSet<Component> repl = map.get(prev);
if (repl == null) {
repl = new HashSet<Component>(next.size());
map.put(prev, repl);
}
repl.addAll(next);
for (Component n : next) {
repl = inverse.get(n);
if (repl == null) {
repl = new HashSet<Component>(3);
inverse.put(n, repl);
}
repl.add(prev);
}
}
public void remove(Component comp) {
if (frozen) {
throw new IllegalStateException("cannot change map after frozen");
}
map.put(comp, new HashSet<Component>(3));
}
public void replace(Component prev, Component next) {
put(prev, Collections.singleton(next));
}
public void reset() {
map.clear();
inverse.clear();
}
}