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: CellBackup.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.IdManager;
import com.sun.electric.database.id.IdReader;
import com.sun.electric.database.id.IdWriter;
import com.sun.electric.database.id.NodeProtoId;
import com.sun.electric.database.id.PortProtoId;
import com.sun.electric.database.id.PrimitiveNodeId;
import com.sun.electric.database.text.CellName;
import com.sun.electric.database.variable.TextDescriptor;
import com.sun.electric.database.variable.Variable;
import com.sun.electric.technology.AbstractShapeBuilder;
import com.sun.electric.technology.ArcProto;
import com.sun.electric.technology.BoundsBuilder;
import com.sun.electric.technology.PrimitiveNode;
import com.sun.electric.technology.TechPool;
import com.sun.electric.technology.Technology;
import com.sun.electric.technology.technologies.Generic;
import com.sun.electric.util.collections.ArrayIterator;
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.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
/**
* CellBackup is a pair of CellRevision and TechPool.
* It caches data that can be calculated when Technology is already
* known, but subcells are unknown.
*/
public class CellBackup {
private static final int BIN_SORT_THRESHOLD = 32;
public static final CellBackup[] NULL_ARRAY = {};
public static final ImmutableArrayList EMPTY_LIST = new ImmutableArrayList(NULL_ARRAY);
static int cellBackupsCreated = 0;
static int cellBackupsMemoized = 0;
/** Cell data. */
public final CellRevision cellRevision;
/** Technologies mapping */
public final TechPool techPool;
/** "Modified" flag of the Cell. */
public final boolean modified;
/** Memoized data for size computation (connectivity etc). */
private volatile Memoization m;
/** Arc shrinkage data */
private AbstractShapeBuilder.Shrinkage shrinkage;
/** Bounds of primitive arcs in this Cell. */
private ERectangle primitiveBounds;
/** Creates a new instance of CellBackup */
private CellBackup(CellRevision cellRevision, TechPool techPool, boolean modified) {
this.cellRevision = cellRevision;
this.techPool = techPool;
this.modified = modified;
cellBackupsCreated++;
}
/** Creates a new instance of CellBackup */
public static CellBackup newInstance(ImmutableCell d, TechPool techPool) {
if (d.cellId.idManager != techPool.idManager) {
throw new IllegalArgumentException();
}
if (techPool.getTech(d.techId) == null) {
throw new IllegalArgumentException();
}
CellRevision cellRevision = new CellRevision(d);
TechPool restrictedPool = techPool.restrict(cellRevision.techUsages, techPool);
return new CellBackup(cellRevision, restrictedPool, true);
}
/**
* Creates a new instance of CellBackup which differs from this CellBackup.
* Four array parameters are supplied. Each parameter may be null if its contents is the same as in this Snapshot.
* @param d new persistent data of a cell.
* @param nodesArray new array of nodes
* @param arcsArray new array of arcs
* @param exportsArray new array of exports
* @param superPool TechPool which defines all used technologies
* @return new snapshot which differs froms this Snapshot or this Snapshot.
* @throws IllegalArgumentException on invariant violation.
* @throws ArrayOutOfBoundsException on some invariant violations.
*/
public CellBackup with(ImmutableCell d,
ImmutableNodeInst[] nodesArray, ImmutableArcInst[] arcsArray, ImmutableExport[] exportsArray,
TechPool superPool) {
CellRevision newRevision = cellRevision.with(d, nodesArray, arcsArray, exportsArray);
TechPool restrictedPool = superPool.restrict(newRevision.techUsages, techPool);
if (newRevision == cellRevision && restrictedPool == techPool) {
return this;
}
if (arcsArray != null) {
for (ImmutableArcInst a : arcsArray) {
if (a != null && !a.check(restrictedPool)) {
throw new IllegalArgumentException("arc " + a.name + " is not compatible with TechPool");
}
}
}
return new CellBackup(newRevision, restrictedPool, modified || newRevision != cellRevision);
}
/**
* Creates a new instance of CellBackup which differs from this CellBackup by revision date.
* @param revisionDate new revision date.
* @return new CellBackup which differs from this CellBackup by revision date.
*/
public CellBackup withRevisionDate(long revisionDate) {
CellRevision newRevision = cellRevision.withRevisionDate(revisionDate);
if (newRevision == cellRevision) {
return this;
}
return new CellBackup(newRevision, this.techPool, true);
}
/**
* Creates a new instance of CellBackup with modified flag off.
* @return new snapshot which differs froms this Snapshot or this Snapshot.
*/
public CellBackup withoutModified() {
if (!this.modified) {
return this;
}
return new CellBackup(this.cellRevision, this.techPool, false);
}
/**
* Returns CellBackup which differs from this CellBackup by TechPool.
* @param techPool technology map.
* @return CellBackup with new TechPool.
*/
public CellBackup withTechPool(TechPool techPool) {
TechPool restrictedPool = techPool.restrict(cellRevision.techUsages, this.techPool);
if (this.techPool == restrictedPool) {
return this;
}
if (techPool.idManager != this.techPool.idManager) {
throw new IllegalArgumentException();
}
// for (Technology tech: this.techPool.values()) {
// if (techPool.get(tech.getId()) != tech)
// throw new IllegalArgumentException();
// }
return new CellBackup(this.cellRevision, restrictedPool, this.modified);
}
/**
* Returns CellBackup which differs from this CellBackup by renamed Ids.
* @param idMapper a map from old Ids to new Ids.
* @return CellBackup with renamed Ids.
*/
CellBackup withRenamedIds(IdMapper idMapper, CellName newGroupName) {
CellRevision newRevision = cellRevision.withRenamedIds(idMapper, newGroupName);
if (newRevision == cellRevision) {
return this;
}
return new CellBackup(newRevision, this.techPool, true);
}
/**
* Writes this CellBackup to IdWriter.
* @param writer where to write.
*/
void write(IdWriter writer) throws IOException {
cellRevision.write(writer);
writer.writeBoolean(modified);
}
/**
* Reads CellBackup from SnapshotReader.
* @param reader where to read.
*/
static CellBackup read(IdReader reader, TechPool techPool) throws IOException {
CellRevision newRevision = CellRevision.read(reader);
boolean modified = reader.readBoolean();
TechPool restrictedPool = techPool.restrict(newRevision.techUsages, techPool);
return new CellBackup(newRevision, restrictedPool, modified);
}
/**
* Checks invariant of this CellBackup.
* @throws AssertionError if invariant is broken.
*/
public void check() {
cellRevision.check();
IdManager idManager = cellRevision.d.cellId.idManager;
assert techPool.idManager == idManager;
BitSet techUsages = new BitSet();
for (Technology tech : techPool.values()) {
int techIndex = tech.getId().techIndex;
assert !techUsages.get(techIndex);
techUsages.set(techIndex);
}
assert techUsages.equals(cellRevision.techUsages);
// for (int techIndex = 0; techIndex < cellRevision.techUsages.length(); techIndex++) {
// if (cellRevision.techUsages.get(techIndex))
// assert techPool.getTech(idManager.getTechId(techIndex)) != null;
// }
for (ImmutableArcInst a : cellRevision.arcs) {
if (a != null) {
a.check(techPool);
}
}
if (m != null) {
m.check();
}
}
@Override
public String toString() {
return cellRevision.toString();
}
/**
* Returns data for size computation (connectivity etc).
* @return data for size computation.
*/
public Memoization getMemoization() {
Memoization m = this.m;
if (m != null) {
return m;
}
return this.m = new Memoization();
}
public Memoization computeMemoization() {
return new Memoization();
}
/**
* Returns data for arc shrinkage computation.
* @return data for arc shrinkage computation.
*/
public AbstractShapeBuilder.Shrinkage getShrinkage() {
if (shrinkage == null) {
shrinkage = new AbstractShapeBuilder.Shrinkage(this);
}
return shrinkage;
}
/**
* Returns bounds of all primitive arcs in this Cell or null if there are not primitives.
* @return bounds of all primitive arcs or null.
*/
public ERectangle getPrimitiveBounds() {
ERectangle primitiveBounds = this.primitiveBounds;
if (primitiveBounds != null) {
return primitiveBounds;
}
return this.primitiveBounds = computePrimitiveBounds();
}
public ERectangle computePrimitiveBounds() {
ERectangle primitiveArcBounds = computePrimitiveBoundsOfArcs();
long gridMinX = Long.MAX_VALUE, gridMinY = Long.MAX_VALUE, gridMaxX = Long.MIN_VALUE, gridMaxY = Long.MIN_VALUE;
long[] gridCoords = new long[4];
for (ImmutableNodeInst n : cellRevision.nodes) {
if (!(n.protoId instanceof PrimitiveNodeId)) {
continue;
}
PrimitiveNode pn = techPool.getPrimitiveNode((PrimitiveNodeId) n.protoId);
// special case: do not include "cell center" primitives from Generic
if (pn == Generic.tech().cellCenterNode) {
continue;
}
// special case for invisible pins: do not include if inheritable or interior-only
if (pn == Generic.tech().invisiblePinNode) {
boolean found = false;
for (Iterator it = n.getVariables(); it.hasNext();) {
Variable var = it.next();
if (var.isDisplay()) {
TextDescriptor td = var.getTextDescriptor();
if (td.isInterior() || td.isInherit()) {
found = true;
break;
}
}
}
if (found) {
continue;
}
}
pn.genBounds(n, gridCoords);
gridMinX = Math.min(gridMinX, gridCoords[0]);
gridMinY = Math.min(gridMinY, gridCoords[1]);
gridMaxX = Math.max(gridMaxX, gridCoords[2]);
gridMaxY = Math.max(gridMaxY, gridCoords[3]);
}
if (gridMinX > gridMaxX || gridMinY > gridMaxY) {
return primitiveArcBounds;
}
if (primitiveArcBounds != null) {
gridMinX = Math.min(gridMinX, primitiveArcBounds.getGridMinX());
gridMaxX = Math.max(gridMaxX, primitiveArcBounds.getGridMaxX());
gridMinY = Math.min(gridMinY, primitiveArcBounds.getGridMinY());
gridMaxY = Math.max(gridMaxY, primitiveArcBounds.getGridMaxY());
}
return ERectangle.fromGrid(gridMinX, gridMinY, gridMaxX - gridMinX, gridMaxY - gridMinY);
}
ERectangle getElibPrimitiveBounds() {
ERectangle primitiveArcBounds = computePrimitiveBoundsOfArcs();
long gridMinX = Long.MAX_VALUE, gridMinY = Long.MAX_VALUE, gridMaxX = Long.MIN_VALUE, gridMaxY = Long.MIN_VALUE;
long[] gridCoords = new long[4];
for (ImmutableNodeInst n : cellRevision.nodes) {
if (!(n.protoId instanceof PrimitiveNodeId)) {
continue;
}
PrimitiveNode pn = techPool.getPrimitiveNode((PrimitiveNodeId) n.protoId);
// special case: do not include "cell center" primitives from Generic
if (pn == Generic.tech().cellCenterNode) {
continue;
}
// special case for invisible pins: do not include if inheritable or interior-only
if (pn == Generic.tech().invisiblePinNode) {
boolean found = false;
for (Iterator it = n.getVariables(); it.hasNext();) {
Variable var = it.next();
if (var.isDisplay()) {
TextDescriptor td = var.getTextDescriptor();
if (td.isInterior() || td.isInherit()) {
found = true;
break;
}
}
}
if (found) {
continue;
}
}
pn.genElibBounds(getMemoization(), n, gridCoords);
gridMinX = Math.min(gridMinX, gridCoords[0]);
gridMinY = Math.min(gridMinY, gridCoords[1]);
gridMaxX = Math.max(gridMaxX, gridCoords[2]);
gridMaxY = Math.max(gridMaxY, gridCoords[3]);
}
if (gridMinX > gridMaxX || gridMinY > gridMaxY) {
return primitiveArcBounds;
}
if (primitiveArcBounds != null) {
gridMinX = Math.min(gridMinX, primitiveArcBounds.getGridMinX());
gridMaxX = Math.max(gridMaxX, primitiveArcBounds.getGridMaxX());
gridMinY = Math.min(gridMinY, primitiveArcBounds.getGridMinY());
gridMaxY = Math.max(gridMaxY, primitiveArcBounds.getGridMaxY());
}
return ERectangle.fromGrid(gridMinX, gridMinY, gridMaxX - gridMinX, gridMaxY - gridMinY);
}
private ERectangle computePrimitiveBoundsOfArcs() {
ImmutableArrayList arcs = cellRevision.arcs;
if (arcs.isEmpty()) {
return null;
}
long gridMinX = Long.MAX_VALUE, gridMinY = Long.MAX_VALUE, gridMaxX = Long.MIN_VALUE, gridMaxY = Long.MIN_VALUE;
long[] gridCoords = new long[4];
BoundsBuilder boundsBuilder = new BoundsBuilder(techPool);
for (ImmutableArcInst a : arcs) {
if (boundsBuilder.genBoundsEasy(a, gridCoords)) {
gridMinX = Math.min(gridMinX, gridCoords[0]);
gridMinY = Math.min(gridMinY, gridCoords[1]);
gridMaxX = Math.max(gridMaxX, gridCoords[2]);
gridMaxY = Math.max(gridMaxY, gridCoords[3]);
continue;
}
boundsBuilder.genShapeOfArc(a);
}
ERectangle bounds = boundsBuilder.makeBounds();
if (bounds != null) {
gridMinX = Math.min(gridMinX, bounds.getGridMinX());
gridMinY = Math.min(gridMinY, bounds.getGridMinY());
gridMaxX = Math.max(gridMaxX, bounds.getGridMaxX());
gridMaxY = Math.max(gridMaxY, bounds.getGridMaxY());
}
assert gridMinX <= gridMaxX && gridMinY <= gridMaxY;
long gridW = gridMaxX - gridMinX;
long gridH = gridMaxY - gridMinY;
return ERectangle.fromGrid(gridMinX, gridMinY, gridW, gridH);
}
/**
* Class which memoizes data for size computation (connectivity etc).
*/
public class Memoization {
// /**
// * Base of a segment in portCounts array for valid nodeIds
// */
// private int[] portBasesForNodes;
// /**
// * Array which has an entry for every port instance.
// * The index for port instance (nodeInd, portProtoId) is
// * portBasesForNodes[nodeId] + portProtoId.chronIndex
// */
// private int[] portCounts;
private final int[] connections;
/** ImmutableExports sorted by original PortInst. */
private final ImmutableExport[] exportIndexByOriginalPort;
private final BitSet wiped = new BitSet();
private final BitSet hardArcs = new BitSet();
Memoization() {
// long startTime = System.currentTimeMillis();
cellBackupsMemoized++;
connections = makeConnections1();
exportIndexByOriginalPort = makeExportIndexByOriginalPort1();
// if (USE_COUNTS_FOR_CONNECTIONS || USE_COUNTS_FOR_EXPORTS) {
// initPortCounts();
// }
// connections = USE_COUNTS_FOR_CONNECTIONS ? makeConnections2() : makeConnections1();
// exportIndexByOriginalPort = USE_COUNTS_FOR_EXPORTS ? makeExportIndexByOriginalPort2() : makeExportIndexByOriginalPort1();
// portBasesForNodes = null;
// portCounts = null;
for (ImmutableArcInst a : cellRevision.arcs) {
ArcProto ap = techPool.getArcProto(a.protoId);
// wipe status
if (ap.isWipable()) {
wiped.set(a.tailNodeId);
wiped.set(a.headNodeId);
}
// hard arcs
if (!ap.isEasyShape(a, false)) {
hardArcs.set(a.arcId);
}
}
ImmutableArrayList nodes = cellRevision.nodes;
for (int nodeIndex = 0; nodeIndex < nodes.size(); nodeIndex++) {
ImmutableNodeInst n = nodes.get(nodeIndex);
NodeProtoId np = n.protoId;
if (!(np instanceof PrimitiveNodeId && techPool.getPrimitiveNode((PrimitiveNodeId) np).isArcsWipe())) {
wiped.clear(n.nodeId);
}
}
// long stopTime = System.currentTimeMillis();
// System.out.println("Memoization " + cellRevision.d.cellId + " took " + (stopTime - startTime) + " msec");
check();
}
/**
* Compute connections using sortConnections
* @return connections
*/
private int[] makeConnections1() {
ImmutableArrayList arcs = cellRevision.arcs;
// Put connections into buckets by nodeId.
int[] connections = new int[arcs.size() * 2];
int[] connectionsByNodeId = new int[cellRevision.nodeIndex.length];
for (ImmutableArcInst a : arcs) {
connectionsByNodeId[a.headNodeId]++;
connectionsByNodeId[a.tailNodeId]++;
}
int sum = 0;
for (int nodeId = 0; nodeId < connectionsByNodeId.length; nodeId++) {
int start = sum;
sum += connectionsByNodeId[nodeId];
connectionsByNodeId[nodeId] = start;
}
for (int i = 0; i < arcs.size(); i++) {
ImmutableArcInst a = arcs.get(i);
connections[connectionsByNodeId[a.tailNodeId]++] = i * 2;
connections[connectionsByNodeId[a.headNodeId]++] = i * 2 + 1;
}
// Sort each bucket by portId.
sum = 0;
for (int nodeId = 0; nodeId < connectionsByNodeId.length; nodeId++) {
int start = sum;
sum = connectionsByNodeId[nodeId];
if (sum - 1 > start) {
sortConnections(connections, start, sum - 1);
}
}
return connections;
}
/**
* Compute exportIndexByOriginalPort using Arrays.sort
* @return exportIndexByOriginalPort
*/
private ImmutableExport[] makeExportIndexByOriginalPort1() {
ImmutableExport[] exportIndexByOriginalPort = cellRevision.exports.toArray(new ImmutableExport[cellRevision.exports.size()]);
Arrays.sort(exportIndexByOriginalPort, BY_ORIGINAL_PORT);
return exportIndexByOriginalPort;
}
// /**
// * Compute connections using portBasesForNodes and portCounts
// * @return connections
// */
// private int[] makeConnections2() {
// ImmutableArrayList arcs = cellRevision.arcs;
//
// clearPortCounts();
// for (int arcIndex = 0; arcIndex < arcs.size(); arcIndex++) {
// ImmutableArcInst a = arcs.get(arcIndex);
// incrementPortCount(a.tailNodeId, a.tailPortId);
// incrementPortCount(a.headNodeId, a.headPortId);
// }
// portCountsToPortOffsets();
// int[] connections = new int[arcs.size() * 2];
// Arrays.fill(connections, -1);
// for (int arcIndex = 0; arcIndex < arcs.size(); arcIndex++) {
// ImmutableArcInst a = arcs.get(arcIndex);
// connections[incrementPortCount(a.tailNodeId, a.tailPortId)] = arcIndex << 1;
// connections[incrementPortCount(a.headNodeId, a.headPortId)] = (arcIndex << 1) | 1;
// }
// return connections;
// }
//
// /**
// * Compute exportIndexByOriginalPort using portBasesForNodes and portCounts
// * @return exportIndexByOriginalPort
// */
// private ImmutableExport[] makeExportIndexByOriginalPort2() {
// clearPortCounts();
// for (ImmutableExport e: cellRevision.exports) {
// incrementPortCount(e.originalNodeId, e.originalPortId);
// }
// portCountsToPortOffsets();
// ImmutableExport[] exportIndexByOriginalPort = new ImmutableExport[cellRevision.exports.size()];
// for (int exportId = 0; exportId < cellRevision.exportIndex.length; exportId++) {
// int exportIndex = cellRevision.exportIndex[exportId];
// if (exportIndex < 0) continue;
// ImmutableExport e = cellRevision.exports.get(exportIndex);
// exportIndexByOriginalPort[incrementPortCount(e.originalNodeId, e.originalPortId)] = e;
// }
// return exportIndexByOriginalPort;
// }
//
// /**
// * Initialize portBasesForNodes and portCounts
// */
// private void initPortCounts() {
// // Prepare port map
// CellId cellId = cellRevision.d.cellId;
// IdentityHashMap maxPortIds = new IdentityHashMap();
// for (int i = 0; i < cellRevision.cellUsages.length; i++) {
// CellRevision.CellUsageInfo cui = cellRevision.cellUsages[i];
// if (cui == null) continue;
// assert cui.instCount > 0;
// maxPortIds.put(cellId.getUsageIn(i).protoId, cui.usedExportsLength);
// }
// int totalPortCount = 0;
// portBasesForNodes = new int[nodeIndexByNodeId.length];
// Arrays.fill(portBasesForNodes, Integer.MIN_VALUE);
// for (int nodeId = 0; nodeId < nodeIndexByNodeId.length; nodeId++) {
// int nodeIndex = nodeIndexByNodeId[nodeId];
// if (nodeIndex < 0) continue;
// ImmutableNodeInst n = cellRevision.nodes.get(nodeIndex);
// Integer portCount = maxPortIds.get(n.protoId);
// if (portCount == null) {
// PrimitiveNode pn = techPool.getPrimitiveNode((PrimitiveNodeId)n.protoId);
// int maxPortId = -1;
// for (Iterator it = pn.getPorts(); it.hasNext(); )
// maxPortId = Math.max(maxPortId, it.next().getId().chronIndex);
// portCount = maxPortId + 1;
// maxPortIds.put(n.protoId, portCount);
// }
// portBasesForNodes[n.nodeId] = totalPortCount;
// totalPortCount += portCount;
// }
// portCounts = new int[totalPortCount];
// }
//
// /*
// * Clear portCounts
// */
// private void clearPortCounts() {
// Arrays.fill(portCounts, 0);
// }
//
// /**
// * Increment portCounts entry for specified port intance
// * @param nodeId nodeId of port instance
// * @param portId PortProtoId of port instance
// * @return the value of portCounts entry before increment
// */
// private int incrementPortCount(int nodeId, PortProtoId portId) {
// return portCounts[portBasesForNodes[nodeId] + portId.chronIndex]++;
// }
//
// /**
// * Convert port counts to port offsets
// */
// private void portCountsToPortOffsets() {
// int connOffset = 0;
// for (int i = 0; i < portCounts.length; i++) {
// int numConns = portCounts[i];
// portCounts[i] = connOffset;
// connOffset += numConns;
// }
// }
/**
* Returns true of there are Exports on specified NodeInst.
* @param originalNode specified NodeInst.
* @return true if there are Exports on specified NodeInst.
*/
public boolean hasExports(ImmutableNodeInst originalNode) {
int startIndex = searchExportByOriginalPort(originalNode.nodeId, 0);
if (startIndex >= exportIndexByOriginalPort.length) {
return false;
}
ImmutableExport e = exportIndexByOriginalPort[startIndex];
return e.originalNodeId == originalNode.nodeId;
}
/**
* Method to return the number of Exports on specified NodeInst.
* @param originalNodeId nodeId of specified NodeInst.
* @return the number of Exports on specified NodeInst.
*/
public int getNumExports(int originalNodeId) {
int startIndex = searchExportByOriginalPort(originalNodeId, 0);
int j = startIndex;
for (; j < exportIndexByOriginalPort.length; j++) {
ImmutableExport e = exportIndexByOriginalPort[j];
if (e.originalNodeId != originalNodeId) {
break;
}
}
return j - startIndex;
}
/**
* Method to return an Iterator over all ImmutableExports on specified NodeInst.
* @param originalNodeId nodeId of specified NodeInst.
* @return an Iterator over all ImmutableExports on specified NodeInst.
*/
public Iterator getExports(int originalNodeId) {
int startIndex = searchExportByOriginalPort(originalNodeId, 0);
int j = startIndex;
for (; j < exportIndexByOriginalPort.length; j++) {
ImmutableExport e = exportIndexByOriginalPort[j];
if (e.originalNodeId != originalNodeId) {
break;
}
}
return ArrayIterator.iterator(exportIndexByOriginalPort, startIndex, j);
}
/**
* Method to determine whether the display of specified pin NodeInst should be supressed.
* In Schematics technologies, pins are not displayed if there are 1 or 2 connections,
* but are shown for 0 or 3 or more connections (called "Steiner points").
* @param pin specified pin ImmutableNodeInst
* @return true if specieifed pin NodeInst should be supressed.
*/
public boolean pinUseCount(ImmutableNodeInst pin) {
int numConnections = getNumConnections(pin);
if (numConnections > 2) {
return false;
}
if (hasExports(pin)) {
return true;
}
if (numConnections == 0) {
return false;
}
return true;
}
/**
* Method to return a list of arcs connected to speciefed or all ports of
* specified ImmutableNodeInst.
* @param headEnds true if i-th arc connects by head end
* @param n specified ImmutableNodeInst
* @param portId specified port or null
* @return a List of connected ImmutableArcInsts
*/
public List getConnections(BitSet headEnds, ImmutableNodeInst n, PortProtoId portId) {
ArrayList result = null;
if (headEnds != null) {
headEnds.clear();
}
int myNodeId = n.nodeId;
int chronIndex = 0;
if (portId != null) {
assert portId.parentId == n.protoId;
chronIndex = portId.chronIndex;
}
int i = searchConnectionByPort(myNodeId, chronIndex);
int j = i;
for (; j < connections.length; j++) {
int con = connections[j];
ImmutableArcInst a = getArcs().get(con >>> 1);
boolean end = (con & 1) != 0;
int nodeId = end ? a.headNodeId : a.tailNodeId;
if (nodeId != myNodeId) {
break;
}
if (portId != null) {
PortProtoId endProtoId = end ? a.headPortId : a.tailPortId;
if (endProtoId.getChronIndex() != chronIndex) {
break;
}
}
if (result == null) {
result = new ArrayList();
}
if (headEnds != null && end) {
headEnds.set(result.size());
}
result.add(a);
}
return result != null ? result : Collections.emptyList();
}
/**
* Returns true of there are Connections on specified ImmutableNodeInst
* connected either to specified port or to all ports
* @param n specified ImmutableNodeInst
* @param portId specified port or null
* @return true if there are Connections on specified ImmutableNodeInst amd specified port.
*/
public boolean hasConnections(ImmutableNodeInst n, PortProtoId portId) {
int chronIndex = 0;
if (portId != null) {
assert portId.parentId == n.protoId;
chronIndex = portId.chronIndex;
}
int i = searchConnectionByPort(n.nodeId, chronIndex);
if (i >= connections.length) {
return false;
}
int con = connections[i];
ImmutableArcInst a = getArcs().get(con >>> 1);
boolean end = (con & 1) != 0;
int nodeId = end ? a.headNodeId : a.tailNodeId;
if (nodeId != n.nodeId) {
return false;
}
return portId == null || portId == (end ? a.headPortId : a.tailPortId);
}
/**
* Method to return the number of Connections on specified ImmutableNodeInst.
* @param n specified ImmutableNodeInst
* @return the number of Connections on specified ImmutableNodeInst.
*/
public int getNumConnections(ImmutableNodeInst n) {
int myNodeId = n.nodeId;
int i = searchConnectionByPort(myNodeId, 0);
int j = i;
for (; j < connections.length; j++) {
int con = connections[j];
ImmutableArcInst a = getArcs().get(con >>> 1);
boolean end = (con & 1) != 0;
int nodeId = end ? a.headNodeId : a.tailNodeId;
if (nodeId != myNodeId) {
break;
}
}
return j - i;
}
private int searchExportByOriginalPort(int originalNodeId, int originalChronIndex) {
int low = 0;
int high = exportIndexByOriginalPort.length - 1;
while (low <= high) {
int mid = (low + high) >> 1; // try in a middle
ImmutableExport e = exportIndexByOriginalPort[mid];
int cmp = e.originalNodeId - originalNodeId;
if (cmp == 0) {
cmp = e.originalPortId.getChronIndex() >= originalChronIndex ? 1 : -1;
}
if (cmp < 0) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return low;
}
private int searchConnectionByPort(int nodeId, int chronIndex) {
int low = 0;
int high = connections.length - 1;
while (low <= high) {
int mid = (low + high) >> 1; // try in a middle
int con = connections[mid];
ImmutableArcInst a = cellRevision.arcs.get(con >>> 1);
boolean end = (con & 1) != 0;
int endNodeId = end ? a.headNodeId : a.tailNodeId;
int cmp = endNodeId - nodeId;
if (cmp == 0) {
PortProtoId portId = end ? a.headPortId : a.tailPortId;
cmp = portId.getChronIndex() - chronIndex;
}
if (cmp < 0) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return low;
}
public CellBackup getCellBackup() {
return CellBackup.this;
}
public TechPool getTechPool() {
return techPool;
}
/**
* Returns arcs in sorted order.
* @return ImmutableArcInsts in sorted order.
*/
private ImmutableArrayList getArcs() {
return cellRevision.arcs;
}
/**
* Method to tell whether the specified ImmutableNodeInst is wiped.
* Wiped ImmutableNodeInsts are erased. Typically, pin ImmutableNodeInsts can be wiped.
* This means that when an arc connects to the pin, it is no longer drawn.
* In order for a ImmutableNodeInst to be wiped, its prototype must have the "setArcsWipe" state,
* and the arcs connected to it must have "setWipable" in their prototype.
* @param n specified ImmutableNodeInst
* @return true if specified ImmutableNodeInst is wiped.
*/
public boolean isWiped(ImmutableNodeInst n) {
return wiped.get(n.nodeId);
}
public boolean isHardArc(int arcId) {
return hardArcs.get(arcId);
}
/**
* Checks invariant of this CellBackup.
* @throws AssertionError if invariant is broken.
*/
private void check() {
assert exportIndexByOriginalPort.length == cellRevision.exports.size();
ImmutableExport prevE = null;
for (ImmutableExport e : exportIndexByOriginalPort) {
if (prevE != null) {
assert BY_ORIGINAL_PORT.compare(prevE, e) < 0;
}
assert e == cellRevision.getExport(e.exportId);
prevE = e;
}
assert connections.length == cellRevision.arcs.size() * 2;
for (int i = 1; i < connections.length; i++) {
assert compareConnections(connections[i - 1], connections[i]) < 0;
}
}
private void sortConnections(int[] connections, int l, int r) {
ImmutableArrayList arcs = cellRevision.arcs;
while (r - l > BIN_SORT_THRESHOLD) {
int x = connections[(l + r) >>> 1];
ImmutableArcInst ax = arcs.get(x >>> 1);
boolean endx = (x & 1) != 0;
PortProtoId portIdX = endx ? ax.headPortId : ax.tailPortId;
int chronIndexX = portIdX.getChronIndex();
int i = l, j = r;
do {
// while (compareConnections(connections[i], x) < 0) i++;
for (;;) {
int con = connections[i];
ImmutableArcInst a = arcs.get(con >>> 1);
boolean end = (con & 1) != 0;
PortProtoId portId = end ? a.headPortId : a.tailPortId;
if (portId.getChronIndex() > chronIndexX) {
break;
}
if (portId.getChronIndex() == chronIndexX && con >= x) {
break;
}
i++;
}
// while (compareConnections(x, connections[j]) < 0) j--;
for (;;) {
int con = connections[j];
ImmutableArcInst a = arcs.get(con >>> 1);
boolean end = (con & 1) != 0;
PortProtoId portId = end ? a.headPortId : a.tailPortId;
if (chronIndexX > portId.getChronIndex()) {
break;
}
if (chronIndexX == portId.getChronIndex() && x >= con) {
break;
}
j--;
}
if (i <= j) {
int w = connections[i];
connections[i] = connections[j];
connections[j] = w;
i++;
j--;
}
} while (i <= j);
if (j - l < r - i) {
sortConnections(connections, l, j);
l = i;
} else {
sortConnections(connections, i, r);
r = j;
}
}
binarySort(connections, l, r + 1);
}
/**
* This is a specifalized version of {@link java.utils.TimSort#binarySort}.
*
* Sorts the specified portion of the specified array using a binary
* insertion sort. This is the best method for sorting small numbers
* of elements. It requires O(n log n) compares, but O(n^2) data
* movement (worst case).
*
* If the initial part of the specified range is already sorted,
* this method can take advantage of it: the method assumes that the
* elements from index {@code lo}, inclusive, to {@code start},
* exclusive are already sorted.
*
* @param a the array in which a range is to be sorted
* @param lo the index of the first element in the range to be sorted
* @param hi the index after the last element in the range to be sorted
* @param start the index of the first element in the range that is
* not already known to be sorted (@code lo <= start <= hi}
* @param c comparator to used for the sort
*/
@SuppressWarnings("fallthrough")
private void binarySort(int[] connections, int lo, int hi) {
ImmutableArrayList arcs = cellRevision.arcs;
assert lo <= hi;
int start = lo + 1;
if (start >= hi) {
return;
}
int conS;
ImmutableArcInst aS;
PortProtoId portIdS;
int conL = connections[lo];
ImmutableArcInst aL = arcs.get(conL >>> 1);
PortProtoId portIdL = (conL & 1) != 0 ? aL.headPortId : aL.tailPortId;
for (;;) {
conS = connections[start];
aS = arcs.get(conS >>> 1);
portIdS = (conS & 1) != 0 ? aS.headPortId : aS.tailPortId;
int cmp = portIdS.chronIndex - portIdL.chronIndex;
if (cmp < 0) {
break;
}
if (cmp == 0 && conS < conL) {
break;
}
start++;
if (start >= hi) {
return;
}
conL = conS;
aL = aS;
portIdL = portIdS;
}
for (;;) {
assert start < hi;
// Set left (and right) to the index where a[start] (pivot) belongs
int left = lo;
int right = start;
assert left <= right;
/*
* Invariants:
* pivot >= all in [lo, left).
* pivot < all in [right, start).
*/
while (left < right) {
int mid = (left + right) >>> 1;
int conM = connections[mid];
ImmutableArcInst aM = arcs.get(conM >>> 1);
PortProtoId portIdM = (conM & 1) != 0 ? aM.headPortId : aM.tailPortId;
int cmp = portIdS.chronIndex - portIdM.chronIndex;
if (cmp == 0) {
cmp = conS - conM;
}
if (cmp < 0) {
right = mid;
} else {
left = mid + 1;
}
}
assert left == right;
/*
* The invariants still hold: pivot >= all in [lo, left) and
* pivot < all in [left, start), so pivot belongs at left. Note
* that if there are elements equal to pivot, left points to the
* first slot after them -- that's why this sort is stable.
* Slide elements over to make room for pivot.
*/
int n = start - left; // The number of elements to move
// Switch is just an optimization for arraycopy in default case
switch (n) {
case 2:
connections[left + 2] = connections[left + 1];
case 1:
connections[left + 1] = connections[left];
break;
default:
System.arraycopy(connections, left, connections, left + 1, n);
}
connections[left] = conS;
start++;
if (start >= hi) {
return;
}
conS = connections[start];
aS = arcs.get(conS >>> 1);
portIdS = (conS & 1) != 0 ? aS.headPortId : aS.tailPortId;
}
}
private int compareConnectionsSameNode(int con1, int con2) {
ImmutableArcInst a1 = cellRevision.arcs.get(con1 >>> 1);
ImmutableArcInst a2 = cellRevision.arcs.get(con2 >>> 1);
PortProtoId portId1 = (con1 & 1) != 0 ? a1.headPortId : a1.tailPortId;
PortProtoId portId2 = (con2 & 1) != 0 ? a2.headPortId : a2.tailPortId;
int cmp = portId1.chronIndex - portId2.chronIndex;
return cmp != 0 ? cmp : con1 - con2;
}
private int compareConnections(int con1, int con2) {
ImmutableArcInst a1 = cellRevision.arcs.get(con1 >>> 1);
ImmutableArcInst a2 = cellRevision.arcs.get(con2 >>> 1);
boolean end1 = (con1 & 1) != 0;
boolean end2 = (con2 & 1) != 0;
int nodeId1 = end1 ? a1.headNodeId : a1.tailNodeId;
int nodeId2 = end2 ? a2.headNodeId : a2.tailNodeId;
int cmp = nodeId1 - nodeId2;
if (cmp != 0) {
return cmp;
}
PortProtoId portId1 = end1 ? a1.headPortId : a1.tailPortId;
PortProtoId portId2 = end2 ? a2.headPortId : a2.tailPortId;
cmp = portId1.getChronIndex() - portId2.getChronIndex();
if (cmp != 0) {
return cmp;
}
return con1 - con2;
}
}
private static final Comparator BY_ORIGINAL_PORT = new Comparator() {
@Override
public int compare(ImmutableExport e1, ImmutableExport e2) {
int result = e1.originalNodeId - e2.originalNodeId;
if (result != 0) {
return result;
}
result = e1.originalPortId.getChronIndex() - e2.originalPortId.getChronIndex();
if (result != 0) {
return result;
}
return e1.exportId.chronIndex - e2.exportId.chronIndex;
}
};
}