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.dexgen.rop.cst;
18
19import com.android.dexgen.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     * Returns an interned instance of this class for the given
138     * {@code Class} instance.
139     *
140     * @param clazz {@code non-null;} the underlying {@code Class} object
141     * @return {@code non-null;} an appropriately-constructed instance
142     */
143    public static CstType intern(Class clazz) {
144        return intern(Type.intern(clazz));
145    }
146
147    /**
148     * Constructs an instance.
149     *
150     * @param type {@code non-null;} the underlying type
151     */
152    public CstType(Type type) {
153        if (type == null) {
154            throw new NullPointerException("type == null");
155        }
156
157        if (type == type.KNOWN_NULL) {
158            throw new UnsupportedOperationException(
159                    "KNOWN_NULL is not representable");
160        }
161
162        this.type = type;
163        this.descriptor = null;
164    }
165
166    /** {@inheritDoc} */
167    @Override
168    public boolean equals(Object other) {
169        if (!(other instanceof CstType)) {
170            return false;
171        }
172
173        return type == ((CstType) other).type;
174    }
175
176    /** {@inheritDoc} */
177    @Override
178    public int hashCode() {
179        return type.hashCode();
180    }
181
182    /** {@inheritDoc} */
183    @Override
184    protected int compareTo0(Constant other) {
185        String thisDescriptor = type.getDescriptor();
186        String otherDescriptor = ((CstType) other).type.getDescriptor();
187        return thisDescriptor.compareTo(otherDescriptor);
188    }
189
190    /** {@inheritDoc} */
191    @Override
192    public String toString() {
193        return "type{" + toHuman() + '}';
194    }
195
196    /** {@inheritDoc} */
197    public Type getType() {
198        return Type.CLASS;
199    }
200
201    /** {@inheritDoc} */
202    @Override
203    public String typeName() {
204        return "type";
205    }
206
207    /** {@inheritDoc} */
208    @Override
209    public boolean isCategory2() {
210        return false;
211    }
212
213    /** {@inheritDoc} */
214    public String toHuman() {
215        return type.toHuman();
216    }
217
218    /**
219     * Gets the underlying type (as opposed to the type corresponding
220     * to this instance as a constant, which is always
221     * {@code Class}).
222     *
223     * @return {@code non-null;} the type corresponding to the name
224     */
225    public Type getClassType() {
226        return type;
227    }
228
229    /**
230     * Gets the type descriptor for this instance.
231     *
232     * @return {@code non-null;} the descriptor
233     */
234    public CstUtf8 getDescriptor() {
235        if (descriptor == null) {
236            descriptor = new CstUtf8(type.getDescriptor());
237        }
238
239        return descriptor;
240    }
241}