All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.electric.database.UsageCollector Maven / Gradle / Ivy

There is a newer version: 9.02-e
Show newest version
/* -*- tab-width: 4 -*-
 *
 * Electric(tm) VLSI Design System
 *
 * File: UsageCollector.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.id.CellId;
import com.sun.electric.database.id.CellUsage;
import com.sun.electric.database.id.ExportId;
import com.sun.electric.database.id.PortProtoId;
import com.sun.electric.database.id.PrimitiveNodeId;
import com.sun.electric.database.id.PrimitivePortId;
import com.sun.electric.database.id.TechId;
import com.sun.electric.database.variable.TextDescriptor;
import com.sun.electric.database.variable.Variable;
import com.sun.electric.util.collections.ImmutableArrayList;

import java.util.Arrays;
import java.util.BitSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.TreeMap;

/**
 * Package-private class to collect usage of libraries/cells/exports in CellBackup or in Library variables.
 * Export usages of subcells are represented by BitSet of ExportId's chronological indices.
 * If a subcell is used and no its ExportIds are used, it is represented by empty BitSet.
 */
class UsageCollector {

    static final BitSet EMPTY_BITSET = new BitSet();
    static final TreeMap EMPTY_ATTRIBUTES = new TreeMap();
    private final ImmutableCell d;
    private final HashMap cellIndices = new HashMap(16, 0.5f);
    private final HashSet techUsed = new HashSet(16, 0.5f);

    /**
     * Collect usages in lists of nodes/arcs/exports together with Cell's variables.
     */
    UsageCollector(ImmutableCell d,
            ImmutableArrayList nodes,
            ImmutableArrayList arcs,
            ImmutableArrayList exports) {
        this.d = d;
        for (int nodeIndex = 0; nodeIndex < nodes.size(); nodeIndex++) {
            ImmutableNodeInst n = nodes.get(nodeIndex);
            if (n.protoId instanceof CellId) {
                CellUsageInfoBuilder cellCount = add((CellId) n.protoId, true);
                if (cellCount.isIcon) {
                    for (Variable param : n.getDefinedParams()) {
                        cellCount.addAttribute((Variable.AttrKey) param.getKey(), param.getUnit());
                    }
                    for (int varIndex = 0; varIndex < n.getNumVariables(); varIndex++) {
                        Variable.Key varKey = n.getVar(varIndex).getKey();
                        if (varKey.isAttribute()) {
                            cellCount.addAttribute((Variable.AttrKey) varKey, null);
                        }
                    }
                }
            } else {
                techUsed.add(((PrimitiveNodeId) n.protoId).techId);
            }
            for (int chronIndex = 0; chronIndex < n.ports.length; chronIndex++) {
                ImmutablePortInst pi = n.ports[chronIndex];
                if (pi == ImmutablePortInst.EMPTY) {
                    continue;
                }
                PortProtoId pp = n.protoId.getPortId(chronIndex);
                add(pp);
            }
        }
        for (int arcIndex = 0; arcIndex < arcs.size(); arcIndex++) {
            ImmutableArcInst a = arcs.get(arcIndex);
            techUsed.add(a.protoId.techId);
            add(a.tailPortId);
            add(a.headPortId);
        }
        for (int portIndex = 0; portIndex < exports.size(); portIndex++) {
            ImmutableExport e = exports.get(portIndex);
            add(e.originalPortId);
        }
    }

    private void add(PortProtoId portId) {
        if (portId instanceof PrimitivePortId) {
            return;
        }
        ExportId eId = (ExportId) portId;
        add(eId.getParentId(), false).usedExports.set(eId.chronIndex);
    }

    private CellUsageInfoBuilder add(CellId cellId, boolean isInstance) {
        CellUsageInfoBuilder cellCount = cellIndices.get(cellId);
        if (cellCount == null) {
            cellCount = new CellUsageInfoBuilder(d.cellId.getUsageIn(cellId));
            cellIndices.put(cellId, cellCount);
        }
        if (isInstance) {
            cellCount.instCount++;
        }
        return cellCount;
    }

    /**
     * Return TechId usages for CellBackup.
     */
    BitSet getTechUsages(BitSet oldTechUsages) {
        BitSet techUsages = new BitSet();
        techUsages.set(d.techId.techIndex);
        for (TechId techId : techUsed) {
            techUsages.set(techId.techIndex);
        }
        return bitSetWith(oldTechUsages, techUsages);
    }

    /**
     * Return usages for CellRevision.
     */
    CellRevision.CellUsageInfo[] getCellUsages(CellRevision.CellUsageInfo[] oldCellUsages) {
        if (cellIndices.isEmpty()) {
            return CellRevision.NULL_CELL_USAGE_INFO_ARRAY;
        }
        CellId parentId = d.cellId;
        int length = 0;
        for (CellId cellId : cellIndices.keySet()) {
            length = Math.max(length, parentId.getUsageIn(cellId).indexInParent + 1);
        }
        CellRevision.CellUsageInfo[] newCellUsages = new CellRevision.CellUsageInfo[length];
        for (CellId cellId : cellIndices.keySet()) {
            CellUsage u = parentId.getUsageIn(cellId);
            int indexInParent = u.indexInParent;
            CellUsageInfoBuilder cellCount = cellIndices.get(cellId);
            if (cellCount != null) {
                CellRevision.CellUsageInfo oldC = indexInParent < oldCellUsages.length ? oldCellUsages[indexInParent] : null;
                newCellUsages[indexInParent] = cellCount.getCellUsageInfo(oldC);
            }
        }
        return Arrays.equals(newCellUsages, oldCellUsages) ? oldCellUsages : newCellUsages;
    }

    static BitSet bitSetWith(BitSet oldBitSet, BitSet newBitSet) {
        if (newBitSet.isEmpty()) {
            return EMPTY_BITSET;
        }
        return newBitSet.equals(oldBitSet) ? oldBitSet : newBitSet;
    }

    static TreeMap usedAttributesWith(TreeMap oldAttributes,
            TreeMap newAttributes) {
        if (newAttributes == null) {
            return null;
        }
        if (newAttributes.isEmpty()) {
            return EMPTY_ATTRIBUTES;
        }
        return newAttributes.equals(oldAttributes) ? oldAttributes : newAttributes;
    }

    private static class CellUsageInfoBuilder {

        private final CellUsage cellUsage;
        private final boolean isIcon;
        private int instCount;
        private final BitSet usedExports = new BitSet();
        private final TreeMap usedAttributes;

        private CellUsageInfoBuilder(CellUsage cellUsage) {
            this.cellUsage = cellUsage;
            isIcon = cellUsage.protoId.isIcon();
            usedAttributes = isIcon ? new TreeMap() : null;
        }

        private void addAttribute(Variable.AttrKey attrKey, TextDescriptor.Unit unit) {
            TextDescriptor.Unit oldUnit = usedAttributes.get(attrKey);
            if (oldUnit != null) {
                if (unit != oldUnit) {
                    throw new IllegalArgumentException(attrKey + " " + unit);
                }
            } else {
                usedAttributes.put(attrKey, unit);
            }
        }

        private CellRevision.CellUsageInfo getCellUsageInfo(CellRevision.CellUsageInfo oldCellUsageInfo) {
            if (oldCellUsageInfo != null) {
                return oldCellUsageInfo.with(instCount, usedExports, usedAttributes);
            } else {
                return new CellRevision.CellUsageInfo(instCount, usedExports, usedAttributes);
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy