1 /*
2  * Copyright (C) 2012 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.inputmethod.latin.common;
18 
19 import com.android.inputmethod.annotations.UsedForTesting;
20 
21 import java.util.Arrays;
22 
23 import javax.annotation.Nonnull;
24 
25 // TODO: This class is not thread-safe.
26 public final class ResizableIntArray {
27     @Nonnull
28     private int[] mArray;
29     private int mLength;
30 
ResizableIntArray(final int capacity)31     public ResizableIntArray(final int capacity) {
32         reset(capacity);
33     }
34 
get(final int index)35     public int get(final int index) {
36         if (index < mLength) {
37             return mArray[index];
38         }
39         throw new ArrayIndexOutOfBoundsException("length=" + mLength + "; index=" + index);
40     }
41 
addAt(final int index, final int val)42     public void addAt(final int index, final int val) {
43         if (index < mLength) {
44             mArray[index] = val;
45         } else {
46             mLength = index;
47             add(val);
48         }
49     }
50 
add(final int val)51     public void add(final int val) {
52         final int currentLength = mLength;
53         ensureCapacity(currentLength + 1);
54         mArray[currentLength] = val;
55         mLength = currentLength + 1;
56     }
57 
58     /**
59      * Calculate the new capacity of {@code mArray}.
60      * @param minimumCapacity the minimum capacity that the {@code mArray} should have.
61      * @return the new capacity that the {@code mArray} should have. Returns zero when there is no
62      * need to expand {@code mArray}.
63      */
calculateCapacity(final int minimumCapacity)64     private int calculateCapacity(final int minimumCapacity) {
65         final int currentCapcity = mArray.length;
66         if (currentCapcity < minimumCapacity) {
67             final int nextCapacity = currentCapcity * 2;
68             // The following is the same as return Math.max(minimumCapacity, nextCapacity);
69             return minimumCapacity > nextCapacity ? minimumCapacity : nextCapacity;
70         }
71         return 0;
72     }
73 
ensureCapacity(final int minimumCapacity)74     private void ensureCapacity(final int minimumCapacity) {
75         final int newCapacity = calculateCapacity(minimumCapacity);
76         if (newCapacity > 0) {
77             // TODO: Implement primitive array pool.
78             mArray = Arrays.copyOf(mArray, newCapacity);
79         }
80     }
81 
getLength()82     public int getLength() {
83         return mLength;
84     }
85 
setLength(final int newLength)86     public void setLength(final int newLength) {
87         ensureCapacity(newLength);
88         mLength = newLength;
89     }
90 
reset(final int capacity)91     public void reset(final int capacity) {
92         // TODO: Implement primitive array pool.
93         mArray = new int[capacity];
94         mLength = 0;
95     }
96 
97     @Nonnull
getPrimitiveArray()98     public int[] getPrimitiveArray() {
99         return mArray;
100     }
101 
set(@onnull final ResizableIntArray ip)102     public void set(@Nonnull final ResizableIntArray ip) {
103         // TODO: Implement primitive array pool.
104         mArray = ip.mArray;
105         mLength = ip.mLength;
106     }
107 
copy(@onnull final ResizableIntArray ip)108     public void copy(@Nonnull final ResizableIntArray ip) {
109         final int newCapacity = calculateCapacity(ip.mLength);
110         if (newCapacity > 0) {
111             // TODO: Implement primitive array pool.
112             mArray = new int[newCapacity];
113         }
114         System.arraycopy(ip.mArray, 0, mArray, 0, ip.mLength);
115         mLength = ip.mLength;
116     }
117 
append(@onnull final ResizableIntArray src, final int startPos, final int length)118     public void append(@Nonnull final ResizableIntArray src, final int startPos, final int length) {
119         if (length == 0) {
120             return;
121         }
122         final int currentLength = mLength;
123         final int newLength = currentLength + length;
124         ensureCapacity(newLength);
125         System.arraycopy(src.mArray, startPos, mArray, currentLength, length);
126         mLength = newLength;
127     }
128 
fill(final int value, final int startPos, final int length)129     public void fill(final int value, final int startPos, final int length) {
130         if (startPos < 0 || length < 0) {
131             throw new IllegalArgumentException("startPos=" + startPos + "; length=" + length);
132         }
133         final int endPos = startPos + length;
134         ensureCapacity(endPos);
135         Arrays.fill(mArray, startPos, endPos, value);
136         if (mLength < endPos) {
137             mLength = endPos;
138         }
139     }
140 
141     /**
142      * Shift to the left by elementCount, discarding elementCount pointers at the start.
143      * @param elementCount how many elements to shift.
144      */
145     @UsedForTesting
shift(final int elementCount)146     public void shift(final int elementCount) {
147         System.arraycopy(mArray, elementCount, mArray, 0, mLength - elementCount);
148         mLength -= elementCount;
149     }
150 
151     @Override
toString()152     public String toString() {
153         final StringBuilder sb = new StringBuilder();
154         for (int i = 0; i < mLength; i++) {
155             if (i != 0) {
156                 sb.append(",");
157             }
158             sb.append(mArray[i]);
159         }
160         return "[" + sb + "]";
161     }
162 }
163