/* This file is part of the db4o object database http://www.db4o.com
Copyright (C) 2004 - 2011 Versant Corporation http://www.versant.com
db4o is free software; you can redistribute it and/or modify it under
the terms of version 3 of the GNU General Public License as published
by the Free Software Foundation.
db4o 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 this program. If not, see http://www.gnu.org/licenses/. */
package EDU.purdue.cs.bloat.reflect;
/**
* A Constant is used to represent an item in the constant pool of a class.
*
* @author Nate Nystrom (<a
* href="mailto:nystrom@cs.purdue.edu">nystrom@cs.purdue.edu</a>)
*/
public final class Constant {
private int tag;
private Object value;
/**
* Constant tag for class types. This is used to reference other classes,
* such as the superclass, and is used by the checkcast and instanceof
* instructions. The Fieldref, Methodref and InterfaceMethodref constant
* types refer to this constant type.
*/
public static final byte CLASS = 7;
/**
* Constant tag for field references. This is used to reference a field in
* (possibly) another class. The getfield, putfield, getstatic, and
* putstatic instructions use this constant type.
*/
public static final byte FIELD_REF = 9;
/**
* Constant tag for method references. This is used to reference a method in
* (possibly) another class. The invokevirtual, invokespecial, and
* invokestatic instructions use this constant type.
*/
public static final byte METHOD_REF = 10;
/**
* Constant tag for java.lang.String constants. The actual string value is
* stored indirectly in a Utf8 constant.
*/
public static final byte STRING = 8;
/**
* Constant tag for int, short, byte, char, and boolean constants.
*/
public static final byte INTEGER = 3;
/**
* Constant tag for float constants.
*/
public static final byte FLOAT = 4;
/**
* Constant tag for long constants.
*/
public static final byte LONG = 5;
/**
* Constant tag for double constants.
*/
public static final byte DOUBLE = 6;
/**
* Constant tag for method references. This is used to reference a method in
* an interface. The invokeinterface instruction uses this constant type.
*/
public static final byte INTERFACE_METHOD_REF = 11;
/**
* Constant tag for holding the name and type of a field or method. The
* Fieldref, Methodref and InterfaceMethodref constant types refer to this
* constant type.
*/
public static final byte NAME_AND_TYPE = 12;
/**
* Constant tag for holding the a UTF8 format string. The string is used to
* hold the name and type descriptor for NameandType constants, the class
* name for Class constants, the string value for String constants.
*/
public static final byte UTF8 = 1;
/**
* @param tag
* The constant's tag.
* @param value
* The constant's value.
*/
public Constant(final int tag, final Object value) {
this.tag = tag;
this.value = value;
}
/**
* Get the tag of the constant.
*
* @return The tag.
*/
public final int tag() {
return tag;
}
/**
* Get the value of the constant.
*
* @return The value.
*/
public final Object value() {
return value;
}
/**
* Hash the constant.
*
* @return The hash code.
*/
public int hashCode() {
switch (tag) {
case CLASS:
case STRING:
case INTEGER:
case FLOAT:
case LONG:
case DOUBLE:
case UTF8:
return tag ^ value.hashCode();
case FIELD_REF:
case METHOD_REF:
case INTERFACE_METHOD_REF:
case NAME_AND_TYPE:
return tag ^ ((int[]) value)[0] ^ ((int[]) value)[1];
}
return tag;
}
/**
* Check if an object is equal to this constant.
*
* @param other
* The object to compare against.
* @return true if equal, false if not.
*/
public boolean equals(final Object other) {
if (!(other instanceof Constant)) {
return false;
}
final Constant c = (Constant) other;
if (tag != c.tag) {
return false;
}
switch (tag) {
case CLASS:
case STRING:
case INTEGER:
case FLOAT:
case LONG:
case DOUBLE:
case UTF8:
return value.equals(c.value);
case FIELD_REF:
case METHOD_REF:
case INTERFACE_METHOD_REF:
case NAME_AND_TYPE:
return (((int[]) value)[0] == ((int[]) c.value)[0])
&& (((int[]) value)[1] == ((int[]) c.value)[1]);
}
return false;
}
/**
* Convert the constant to a string.
*
* @return A string representation of the constant.
*/
public String toString() {
switch (tag) {
case CLASS:
return "Class " + value.toString();
case STRING:
return "String " + value.toString();
case INTEGER:
return "Integer " + value.toString();
case FLOAT:
return "Float " + value.toString();
case LONG:
return "Long " + value.toString();
case DOUBLE:
return "Double " + value.toString();
case UTF8:
final StringBuffer sb = new StringBuffer();
final String s = (String) value;
for (int i = 0; i < s.length(); i++) {
final char c = s.charAt(i);
if (Character.isWhitespace(c) || ((0x20 <= c) && (c <= 0x7e))) {
sb.append(c);
} else {
sb.append("\\u");
sb.append(Integer.toHexString(c));
}
if (sb.length() > 50) {
sb.append("...");
break;
}
}
return "Utf8 '" + sb.toString() + "'";
case FIELD_REF:
return "Fieldref " + ((int[]) value)[0] + " " + ((int[]) value)[1];
case METHOD_REF:
return "Methodref " + ((int[]) value)[0] + " " + ((int[]) value)[1];
case INTERFACE_METHOD_REF:
return "InterfaceMethodref " + ((int[]) value)[0] + " "
+ ((int[]) value)[1];
case NAME_AND_TYPE:
return "NameandType " + ((int[]) value)[0] + " "
+ ((int[]) value)[1];
}
return "unknown constant";
}
}