View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   https://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.commons.compress.harmony.pack200;
20  
21  import java.util.Arrays;
22  
23  /**
24   * IntList is based on {@link java.util.ArrayList}, but is written specifically for ints in order to reduce boxing and unboxing to Integers, reduce the memory
25   * required and improve performance of pack200.
26   */
27  public class IntList {
28  
29      private int[] array;
30      private int firstIndex;
31      private int lastIndex;
32      private int modCount;
33  
34      /**
35       * Constructs a new instance of IntList with capacity for ten elements.
36       */
37      public IntList() {
38          this(10);
39      }
40  
41      /**
42       * Constructs a new instance of IntList with the specified capacity.
43       *
44       * @param capacity the initial capacity of this IntList
45       */
46      public IntList(final int capacity) {
47          if (capacity < 0) {
48              throw new IllegalArgumentException();
49          }
50          firstIndex = lastIndex = 0;
51          array = new int[capacity];
52      }
53  
54      /**
55       * Adds the specified object at the end of this IntList.
56       *
57       * @param object the object to add
58       * @return true
59       */
60      public boolean add(final int object) {
61          if (lastIndex == array.length) {
62              growAtEnd(1);
63          }
64          array[lastIndex++] = object;
65          modCount++;
66          return true;
67      }
68  
69      public void add(final int location, final int object) {
70          final int size = lastIndex - firstIndex;
71          if (0 < location && location < size) {
72              if (firstIndex == 0 && lastIndex == array.length) {
73                  growForInsert(location, 1);
74              } else if (location < size / 2 && firstIndex > 0 || lastIndex == array.length) {
75                  System.arraycopy(array, firstIndex, array, --firstIndex, location);
76              } else {
77                  final int index = location + firstIndex;
78                  System.arraycopy(array, index, array, index + 1, size - location);
79                  lastIndex++;
80              }
81              array[location + firstIndex] = object;
82          } else if (location == 0) {
83              if (firstIndex == 0) {
84                  growAtFront(1);
85              }
86              array[--firstIndex] = object;
87          } else if (location == size) {
88              if (lastIndex == array.length) {
89                  growAtEnd(1);
90              }
91              array[lastIndex++] = object;
92          } else {
93              throw new IndexOutOfBoundsException();
94          }
95  
96          modCount++;
97      }
98  
99      public void addAll(final IntList list) {
100         growAtEnd(list.size());
101         for (int i = 0; i < list.size(); i++) {
102             add(list.get(i));
103         }
104     }
105 
106     public void clear() {
107         if (firstIndex != lastIndex) {
108             Arrays.fill(array, firstIndex, lastIndex, -1);
109             firstIndex = lastIndex = 0;
110             modCount++;
111         }
112     }
113 
114     public int get(final int location) {
115         if (0 <= location && location < lastIndex - firstIndex) {
116             return array[firstIndex + location];
117         }
118         throw new IndexOutOfBoundsException("" + location);
119     }
120 
121     private void growAtEnd(final int required) {
122         final int size = lastIndex - firstIndex;
123         if (firstIndex >= required - (array.length - lastIndex)) {
124             final int newLast = lastIndex - firstIndex;
125             if (size > 0) {
126                 System.arraycopy(array, firstIndex, array, 0, size);
127             }
128             firstIndex = 0;
129             lastIndex = newLast;
130         } else {
131             int increment = size / 2;
132             if (required > increment) {
133                 increment = required;
134             }
135             if (increment < 12) {
136                 increment = 12;
137             }
138             final int[] newArray = new int[size + increment];
139             if (size > 0) {
140                 System.arraycopy(array, firstIndex, newArray, 0, size);
141                 firstIndex = 0;
142                 lastIndex = size;
143             }
144             array = newArray;
145         }
146     }
147 
148     private void growAtFront(final int required) {
149         final int size = lastIndex - firstIndex;
150         if (array.length - lastIndex + firstIndex >= required) {
151             final int newFirst = array.length - size;
152             if (size > 0) {
153                 System.arraycopy(array, firstIndex, array, newFirst, size);
154             }
155             firstIndex = newFirst;
156             lastIndex = array.length;
157         } else {
158             int increment = size / 2;
159             if (required > increment) {
160                 increment = required;
161             }
162             if (increment < 12) {
163                 increment = 12;
164             }
165             final int[] newArray = new int[size + increment];
166             if (size > 0) {
167                 System.arraycopy(array, firstIndex, newArray, newArray.length - size, size);
168             }
169             firstIndex = newArray.length - size;
170             lastIndex = newArray.length;
171             array = newArray;
172         }
173     }
174 
175     private void growForInsert(final int location, final int required) {
176         final int size = lastIndex - firstIndex;
177         int increment = size / 2;
178         if (required > increment) {
179             increment = required;
180         }
181         if (increment < 12) {
182             increment = 12;
183         }
184         final int[] newArray = new int[size + increment];
185         final int newFirst = increment - required;
186         // Copy elements after location to the new array skipping inserted
187         // elements
188         System.arraycopy(array, location + firstIndex, newArray, newFirst + location + required, size - location);
189         // Copy elements before location to the new array from firstIndex
190         System.arraycopy(array, firstIndex, newArray, newFirst, location);
191         firstIndex = newFirst;
192         lastIndex = size + increment;
193 
194         array = newArray;
195     }
196 
197     public void increment(final int location) {
198         if (0 > location || location >= lastIndex - firstIndex) {
199             throw new IndexOutOfBoundsException("" + location);
200         }
201         array[firstIndex + location]++;
202     }
203 
204     public boolean isEmpty() {
205         return lastIndex == firstIndex;
206     }
207 
208     public int remove(final int location) {
209         final int result;
210         final int size = lastIndex - firstIndex;
211         if (0 > location || location >= size) {
212             throw new IndexOutOfBoundsException();
213         }
214         if (location == size - 1) {
215             result = array[--lastIndex];
216             array[lastIndex] = 0;
217         } else if (location == 0) {
218             result = array[firstIndex];
219             array[firstIndex++] = 0;
220         } else {
221             final int elementIndex = firstIndex + location;
222             result = array[elementIndex];
223             if (location < size / 2) {
224                 System.arraycopy(array, firstIndex, array, firstIndex + 1, location);
225                 array[firstIndex++] = 0;
226             } else {
227                 System.arraycopy(array, elementIndex + 1, array, elementIndex, size - location - 1);
228                 array[--lastIndex] = 0;
229             }
230         }
231         if (firstIndex == lastIndex) {
232             firstIndex = lastIndex = 0;
233         }
234 
235         modCount++;
236         return result;
237     }
238 
239     public int size() {
240         return lastIndex - firstIndex;
241     }
242 
243     public int[] toArray() {
244         final int size = lastIndex - firstIndex;
245         final int[] result = new int[size];
246         System.arraycopy(array, firstIndex, result, 0, size);
247         return result;
248     }
249 
250 }