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 17package com.android.dx.rop.cst; 18 19import com.android.dx.rop.type.Type; 20 21import java.util.HashMap; 22 23/** 24 * Constants that represent an arbitrary type (reference or primitive). 25 */ 26public final class CstType extends TypedConstant { 27 /** {@code non-null;} map of interned types */ 28 private static final HashMap<Type, CstType> interns = 29 new HashMap<Type, CstType>(100); 30 31 /** {@code non-null;} instance corresponding to the class {@code Object} */ 32 public static final CstType OBJECT = intern(Type.OBJECT); 33 34 /** {@code non-null;} instance corresponding to the class {@code Boolean} */ 35 public static final CstType BOOLEAN = intern(Type.BOOLEAN_CLASS); 36 37 /** {@code non-null;} instance corresponding to the class {@code Byte} */ 38 public static final CstType BYTE = intern(Type.BYTE_CLASS); 39 40 /** {@code non-null;} instance corresponding to the class {@code Character} */ 41 public static final CstType CHARACTER = intern(Type.CHARACTER_CLASS); 42 43 /** {@code non-null;} instance corresponding to the class {@code Double} */ 44 public static final CstType DOUBLE = intern(Type.DOUBLE_CLASS); 45 46 /** {@code non-null;} instance corresponding to the class {@code Float} */ 47 public static final CstType FLOAT = intern(Type.FLOAT_CLASS); 48 49 /** {@code non-null;} instance corresponding to the class {@code Long} */ 50 public static final CstType LONG = intern(Type.LONG_CLASS); 51 52 /** {@code non-null;} instance corresponding to the class {@code Integer} */ 53 public static final CstType INTEGER = intern(Type.INTEGER_CLASS); 54 55 /** {@code non-null;} instance corresponding to the class {@code Short} */ 56 public static final CstType SHORT = intern(Type.SHORT_CLASS); 57 58 /** {@code non-null;} instance corresponding to the class {@code Void} */ 59 public static final CstType VOID = intern(Type.VOID_CLASS); 60 61 /** {@code non-null;} instance corresponding to the type {@code boolean[]} */ 62 public static final CstType BOOLEAN_ARRAY = intern(Type.BOOLEAN_ARRAY); 63 64 /** {@code non-null;} instance corresponding to the type {@code byte[]} */ 65 public static final CstType BYTE_ARRAY = intern(Type.BYTE_ARRAY); 66 67 /** {@code non-null;} instance corresponding to the type {@code char[]} */ 68 public static final CstType CHAR_ARRAY = intern(Type.CHAR_ARRAY); 69 70 /** {@code non-null;} instance corresponding to the type {@code double[]} */ 71 public static final CstType DOUBLE_ARRAY = intern(Type.DOUBLE_ARRAY); 72 73 /** {@code non-null;} instance corresponding to the type {@code float[]} */ 74 public static final CstType FLOAT_ARRAY = intern(Type.FLOAT_ARRAY); 75 76 /** {@code non-null;} instance corresponding to the type {@code long[]} */ 77 public static final CstType LONG_ARRAY = intern(Type.LONG_ARRAY); 78 79 /** {@code non-null;} instance corresponding to the type {@code int[]} */ 80 public static final CstType INT_ARRAY = intern(Type.INT_ARRAY); 81 82 /** {@code non-null;} instance corresponding to the type {@code short[]} */ 83 public static final CstType SHORT_ARRAY = intern(Type.SHORT_ARRAY); 84 85 /** {@code non-null;} the underlying type */ 86 private final Type type; 87 88 /** 89 * {@code 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}. 99 * 100 * @param primitiveType {@code non-null;} the primitive type 101 * @return {@code non-null;} the corresponding wrapper class 102 */ 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 {@code non-null;} the underlying type 123 * @return {@code non-null;} an appropriately-constructed instance 124 */ 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 {@code non-null;} the underlying type 140 */ 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 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 167 public int hashCode() { 168 return type.hashCode(); 169 } 170 171 /** {@inheritDoc} */ 172 @Override 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 181 public String toString() { 182 return "type{" + toHuman() + '}'; 183 } 184 185 /** {@inheritDoc} */ 186 public Type getType() { 187 return Type.CLASS; 188 } 189 190 /** {@inheritDoc} */ 191 @Override 192 public String typeName() { 193 return "type"; 194 } 195 196 /** {@inheritDoc} */ 197 @Override 198 public boolean isCategory2() { 199 return false; 200 } 201 202 /** {@inheritDoc} */ 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}). 211 * 212 * @return {@code non-null;} the type corresponding to the name 213 */ 214 public Type getClassType() { 215 return type; 216 } 217 218 /** 219 * Gets the type descriptor for this instance. 220 * 221 * @return {@code non-null;} the descriptor 222 */ 223 public CstUtf8 getDescriptor() { 224 if (descriptor == null) { 225 descriptor = new CstUtf8(type.getDescriptor()); 226 } 227 228 return descriptor; 229 } 230} 231