/* * Bytecode Analysis Framework * Copyright (C) 2003,2004 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.vna; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Map; import javax.annotation.CheckForNull; import edu.umd.cs.findbugs.internalAnnotations.DottedClassName; /** * Factory for ValueNumbers. A single Factory must be used to create all of the * ValueNumbers for a method. * * @author David Hovemeyer * @see ValueNumber */ public class ValueNumberFactory { /** * Store all allocated value numbers. */ private ArrayList<ValueNumber> allocatedValueList = new ArrayList<ValueNumber>(); private HashMap<String, ValueNumber> classObjectValueMap = new HashMap<String, ValueNumber>(); /** * Create a fresh (unique) value number. */ public ValueNumber createFreshValue() { ValueNumber result = ValueNumber.createValueNumber(getNumValuesAllocated()); allocatedValueList.add(result); return result; } public ValueNumber createFreshValue(int flags) { ValueNumber result = ValueNumber.createValueNumber(getNumValuesAllocated(), flags); allocatedValueList.add(result); return result; } /** * Return a previously allocated value. */ public ValueNumber forNumber(int number) { if (number >= getNumValuesAllocated()) throw new IllegalArgumentException("Value " + number + " has not been allocated"); return allocatedValueList.get(number); } /** * Get the number of values which have been created. */ public int getNumValuesAllocated() { return allocatedValueList.size(); } /** * Compact the value numbers produced by this factory. * * @param map * array mapping old numbers to new numbers * @param numValuesAllocated * the number of values allocated in the new numbering */ @Deprecated public void compact(int[] map, int numValuesAllocated) { if (true) throw new UnsupportedOperationException(); ArrayList<ValueNumber> oldList = this.allocatedValueList; ArrayList<ValueNumber> newList = new ArrayList<ValueNumber>(Collections.<ValueNumber> nCopies(numValuesAllocated, null)); for (ValueNumber value : oldList) { int newNumber = map[value.getNumber()]; if (newNumber >= 0) { // Note: because we are simply assigning new numbers to the // old ValueNumber objects, their flags remain valid. // value.number = newNumber; newList.set(newNumber, value); } } this.allocatedValueList = newList; } /** * Get the ValueNumber for given class's Class object. * * @param className * the class */ public ValueNumber getClassObjectValue(@DottedClassName String className) { // assert className.indexOf('.') == -1; // TODO: Check to see if we need to do this className = className.replace('/', '.'); ValueNumber value = classObjectValueMap.get(className); if (value == null) { value = createFreshValue(ValueNumber.CONSTANT_CLASS_OBJECT); classObjectValueMap.put(className, value); } return value; } public @CheckForNull @DottedClassName String getClassName(ValueNumber v) { if (!v.hasFlag(ValueNumber.CONSTANT_CLASS_OBJECT)) throw new IllegalArgumentException("Not a value number for a constant class"); for (Map.Entry<String, ValueNumber> e : classObjectValueMap.entrySet()) { if (e.getValue().equals(v)) return e.getKey(); } return null; } } // vim:ts=4