Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.sun.electric.database.Snapshot Maven / Gradle / Ivy
/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: Snapshot.java
* Written by: Dmitry Nadezhin, Sun Microsystems.
*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
*
* Electric(tm) 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.
*
* Electric(tm) 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 Electric(tm); see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, Mass 02111-1307, USA.
*/
package com.sun.electric.database;
import com.sun.electric.database.geometry.ERectangle;
import com.sun.electric.database.id.CellId;
import com.sun.electric.database.id.CellUsage;
import com.sun.electric.database.id.IdManager;
import com.sun.electric.database.id.IdReader;
import com.sun.electric.database.id.IdWriter;
import com.sun.electric.database.id.LibId;
import com.sun.electric.database.id.TechId;
import com.sun.electric.database.text.CellName;
import com.sun.electric.database.text.Setting;
import com.sun.electric.technology.TechPool;
import com.sun.electric.technology.Technology;
import com.sun.electric.technology.technologies.Artwork;
import com.sun.electric.technology.technologies.Generic;
import com.sun.electric.technology.technologies.Schematics;
import com.sun.electric.tool.Tool;
import com.sun.electric.util.TextUtils;
import com.sun.electric.util.collections.ImmutableArrayList;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
/**
*
*/
public class Snapshot {
public final IdManager idManager;
public final int snapshotId;
public final Tool tool;
public final ImmutableArrayList cellTrees;
public final ImmutableArrayList cellBackups;
private final int[] cellGroups;
private final CellId[] groupMainSchematics;
public final ImmutableArrayList libBackups;
public final Environment environment;
public final TechPool techPool;
final EquivalentSchematicExports[] equivSchemExports;
/** Creates a new instance of Snapshot */
private Snapshot(IdManager idManager, int snapshotId, Tool tool,
ImmutableArrayList cellTrees,
ImmutableArrayList cellBackups,
int[] cellGroups, CellId[] groupMainSchematics,
ImmutableArrayList libBackups,
Environment environment) {
this.idManager = idManager;
this.snapshotId = snapshotId;
this.tool = tool;
this.cellTrees = cellTrees;
this.cellBackups = cellBackups;
this.cellGroups = cellGroups;
this.groupMainSchematics = groupMainSchematics;
this.libBackups = libBackups;
this.environment = environment;
techPool = environment.techPool;
equivSchemExports = new EquivalentSchematicExports[cellTrees.size()];
}
/**
* Creates empty snapshot.
*/
public Snapshot(IdManager idManager) {
this(idManager, 0, null, CellTree.EMPTY_LIST, CellBackup.EMPTY_LIST,
new int[0], new CellId[0],
LibraryBackup.EMPTY_LIST, idManager.getInitialEnvironment());
}
/**
* Creates a new instance of Snapshot which differs from this Snapshot.
* Four array parameters are supplied. Each parameter may be null if its contents is the same as in this Snapshot.
* @param tool Tool which initiated database changes.
* @param environment Environment of this Snapshot
* @param cellBackupsArray array indexed by cellIndex of new CellBackups.
* @param libBackupsArray array indexed by libIndex of LibraryBackups.
* @return new snapshot which differs froms this Snapshot or this Snapshot.
* @throws IllegalArgumentException on invariant violation.
* @throws ArrayOutOfBoundsException on some invariant violations.
*/
public Snapshot with(Tool tool, Environment environment, CellBackup[] cellBackupsArray, LibraryBackup[] libBackupsArray) {
if (environment == null) {
environment = this.environment;
}
CellTree[] cellTreesArray = null;
if (cellBackupsArray != null) {
cellTreesArray = computeCellTrees(new ImmutableArrayList(cellBackupsArray), environment.techPool);
}
return with(tool, environment, cellTreesArray, libBackupsArray);
}
/**
* Creates a new instance of Snapshot which differs from this Snapshot.
* Four array parameters are supplied. Each parameter may be null if its contents is the same as in this Snapshot.
* @param tool Tool which initiated database changes.
* @param environment Environment of this Snapshot
* @param cellTreesArray array indexed by cellIndex of new CellTrees.
* @param libBackupsArray array indexed by libIndex of LibraryBackups.
* @return new snapshot which differs froms this Snapshot or this Snapshot.
* @throws IllegalArgumentException on invariant violation.
* @throws ArrayOutOfBoundsException on some invariant violations.
*/
public Snapshot with(Tool tool, Environment environment, CellTree[] cellTreesArray, LibraryBackup[] libBackupsArray) {
// long startTime = System.currentTimeMillis();
if (environment == null) {
environment = this.environment;
}
ImmutableArrayList cellTrees = copyArray(cellTreesArray, this.cellTrees);
ImmutableArrayList libBackups = copyArray(libBackupsArray, this.libBackups);
if (this.cellTrees == cellTrees && this.libBackups == libBackups && this.environment == environment) {
return this;
}
TechPool techPool = environment.techPool;
// Check usages in cells
boolean namesChanged = this.libBackups != libBackups || this.cellTrees.size() != cellTrees.size();
for (int cellIndex = 0; cellIndex < cellTrees.size(); cellIndex++) {
CellTree newTree = cellTrees.get(cellIndex);
CellTree oldTree = getCellTree(cellIndex);
if (newTree == null) {
if (oldTree != null) {
namesChanged = true;
}
continue;
}
CellBackup newBackup = newTree.top;
ImmutableCell newCell = newBackup.cellRevision.d;
if (!newBackup.techPool.isRestriction(techPool)) {
throw new IllegalArgumentException();
}
// Check that sub trees match
if (newCell.cellId.cellIndex != cellIndex) {
throw new IllegalArgumentException();
}
if (newCell.cellId.idManager != idManager) {
throw new IllegalArgumentException();
}
for (CellTree cellSubTree : newTree.subTrees) {
if (cellSubTree == null) {
continue;
}
if (cellSubTree != cellTrees.get(cellSubTree.top.cellRevision.d.cellId.cellIndex)) {
throw new IllegalArgumentException();
}
}
CellBackup oldBackup = getCell(cellIndex);
if (oldBackup == null || newCell.groupName != oldBackup.cellRevision.d.groupName
|| newCell.params != oldBackup.cellRevision.d.params) {
namesChanged = true;
}
}
ImmutableArrayList cellBackups = this.cellBackups;
if (this.cellTrees != cellTrees) {
CellBackup[] cellBackupArray = new CellBackup[cellTrees.size()];
for (int cellIndex = 0; cellIndex < cellTrees.size(); cellIndex++) {
CellTree cellTree = cellTrees.get(cellIndex);
if (cellTree != null) {
cellBackupArray[cellIndex] = cellTree.top;
}
}
cellBackups = new ImmutableArrayList(cellBackupArray);
}
// Check names
int[] cellGroups = this.cellGroups;
CellId[] groupMainSchematics = this.groupMainSchematics;
if (namesChanged) {
cellGroups = new int[cellBackups.size()];
checkNames(idManager, cellBackups, cellGroups, libBackups);
if (Arrays.equals(this.cellGroups, cellGroups)) {
cellGroups = this.cellGroups;
} else {
int maxGroup = -1;
for (int groupIndex : cellGroups) {
maxGroup = Math.max(maxGroup, groupIndex);
}
groupMainSchematics = new CellId[maxGroup + 1];
for (int cellIndex = 0; cellIndex < cellBackups.size(); cellIndex++) {
CellBackup cellBackup = cellBackups.get(cellIndex);
if (cellBackup == null) {
continue;
}
CellId cellId = cellBackup.cellRevision.d.cellId;
if (!cellId.isSchematic()) {
continue;
}
int groupIndex = cellGroups[cellIndex];
CellId mainSchematics = groupMainSchematics[groupIndex];
if (mainSchematics == null || cellId.cellName.compareTo(mainSchematics.cellName) < 0) {
groupMainSchematics[groupIndex] = cellId;
}
}
if (Arrays.equals(this.groupMainSchematics, groupMainSchematics)) {
groupMainSchematics = this.groupMainSchematics;
}
}
}
Snapshot snapshot = new Snapshot(idManager, idManager.newSnapshotId(), tool,
cellTrees, cellBackups, cellGroups, groupMainSchematics,
libBackups, environment);
// Try to reuse EquivalenSchematicExports
for (CellTree cellTree : snapshot.cellTrees) {
if (cellTree == null) {
continue;
}
reuseSchemEq(snapshot, cellTree.top.cellRevision.d.cellId);
}
// long endTime = System.currentTimeMillis();
// System.out.println("Creating snapshot took: " + (endTime - startTime) + " msec");
return snapshot;
}
private EquivalentSchematicExports reuseSchemEq(Snapshot snapshot, CellId cellId) {
EquivalentSchematicExports newSchemEq = snapshot.equivSchemExports[cellId.cellIndex];
if (newSchemEq != null) {
return newSchemEq;
}
// if (cellId.toString().equals("redFour:NMOS;1{sch}") || cellId.toString().equals("orangeST090nm:NMOSf;1{ic}"))
// cellId = cellId;
CellTree oldCellTree = getCellTree(cellId);
CellTree newCellTree = snapshot.getCellTree(cellId);
if (newCellTree != oldCellTree) {
return null;
}
newSchemEq = equivSchemExports[cellId.cellIndex];
if (newSchemEq == null) {
return null;
}
assert cellId.isIcon() || cellId.isSchematic();
CellId mainSchemId = snapshot.groupMainSchematics[snapshot.cellGroups[cellId.cellIndex]];
if (mainSchemId != groupMainSchematics[cellGroups[cellId.cellIndex]]) {
return null;
}
if (mainSchemId != cellId && mainSchemId != null) {
EquivalentSchematicExports oldMainSchemEq = equivSchemExports[mainSchemId.cellIndex];
if (oldMainSchemEq == null) {
assert cellId.isSchematic();
return null;
}
EquivalentSchematicExports newMainSchemEq = reuseSchemEq(snapshot, mainSchemId);
if (newMainSchemEq == null) {
newMainSchemEq = snapshot.getEquivExports(mainSchemId);
}
if (newMainSchemEq != oldMainSchemEq) {
newSchemEq = null;
}
}
for (CellTree subTree : newCellTree.subTrees) {
if (subTree == null) {
continue;
}
CellId subCellId = subTree.top.cellRevision.d.cellId;
if (subCellId.isIcon()) {
if (cellId.isSchematic() && snapshot.cellGroups[cellId.cellIndex] == snapshot.cellGroups[subCellId.cellIndex]) {
// Icon of parent
continue;
}
} else if (!subCellId.isSchematic()) {
continue;
}
EquivalentSchematicExports oldSubSchemEq = equivSchemExports[subCellId.cellIndex];
assert oldSubSchemEq != null;
EquivalentSchematicExports newSubSchemEq = reuseSchemEq(snapshot, subCellId);
if (newSubSchemEq == null) {
newSubSchemEq = snapshot.getEquivExports(subCellId);
}
if (!newSubSchemEq.equals(oldSubSchemEq)) {
newSchemEq = null;
}
}
if (newSchemEq != null) {
snapshot.equivSchemExports[cellId.cellIndex] = newSchemEq;
}
return newSchemEq;
}
public Snapshot with(Tool tool, Environment environment) {
TechPool techPool = environment.techPool;
CellBackup[] cellBackupArray = new CellBackup[cellBackups.size()];
for (CellBackup cellBackup : cellBackups) {
if (cellBackup == null) {
continue;
}
cellBackupArray[cellBackup.cellRevision.d.cellId.cellIndex] = cellBackup.withTechPool(techPool);
}
return with(tool, environment, cellBackupArray, null);
}
private static ImmutableArrayList copyArray(T[] newArray, ImmutableArrayList oldList) {
if (newArray == null) {
return oldList;
}
int l;
for (l = newArray.length; l > 0 && newArray[l - 1] == null; l--);
if (l == oldList.size()) {
int i = 0;
while (i < oldList.size() && newArray[i] == oldList.get(i)) {
i++;
}
if (i == l) {
return oldList;
}
}
return new ImmutableArrayList(newArray, 0, l);
}
private CellTree[] computeCellTrees(ImmutableArrayList cellBackups, TechPool techPool) {
CellTree[] result = new CellTree[cellBackups.size()];
for (int cellIndex = 0; cellIndex < result.length; cellIndex++) {
CellBackup cellBackup = cellBackups.get(cellIndex);
if (cellBackup == null) {
continue;
}
computeCellTrees(cellBackup.cellRevision.d.cellId, cellBackups, techPool, result);
}
return result;
}
private CellTree computeCellTrees(CellId topCellId, ImmutableArrayList cellBackups, TechPool techPool, CellTree[] cellTrees) {
int cellIndex = topCellId.cellIndex;
CellTree cellTree = cellTrees[cellIndex];
if (cellTree == null) {
CellBackup top = cellBackups.get(cellIndex);
int[] instCounts = top.cellRevision.getInstCounts();
CellTree[] subTrees = new CellTree[instCounts.length];
for (int i = 0; i < subTrees.length; i++) {
if (instCounts[i] == 0) {
continue;
}
subTrees[i] = computeCellTrees(topCellId.getUsageIn(i).protoId, cellBackups, techPool, cellTrees);
}
cellTree = getCellTree(topCellId);
if (cellTree == null) {
cellTree = CellTree.newInstance(top.cellRevision.d, techPool);
}
cellTree = cellTree.with(top, subTrees, techPool);
cellTrees[cellIndex] = cellTree;
}
return cellTree;
}
/**
* Returns Snapshot which differs from this Snapshot by renamed Ids.
* @param idMapper a map from old Ids to new Ids.
* @return Snapshot with renamed Ids.
*/
public Snapshot withRenamedIds(IdMapper idMapper, CellId fromGroup, String toGroup) {
int maxCellIndex = -1;
for (CellBackup cellBackup : cellBackups) {
if (cellBackup == null) {
continue;
}
maxCellIndex = Math.max(maxCellIndex, idMapper.get(cellBackup.cellRevision.d.cellId).cellIndex);
}
int maxLibIndex = -1;
for (LibraryBackup libBackup : libBackups) {
if (libBackup == null) {
continue;
}
maxLibIndex = Math.max(maxLibIndex, idMapper.get(libBackup.d.libId).libIndex);
}
CellBackup[] cellBackupsArray = new CellBackup[maxCellIndex + 1];
LibraryBackup[] libBackupsArray = new LibraryBackup[maxLibIndex + 1];
BitSet cellBackupsChangedInLib = new BitSet();
BitSet fromGroupCellIds = new BitSet();
BitSet toGroupCellIds = new BitSet();
CellName fromGroupName = null;
CellName toGroupName = null;
if (fromGroup != null) {
assert getCell(fromGroup) != null;
CellId toGroupCellId = idMapper.get(fromGroup);
assert toGroupCellId != null;
assert getCell(toGroupCellId) == null;
int fromGroupIndex = cellGroups[fromGroup.cellIndex];
assert fromGroupIndex >= 0;
int toGroupIndex1 = -1, toGroupIndex2 = -1;
if (toGroup == null) {
toGroupIndex2 = fromGroupIndex;
}
for (int cellIndex = 0; cellIndex < cellBackups.size(); cellIndex++) {
CellBackup cellBackup = cellBackups.get(cellIndex);
if (cellBackup == null) {
continue;
}
CellId cellId = cellBackup.cellRevision.d.cellId;
if (cellId.libId == fromGroup.libId) {
if (cellId.cellName.getName().equals(toGroupCellId.cellName.getName())) {
toGroupIndex1 = cellGroups[cellIndex];
}
if (toGroup != null && cellId.cellName.getName().equals(toGroup)) {
toGroupIndex2 = cellGroups[cellIndex];
}
}
}
ArrayList fromCellNames = new ArrayList();
ArrayList toCellNames = new ArrayList();
toGroupCellIds.set(toGroupCellId.cellIndex);
toCellNames.add(toGroupCellId.cellName);
for (int cellIndex = 0; cellIndex < cellBackups.size(); cellIndex++) {
CellBackup cellBackup = cellBackups.get(cellIndex);
if (cellBackup == null || cellIndex == fromGroup.cellIndex) {
continue;
}
CellId cellId = cellBackup.cellRevision.d.cellId;
if (cellGroups[cellIndex] == fromGroupIndex) {
fromGroupCellIds.set(cellIndex);
fromCellNames.add(cellId.cellName);
}
if (cellGroups[cellIndex] == toGroupIndex1 || cellGroups[cellIndex] == toGroupIndex2) {
toGroupCellIds.set(cellIndex);
toCellNames.add(cellId.cellName);
}
}
if (!fromCellNames.isEmpty()) {
fromGroupName = makeCellGroupName(fromCellNames);
}
if (!toCellNames.isEmpty()) {
toGroupName = makeCellGroupName(toCellNames);
}
}
for (int cellIndex = 0; cellIndex < cellBackups.size(); cellIndex++) {
CellBackup oldCellBackup = cellBackups.get(cellIndex);
if (oldCellBackup == null) {
continue;
}
CellName newGroupName = oldCellBackup.cellRevision.d.groupName;
if (fromGroup != null) {
if (toGroupCellIds.get(cellIndex) || cellIndex == fromGroup.cellIndex) {
newGroupName = toGroupName;
} else if (fromGroupCellIds.get(cellIndex)) {
newGroupName = fromGroupName;
}
}
CellBackup newCellBackup = oldCellBackup.withRenamedIds(idMapper, newGroupName);
if (newCellBackup != oldCellBackup) {
cellBackupsChangedInLib.set(newCellBackup.cellRevision.d.cellId.libId.libIndex);
}
int newCellIndex = newCellBackup.cellRevision.d.cellId.cellIndex;
cellBackupsArray[newCellIndex] = newCellBackup;
}
if (cellBackupsChangedInLib.isEmpty()) {
cellBackupsArray = null;
}
boolean libBackupsChanged = false;
for (int libIndex = 0; libIndex < libBackups.size(); libIndex++) {
LibraryBackup oldLibBackup = libBackups.get(libIndex);
if (oldLibBackup == null) {
continue;
}
LibraryBackup newLibBackup = oldLibBackup.withRenamedIds(idMapper);
if (cellBackupsChangedInLib.get(libIndex)) {
newLibBackup = newLibBackup.withModified();
}
if (newLibBackup != oldLibBackup) {
libBackupsChanged = true;
}
libBackupsArray[newLibBackup.d.libId.libIndex] = newLibBackup;
}
if (!libBackupsChanged) {
libBackupsArray = null;
}
if (cellBackupsArray == null && libBackups == null) {
return this;
}
return with(tool, null, cellBackupsArray, libBackupsArray);
}
public List getChangedLibraries(Snapshot oldSnapshot) {
if (oldSnapshot == null) {
oldSnapshot = idManager.getInitialSnapshot();
}
if (idManager != oldSnapshot.idManager) {
throw new IllegalArgumentException();
}
List changed = null;
if (oldSnapshot.libBackups != libBackups) {
int numLibs = Math.max(oldSnapshot.libBackups.size(), libBackups.size());
for (int i = 0; i < numLibs; i++) {
LibraryBackup oldBackup = oldSnapshot.getLib(i);
LibraryBackup newBackup = getLib(i);
if (oldBackup == newBackup) {
continue;
}
if (changed == null) {
changed = new ArrayList();
}
changed.add(idManager.getLibId(i));
}
}
if (changed == null) {
changed = Collections.emptyList();
}
return changed;
}
public List getChangedCells(Snapshot oldSnapshot) {
if (oldSnapshot == null) {
oldSnapshot = idManager.getInitialSnapshot();
}
List changed = null;
int numCells = Math.max(oldSnapshot.cellBackups.size(), cellBackups.size());
for (int i = 0; i < numCells; i++) {
CellBackup oldBackup = oldSnapshot.getCell(i);
CellBackup newBackup = getCell(i);
if (oldBackup == newBackup) {
continue;
}
if (changed == null) {
changed = new ArrayList();
}
changed.add(idManager.getCellId(i));
}
if (changed == null) {
changed = Collections.emptyList();
}
return changed;
}
public Collection getCellsDownTop() {
LinkedHashSet order = new LinkedHashSet();
for (CellBackup cellBackup : cellBackups) {
if (cellBackup == null) {
continue;
}
getCellsDownTop(cellBackup.cellRevision.d.cellId, order);
}
return order;
}
private void getCellsDownTop(CellId root, LinkedHashSet order) {
if (order.contains(root)) {
return;
}
CellBackup cellBackup = getCell(root);
CellRevision cellRevision = cellBackup.cellRevision;
for (int i = 0; i < cellRevision.cellUsages.length; i++) {
if (cellRevision.cellUsages[i] == null) {
continue;
}
CellUsage cu = root.getUsageIn(i);
getCellsDownTop(cu.protoId, order);
}
boolean added = order.add(root);
assert added;
}
public CellTree getCellTree(CellId cellId) {
if (cellId.getIdManager() != idManager) {
throw new IllegalArgumentException();
}
return getCellTree(cellId.cellIndex);
}
public CellBackup getCell(CellId cellId) {
if (cellId.getIdManager() != idManager) {
throw new IllegalArgumentException();
}
return getCell(cellId.cellIndex);
}
public CellRevision getCellRevision(CellId cellId) {
CellBackup cellBackup = getCell(cellId);
return cellBackup != null ? cellBackup.cellRevision : null;
}
public CellTree getCellTree(int cellIndex) {
return cellIndex < cellTrees.size() ? cellTrees.get(cellIndex) : null;
}
public CellBackup getCell(int cellIndex) {
return cellIndex < cellBackups.size() ? cellBackups.get(cellIndex) : null;
}
public CellRevision getCellRevision(int cellIndex) {
CellBackup cellBackup = getCell(cellIndex);
return cellBackup != null ? cellBackup.cellRevision : null;
}
/**
* Returns group name of group with specified CellNames.
* Name of cell group is a base name of main schematics cell if any.
* Otherwise it is a shortest base name among cells in the group.
* @param cellNames collection of CellNames in a group.
* @return name of cell group.
* @throws InvalidArgumentException if cellNames is empty
*/
public static CellName makeCellGroupName(Collection cellNames) {
if (cellNames.isEmpty()) {
throw new IllegalArgumentException();
}
String groupName = null;
for (CellName cellName : cellNames) {
if (!cellName.isSchematic()) {
continue;
}
String name = cellName.getName();
if (groupName == null || TextUtils.STRING_NUMBER_ORDER.compare(name, groupName) < 0) {
groupName = name;
}
}
if (groupName == null) {
for (CellName cellName : cellNames) {
String name = cellName.getName();
if (groupName == null || name.length() < groupName.length()
|| name.length() == groupName.length() && TextUtils.STRING_NUMBER_ORDER.compare(name, groupName) < 0) {
groupName = name;
}
}
}
assert groupName != null;
return CellName.parseName(groupName + "{sch}");
}
public EquivalentSchematicExports getEquivExports(CellId top) {
EquivalentSchematicExports eq = equivSchemExports[top.cellIndex];
if (eq == null) {
ImmutableNetSchem netSchem = new ImmutableNetSchem(this, top);
eq = new EquivalentSchematicExports(netSchem);
equivSchemExports[top.cellIndex] = eq;
}
return eq;
}
public ERectangle getCellBounds(CellId cellId) {
return getCellBounds(cellId.cellIndex);
}
public ERectangle getCellBounds(int cellIndex) {
CellTree cellTree = getCellTree(cellIndex);
return cellTree != null ? cellTree.getBounds() : null;
}
public int getCellGroupIndex(CellId cellId) {
return cellGroups[cellId.cellIndex];
}
public boolean cellGroupsProbablyChanged(Snapshot that) {
return this.cellGroups != that.cellGroups;
}
public CellId getMainSchematics(CellId cellId) {
return groupMainSchematics[cellGroups[cellId.cellIndex]];
}
/** Returns TechPool of this Snapshot */
public TechPool getTechPool() {
return techPool;
}
/**
* Get Technology by TechId
* TechId must belong to same IdManager as TechPool
* @param techId TechId to find
* @return Technology b giben TechId or null
* @throws IllegalArgumentException of TechId is not from this IdManager
*/
public Technology getTech(TechId techId) {
return techPool.getTech(techId);
}
/** Returns Artwork technology in this database */
public Artwork getArtwork() {
return techPool.getArtwork();
}
/** Returns Generic technology in this database */
public Generic getGeneric() {
return techPool.getGeneric();
}
/** Returns Schematic technology in this database */
public Schematics getSchematics() {
return techPool.getSchematics();
}
// private Technology getTech(int techIndex) {
// return techIndex < technologies.size() ? technologies.get(techIndex) : null;
// }
/** Returns map from Setting to its value in this Snapshot */
public Map getSettings() {
return environment.getSettings();
}
public LibraryBackup getLib(LibId libId) {
return getLib(libId.libIndex);
}
private LibraryBackup getLib(int libIndex) {
return libIndex < libBackups.size() ? libBackups.get(libIndex) : null;
}
// private boolean equals(Snapshot that) {
// return this.cellBackups.equals(that.cellBackups) &&
// this.libBackups.equals(that.libBackups) &&
// Arrays.equals(this.cellGroups, that.cellGroups) &&
// this.cellBounds.equals(that.cellBounds);
// }
public void writeDiffs(IdWriter writer, Snapshot oldSnapshot) throws IOException {
writer.writeDiffs();
writer.writeInt(snapshotId);
writer.writeBoolean(tool != null);
if (tool != null) {
writer.writeTool(tool);
}
environment.writeDiff(writer, oldSnapshot.environment);
boolean libsChanged = oldSnapshot.libBackups != libBackups;
writer.writeBoolean(libsChanged);
if (libsChanged) {
writer.writeInt(libBackups.size());
for (int i = 0; i < libBackups.size(); i++) {
LibraryBackup oldBackup = oldSnapshot.getLib(i);
LibraryBackup newBackup = getLib(i);
if (oldBackup == newBackup) {
continue;
}
if (oldBackup == null) {
writer.writeInt(i);
newBackup.write(writer);
} else if (newBackup == null) {
writer.writeInt(~i);
} else {
writer.writeInt(i);
newBackup.write(writer);
}
}
writer.writeInt(Integer.MAX_VALUE);
}
writer.writeInt(cellBackups.size());
for (int i = 0; i < cellBackups.size(); i++) {
CellBackup oldBackup = oldSnapshot.getCell(i);
CellBackup newBackup = getCell(i);
if (oldBackup == newBackup) {
continue;
}
if (oldBackup == null) {
writer.writeInt(i);
newBackup.write(writer);
} else if (newBackup == null) {
writer.writeInt(~i);
} else {
writer.writeInt(i);
newBackup.write(writer);
}
}
writer.writeInt(Integer.MAX_VALUE);
boolean cellGroupsChanged = cellGroups != oldSnapshot.cellGroups;
writer.writeBoolean(cellGroupsChanged);
if (cellGroupsChanged) {
assert cellGroups.length == cellBackups.size();
for (int cellIndex = 0; cellIndex < cellGroups.length; cellIndex++) {
writer.writeInt(cellGroups[cellIndex]);
}
for (int groupIndex = 0; groupIndex < groupMainSchematics.length; groupIndex++) {
CellId mainSchematics = groupMainSchematics[groupIndex];
writer.writeInt(mainSchematics != null ? mainSchematics.cellIndex : -1);
}
}
}
public static Snapshot readSnapshot(IdReader reader, Snapshot oldSnapshot) throws IOException {
assert reader.idManager == oldSnapshot.idManager;
reader.readDiffs();
int snapshotId = reader.readInt();
boolean hasTool = reader.readBoolean();
Tool tool = hasTool ? reader.readTool() : null;
Environment environment = Environment.readEnvironment(reader, oldSnapshot.environment);
TechPool techPool = environment.techPool;
boolean technologiesChanged = techPool != oldSnapshot.techPool;
ImmutableArrayList libBackups = oldSnapshot.libBackups;
boolean libsChanged = reader.readBoolean();
if (libsChanged) {
int libLen = reader.readInt();
LibraryBackup[] libBackupsArray = new LibraryBackup[libLen];
for (int libIndex = 0, numLibs = Math.min(oldSnapshot.libBackups.size(), libLen); libIndex < numLibs; libIndex++) {
libBackupsArray[libIndex] = oldSnapshot.libBackups.get(libIndex);
}
for (;;) {
int libIndex = reader.readInt();
if (libIndex == Integer.MAX_VALUE) {
break;
}
if (libIndex >= 0) {
LibraryBackup newBackup = LibraryBackup.read(reader);
libBackupsArray[libIndex] = newBackup;
} else {
libIndex = ~libIndex;
assert libBackupsArray[libIndex] != null;
libBackupsArray[libIndex] = null;
}
}
libBackups = new ImmutableArrayList(libBackupsArray);
}
int cellLen = reader.readInt();
int cellMax = Math.min(oldSnapshot.cellBackups.size(), cellLen);
CellBackup[] cellBackupsArray = new CellBackup[cellLen];
for (int cellIndex = 0; cellIndex < cellMax; cellIndex++) {
cellBackupsArray[cellIndex] = oldSnapshot.cellBackups.get(cellIndex);
}
if (technologiesChanged) {
for (int cellIndex = 0; cellIndex < cellLen; cellIndex++) {
CellBackup cellBackup = cellBackupsArray[cellIndex];
if (cellBackup == null) {
continue;
}
cellBackupsArray[cellIndex] = cellBackup.withTechPool(techPool);
}
}
for (;;) {
int cellIndex = reader.readInt();
if (cellIndex == Integer.MAX_VALUE) {
break;
}
if (cellIndex >= 0) {
CellBackup newBackup = CellBackup.read(reader, techPool);
cellBackupsArray[cellIndex] = newBackup;
} else {
cellIndex = ~cellIndex;
assert cellBackupsArray[cellIndex] != null;
cellBackupsArray[cellIndex] = null;
}
}
ImmutableArrayList cellBackups = new ImmutableArrayList(cellBackupsArray);
int[] cellGroups = oldSnapshot.cellGroups;
CellId[] groupMainSchematics = oldSnapshot.groupMainSchematics;
boolean cellGroupsChanged = reader.readBoolean();
if (cellGroupsChanged) {
cellGroups = new int[cellBackups.size()];
int maxGroup = -1;
for (int cellIndex = 0; cellIndex < cellGroups.length; cellIndex++) {
int groupIndex = reader.readInt();
maxGroup = Math.max(maxGroup, groupIndex);
cellGroups[cellIndex] = groupIndex;
}
groupMainSchematics = new CellId[maxGroup + 1];
for (int groupIndex = 0; groupIndex < groupMainSchematics.length; groupIndex++) {
CellId mainSchematics = null;
int cellIndex = reader.readInt();
if (cellIndex >= 0) {
mainSchematics = reader.idManager.getCellId(cellIndex);
}
groupMainSchematics[groupIndex] = mainSchematics;
}
}
for (int i = 0; i < cellBackups.size(); i++) {
assert (cellBackups.get(i) != null) == (cellGroups[i] >= 0);
}
CellTree[] cellTreesArray = oldSnapshot.computeCellTrees(cellBackups, environment.techPool);
ImmutableArrayList cellTrees = new ImmutableArrayList(cellTreesArray);
return new Snapshot(oldSnapshot.idManager, snapshotId, tool, cellTrees, cellBackups,
cellGroups, groupMainSchematics,
libBackups, environment);
}
/**
* Checks invariant of this Snapshot.
* @throws IllegalArgumentException on invariant violation.
* @throws ArrayOutOfBoundsException on some invariant violations.
* @throws AssertionError if invariant is broken.
* @throws AssertionError if invariant is broken.
*/
public void check() {
// long startTime = System.currentTimeMillis();
techPool.check();
environment.check();
assert environment.techPool == techPool;
assert techPool.idManager == idManager;
for (LibraryBackup libBackup : libBackups) {
if (libBackup == null) {
continue;
}
libBackup.check();
}
assert cellTrees.size() == cellBackups.size();
for (int cellIndex = 0; cellIndex < cellTrees.size(); cellIndex++) {
CellTree cellTree = cellTrees.get(cellIndex);
CellBackup cellBackup = cellBackups.get(cellIndex);
if (cellTree == null) {
assert cellBackup == null;
continue;
}
assert cellBackup == cellTree.top;
for (CellTree subCellTree : cellTree.subTrees) {
if (subCellTree == null) {
continue;
}
CellId subCellId = subCellTree.top.cellRevision.d.cellId;
assert subCellTree == cellTrees.get(subCellId.cellIndex);
}
cellTree.check();
assert cellTree.techPool.isRestriction(techPool);
}
if (libBackups.size() > 0) {
assert libBackups.get(libBackups.size() - 1) != null;
}
if (cellTrees.size() > 0) {
assert cellTrees.get(cellTrees.size() - 1) != null;
}
checkRecursion(cellBackups);
int[] cellGroups = new int[cellBackups.size()];
checkNames(idManager, cellBackups, cellGroups, libBackups);
assert Arrays.equals(this.cellGroups, cellGroups);
int maxGroup = -1;
for (int groupIndex : cellGroups) {
maxGroup = Math.max(maxGroup, groupIndex);
}
assert groupMainSchematics.length == maxGroup + 1;
BitSet foundMainSchematics = new BitSet();
for (CellBackup cellBackup : cellBackups) {
if (cellBackup == null) {
continue;
}
CellId cellId = cellBackup.cellRevision.d.cellId;
if (!cellId.isSchematic()) {
continue;
}
int groupIndex = cellGroups[cellId.cellIndex];
int cmp = cellId.cellName.compareTo(groupMainSchematics[groupIndex].cellName);
assert cmp >= 0;
if (cmp == 0) {
assert groupMainSchematics[groupIndex] == cellId;
foundMainSchematics.set(groupIndex);
}
}
for (int groupIndex = 0; groupIndex < groupMainSchematics.length; groupIndex++) {
assert foundMainSchematics.get(groupIndex) == (groupMainSchematics[groupIndex] != null);
}
// long endTime = System.currentTimeMillis();
// System.out.println("Checking snapshot invariants took: " + (endTime - startTime) + " msec");
}
/*
* Checks name consistency of arrays intended for Sbapshot construction.
* @throws IllegalArgumentException on invariant violation.
* @throws ArrayOutOfBoundsException on some invariant violations.
*/
private static void checkNames(IdManager idManager, ImmutableArrayList cellBackups, int[] cellGroups, ImmutableArrayList libBackups) {
HashSet libNames = new HashSet();
ArrayList> protoNameToGroupName = new ArrayList>();
ArrayList> cellNames = new ArrayList>();
ArrayList> groupNameToGroupIndex = new ArrayList>();
for (int libIndex = 0; libIndex < libBackups.size(); libIndex++) {
LibraryBackup libBackup = libBackups.get(libIndex);
if (libBackup == null) {
protoNameToGroupName.add(null);
cellNames.add(null);
groupNameToGroupIndex.add(null);
continue;
}
protoNameToGroupName.add(new HashMap());
cellNames.add(new HashSet());
groupNameToGroupIndex.add(new HashMap());
if (libBackup.d.libId != idManager.getLibId(libIndex)) {
throw new IllegalArgumentException("LibId");
}
String libName = libBackup.d.libId.libName;
if (!libNames.add(libName)) {
throw new IllegalArgumentException("duplicate libName");
}
for (LibId libId : libBackup.referencedLibs) {
if (libId != libBackups.get(libId.libIndex).d.libId) {
throw new IllegalArgumentException("LibId in referencedLibs");
}
}
}
assert protoNameToGroupName.size() == libBackups.size() && cellNames.size() == libBackups.size() && groupNameToGroupIndex.size() == libBackups.size();
assert cellBackups.size() == cellGroups.length;
Arrays.fill(cellGroups, -1);
ArrayList groupParamOwners = new ArrayList();
for (int cellIndex = 0; cellIndex < cellBackups.size(); cellIndex++) {
CellBackup cellBackup = cellBackups.get(cellIndex);
if (cellBackup == null) {
continue;
}
ImmutableCell d = cellBackup.cellRevision.d;
CellId cellId = d.cellId;
if (cellId != idManager.getCellId(cellIndex)) {
throw new IllegalArgumentException("CellId");
}
LibId libId = d.getLibId();
int libIndex = libId.libIndex;
if (libId != libBackups.get(libIndex).d.libId) {
throw new IllegalArgumentException("LibId in ImmutableCell");
}
HashMap cellNameToGroupNameInLibrary = protoNameToGroupName.get(libId.libIndex);
HashSet cellNamesInLibrary = cellNames.get(libId.libIndex);
HashMap groupNameToGroupIndexInLibrary = groupNameToGroupIndex.get(libId.libIndex);
String protoName = cellId.cellName.getName();
CellName groupName = cellNameToGroupNameInLibrary.get(protoName);
if (groupName == null) {
groupName = d.groupName;
cellNameToGroupNameInLibrary.put(protoName, groupName);
} else if (!d.groupName.equals(groupName)) {
throw new IllegalArgumentException("cells with same proto name in different groups");
}
Integer gn = groupNameToGroupIndexInLibrary.get(groupName);
if (gn == null) {
gn = Integer.valueOf(groupParamOwners.size());
groupParamOwners.add(null);
groupNameToGroupIndexInLibrary.put(groupName, gn);
}
cellGroups[cellIndex] = gn.intValue();
if (!cellNamesInLibrary.add(cellId.cellName)) {
throw new IllegalArgumentException("duplicate CellName in library");
}
if (d.paramsAllowed()) {
ImmutableCell paramOwner = groupParamOwners.get(gn.intValue());
if (paramOwner != null) {
d.checkSimilarParams(paramOwner);
} else {
groupParamOwners.set(gn.intValue(), paramOwner);
}
}
}
}
private static void checkRecursion(ImmutableArrayList cellBackups) {
BitSet visited = new BitSet();
BitSet checked = new BitSet();
for (CellBackup cellBackup : cellBackups) {
if (cellBackup == null) {
continue;
}
checkRecursion(cellBackup.cellRevision.d.cellId, cellBackups, visited, checked);
}
assert visited.equals(checked);
}
private static void checkRecursion(CellId cellId, ImmutableArrayList cellBackups, BitSet visited, BitSet checked) {
int cellIndex = cellId.cellIndex;
if (checked.get(cellIndex)) {
return;
}
assert !visited.get(cellIndex);
visited.set(cellIndex);
CellBackup cellBackup = cellBackups.get(cellIndex);
CellRevision cellRevision = cellBackup.cellRevision;
for (int i = 0; i < cellRevision.cellUsages.length; i++) {
CellRevision.CellUsageInfo cui = cellRevision.cellUsages[i];
if (cui == null) {
continue;
}
CellUsage u = cellId.getUsageIn(i);
int subCellIndex = u.protoId.cellIndex;
if (checked.get(subCellIndex)) {
continue;
}
if (visited.get(subCellIndex)) {
throw new IllegalArgumentException("Recursive instance of " + u.protoId + " in " + u.parentId);
}
checkRecursion(u.protoId, cellBackups, visited, checked);
}
checked.set(cellIndex);
}
}