/* * Bytecode Analysis Framework * Copyright (C) 2004,2005 University of Maryland * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package edu.umd.cs.findbugs.ba.obl; import java.util.Arrays; /** * A multiset of obligations that must be cleaned up by * error-handling code. * * <p>See Weimer and Necula, * <a href="http://doi.acm.org/10.1145/1028976.1029011" * >Finding and preventing run-time error handling mistakes</a>, * OOPSLA 2004.</p> * * @author David Hovemeyer */ public class ObligationSet { private static final int INVALID_HASH_CODE = -1; private final short[] countList; // private final short[] whereCreated; private final ObligationFactory factory; private int cachedHashCode; public ObligationSet(/*int maxObligationTypes, */ObligationFactory factory) { this.countList = new short[factory.getMaxObligationTypes()]; // this.whereCreated = new short[factory.getMaxObligationTypes()]; this.factory = factory; invalidate(); } public void add(Obligation obligation) { invalidate(); countList[obligation.getId()]++; } public void remove(Obligation obligation) { invalidate(); int count = countList[obligation.getId()]; if (count > 0) countList[obligation.getId()]--; // = (short)(count - 1); } public int getCount(int id) { return countList[id]; } // public int getCount(Obligation obligation) { // return getCount(obligation.getId()); // } // /** // * Called upon the first creation of given kind of obligation on path. // * // * @param obligation an Obligation // * @param basicBlockId BasicBlock id of first creation of the given obligation type // */ // public void setWhereCreated(Obligation obligation, int basicBlockId) { // assert getCount(obligation.getId()) == 1; // invalidate(); // // if (basicBlockId > Short.MAX_VALUE) { // whereCreated[obligation.getId()] = -1; // return; // } // // whereCreated[obligation.getId()] = (short) basicBlockId; // } // /** // * Find out where the first instance of given obligation type was created. // * // * @param obligation an obligation // * @return id of basic block where created, or -1 if the basic block couldn't be stored // */ // public int getWhereCreated(Obligation obligation) { // return whereCreated[obligation.getId()]; // } @Override public boolean equals(Object o) { if (o == null || o.getClass() != this.getClass()) return false; ObligationSet other = (ObligationSet) o; if (!Arrays.equals(this.countList, other.countList) /*|| !Arrays.equals(this.whereCreated, other.whereCreated)*/) { return false; } return true; } /* * NOTE: this string is incorporated into a StringAnnotation when * reporting OBL_ warnings, so the output needs to be * user-friendly. */ @Override public String toString() { StringBuilder buf = new StringBuilder(); buf.append("{"); int count = 0; for (int i = 0; i < countList.length; ++i) { if (countList[i] == 0) continue; if (count > 0) buf.append(","); buf.append(factory.getObligationById(i).toString()); buf.append(" x "); buf.append(countList[i]); ++count; } buf.append("}"); //buf.append("@" + System.identityHashCode(this)); return buf.toString(); } public void copyFrom(ObligationSet other) { System.arraycopy(other.countList, 0, this.countList, 0, other.countList.length); // System.arraycopy(other.whereCreated, 0, this.whereCreated, 0, other.whereCreated.length); invalidate(); } public ObligationSet duplicate() { ObligationSet dup = new ObligationSet(/*countList.length, */factory); dup.copyFrom(this); return dup; } @Override public int hashCode() { if (cachedHashCode == INVALID_HASH_CODE) { int value = 0; for (int i = 0; i < countList.length; ++i) { value += (13 * i * (countList[i]/* + whereCreated[i]*/)); } cachedHashCode = value; } return cachedHashCode; } private void invalidate() { this.cachedHashCode = INVALID_HASH_CODE; } } // vim:ts=4