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.
/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: Topology.java
* Written by: Dmitry Nadezhin, Sun Microsystems.
*
* Copyright (c) 2006, 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.topology;
import com.sun.electric.database.CellBackup;
import com.sun.electric.database.CellRevision;
import com.sun.electric.database.ImmutableArcInst;
import com.sun.electric.database.ImmutableNodeInst;
import com.sun.electric.database.constraint.Constraints;
import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.database.hierarchy.EDatabase;
import com.sun.electric.database.hierarchy.Export;
import com.sun.electric.database.hierarchy.Nodable;
import com.sun.electric.database.id.CellId;
import com.sun.electric.database.id.CellUsage;
import com.sun.electric.database.id.PortProtoId;
import com.sun.electric.database.prototype.NodeProto;
import com.sun.electric.database.prototype.PortProto;
import com.sun.electric.database.text.Name;
import com.sun.electric.technology.BoundsBuilder;
import com.sun.electric.technology.technologies.Generic;
import com.sun.electric.util.TextUtils;
import com.sun.electric.util.collections.ImmutableArrayList;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
/**
* A class to manage nodes and arcs of a Cell.
*/
public class Topology {
private class MaxSuffix {
int v = 0;
}
/** Owner cell of this Topology. */
final Cell cell;
/** The Cell's essential-bounds. */
private final ArrayList essenBounds = new ArrayList();
/** Chronological list of NodeInsts in this Cell. */
private final ArrayList chronNodes = new ArrayList();
/** A list of NodeInsts in this Cell. */
private final ArrayList nodes = new ArrayList();
/** A map from canonic String to Integer maximal numeric suffix */
private final HashMap maxSuffix = new HashMap();
/** A maximal suffix of temporary arc name. */
private int maxArcSuffix = -1;
/** Chronological list of ArcInst in this Cell. */
private final ArrayList chronArcs = new ArrayList();
/** A list of ArcInsts in this Cell. */
private final ArrayList arcs = new ArrayList();
/** True if arc bounds are valid. */
boolean validArcBounds;
/** The geometric data structure. */
private RTNode rTree = RTNode.makeTopLevel();
/** True of RTree matches node/arc sizes */
private boolean rTreeFresh;
/** Creates a new instance of Topology */
public Topology(Cell cell, boolean loadBackup) {
this.cell = cell;
if (loadBackup) {
CellRevision cellRevision = cell.backup().cellRevision;
updateNodes(true, cellRevision, null, cell.lowLevelExpandedNodes());
updateArcs(cellRevision);
}
}
/****************************** NODES ******************************/
/**
* Method to return an Iterator over all NodeInst objects in this Cell.
* @return an Iterator over all NodeInst objects in this Cell.
*/
public synchronized Iterator getNodes() {
ArrayList nodesCopy = new ArrayList(nodes);
return nodesCopy.iterator();
}
/**
* Method to return an Iterator over all NodeInst objects in this Cell.
* @return an Iterator over all NodeInst objects in this Cell.
*/
public synchronized Iterator getNodables() {
ArrayList nodesCopy = new ArrayList(nodes);
return nodesCopy.iterator();
}
/**
* Method to return the number of NodeInst objects in this Cell.
* @return the number of NodeInst objects in this Cell.
*/
public int getNumNodes() {
return nodes.size();
}
/**
* Method to return the NodeInst at specified position.
* @param nodeIndex specified position of NodeInst.
* @return the NodeInst at specified position.
*/
public final NodeInst getNode(int nodeIndex) {
return nodes.get(nodeIndex);
}
/**
* Method to return the NodeInst by its chronological index.
* @param nodeId chronological index of NodeInst.
* @return the NodeInst with specified chronological index.
*/
public NodeInst getNodeById(int nodeId) {
return nodeId < chronNodes.size() ? chronNodes.get(nodeId) : null;
}
// /**
// * Tells expanded status of NodeInst with specified nodeId.
// * @return true if NodeInst with specified nodeId is expanded.
// */
// public boolean isExpanded(int nodeId) {
// return expandedNodes.get(nodeId);
// }
//
// /**
// * Method to set expanded status of specified NodeInst.
// * Expanded NodeInsts are instances of Cells that show their contents.
// * Unexpanded Cell instances are shown as boxes with the node prototype names in them.
// * The state has no meaning for instances of primitive node prototypes.
// * @param nodeId specified nodeId
// * @param value true if NodeInst is expanded.
// */
// public void setExpanded(int nodeId, boolean value) {
// NodeInst ni = getNodeById(nodeId);
// if (ni == null) {
// return;
// }
// NodeProto protoType = ni.getProto();
// if (!(protoType instanceof Cell) || ((Cell) protoType).isIcon()) {
// return;
// }
// boolean oldValue = expandedNodes.get(nodeId);
// if (oldValue == value) {
// return;
// }
// expandedNodes.set(nodeId, value);
// expandStatusModified = true;
// }
//
// /**
// * Method to set expand specified subcells.
// * Expanded NodeInsts are instances of Cells that show their contents.
// * @param subCells nodeIds of subCells to expand
// */
// void expand(BitSet subCells) {
// for (int nodeId = subCells.nextSetBit(0); nodeId >= 0; nodeId = subCells.nextSetBit(nodeId + 1)) {
// setExpanded(nodeId, true);
// }
// }
/**
* Update PortInsts of all instances of specified Cell accoding to pattern.
* Pattern contains an element for each Export.
* If Export was just created, the element contains -1.
* For old Exports the element contains old index of the Export.
* @param pattern array with elements describing new PortInsts.
*/
public void updatePortInsts(Cell proto, int[] pattern) {
for (NodeInst ni : nodes) {
if (ni.getProto() == proto) {
ni.updatePortInsts(pattern);
ni.check();
}
}
}
/**
* Method to return the PortInst by nodeId and PortProtoId.
* @param nodeId specified NodeId.
* @param portProtoId
* @return the PortInst at specified position..
*/
public PortInst getPortInst(int nodeId, PortProtoId portProtoId) {
NodeInst ni = chronNodes.get(nodeId);
assert ni.getD().protoId == portProtoId.getParentId();
NodeProto np = ni.getProto();
PortProto pp = np.getPort(portProtoId);
PortInst pi = ni.getPortInst(pp.getPortIndex());
assert pi.getNodeInst().getD().nodeId == nodeId;
assert pi.getPortProto().getId() == portProtoId;
return pi;
}
/**
* Method to find a named NodeInst on this Cell.
* @param name the name of the NodeInst.
* @return the NodeInst. Returns null if none with that name are found.
*/
public NodeInst findNode(String name) {
int nodeIndex = searchNode(name);
return nodeIndex >= 0 ? nodes.get(nodeIndex) : null;
}
/**
* Method to unlink a set of these NodeInsts from this Cell.
* @param killedNodes a set of NodeInsts to kill.
*/
public void killNodes(Set killedNodes) {
if (killedNodes.isEmpty()) {
return;
}
for (NodeInst ni : killedNodes) {
if (ni.getParent() != cell) {
throw new IllegalArgumentException("parent");
}
}
Set arcsToKill = new HashSet();
for (Iterator it = getArcs(); it.hasNext();) {
ArcInst ai = it.next();
if (killedNodes.contains(ai.getTailPortInst().getNodeInst()) || killedNodes.contains(ai.getHeadPortInst().getNodeInst())) {
arcsToKill.add(ai);
}
}
Set exportsToKill = new HashSet();
for (Iterator it = cell.getExports(); it.hasNext();) {
Export export = it.next();
if (killedNodes.contains(export.getOriginalPort().getNodeInst())) {
exportsToKill.add(export);
}
}
for (ArcInst ai : arcsToKill) {
ai.kill();
}
cell.killExports(exportsToKill);
for (NodeInst ni : killedNodes) {
if (!ni.isLinked()) {
continue;
}
// remove this node from the cell
removeNode(ni);
// handle change control, constraint, and broadcast
Constraints.getCurrent().killObject(ni);
}
}
public ImmutableNodeInst[] backupNodes(ImmutableArrayList oldNodes) {
ImmutableNodeInst[] newNodes = new ImmutableNodeInst[nodes.size()];
boolean changed = nodes.size() != oldNodes.size();
for (int i = 0; i < nodes.size(); i++) {
NodeInst ni = nodes.get(i);
ImmutableNodeInst d = ni.getD();
changed = changed || oldNodes.get(i) != d;
newNodes[i] = d;
}
return changed ? newNodes : null;
}
public boolean updateNodes(boolean full, CellRevision newRevision, BitSet exportsModified, BitSet expandedNodes) {
boolean expandStatusModified = false;
// Update NodeInsts
nodes.clear();
essenBounds.clear();
maxSuffix.clear();
// cellUsages = newRevision.getInstCounts();
for (int i = 0; i < newRevision.nodes.size(); i++) {
ImmutableNodeInst d = newRevision.nodes.get(i);
while (d.nodeId >= chronNodes.size()) {
chronNodes.add(null);
}
NodeInst ni = chronNodes.get(d.nodeId);
if (ni != null && ni.getProto().getId().isIcon() == d.protoId.isIcon()) {
NodeProto oldProto = ni.getProto();
ni.setDInUndo(d);
if (ni.getProto() != oldProto) {
ni.updatePortInsts(true);
} else if (ni.isCellInstance()) {
int subCellIndex = ((Cell) ni.getProto()).getCellIndex();
if (full || exportsModified != null && exportsModified.get(subCellIndex)) {
ni.updatePortInsts(full);
}
}
} else {
ni = NodeInst.lowLevelNewInstance(this, d);
chronNodes.set(d.nodeId, ni);
if (ni.isCellInstance()) {
Cell subCell = (Cell) ni.getProto();
boolean oldEx = expandedNodes.get(d.nodeId);
// Remember previous user'setup
expandedNodes.set(d.nodeId, oldEx || subCell.isWantExpanded());
expandStatusModified = true;
}
}
ni.setNodeIndex(i);
nodes.add(ni);
updateMaxSuffix(ni);
NodeProto np = ni.getProto();
if (np == Generic.tech().essentialBoundsNode) {
essenBounds.add(ni);
}
// ni.check();
}
assert nodes.size() == newRevision.nodes.size();
int nodeCount = 0;
for (int i = 0; i < chronNodes.size(); i++) {
NodeInst ni = chronNodes.get(i);
if (ni == null) {
continue;
}
int nodeIndex = ni.getNodeIndex();
if (nodeIndex >= nodes.size() || ni != nodes.get(nodeIndex)) {
ni.setNodeIndex(-1);
chronNodes.set(i, null);
continue;
}
nodeCount++;
}
assert nodeCount == nodes.size();
return expandStatusModified;
}
public void updateSubCells(BitSet exportsModified, BitSet boundsModified) {
unfreshRTree();
for (int i = 0; i < nodes.size(); i++) {
NodeInst ni = nodes.get(i);
if (!ni.isCellInstance()) {
continue;
}
int subCellIndex = ((Cell) ni.getProto()).getCellIndex();
if (exportsModified != null && exportsModified.get(subCellIndex)) {
ni.updatePortInsts(false);
}
if (boundsModified != null && boundsModified.get(subCellIndex)) {
ni.redoGeometric();
}
}
}
/**
* Method to add a new NodeInst to the cell.
* @param newNodes the NodeInsts to be included in the cell.
*/
public void addNodes(List newNodes) {
cell.checkChanging();
int oldI = nodes.size() - 1;
for (int i = 0; i < newNodes.size(); i++) {
nodes.add(null);
}
int newI = newNodes.size() - 1;
int outI = nodes.size() - 1;
while (oldI >= 0 && newI >= 0) {
int cmp = TextUtils.STRING_NUMBER_ORDER.compare(nodes.get(oldI).getName(), newNodes.get(newI).getName());
assert cmp != 0;
NodeInst ni = cmp > 0 ? nodes.get(oldI--) : newNodes.get(newI--);
ni.setNodeIndex(outI);
nodes.set(outI--, ni);
}
while (oldI >= 0) {
NodeInst ni = nodes.get(oldI--);
ni.setNodeIndex(outI);
nodes.set(outI--, ni);
}
while (newI >= 0) {
NodeInst ni = newNodes.get(newI--);
ni.setNodeIndex(outI);
nodes.set(outI--, ni);
}
assert oldI == -1 && newI == -1 && outI == -1;
for (int i = 1; i < nodes.size() - 1; i++) {
assert TextUtils.STRING_NUMBER_ORDER.compare(nodes.get(i - 1).getName(), nodes.get(i).getName()) < 0;
}
for (NodeInst ni : newNodes) {
int nodeId = ni.getD().nodeId;
while (chronNodes.size() <= nodeId) {
chronNodes.add(null);
}
assert chronNodes.get(nodeId) == null;
chronNodes.set(nodeId, ni);
updateMaxSuffix(ni);
// make additional checks to keep circuit up-to-date
if (ni.getProto() == Generic.tech().essentialBoundsNode) {
essenBounds.add(ni);
}
}
unfreshRTree();
}
/**
* Method to add a new NodeInst to the cell.
* @param ni the NodeInst to be included in the cell.
* @return true on failure
*/
public int addNode(NodeInst ni) {
cell.checkChanging();
addNodeName(ni);
int nodeId = ni.getD().nodeId;
while (chronNodes.size() <= nodeId) {
chronNodes.add(null);
}
assert chronNodes.get(nodeId) == null;
chronNodes.set(nodeId, ni);
// make additional checks to keep circuit up-to-date
if (ni.getProto() == Generic.tech().essentialBoundsNode) {
essenBounds.add(ni);
}
unfreshRTree();
return nodeId;
}
/**
* Method to add a new NodeInst to the name index of this cell.
* @param ni the NodeInst to be included tp the name index in the cell.
*/
void addNodeName(NodeInst ni) {
// Gilda's test
// int nodeIndex = nodes.size();
// nodes.add(ni);
// ni.setNodeIndex(nodeIndex);
int nodeIndex = searchNode(ni.getName());
assert nodeIndex < 0;
nodeIndex = -nodeIndex - 1;
nodes.add(nodeIndex, ni);
for (; nodeIndex < nodes.size(); nodeIndex++) {
NodeInst n = nodes.get(nodeIndex);
n.setNodeIndex(nodeIndex);
}
updateMaxSuffix(ni);
}
/**
* add temp name of NodeInst to maxSuffix map.
* @param ni NodeInst.
*/
private void updateMaxSuffix(NodeInst ni) {
Name name = ni.getNameKey();
if (!name.isTempname()) {
return;
}
Name basename = name.getBasename();
String basenameString = basename.toString();
// String basenameString = basename.canonicString();
MaxSuffix ms = maxSuffix.get(basenameString);
if (ms == null) {
ms = new MaxSuffix();
maxSuffix.put(basenameString, ms);
}
int numSuffix = name.getNumSuffix();
if (numSuffix > ms.v) {
ms.v = numSuffix;
}
}
/**
* Method to return unique autoname for NodeInst in this cell.
* @param basename base name of autoname
* @return autoname
*/
Name getNodeAutoname(Name basename) {
String basenameString = basename.toString();
// String basenameString = basename.canonicString();
MaxSuffix ms = maxSuffix.get(basenameString);
Name name;
if (ms == null) {
ms = new MaxSuffix();
maxSuffix.put(basenameString, ms);
name = basename.findSuffixed(0);
} else {
ms.v++;
name = basename.findSuffixed(ms.v);
}
assert searchNode(name.toString()) < 0;
return name;
}
/**
* Method to remove an NodeInst from the cell.
* @param ni the NodeInst to be removed from the cell.
*/
public void removeNode(NodeInst ni) {
assert ni.topology == this;
// cell.checkChanging();
// assert ni.isLinked();
essenBounds.remove(ni);
// // remove usage count
// if (ni.isCellInstance()) {
// Cell subCell = (Cell) ni.getProto();
// CellUsage u = cell.getId().getUsageIn(subCell.getId());
// cellUsages[u.indexInParent]--;
// if (cellUsages[u.indexInParent] <= 0) {
// assert cellUsages[u.indexInParent] == 0;
// // remove library dependency, if possible
// cell.getLibrary().removeReferencedLib(((Cell) ni.getProto()).getLibrary());
// }
// }
// cell.setContentsModified();
removeNodeName(ni);
int nodeId = ni.getD().nodeId;
assert chronNodes.get(nodeId) == ni;
chronNodes.set(nodeId, null);
// setDirty();
unfreshRTree();
}
/**
* Method to remove an NodeInst from the name index of this cell.
* @param ni the NodeInst to be removed from the cell.
*/
void removeNodeName(NodeInst ni) {
int nodeIndex = ni.getNodeIndex();
NodeInst removedNi = nodes.remove(nodeIndex);
assert removedNi == ni;
for (int i = nodeIndex; i < nodes.size(); i++) {
NodeInst n = nodes.get(i);
n.setNodeIndex(i);
}
ni.setNodeIndex(-1);
}
/**
* Searches the nodes for the specified name using the binary
* search algorithm.
* @param name the name to be searched.
* @return index of the search name, if it is contained in the nodes;
* otherwise, (-(insertion point) - 1). The
* insertion point is defined as the point at which the
* NodeInst would be inserted into the list: the index of the first
* element greater than the name, or nodes.size(), if all
* elements in the list are less than the specified name. Note
* that this guarantees that the return value will be >= 0 if
* and only if the NodeInst is found.
*/
private int searchNode(String name) {
int low = 0;
int high = nodes.size() - 1;
int pick = high; // initially try the last postition
while (low <= high) {
NodeInst ni = nodes.get(pick);
int cmp = TextUtils.STRING_NUMBER_ORDER.compare(ni.getName(), name);
if (cmp < 0) {
low = pick + 1;
} else if (cmp > 0) {
high = pick - 1;
} else {
return pick; // NodeInst found
}
pick = (low + high) >> 1; // try in a middle
}
return -(low + 1); // NodeInst not found.
}
/**
* Method to compute the "essential bounds" of this Cell.
* It looks for NodeInst objects in the cell that are of the type
* "generic:Essential-Bounds" and builds a rectangle from their locations.
* @return the bounding area of the essential bounds.
* Returns null if an essential bounds cannot be determined.
*/
public Rectangle2D findEssentialBounds() {
if (essenBounds.size() < 2) {
return null;
}
double minX = Double.MAX_VALUE;
double maxX = -Double.MAX_VALUE;
double minY = Double.MAX_VALUE;
double maxY = -Double.MAX_VALUE;
for (int i = 0; i < essenBounds.size(); i++) {
NodeInst ni = essenBounds.get(i);
minX = Math.min(minX, ni.getTrueCenterX());
maxX = Math.max(maxX, ni.getTrueCenterX());
minY = Math.min(minY, ni.getTrueCenterY());
maxY = Math.max(maxY, ni.getTrueCenterY());
}
return new Rectangle2D.Double(minX, minY, maxX - minX, maxY - minY);
}
/****************************** ARCS ******************************/
/**
* Method to return an Iterator over all ArcInst objects in this Cell.
* @return an Iterator over all ArcInst objects in this Cell.
*/
public synchronized Iterator getArcs() {
ArrayList arcsCopy = new ArrayList(arcs);
return arcsCopy.iterator();
}
/**
* Method to return the number of ArcInst objects in this Cell.
* @return the number of ArcInst objects in this Cell.
*/
public int getNumArcs() {
return arcs.size();
}
/**
* Method to return the ArcInst at specified position.
* @param arcIndex specified position of ArcInst.
* @return the ArcInst at specified position..
*/
public final ArcInst getArc(int arcIndex) {
return arcs.get(arcIndex);
}
/**
* Method to return the ArcInst by its chronological index.
* @param arcId chronological index of ArcInst.
* @return the ArcInst with specified chronological index.
*/
public ArcInst getArcById(int arcId) {
return arcId < chronArcs.size() ? chronArcs.get(arcId) : null;
}
/**
* Method to find a named ArcInst on this Cell.
* @param name the name of the ArcInst.
* @return the ArcInst. Returns null if none with that name are found.
*/
public ArcInst findArc(String name) {
int arcIndex = searchArc(name, 0);
if (arcIndex >= 0) {
return arcs.get(arcIndex);
}
arcIndex = -arcIndex - 1;
if (arcIndex < arcs.size()) {
ArcInst ai = arcs.get(arcIndex);
if (ai.getName().equals(name)) {
return ai;
}
}
return null;
}
/**
* Method to add a new ArcInst to the cell.
* @param ai the ArcInst to be included in the cell.
*/
void addArc(ArcInst ai) {
cell.setTopologyModified();
validArcBounds = false;
unfreshRTree();
int arcIndex = searchArc(ai);
assert arcIndex < 0;
arcIndex = -arcIndex - 1;
arcs.add(arcIndex, ai);
// //scanline
// ai.setArcIndex( arcIndex );
// for ( int i = arcIndex + 1; i < arcs.size(); i++ ){
// ArcInst a = arcs.get(i);
// a.setArcIndex(i);
// }
int arcId = ai.getArcId();
while (chronArcs.size() <= arcId) {
chronArcs.add(null);
}
assert chronArcs.get(arcId) == null;
chronArcs.set(arcId, ai);
// update maximal arc name suffux temporary name
if (ai.isUsernamed()) {
return;
}
Name name = ai.getNameKey();
assert name.getBasename() == ImmutableArcInst.BASENAME;
maxArcSuffix = Math.max(maxArcSuffix, name.getNumSuffix());
// cell.setDirty();
}
/**
* Method to return unique autoname for ArcInst in this cell.
* @return a unique autoname for ArcInst in this cell.
*/
Name getArcAutoname() {
if (maxArcSuffix < Integer.MAX_VALUE) {
return ImmutableArcInst.BASENAME.findSuffixed(++maxArcSuffix);
}
for (int i = 0;; i++) {
Name name = ImmutableArcInst.BASENAME.findSuffixed(i);
if (!hasTempArcName(name)) {
return name;
}
}
}
/**
* Method check if ArcInst with specified temporary name key exists in a cell.
* @param name specified temorary name key.
*/
boolean hasTempArcName(Name name) {
return name.isTempname() && findArc(name.toString()) != null;
}
/**
* Method to remove an ArcInst from the cell.
* @param ai the ArcInst to be removed from the cell.
*/
void removeArc(ArcInst ai) {
cell.checkChanging();
cell.setTopologyModified();
unfreshRTree();
assert ai.isLinked();
int arcIndex = searchArc(ai);
ArcInst removedAi = arcs.remove(arcIndex);
assert removedAi == ai;
// //scanline
// for ( int i = arcIndex; i < arcs.size(); i++ ){
// ArcInst a = arcs.get(i);
// a.setArcIndex(i);
// }
// removedAi.setArcIndex( -1 );
int arcId = ai.getArcId();
assert chronArcs.get(arcId) == ai;
chronArcs.set(arcId, null);
// cell.setDirty();
}
public ImmutableArcInst[] backupArcs(ImmutableArrayList oldArcs) {
ImmutableArcInst[] newArcs = new ImmutableArcInst[arcs.size()];
boolean changed = arcs.size() != oldArcs.size();
for (int i = 0; i < arcs.size(); i++) {
ArcInst ai = arcs.get(i);
ImmutableArcInst d = ai.getD();
changed = changed || oldArcs.get(i) != d;
newArcs[i] = d;
}
return changed ? newArcs : null;
}
public void updateArcs(CellRevision newRevision) {
validArcBounds = false;
arcs.clear();
maxArcSuffix = -1;
for (int i = 0; i < newRevision.arcs.size(); i++) {
ImmutableArcInst d = newRevision.arcs.get(i);
while (d.arcId >= chronArcs.size()) {
chronArcs.add(null);
}
ArcInst ai = chronArcs.get(d.arcId);
PortInst headPi = getPortInst(d.headNodeId, d.headPortId);
PortInst tailPi = getPortInst(d.tailNodeId, d.tailPortId);
if (ai != null && (/*!full ||*/ai.getHeadPortInst() == headPi && ai.getTailPortInst() == tailPi)) {
ai.setDInUndo(d);
} else {
ai = new ArcInst(this, d, headPi, tailPi);
chronArcs.set(d.arcId, ai);
}
arcs.add(ai);
// ai.setArcIndex( arcs.size() - 1 ); //scanline
if (!ai.isUsernamed()) {
Name name = ai.getNameKey();
assert name.getBasename() == ImmutableArcInst.BASENAME;
maxArcSuffix = Math.max(maxArcSuffix, name.getNumSuffix());
}
}
int arcCount = 0;
for (int i = 0; i < chronArcs.size(); i++) {
ArcInst ai = chronArcs.get(i);
if (ai == null) {
continue;
}
int arcIndex = searchArc(ai);
if (arcIndex < 0 || arcIndex >= arcs.size() || ai != arcs.get(arcIndex)) {
chronArcs.set(i, null);
continue;
}
arcCount++;
}
assert arcCount == arcs.size();
}
/**
* Low-level routine.
*/
void computeArcBounds() {
long[] gridCoords = new long[4];
BoundsBuilder b = new BoundsBuilder(cell.getTechPool());
for (int arcIndex = 0; arcIndex < arcs.size(); arcIndex++) {
ArcInst ai = arcs.get(arcIndex);
ai.computeBounds(b, gridCoords);
}
validArcBounds = true;
}
private int searchArc(ArcInst ai) {
return searchArc(ai.getName(), ai.getArcId());
}
/**
* Searches the arcs for the specified (name,arcId) using the binary
* search algorithm.
* @param name the name to be searched.
* @param arcId the arcId index to be searched.
* @return index of the search name, if it is contained in the arcs;
* otherwise, (-(insertion point) - 1). The
* insertion point is defined as the point at which the
* ArcInst would be inserted into the list: the index of the first
* element greater than the name, or arcs.size(), if all
* elements in the list are less than the specified name. Note
* that this guarantees that the return value will be >= 0 if
* and only if the ArcInst is found.
*/
private int searchArc(String name, int arcId) {
int low = 0;
int high = arcs.size() - 1;
int pick = high; // initially try the last postition
while (low <= high) {
ArcInst ai = arcs.get(pick);
int cmp = TextUtils.STRING_NUMBER_ORDER.compare(ai.getName(), name);
if (cmp == 0) {
cmp = ai.getArcId() - arcId;
}
if (cmp < 0) {
low = pick + 1;
} else if (cmp > 0) {
high = pick - 1;
} else {
return pick; // ArcInst found
}
pick = (low + high) >> 1; // try in a middle
}
return -(low + 1); // ArcInst not found.
}
// void setArcsModified() {
// cell.checkChanging();
// cell.setTopologyModified();
// }
/****************************** GRAPHICS ******************************/
/**
* Method to return an interator over all RTBounds objects in a given area of this Cell that allows
* to ignore elements touching the area.
* Note that Geometric objects implement RTBounds, so for database searches, the iterator
* returns Geometrics (NodeInsts and ArcInsts).
* @param bounds the specified area to search.
* @param includeEdges true if RTBounds objects along edges are considered in.
* @return an iterator over all of the RTBounds objects in that area.
*/
public Iterator searchIterator(Rectangle2D bounds, boolean includeEdges) {
return new RTNode.Search(bounds, getRTree(), includeEdges);
}
void setArcsDirty() {
cell.setTopologyModified();
// cell.setDirty();
validArcBounds = false;
unfreshRTree();
}
public void unfreshRTree() {
rTreeFresh = false;
}
/**
* Method to R-Tree of this Cell.
* The R-Tree organizes all of the Geometric objects spatially for quick search.
* @return R-Tree of this Cell.
*/
private RTNode getRTree() {
if (rTreeFresh) {
return rTree;
}
rebuildRTree();
rTreeFresh = true;
return rTree;
}
private void rebuildRTree() {
// long startTime = System.currentTimeMillis();
if (!validArcBounds) {
computeArcBounds();
}
CellId cellId = cell.getId();
RTNode root = RTNode.makeTopLevel();
for (Iterator it = cell.getNodes(); it.hasNext();) {
NodeInst ni = it.next();
root = RTNode.linkGeom(cellId, root, ni);
}
for (Iterator it = cell.getArcs(); it.hasNext();) {
ArcInst ai = it.next();
root = RTNode.linkGeom(cellId, root, ai);
}
root.checkRTree(0, cellId);
rTree = root;
rTreeFresh = true;
// long stopTime = System.currentTimeMillis();
// if (Job.getDebug()) System.out.println("Rebuilding R-Tree in " + this + " took " + (stopTime - startTime) + " msec");
}
/**
* Method to check invariants in this Cell.
* @exception AssertionError if invariants are not valid
*/
public void check(int[] cellUsages) {
// check arcs
ArcInst prevAi = null;
BoundsBuilder b = new BoundsBuilder(cell.getTechPool());
// Poly.Builder b = Poly.newGridBuilder();
for (int arcIndex = 0; arcIndex < arcs.size(); arcIndex++) {
ArcInst ai = arcs.get(arcIndex);
// assert ai.getArcIndex() == arcIndex; // scanline
ImmutableArcInst a = ai.getD();
assert ai.getParent() == cell;
assert chronArcs.get(a.arcId) == ai;
if (prevAi != null) {
int cmp = TextUtils.STRING_NUMBER_ORDER.compare(prevAi.getName(), ai.getName());
assert cmp <= 0;
if (cmp == 0) {
assert prevAi.getArcId() < a.arcId;
}
}
assert ai.getHeadPortInst() == cell.getPortInst(a.headNodeId, a.headPortId);
assert ai.getTailPortInst() == cell.getPortInst(a.tailNodeId, a.tailPortId);
if (validArcBounds) {
ai.check(b);
}
prevAi = ai;
}
for (int arcId = 0; arcId < chronArcs.size(); arcId++) {
ArcInst ai = chronArcs.get(arcId);
if (ai == null) {
continue;
}
assert ai.getArcId() == arcId;
int arcIndex = searchArc(ai);
assert ai == arcs.get(arcIndex);
}
// check nodes
NodeInst prevNi = null;
EDatabase database = cell.getDatabase();
CellId cellId = cell.getId();
int[] usages = new int[cellId.numUsagesIn()];
for (int nodeIndex = 0; nodeIndex < nodes.size(); nodeIndex++) {
NodeInst ni = nodes.get(nodeIndex);
ImmutableNodeInst n = ni.getD();
assert ni.getParent() == cell;
assert ni.getNodeIndex() == nodeIndex;
assert chronNodes.get(n.nodeId) == ni;
if (prevNi != null) {
assert TextUtils.STRING_NUMBER_ORDER.compare(prevNi.getName(), ni.getName()) < 0;
}
if (ni.isCellInstance()) {
Cell subCell = (Cell) ni.getProto();
assert subCell.isLinked();
assert subCell.getDatabase() == database;
CellUsage u = cellId.getUsageIn(subCell.getId());
usages[u.indexInParent]++;
}
ni.check();
prevNi = ni;
}
for (int nodeId = 0; nodeId < chronNodes.size(); nodeId++) {
NodeInst ni = chronNodes.get(nodeId);
if (ni == null) {
continue;
}
assert ni.getD().nodeId == nodeId;
assert ni == nodes.get(ni.getNodeIndex());
}
// check node usages
for (int i = 0; i < cellUsages.length; i++) {
assert cellUsages[i] == usages[i];
}
for (int i = cellUsages.length; i < usages.length; i++) {
assert usages[i] == 0;
}
if (rTreeFresh) {
rTree.checkRTree(0, cell.getId());
}
}
}