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