1 /*
2 * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26 package impl.java.dyn.util;
27
28 import java.util.HashMap;
29
30 public class Wrappers {
31
32 private Wrappers() { } // cannot instantiate
33
34 /** If {@code type} is a primitive type, return the corresponding
35 * wrapper type, else return {@code type} unchanged.
36 */
37 public static <T> Class<T> asWrapperType(Class<T> type) {
38 if (!type.isPrimitive()) {
39 return type;
40 }
41 if (wrappers.isEmpty()) {
42 fillWrappers();
43 }
44 Object[] memo = wrappers.get(type);
45 assert (memo != null);
46 return (Class<T>) memo[0]; // unchecked warning is OK here
47 }
48
49 /** If {@code type} is a wrapper type, return the corresponding
50 * primitive type, else return {@code type} unchanged.
51 */
52 public static <T> Class<T> asPrimitiveType(Class<T> type) {
53 if (type.isPrimitive()) {
54 return type;
55 }
56 if (wrappers.isEmpty()) {
57 fillWrappers();
58 }
59 Object[] memo = wrappers.get(type);
60 if (memo == null) {
61 return type;
62 }
63 return (Class<T>) memo[1]; // unchecked warning is OK here
64 }
65
66 public static boolean isWrapperType(Class<?> type) {
67 return asPrimitiveType(type) != type;
68 }
69
70 public static boolean isPrimitiveType(Class<?> type) {
71 return type.isPrimitive();
72 }
73
74 public static char basicTypeChar(Class<?> type) {
75 if (!type.isPrimitive()) {
76 return 'L';
77 }
78 if (wrappers.isEmpty()) {
79 fillWrappers();
80 }
81 Object[] memo = wrappers.get(type);
82 assert (memo != null);
83 return (char) (Character) memo[2];
84 }
85
86 static final String PRIMITIVE_BITS_TABLE = "LZBCSFIZZDJ";
87 // "--01234 78"
88
89 /** Return the number of bits in the given type, or zero for refs. */
90 public static int bitWidth(Class<?> type) {
91 return bitWidth(basicTypeChar(type));
92 }
93
94 /** Return the number of bits in the given basic type, or zero for refs. */
95 public static int bitWidth(char c) {
96 int i = PRIMITIVE_BITS_TABLE.indexOf(c);
97 if (i < 0) throw new IllegalArgumentException("not a basic type char: "+c);
98 i -= 2;
99 switch (i) {
100 case -2: return 0; // L
101 case -1: return 1; // Z
102 case 0: return 8; // B
103 default: return (i + (i & 1)) * 8;
104 }
105 }
106
107 static final String PRIMITIVE_SIGN_TABLE = "JZICSZB";
108 // "SuSuS S"
109 /** Return whether the given type is a signed integral type. */
110 public static boolean isSigned(Class<?> type) {
111 return isSigned(basicTypeChar(type));
112 }
113
114 /** Return whether the given type is a signed integral type. */
115 public static boolean isSigned(char c) {
116 int i = PRIMITIVE_SIGN_TABLE.indexOf(c);
117 return (i & 1) == 0;
118 }
119
120 /** Return whether the given type is a unsigned integral type. */
121 public static boolean isUnsigned(Class<?> type) {
122 return isUnsigned(basicTypeChar(type));
123 }
124
125 /** Return whether the given type is a unsigned integral type. */
126 public static boolean isUnsigned(char c) {
127 int i = PRIMITIVE_SIGN_TABLE.indexOf(c);
128 return (i & 0x11) == 1;
129 }
130
131 /** Return whether the given type is an integral type. */
132 public static boolean isIntegral(Class<?> type) {
133 return isIntegral(basicTypeChar(type));
134 }
135
136 /** Return whether the given type is an integral type. */
137 public static boolean isIntegral(char c) {
138 int i = PRIMITIVE_SIGN_TABLE.indexOf(c);
139 return i >= 0;
140 }
141
142 /** Report if the type is one of int, boolean, byte, char, or short. */
143 public static boolean isSubwordOrInt(Class<?> type) {
144 return isSubwordOrInt(basicTypeChar(type));
145 }
146
147 /** Report if the type char is one of "IZBCS". */
148 public static boolean isSubwordOrInt(char c) {
149 return PRIMITIVE_SIGN_TABLE.indexOf(c) > 0;
150 }
151
152 /** Return whether the given type is a floating primitive type. */
153 public static boolean isFloating(Class<?> type) {
154 return isFloating(basicTypeChar(type));
155 }
156
157 /** Return whether the given type is a floating primitive type. */
158 public static boolean isFloating(char c) {
159 return c == 'F' || c == 'D';
160 }
161
162 /** Return the primitive type that corresponds to the given bytecode
163 * signature character. Return {@code Object.class} for the character
164 * 'L', and null for any non-signature character or '['.
165 */
166 public static Class<?> basicTypeFromChar(char c) {
167 if (c == 'L') {
168 return Object.class;
169 }
170 // if (c == '[') {
171 // return Object[].class;
172 // }
173 if (wrappers.isEmpty()) {
174 fillWrappers();
175 }
176 Object[] memo = wrappers.get((Character)c);
177 if (memo == null)
178 return null; // random junk character
179 return (Class<?>) memo[1];
180 }
181
182 public static Object zeroValue(Class<?> type) {
183 if (!type.isPrimitive()) {
184 return null;
185 }
186 if (wrappers.isEmpty()) {
187 fillWrappers();
188 }
189 Object[] memo = wrappers.get(type);
190 assert (memo != null);
191 return memo[3];
192 }
193
194 public static <T> T wrap(Object x, Class<T> numClass) {
195 if (wrappers.isEmpty()) {
196 fillWrappers();
197 }
198 Object[] memo = wrappers.get(numClass);
199 if (memo == null) return numClass.cast(x); // no change
200 Class<T> wrapType = (Class<T>) memo[0]; // unchecked warning is OK here
201 return wrapType.cast(wrap(x, (Character) memo[2]));
202 }
203 public static Object wrap(Object x, char c) {
204 Number xn = numberValue(x);
205 switch (c) {
206 case 'I': return Integer.valueOf(xn.intValue());
207 case 'J': return Long.valueOf(xn.longValue());
208 case 'F': return Float.valueOf(xn.floatValue());
209 case 'D': return Double.valueOf(xn.doubleValue());
210 case 'S': return Short.valueOf((short) xn.intValue());
211 case 'B': return Byte.valueOf((byte) xn.intValue());
212 case 'C': return Character.valueOf((char) xn.intValue());
213 case 'Z': return Boolean.valueOf(boolValue(xn.longValue()));
214 case 'V': return null;
215 }
216 return xn;
217 }
218
219 private static Number numberValue(Object x) {
220 if (x instanceof Number) return (Number)x;
221 if (x instanceof Character) return (int)(Character)x;
222 if (x instanceof Boolean) return (Boolean)x ? 1 : 0;
223 // Remaining allowed case of void: Must be a null reference.
224 return (Number)x;
225 }
226 private static boolean boolValue(long bits) {
227 bits &= 1; // simple 31-bit zero extension
228 return (bits != 0);
229 }
230
231 private static final HashMap<Object, Object[]> wrappers
232 = new HashMap<Object, Object[]>(20);
233
234 private static void fillWrappers() {
235 Object[][] memos = {
236 {Boolean.class, Boolean.TYPE, 'Z', (Boolean) false},
237 {Character.class, Character.TYPE, 'C', (Character) '\000'},
238 {Byte.class, Byte.TYPE, 'B', (Byte) (byte) 0},
239 {Short.class, Short.TYPE, 'S', (Short) (short) 0},
240 {Integer.class, Integer.TYPE, 'I', (Integer) 0},
241 {Long.class, Long.TYPE, 'J', (Long) 0L},
242 {Float.class, Float.TYPE, 'F', (Float) 0.0F},
243 {Double.class, Double.TYPE, 'D', (Double) 0.0},
244 {Void.class, Void.TYPE, 'V', null}
245 };
246 for (Object[] memo : memos) {
247 wrappers.put(memo[0], memo);
248 wrappers.put(memo[1], memo);
249 wrappers.put(memo[2], memo);
250 }
251 }
252
253 // TO DO: Put these into a unit test.
254 private static Class<Integer> PTYPE = int.class, WTYPE = Integer.class;
255 static {
256 assert(PTYPE != WTYPE);
257 assert(asPrimitiveType(PTYPE) == PTYPE);
258 assert(asPrimitiveType(WTYPE) == PTYPE);
259 assert( asWrapperType(PTYPE) == WTYPE);
260 assert( asWrapperType(WTYPE) == WTYPE);
261
262 assert(bitWidth(String.class) == 0);
263 assert(bitWidth(Integer.class) == 0);
264 assert(bitWidth(int.class) == 32);
265 assert(bitWidth(char.class) == 16);
266 assert(bitWidth(short.class) == 16);
267 assert(bitWidth(byte.class) == 8);
268 assert(bitWidth(boolean.class) == 1);
269 assert(bitWidth(double.class) == 64);
270 assert(bitWidth(float.class) == 32);
271 }
272 }