• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.util;
18 
19 import java.util.Arrays;
20 
21 /**
22  * Simple list of <code>int</code>s.
23  */
24 public final class IntList extends MutabilityControl {
25     /** non-null; immutable, no-element instance */
26     public static final IntList EMPTY = new IntList(0);
27 
28     /** non-null; array of elements */
29     private int[] values;
30 
31     /** &gt;= 0; current size of the list */
32     private int size;
33 
34     /** whether the values are currently sorted */
35     private boolean sorted;
36 
37     static {
EMPTY.setImmutable()38         EMPTY.setImmutable();
39     }
40 
41     /**
42      * Constructs a new immutable instance with the given element.
43      *
44      * @param value the sole value in the list
45      */
makeImmutable(int value)46     public static IntList makeImmutable(int value) {
47         IntList result = new IntList(1);
48 
49         result.add(value);
50         result.setImmutable();
51 
52         return result;
53     }
54 
55     /**
56      * Constructs a new immutable instance with the given elements.
57      *
58      * @param value0 the first value in the list
59      * @param value1 the second value in the list
60      */
makeImmutable(int value0, int value1)61     public static IntList makeImmutable(int value0, int value1) {
62         IntList result = new IntList(2);
63 
64         result.add(value0);
65         result.add(value1);
66         result.setImmutable();
67 
68         return result;
69     }
70 
71     /**
72      * Constructs an empty instance with a default initial capacity.
73      */
IntList()74     public IntList() {
75         this(4);
76     }
77 
78     /**
79      * Constructs an empty instance.
80      *
81      * @param initialCapacity &gt;= 0; initial capacity of the list
82      */
IntList(int initialCapacity)83     public IntList(int initialCapacity) {
84         super(true);
85 
86         try {
87             values = new int[initialCapacity];
88         } catch (NegativeArraySizeException ex) {
89             // Translate the exception.
90             throw new IllegalArgumentException("size < 0");
91         }
92 
93         size = 0;
94         sorted = true;
95     }
96 
97     /** {@inheritDoc} */
98     @Override
hashCode()99     public int hashCode() {
100         int result = 0;
101 
102         for (int i = 0; i < size; i++) {
103             result = (result * 31) + values[i];
104         }
105 
106         return result;
107     }
108 
109     /** {@inheritDoc} */
110     @Override
equals(Object other)111     public boolean equals(Object other) {
112         if (other == this) {
113             return true;
114         }
115 
116         if (! (other instanceof IntList)) {
117             return false;
118         }
119 
120         IntList otherList = (IntList) other;
121 
122         if (sorted != otherList.sorted) {
123             return false;
124         }
125 
126         if (size != otherList.size) {
127             return false;
128         }
129 
130         for (int i = 0; i < size; i++) {
131             if (values[i] != otherList.values[i]) {
132                 return false;
133             }
134         }
135 
136         return true;
137     }
138 
139     /** {@inheritDoc} */
140     @Override
toString()141     public String toString() {
142         StringBuffer sb = new StringBuffer(size * 5 + 10);
143 
144         sb.append('{');
145 
146         for (int i = 0; i < size; i++) {
147             if (i != 0) {
148                 sb.append(", ");
149             }
150             sb.append(values[i]);
151         }
152 
153         sb.append('}');
154 
155         return sb.toString();
156     }
157 
158     /**
159      * Gets the number of elements in this list.
160      */
size()161     public int size() {
162         return size;
163     }
164 
165     /**
166      * Gets the indicated value.
167      *
168      * @param n &gt;= 0, &lt; size(); which element
169      * @return the indicated element's value
170      */
get(int n)171     public int get(int n) {
172         if (n >= size) {
173             throw new IndexOutOfBoundsException("n >= size()");
174         }
175 
176         try {
177             return values[n];
178         } catch (ArrayIndexOutOfBoundsException ex) {
179             // Translate exception.
180             throw new IndexOutOfBoundsException("n < 0");
181         }
182     }
183 
184     /**
185      * Sets the value at the given index.
186      *
187      * @param n &gt;= 0, &lt; size(); which element
188      * @param value value to store
189      */
set(int n, int value)190     public void set(int n, int value) {
191         throwIfImmutable();
192 
193         if (n >= size) {
194             throw new IndexOutOfBoundsException("n >= size()");
195         }
196 
197         try {
198             values[n] = value;
199             sorted = false;
200         } catch (ArrayIndexOutOfBoundsException ex) {
201             // Translate the exception.
202             if (n < 0) {
203                 throw new IllegalArgumentException("n < 0");
204             }
205         }
206     }
207 
208     /**
209      * Adds an element to the end of the list. This will increase the
210      * list's capacity if necessary.
211      *
212      * @param value the value to add
213      */
add(int value)214     public void add(int value) {
215         throwIfImmutable();
216 
217         growIfNeeded();
218 
219         values[size++] = value;
220 
221         if (sorted && (size > 1)) {
222             sorted = (value >= values[size - 2]);
223         }
224     }
225 
226     /**
227      * Inserts element into specified index, moving elements at and above
228      * that index up one. May not be used to insert at an index beyond the
229      * current size (that is, insertion as a last element is legal but
230      * no further).
231      *
232      * @param n &gt=0 &lt=size(); index of where to insert
233      * @param value value to insert
234      */
insert(int n, int value)235     public void insert(int n, int value) {
236         if (n > size) {
237             throw new IndexOutOfBoundsException("n > size()");
238         }
239 
240         growIfNeeded();
241 
242         System.arraycopy (values, n, values, n+1, size - n);
243         values[n] = value;
244         size++;
245 
246         sorted = sorted
247                 && (n == 0 || value > values[n-1])
248                 && (n == (size - 1) || value < values[n+1]);
249     }
250 
251     /**
252      * Removes an element at a given index, shifting elements at greater
253      * indicies down one.
254      *
255      * @param n  &gt=0 &lt size(); index of element to remove
256      */
removeIndex(int n)257     public void removeIndex(int n) {
258         if (n >= size) {
259             throw new IndexOutOfBoundsException("n >= size()");
260         }
261 
262         System.arraycopy (values, n + 1, values, n, size - n - 1);
263         size--;
264 
265         // sort status is unchanged
266     }
267 
268     /**
269      * Increases size of array if needed
270      */
growIfNeeded()271     private void growIfNeeded() {
272         if (size == values.length) {
273             // Resize.
274             int[] newv = new int[size * 3 / 2 + 10];
275             System.arraycopy(values, 0, newv, 0, size);
276             values = newv;
277         }
278     }
279 
280     /**
281      * Returns the last element in the array without modifying the array
282      *
283      * @return last value in the array.
284      * @exception IndexOutOfBoundsException if stack is empty.
285      */
top()286     public int top() {
287         return get(size - 1);
288     }
289 
290     /**
291      * Pops an element off the end of the list and decreasing the size by one.
292      *
293      * @return value from what was the last element.
294      * @exception IndexOutOfBoundsException if stack is empty.
295      */
pop()296     public int pop() {
297         throwIfImmutable();
298 
299         int result;
300 
301         result = get(size-1);
302         size--;
303 
304         return result;
305     }
306 
307     /**
308      * Pops N elements off the end of the list and decreasing the size by N.
309      *
310      * @param n &gt;= 0; number of elements to remove from end.
311      * @exception IndexOutOfBoundsException if stack is smaller than N
312      */
pop(int n)313     public void pop(int n) {
314         throwIfImmutable();
315 
316         size -= n;
317     }
318 
319     /**
320      * Shrinks the size of the list.
321      *
322      * @param newSize &gt;= 0; the new size
323      */
shrink(int newSize)324     public void shrink(int newSize) {
325         if (newSize < 0) {
326             throw new IllegalArgumentException("newSize < 0");
327         }
328 
329         if (newSize > size) {
330             throw new IllegalArgumentException("newSize > size");
331         }
332 
333         throwIfImmutable();
334 
335         size = newSize;
336     }
337 
338     /**
339      * Makes and returns a mutable copy of the list.
340      *
341      * @return non-null; an appropriately-constructed instance
342      */
mutableCopy()343     public IntList mutableCopy() {
344         int sz = size;
345         IntList result = new IntList(sz);
346 
347         for (int i = 0; i < sz; i++) {
348             result.add(values[i]);
349         }
350 
351         return result;
352     }
353 
354     /**
355      * Sorts the elements in the list in-place.
356      */
sort()357     public void sort() {
358         throwIfImmutable();
359 
360         if (!sorted) {
361             Arrays.sort(values, 0, size);
362             sorted = true;
363         }
364     }
365 
366     /**
367      * Returns the index of the given value, or -1 if the value does not
368      * appear in the list.  This will do a binary search if the list is
369      * sorted or a linear search if not.
370      * @param value value to find
371      * @return index of value or -1
372      */
indexOf(int value)373     public int indexOf(int value) {
374         int ret = binarysearch(value);
375 
376         return ret >= 0 ? ret : -1;
377 
378     }
379 
380     /**
381      * Performs a binary search on a sorted list, returning the index of
382      * the given value if it is present or
383      * <code>(-(insertion point) - 1)</code> if the value is not present.
384      * If the list is not sorted, then reverts to linear search and returns
385      * <code>-size()</code> if the element is not found.
386      *
387      * @param value value to find
388      * @return index of value or <code>(-(insertion point) - 1)</code> if the
389      * value is not present
390      */
binarysearch(int value)391     public int binarysearch(int value) {
392         int sz = size;
393 
394         if (!sorted) {
395             // Linear search.
396             for (int i = 0; i < sz; i++) {
397                 if (values[i] == value) {
398                     return i;
399                 }
400             }
401 
402             return -sz;
403         }
404 
405         /*
406          * Binary search. This variant does only one value comparison
407          * per iteration but does one more iteration on average than
408          * the variant that includes a value equality check per
409          * iteration.
410          */
411 
412         int min = -1;
413         int max = sz;
414 
415         while (max > (min + 1)) {
416             /*
417              * The guessIdx calculation is equivalent to ((min + max)
418              * / 2) but won't go wonky when min and max are close to
419              * Integer.MAX_VALUE.
420              */
421             int guessIdx = min + ((max - min) >> 1);
422             int guess = values[guessIdx];
423 
424             if (value <= guess) {
425                 max = guessIdx;
426             } else {
427                 min = guessIdx;
428             }
429         }
430 
431         if ((max != sz)) {
432             return (value == values[max]) ? max : (-max - 1);
433         } else {
434             return -sz - 1;
435         }
436     }
437 
438 
439     /**
440      * Returns whether or not the given value appears in the list.
441      * This will do a binary search if the list is sorted or a linear
442      * search if not.
443      *
444      * @see #sort
445      *
446      * @param value value to look for
447      * @return whether the list contains the given value
448      */
contains(int value)449     public boolean contains(int value) {
450         return indexOf(value) >= 0;
451     }
452 }
453