1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.dx.rop.cst; 18 19 import com.android.dx.rop.type.Type; 20 21 import java.util.HashMap; 22 23 /** 24 * Constants that represent an arbitrary type (reference or primitive). 25 */ 26 public final class CstType extends TypedConstant { 27 /** non-null; map of interned types */ 28 private static final HashMap<Type, CstType> interns = 29 new HashMap<Type, CstType>(100); 30 31 /** non-null; instance corresponding to the class <code>Object</code> */ 32 public static final CstType OBJECT = intern(Type.OBJECT); 33 34 /** non-null; instance corresponding to the class <code>Boolean</code> */ 35 public static final CstType BOOLEAN = intern(Type.BOOLEAN_CLASS); 36 37 /** non-null; instance corresponding to the class <code>Byte</code> */ 38 public static final CstType BYTE = intern(Type.BYTE_CLASS); 39 40 /** non-null; instance corresponding to the class <code>Character</code> */ 41 public static final CstType CHARACTER = intern(Type.CHARACTER_CLASS); 42 43 /** non-null; instance corresponding to the class <code>Double</code> */ 44 public static final CstType DOUBLE = intern(Type.DOUBLE_CLASS); 45 46 /** non-null; instance corresponding to the class <code>Float</code> */ 47 public static final CstType FLOAT = intern(Type.FLOAT_CLASS); 48 49 /** non-null; instance corresponding to the class <code>Long</code> */ 50 public static final CstType LONG = intern(Type.LONG_CLASS); 51 52 /** non-null; instance corresponding to the class <code>Integer</code> */ 53 public static final CstType INTEGER = intern(Type.INTEGER_CLASS); 54 55 /** non-null; instance corresponding to the class <code>Short</code> */ 56 public static final CstType SHORT = intern(Type.SHORT_CLASS); 57 58 /** non-null; instance corresponding to the class <code>Void</code> */ 59 public static final CstType VOID = intern(Type.VOID_CLASS); 60 61 /** non-null; instance corresponding to the type <code>boolean[]</code> */ 62 public static final CstType BOOLEAN_ARRAY = intern(Type.BOOLEAN_ARRAY); 63 64 /** non-null; instance corresponding to the type <code>byte[]</code> */ 65 public static final CstType BYTE_ARRAY = intern(Type.BYTE_ARRAY); 66 67 /** non-null; instance corresponding to the type <code>char[]</code> */ 68 public static final CstType CHAR_ARRAY = intern(Type.CHAR_ARRAY); 69 70 /** non-null; instance corresponding to the type <code>double[]</code> */ 71 public static final CstType DOUBLE_ARRAY = intern(Type.DOUBLE_ARRAY); 72 73 /** non-null; instance corresponding to the type <code>float[]</code> */ 74 public static final CstType FLOAT_ARRAY = intern(Type.FLOAT_ARRAY); 75 76 /** non-null; instance corresponding to the type <code>long[]</code> */ 77 public static final CstType LONG_ARRAY = intern(Type.LONG_ARRAY); 78 79 /** non-null; instance corresponding to the type <code>int[]</code> */ 80 public static final CstType INT_ARRAY = intern(Type.INT_ARRAY); 81 82 /** non-null; instance corresponding to the type <code>short[]</code> */ 83 public static final CstType SHORT_ARRAY = intern(Type.SHORT_ARRAY); 84 85 /** non-null; the underlying type */ 86 private final Type type; 87 88 /** 89 * null-ok; the type descriptor corresponding to this instance, if 90 * calculated 91 */ 92 private CstUtf8 descriptor; 93 94 /** 95 * Returns an instance of this class that represents the wrapper 96 * class corresponding to a given primitive type. For example, if 97 * given {@link Type#INT}, this method returns the class reference 98 * <code>java.lang.Integer</code>. 99 * 100 * @param primitiveType non-null; the primitive type 101 * @return non-null; the corresponding wrapper class 102 */ forBoxedPrimitiveType(Type primitiveType)103 public static CstType forBoxedPrimitiveType(Type primitiveType) { 104 switch (primitiveType.getBasicType()) { 105 case Type.BT_BOOLEAN: return BOOLEAN; 106 case Type.BT_BYTE: return BYTE; 107 case Type.BT_CHAR: return CHARACTER; 108 case Type.BT_DOUBLE: return DOUBLE; 109 case Type.BT_FLOAT: return FLOAT; 110 case Type.BT_INT: return INTEGER; 111 case Type.BT_LONG: return LONG; 112 case Type.BT_SHORT: return SHORT; 113 case Type.BT_VOID: return VOID; 114 } 115 116 throw new IllegalArgumentException("not primitive: " + primitiveType); 117 } 118 119 /** 120 * Returns an interned instance of this class for the given type. 121 * 122 * @param type non-null; the underlying type 123 * @return non-null; an appropriately-constructed instance 124 */ intern(Type type)125 public static CstType intern(Type type) { 126 CstType cst = interns.get(type); 127 128 if (cst == null) { 129 cst = new CstType(type); 130 interns.put(type, cst); 131 } 132 133 return cst; 134 } 135 136 /** 137 * Constructs an instance. 138 * 139 * @param type non-null; the underlying type 140 */ CstType(Type type)141 public CstType(Type type) { 142 if (type == null) { 143 throw new NullPointerException("type == null"); 144 } 145 146 if (type == type.KNOWN_NULL) { 147 throw new UnsupportedOperationException( 148 "KNOWN_NULL is not representable"); 149 } 150 151 this.type = type; 152 this.descriptor = null; 153 } 154 155 /** {@inheritDoc} */ 156 @Override equals(Object other)157 public boolean equals(Object other) { 158 if (!(other instanceof CstType)) { 159 return false; 160 } 161 162 return type == ((CstType) other).type; 163 } 164 165 /** {@inheritDoc} */ 166 @Override hashCode()167 public int hashCode() { 168 return type.hashCode(); 169 } 170 171 /** {@inheritDoc} */ 172 @Override compareTo0(Constant other)173 protected int compareTo0(Constant other) { 174 String thisDescriptor = type.getDescriptor(); 175 String otherDescriptor = ((CstType) other).type.getDescriptor(); 176 return thisDescriptor.compareTo(otherDescriptor); 177 } 178 179 /** {@inheritDoc} */ 180 @Override toString()181 public String toString() { 182 return "type{" + toHuman() + '}'; 183 } 184 185 /** {@inheritDoc} */ getType()186 public Type getType() { 187 return Type.CLASS; 188 } 189 190 /** {@inheritDoc} */ 191 @Override typeName()192 public String typeName() { 193 return "type"; 194 } 195 196 /** {@inheritDoc} */ 197 @Override isCategory2()198 public boolean isCategory2() { 199 return false; 200 } 201 202 /** {@inheritDoc} */ toHuman()203 public String toHuman() { 204 return type.toHuman(); 205 } 206 207 /** 208 * Gets the underlying type (as opposed to the type corresponding 209 * to this instance as a constant, which is always 210 * <code>Class</code>). 211 * 212 * @return non-null; the type corresponding to the name 213 */ getClassType()214 public Type getClassType() { 215 return type; 216 } 217 218 /** 219 * Gets the type descriptor for this instance. 220 * 221 * @return non-null; the descriptor 222 */ getDescriptor()223 public CstUtf8 getDescriptor() { 224 if (descriptor == null) { 225 descriptor = new CstUtf8(type.getDescriptor()); 226 } 227 228 return descriptor; 229 } 230 } 231