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.type;
18
19import com.android.dx.util.FixedSizeList;
20
21/**
22 * Standard implementation of {@link TypeList}.
23 */
24public final class StdTypeList
25        extends FixedSizeList implements TypeList {
26    /** {@code non-null;} no-element instance */
27    public static final StdTypeList EMPTY = new StdTypeList(0);
28
29    /** {@code non-null;} the list {@code [int]} */
30    public static final StdTypeList INT = StdTypeList.make(Type.INT);
31
32    /** {@code non-null;} the list {@code [long]} */
33    public static final StdTypeList LONG = StdTypeList.make(Type.LONG);
34
35    /** {@code non-null;} the list {@code [float]} */
36    public static final StdTypeList FLOAT = StdTypeList.make(Type.FLOAT);
37
38    /** {@code non-null;} the list {@code [double]} */
39    public static final StdTypeList DOUBLE = StdTypeList.make(Type.DOUBLE);
40
41    /** {@code non-null;} the list {@code [Object]} */
42    public static final StdTypeList OBJECT = StdTypeList.make(Type.OBJECT);
43
44    /** {@code non-null;} the list {@code [ReturnAddress]} */
45    public static final StdTypeList RETURN_ADDRESS
46            = StdTypeList.make(Type.RETURN_ADDRESS);
47
48    /** {@code non-null;} the list {@code [Throwable]} */
49    public static final StdTypeList THROWABLE =
50        StdTypeList.make(Type.THROWABLE);
51
52    /** {@code non-null;} the list {@code [int, int]} */
53    public static final StdTypeList INT_INT =
54        StdTypeList.make(Type.INT, Type.INT);
55
56    /** {@code non-null;} the list {@code [long, long]} */
57    public static final StdTypeList LONG_LONG =
58        StdTypeList.make(Type.LONG, Type.LONG);
59
60    /** {@code non-null;} the list {@code [float, float]} */
61    public static final StdTypeList FLOAT_FLOAT =
62        StdTypeList.make(Type.FLOAT, Type.FLOAT);
63
64    /** {@code non-null;} the list {@code [double, double]} */
65    public static final StdTypeList DOUBLE_DOUBLE =
66        StdTypeList.make(Type.DOUBLE, Type.DOUBLE);
67
68    /** {@code non-null;} the list {@code [Object, Object]} */
69    public static final StdTypeList OBJECT_OBJECT =
70        StdTypeList.make(Type.OBJECT, Type.OBJECT);
71
72    /** {@code non-null;} the list {@code [int, Object]} */
73    public static final StdTypeList INT_OBJECT =
74        StdTypeList.make(Type.INT, Type.OBJECT);
75
76    /** {@code non-null;} the list {@code [long, Object]} */
77    public static final StdTypeList LONG_OBJECT =
78        StdTypeList.make(Type.LONG, Type.OBJECT);
79
80    /** {@code non-null;} the list {@code [float, Object]} */
81    public static final StdTypeList FLOAT_OBJECT =
82        StdTypeList.make(Type.FLOAT, Type.OBJECT);
83
84    /** {@code non-null;} the list {@code [double, Object]} */
85    public static final StdTypeList DOUBLE_OBJECT =
86        StdTypeList.make(Type.DOUBLE, Type.OBJECT);
87
88    /** {@code non-null;} the list {@code [long, int]} */
89    public static final StdTypeList LONG_INT =
90        StdTypeList.make(Type.LONG, Type.INT);
91
92    /** {@code non-null;} the list {@code [int[], int]} */
93    public static final StdTypeList INTARR_INT =
94        StdTypeList.make(Type.INT_ARRAY, Type.INT);
95
96    /** {@code non-null;} the list {@code [long[], int]} */
97    public static final StdTypeList LONGARR_INT =
98        StdTypeList.make(Type.LONG_ARRAY, Type.INT);
99
100    /** {@code non-null;} the list {@code [float[], int]} */
101    public static final StdTypeList FLOATARR_INT =
102        StdTypeList.make(Type.FLOAT_ARRAY, Type.INT);
103
104    /** {@code non-null;} the list {@code [double[], int]} */
105    public static final StdTypeList DOUBLEARR_INT =
106        StdTypeList.make(Type.DOUBLE_ARRAY, Type.INT);
107
108    /** {@code non-null;} the list {@code [Object[], int]} */
109    public static final StdTypeList OBJECTARR_INT =
110        StdTypeList.make(Type.OBJECT_ARRAY, Type.INT);
111
112    /** {@code non-null;} the list {@code [boolean[], int]} */
113    public static final StdTypeList BOOLEANARR_INT =
114        StdTypeList.make(Type.BOOLEAN_ARRAY, Type.INT);
115
116    /** {@code non-null;} the list {@code [byte[], int]} */
117    public static final StdTypeList BYTEARR_INT =
118        StdTypeList.make(Type.BYTE_ARRAY, Type.INT);
119
120    /** {@code non-null;} the list {@code [char[], int]} */
121    public static final StdTypeList CHARARR_INT =
122        StdTypeList.make(Type.CHAR_ARRAY, Type.INT);
123
124    /** {@code non-null;} the list {@code [short[], int]} */
125    public static final StdTypeList SHORTARR_INT =
126        StdTypeList.make(Type.SHORT_ARRAY, Type.INT);
127
128    /** {@code non-null;} the list {@code [int, int[], int]} */
129    public static final StdTypeList INT_INTARR_INT =
130        StdTypeList.make(Type.INT, Type.INT_ARRAY, Type.INT);
131
132    /** {@code non-null;} the list {@code [long, long[], int]} */
133    public static final StdTypeList LONG_LONGARR_INT =
134        StdTypeList.make(Type.LONG, Type.LONG_ARRAY, Type.INT);
135
136    /** {@code non-null;} the list {@code [float, float[], int]} */
137    public static final StdTypeList FLOAT_FLOATARR_INT =
138        StdTypeList.make(Type.FLOAT, Type.FLOAT_ARRAY, Type.INT);
139
140    /** {@code non-null;} the list {@code [double, double[], int]} */
141    public static final StdTypeList DOUBLE_DOUBLEARR_INT =
142        StdTypeList.make(Type.DOUBLE, Type.DOUBLE_ARRAY, Type.INT);
143
144    /** {@code non-null;} the list {@code [Object, Object[], int]} */
145    public static final StdTypeList OBJECT_OBJECTARR_INT =
146        StdTypeList.make(Type.OBJECT, Type.OBJECT_ARRAY, Type.INT);
147
148    /** {@code non-null;} the list {@code [int, boolean[], int]} */
149    public static final StdTypeList INT_BOOLEANARR_INT =
150        StdTypeList.make(Type.INT, Type.BOOLEAN_ARRAY, Type.INT);
151
152    /** {@code non-null;} the list {@code [int, byte[], int]} */
153    public static final StdTypeList INT_BYTEARR_INT =
154        StdTypeList.make(Type.INT, Type.BYTE_ARRAY, Type.INT);
155
156    /** {@code non-null;} the list {@code [int, char[], int]} */
157    public static final StdTypeList INT_CHARARR_INT =
158        StdTypeList.make(Type.INT, Type.CHAR_ARRAY, Type.INT);
159
160    /** {@code non-null;} the list {@code [int, short[], int]} */
161    public static final StdTypeList INT_SHORTARR_INT =
162        StdTypeList.make(Type.INT, Type.SHORT_ARRAY, Type.INT);
163
164    /**
165     * Makes a single-element instance.
166     *
167     * @param type {@code non-null;} the element
168     * @return {@code non-null;} an appropriately-constructed instance
169     */
170    public static StdTypeList make(Type type) {
171        StdTypeList result = new StdTypeList(1);
172        result.set(0, type);
173        return result;
174    }
175
176    /**
177     * Makes a two-element instance.
178     *
179     * @param type0 {@code non-null;} the first element
180     * @param type1 {@code non-null;} the second element
181     * @return {@code non-null;} an appropriately-constructed instance
182     */
183    public static StdTypeList make(Type type0, Type type1) {
184        StdTypeList result = new StdTypeList(2);
185        result.set(0, type0);
186        result.set(1, type1);
187        return result;
188    }
189
190    /**
191     * Makes a three-element instance.
192     *
193     * @param type0 {@code non-null;} the first element
194     * @param type1 {@code non-null;} the second element
195     * @param type2 {@code non-null;} the third element
196     * @return {@code non-null;} an appropriately-constructed instance
197     */
198    public static StdTypeList make(Type type0, Type type1, Type type2) {
199        StdTypeList result = new StdTypeList(3);
200        result.set(0, type0);
201        result.set(1, type1);
202        result.set(2, type2);
203        return result;
204    }
205
206    /**
207     * Makes a four-element instance.
208     *
209     * @param type0 {@code non-null;} the first element
210     * @param type1 {@code non-null;} the second element
211     * @param type2 {@code non-null;} the third element
212     * @param type3 {@code non-null;} the fourth element
213     * @return {@code non-null;} an appropriately-constructed instance
214     */
215    public static StdTypeList make(Type type0, Type type1, Type type2,
216                                   Type type3) {
217        StdTypeList result = new StdTypeList(4);
218        result.set(0, type0);
219        result.set(1, type1);
220        result.set(2, type2);
221        result.set(3, type3);
222        return result;
223    }
224
225    /**
226     * Returns the given list as a comma-separated list of human forms. This
227     * is a static method so as to work on arbitrary {@link TypeList}
228     * instances.
229     *
230     * @param list {@code non-null;} the list to convert
231     * @return {@code non-null;} the human form
232     */
233    public static String toHuman(TypeList list) {
234        int size = list.size();
235
236        if (size == 0) {
237            return "<empty>";
238        }
239
240        StringBuffer sb = new StringBuffer(100);
241
242        for (int i = 0; i < size; i++) {
243            if (i != 0) {
244                sb.append(", ");
245            }
246            sb.append(list.getType(i).toHuman());
247        }
248
249        return sb.toString();
250    }
251
252    /**
253     * Returns a hashcode of the contents of the given list. This
254     * is a static method so as to work on arbitrary {@link TypeList}
255     * instances.
256     *
257     * @param list {@code non-null;} the list to inspect
258     * @return {@code non-null;} the hash code
259     */
260    public static int hashContents(TypeList list) {
261        int size = list.size();
262        int hash = 0;
263
264        for (int i = 0; i < size; i++) {
265            hash = (hash * 31) + list.getType(i).hashCode();
266        }
267
268        return hash;
269    }
270
271    /**
272     * Compares the contents of the given two instances for equality. This
273     * is a static method so as to work on arbitrary {@link TypeList}
274     * instances.
275     *
276     * @param list1 {@code non-null;} one list to compare
277     * @param list2 {@code non-null;} another list to compare
278     * @return whether the two lists contain corresponding equal elements
279     */
280    public static boolean equalContents(TypeList list1, TypeList list2) {
281        int size = list1.size();
282
283        if (list2.size() != size) {
284            return false;
285        }
286
287        for (int i = 0; i < size; i++) {
288            if (! list1.getType(i).equals(list2.getType(i))) {
289                return false;
290            }
291        }
292
293        return true;
294    }
295
296    /**
297     * Compares the contents of the given two instances for ordering. This
298     * is a static method so as to work on arbitrary {@link TypeList}
299     * instances.
300     *
301     * @param list1 {@code non-null;} one list to compare
302     * @param list2 {@code non-null;} another list to compare
303     * @return the order of the two lists
304     */
305    public static int compareContents(TypeList list1, TypeList list2) {
306        int size1 = list1.size();
307        int size2 = list2.size();
308        int size = Math.min(size1, size2);
309
310        for (int i = 0; i < size; i++) {
311            int comparison = list1.getType(i).compareTo(list2.getType(i));
312            if (comparison != 0) {
313                return comparison;
314            }
315        }
316
317        if (size1 == size2) {
318            return 0;
319        } else if (size1 < size2) {
320            return -1;
321        } else {
322            return 1;
323        }
324    }
325
326    /**
327     * Constructs an instance. All indices initially contain {@code null}.
328     *
329     * @param size the size of the list
330     */
331    public StdTypeList(int size) {
332        super(size);
333    }
334
335    /** {@inheritDoc} */
336    public Type getType(int n) {
337        return get(n);
338    }
339
340    /** {@inheritDoc} */
341    public int getWordCount() {
342        int sz = size();
343        int result = 0;
344
345        for (int i = 0; i < sz; i++) {
346            result += get(i).getCategory();
347        }
348
349        return result;
350    }
351
352    /** {@inheritDoc} */
353    public TypeList withAddedType(Type type) {
354        int sz = size();
355        StdTypeList result = new StdTypeList(sz + 1);
356
357        for (int i = 0; i < sz; i++) {
358            result.set0(i, get0(i));
359        }
360
361        result.set(sz, type);
362        result.setImmutable();
363        return result;
364    }
365
366    /**
367     * Gets the indicated element. It is an error to call this with the
368     * index for an element which was never set; if you do that, this
369     * will throw {@code NullPointerException}.
370     *
371     * @param n {@code >= 0, < size();} which element
372     * @return {@code non-null;} the indicated element
373     */
374    public Type get(int n) {
375        return (Type) get0(n);
376    }
377
378    /**
379     * Sets the type at the given index.
380     *
381     * @param n {@code >= 0, < size();} which element
382     * @param type {@code non-null;} the type to store
383     */
384    public void set(int n, Type type) {
385        set0(n, type);
386    }
387
388    /**
389     * Returns a new instance, which is the same as this instance,
390     * except that it has an additional type prepended to the
391     * original.
392     *
393     * @param type {@code non-null;} the new first element
394     * @return {@code non-null;} an appropriately-constructed instance
395     */
396    public StdTypeList withFirst(Type type) {
397        int sz = size();
398        StdTypeList result = new StdTypeList(sz + 1);
399
400        result.set0(0, type);
401        for (int i = 0; i < sz; i++) {
402            result.set0(i + 1, getOrNull0(i));
403        }
404
405        return result;
406    }
407}
408