/******************************************************************************* * 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.file; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import com.cburch.logisim.circuit.Circuit; import com.cburch.logisim.circuit.SubcircuitFactory; import com.cburch.logisim.comp.Component; import com.cburch.logisim.comp.ComponentFactory; import com.cburch.logisim.tools.AddTool; import com.cburch.logisim.tools.Library; import com.cburch.logisim.tools.Tool; public class FileStatistics { public static class Count { private Library library; private ComponentFactory factory; private int simpleCount; private int uniqueCount; private int recursiveCount; private Count(ComponentFactory factory) { this.library = null; this.factory = factory; this.simpleCount = 0; this.uniqueCount = 0; this.recursiveCount = 0; } public ComponentFactory getFactory() { return factory; } public Library getLibrary() { return library; } public int getRecursiveCount() { return recursiveCount; } public int getSimpleCount() { return simpleCount; } public int getUniqueCount() { return uniqueCount; } } public static FileStatistics compute(LogisimFile file, Circuit circuit) { Set<Circuit> include = new HashSet<Circuit>(file.getCircuits()); Map<Circuit, Map<ComponentFactory, Count>> countMap; countMap = new HashMap<Circuit, Map<ComponentFactory, Count>>(); doRecursiveCount(circuit, include, countMap); doUniqueCounts(countMap.get(circuit), countMap); List<Count> countList = sortCounts(countMap.get(circuit), file); return new FileStatistics(countList, getTotal(countList, include), getTotal(countList, null)); } private static Map<ComponentFactory, Count> doRecursiveCount( Circuit circuit, Set<Circuit> include, Map<Circuit, Map<ComponentFactory, Count>> countMap) { if (countMap.containsKey(circuit)) { return countMap.get(circuit); } Map<ComponentFactory, Count> counts = doSimpleCount(circuit); countMap.put(circuit, counts); for (Count count : counts.values()) { count.uniqueCount = count.simpleCount; count.recursiveCount = count.simpleCount; } for (Circuit sub : include) { SubcircuitFactory subFactory = sub.getSubcircuitFactory(); if (counts.containsKey(subFactory)) { int multiplier = counts.get(subFactory).simpleCount; Map<ComponentFactory, Count> subCount; subCount = doRecursiveCount(sub, include, countMap); for (Count subcount : subCount.values()) { ComponentFactory subfactory = subcount.factory; Count supercount = counts.get(subfactory); if (supercount == null) { supercount = new Count(subfactory); counts.put(subfactory, supercount); } supercount.recursiveCount += multiplier * subcount.recursiveCount; } } } return counts; } private static Map<ComponentFactory, Count> doSimpleCount(Circuit circuit) { Map<ComponentFactory, Count> counts; counts = new HashMap<ComponentFactory, Count>(); for (Component comp : circuit.getNonWires()) { ComponentFactory factory = comp.getFactory(); Count count = counts.get(factory); if (count == null) { count = new Count(factory); counts.put(factory, count); } count.simpleCount++; } return counts; } private static void doUniqueCounts(Map<ComponentFactory, Count> counts, Map<Circuit, Map<ComponentFactory, Count>> circuitCounts) { for (Count count : counts.values()) { ComponentFactory factory = count.getFactory(); int unique = 0; for (Circuit circ : circuitCounts.keySet()) { Count subcount = circuitCounts.get(circ).get(factory); if (subcount != null) { unique += subcount.simpleCount; } } count.uniqueCount = unique; } } private static Count getTotal(List<Count> counts, Set<Circuit> exclude) { Count ret = new Count(null); for (Count count : counts) { ComponentFactory factory = count.getFactory(); Circuit factoryCirc = null; if (factory instanceof SubcircuitFactory) { factoryCirc = ((SubcircuitFactory) factory).getSubcircuit(); } if (exclude == null || !exclude.contains(factoryCirc)) { ret.simpleCount += count.simpleCount; ret.uniqueCount += count.uniqueCount; ret.recursiveCount += count.recursiveCount; } } return ret; } private static List<Count> sortCounts(Map<ComponentFactory, Count> counts, LogisimFile file) { List<Count> ret = new ArrayList<Count>(); for (AddTool tool : file.getTools()) { ComponentFactory factory = tool.getFactory(); Count count = counts.get(factory); if (count != null) { count.library = file; ret.add(count); } } for (Library lib : file.getLibraries()) { for (Tool tool : lib.getTools()) { if (tool instanceof AddTool) { ComponentFactory factory = ((AddTool) tool).getFactory(); Count count = counts.get(factory); if (count != null) { count.library = lib; ret.add(count); } } } } return ret; } private List<Count> counts; private Count totalWithout; private Count totalWith; private FileStatistics(List<Count> counts, Count totalWithout, Count totalWith) { this.counts = Collections.unmodifiableList(counts); this.totalWithout = totalWithout; this.totalWith = totalWith; } public List<Count> getCounts() { return counts; } public Count getTotalWithoutSubcircuits() { return totalWithout; } public Count getTotalWithSubcircuits() { return totalWith; } }