/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: ImmutableElectricObject.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.IdReader; import com.sun.electric.database.id.IdWriter; import com.sun.electric.database.text.ArrayIterator; import com.sun.electric.database.variable.Variable; import java.io.IOException; import java.util.Arrays; import java.util.Iterator; /** * This immutable class is the base class of all Electric immutable objects that can be extended with Variables. */ public abstract class ImmutableElectricObject { /** array of variables sorted by their keys. */ private final Variable[] vars; /** flags of this IimmutableElectricObject. */ public final int flags; /** * The package-private constructor of ImmutableElectricObject. * Use the factory "newInstance" instead. * @param vars array of Variables sorted by their keys. * @param flags flags of this IimmutableElectricObject. */ ImmutableElectricObject(Variable[] vars, int flags) { this.vars = vars; this.flags = flags; } /** * Returns array of Variables which differs from array of this ImmutableElectricObject by additional Variable. * If this ImmutableElectricObject has Variable with the same key as new, the old variable will not be in new array. * @param var additional Variable. * @return array of Variables with additional Variable. * @throws NullPointerException if var is null */ Variable[] arrayWithVariable(Variable var) { return arrayWithVariable(vars, var); } /** * Returns array of Variables which differs from given array of Variables by additional Variable. * If the array has Variable with the same key as new, the old variable will not be in new array. * @param vars array of Variables * @param var additional Variable. * @return array of Variables with additional Variable. * @throws NullPointerException if var is null */ static Variable[] arrayWithVariable(Variable[] vars, Variable var) { int varIndex = searchVar(vars, var.getKey()); int newLength = vars.length; if (varIndex < 0) { varIndex = ~varIndex; newLength++; } else if (vars[varIndex] == var) { return vars; } Variable[] newVars = new Variable[newLength]; System.arraycopy(vars, 0, newVars, 0, varIndex); newVars[varIndex] = var; int tailLength = newLength - (varIndex + 1); System.arraycopy(vars, vars.length - tailLength, newVars, varIndex + 1, tailLength); return newVars; } /** * Returns array of Variable which differs from array of this ImmutableElectricObject by removing Variable * with the specified key. Returns array of this ImmutableElectricObject if it doesn't contain variable with the specified key. * @param key Variable Key to remove. * @return array of Variables without Variable with the specified key. * @throws NullPointerException if key is null */ Variable[] arrayWithoutVariable(Variable.Key key) { return arrayWithoutVariable(vars, key); } /** * Returns array of Variable which differs from given array of Vasriables by removing Variable * with the specified key. Returns given array if it doesn't contain variable with the specified key. * @param vars array of Variables * @param key Variable Key to remove. * @return array of Variables without Variable with the specified key. * @throws NullPointerException if key is null */ static Variable[] arrayWithoutVariable(Variable[] vars, Variable.Key key) { int varIndex = searchVar(vars, key); if (varIndex < 0) { return vars; } if (vars.length == 1 && varIndex == 0) { return Variable.NULL_ARRAY; } Variable[] newVars = new Variable[vars.length - 1]; System.arraycopy(vars, 0, newVars, 0, varIndex); System.arraycopy(vars, varIndex + 1, newVars, varIndex, newVars.length - varIndex); return newVars; } /** * Returns array of Variable which differs from array of this ImmutableElectricObject by renamed Ids. * Returns array of this ImmutableElectricObject if it doesn't contain reanmed Ids. * @param idMapper a map from old Ids to new Ids. * @return array of Variable with renamed Ids. */ Variable[] arrayWithRenamedIds(IdMapper idMapper) { return arrayWithRenamedIds(vars, idMapper); } /** * Returns array of Variable which differs from given array of Variables by renamed Ids. * Returns given array if it doesn't contain reanmed Ids. * @param idMapper a map from old Ids to new Ids. * @return array of Variable with renamed Ids. */ static Variable[] arrayWithRenamedIds(Variable[] vars, IdMapper idMapper) { Variable[] newVars = null; for (int i = 0; i < vars.length; i++) { Variable oldVar = vars[i]; Variable newVar = oldVar.withRenamedIds(idMapper); if (newVar != oldVar && newVars == null) { newVars = new Variable[vars.length]; System.arraycopy(vars, 0, newVars, 0, i); } if (newVars != null) { newVars[i] = newVar; } } return newVars != null ? newVars : vars; } /** * Method to return the Variable on this ImmuatbleElectricObject with a given key. * @param key the key of the Variable. * @return the Variable with that key, or null if there is no such Variable. * @throws NullPointerException if key is null */ public Variable getVar(Variable.Key key) { int varIndex = searchVar(key); return varIndex >= 0 ? vars[varIndex] : null; } /** * Method to return the value of the Variable on this ImmutableElectricObject with a given key and type. * @param key the key of the Variable. * @param type the required type of the Variable. * @return the value of the Variable with that key and type, or null if there is no such Variable * or default Variable value. * @throws NullPointerException if key or type is null */ public <T> T getVarValue(Variable.Key key, Class type) { Variable var = getVar(key); if (var != null) { Object value = var.getObject(); if (type.isInstance(value)) { return (T) value; } } return null; } /** * Method to return an Iterator over all Variables on this ImmutableElectricObject. * @return an Iterator over all Variables on this ImmutableElectricObject. */ public Iterator<Variable> getVariables() { return ArrayIterator.iterator(vars); } /** * Method to return an array of all Variables on this ImmutableElectricObject. * @return an array of all Variables on this ImmutableElectricObject. */ public Variable[] toVariableArray() { return vars.length == 0 ? vars : (Variable[]) vars.clone(); } /** * Method to return the number of Variables on this ImmutableElectricObject. * @return the number of Variables on this ImmutableElectricObject. */ public int getNumVariables() { return vars.length; } /** * Method to return the Variable by its varIndex. * @param varIndex index of Variable. * @return the Variable with given varIndex. * @throws ArrayIndexOutOfBoundesException if varIndex out of bounds. */ public Variable getVar(int varIndex) { return vars[varIndex]; } /** * The package-private method to get Variable array. * @return Variable array of this ImmutableElectricObject. */ Variable[] getVars() { return vars; } /** * Searches the variables for the specified variable key using the binary * search algorithm. * @param key the variable key to be searched. * @return index of the search variable, if it is contained in the vars; * otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>. The * <i>insertion point</i> is defined as the point at which the * NodeInst would be inserted into the list: the index of the first * element greater than the key, or <tt>nodes.size()</tt>, 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 Variable is found. * @throws NullPointerException if key is null */ public int searchVar(Variable.Key key) { if (key == null) { throw new NullPointerException("key"); } return searchVar(vars, key); } /** * Searches the ordered array of variables for the specified variable key using the binary * search algorithm. * @param vars the ordered array of variables. * @param key the variable key to be searched. * @return index of the search variable, if it is contained in the vars; * otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>. The * <i>insertion point</i> is defined as the point at which the * NodeInst would be inserted into the list: the index of the first * element greater than the key, or <tt>nodes.size()</tt>, 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 Variable is found. */ static int searchVar(Variable[] vars, Variable.Key key) { int low = 0; int high = vars.length - 1; while (low <= high) { int mid = (low + high) >> 1; // try in a middle Variable var = vars[mid]; int cmp = var.getKey().compareTo(key); if (cmp < 0) { low = mid + 1; } else if (cmp > 0) { high = mid - 1; } else { return mid; // Variable found } } return -(low + 1); // Variable not found. } /** * Writes optional variable part of this ImmutableElectricObject. * @param writer where to write. */ void write(IdWriter writer) throws IOException { boolean hasVars = vars.length > 0; writer.writeBoolean(hasVars); if (hasVars) { writeVars(writer); } } /** * Writes variables of this ImmutableElectricObject. * @param writer where to write. */ void writeVars(IdWriter writer) throws IOException { writeVars(vars, writer); } /** * Writes variables of this ImmutableElectricObject. * @param writer where to write. */ static void writeVars(Variable[] vars, IdWriter writer) throws IOException { writer.writeInt(vars.length); for (int i = 0; i < vars.length; i++) { vars[i].write(writer); } } /** * Reads variables of this ImmutableElectricObject. * @param reader where to read. */ static Variable[] readVars(IdReader reader) throws IOException { int length = reader.readInt(); if (length == 0) { return Variable.NULL_ARRAY; } Variable[] vars = new Variable[length]; for (int i = 0; i < length; i++) { vars[i] = Variable.read(reader); } return vars; } /** * Return a hash code value for fields of this object. * Variables of objects are not compared */ public abstract int hashCodeExceptVariables(); /** * Indicates whether fields of other ImmutableElectricObject are equal to fileds of this object. * Variables of objects are not compared. * @param o other ImmutableElectricObject. * @return true if fields of objects are equal. */ public abstract boolean equalsExceptVariables(ImmutableElectricObject o); /** * Indicates whether variables of other ImmutableElectricObject are equal to variables of this ImmutableElectricObject. * Variables of objects are not compared. * @param o other ImmutableElectricObject. * @return true if variables of objects are equal. */ public boolean equalsVariables(ImmutableElectricObject o) { return Arrays.equals(this.vars, o.vars); } /** * Checks invariant of this ImmutableElectricObject. * @param true if inherit is allowed on this ImmutableElectricObject * @throws AssertionError if invariant is broken. */ void check(boolean inheritAllowed) { if (vars.length == 0) { return; } vars[0].check(false, inheritAllowed); for (int i = 1; i < vars.length; i++) { vars[i].check(false, inheritAllowed); assert vars[i - 1].getKey().compareTo(vars[i].getKey()) < 0; } } }