19370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka/*
29370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka * Copyright (C) 2012 The Android Open Source Project
39370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka *
48aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License");
58aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * you may not use this file except in compliance with the License.
68aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * You may obtain a copy of the License at
79370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka *
88aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka *      http://www.apache.org/licenses/LICENSE-2.0
99370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka *
109370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka * Unless required by applicable law or agreed to in writing, software
118aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS,
128aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * See the License for the specific language governing permissions and
148aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * limitations under the License.
159370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka */
169370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka
1736799b2aa2982ec17341cd2c5ed81e608bcee8c6Jean Chalardpackage com.android.inputmethod.latin.common;
189370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka
1954bf24f64b9bbd4c5e4b6d4c3c6144c047d6ddc6Mohammadinamul Sheikimport com.android.inputmethod.annotations.UsedForTesting;
2054bf24f64b9bbd4c5e4b6d4c3c6144c047d6ddc6Mohammadinamul Sheik
219370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaokaimport java.util.Arrays;
229370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka
23519df535996427c87242f8dbdd5993c6ab5a87d0Tadashi G. Takaokaimport javax.annotation.Nonnull;
24519df535996427c87242f8dbdd5993c6ab5a87d0Tadashi G. Takaoka
259370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka// TODO: This class is not thread-safe.
26a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaokapublic final class ResizableIntArray {
27519df535996427c87242f8dbdd5993c6ab5a87d0Tadashi G. Takaoka    @Nonnull
289370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka    private int[] mArray;
299370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka    private int mLength;
309370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka
31c49c85f835ecd14d09abb6d88c85a3303c566741Tadashi G. Takaoka    public ResizableIntArray(final int capacity) {
329370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka        reset(capacity);
339370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka    }
349370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka
35c49c85f835ecd14d09abb6d88c85a3303c566741Tadashi G. Takaoka    public int get(final int index) {
367abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka        if (index < mLength) {
377abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka            return mArray[index];
38c49c85f835ecd14d09abb6d88c85a3303c566741Tadashi G. Takaoka        }
397abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka        throw new ArrayIndexOutOfBoundsException("length=" + mLength + "; index=" + index);
40c49c85f835ecd14d09abb6d88c85a3303c566741Tadashi G. Takaoka    }
41c49c85f835ecd14d09abb6d88c85a3303c566741Tadashi G. Takaoka
42ad78058a93492d4f114c6a6eb56177be9231a9ebTadashi G. Takaoka    public void addAt(final int index, final int val) {
437abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka        if (index < mLength) {
447abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka            mArray[index] = val;
457abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka        } else {
469370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka            mLength = index;
479370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka            add(val);
489370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka        }
499370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka    }
509370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka
51c49c85f835ecd14d09abb6d88c85a3303c566741Tadashi G. Takaoka    public void add(final int val) {
527abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka        final int currentLength = mLength;
537abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka        ensureCapacity(currentLength + 1);
547abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka        mArray[currentLength] = val;
557abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka        mLength = currentLength + 1;
567abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka    }
577abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka
587abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka    /**
597abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka     * Calculate the new capacity of {@code mArray}.
607abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka     * @param minimumCapacity the minimum capacity that the {@code mArray} should have.
617abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka     * @return the new capacity that the {@code mArray} should have. Returns zero when there is no
627abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka     * need to expand {@code mArray}.
637abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka     */
647abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka    private int calculateCapacity(final int minimumCapacity) {
657abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka        final int currentCapcity = mArray.length;
667abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka        if (currentCapcity < minimumCapacity) {
677abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka            final int nextCapacity = currentCapcity * 2;
687abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka            // The following is the same as return Math.max(minimumCapacity, nextCapacity);
697abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka            return minimumCapacity > nextCapacity ? minimumCapacity : nextCapacity;
707abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka        }
717abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka        return 0;
729370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka    }
739370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka
74c49c85f835ecd14d09abb6d88c85a3303c566741Tadashi G. Takaoka    private void ensureCapacity(final int minimumCapacity) {
757abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka        final int newCapacity = calculateCapacity(minimumCapacity);
767abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka        if (newCapacity > 0) {
779370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka            // TODO: Implement primitive array pool.
787abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka            mArray = Arrays.copyOf(mArray, newCapacity);
799370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka        }
809370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka    }
819370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka
829370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka    public int getLength() {
839370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka        return mLength;
849370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka    }
859370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka
86c49c85f835ecd14d09abb6d88c85a3303c566741Tadashi G. Takaoka    public void setLength(final int newLength) {
87c49c85f835ecd14d09abb6d88c85a3303c566741Tadashi G. Takaoka        ensureCapacity(newLength);
88c49c85f835ecd14d09abb6d88c85a3303c566741Tadashi G. Takaoka        mLength = newLength;
89c49c85f835ecd14d09abb6d88c85a3303c566741Tadashi G. Takaoka    }
909370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka
91c49c85f835ecd14d09abb6d88c85a3303c566741Tadashi G. Takaoka    public void reset(final int capacity) {
929370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka        // TODO: Implement primitive array pool.
939370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka        mArray = new int[capacity];
949370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka        mLength = 0;
959370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka    }
969370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka
97519df535996427c87242f8dbdd5993c6ab5a87d0Tadashi G. Takaoka    @Nonnull
989370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka    public int[] getPrimitiveArray() {
999370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka        return mArray;
1009370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka    }
1019370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka
102519df535996427c87242f8dbdd5993c6ab5a87d0Tadashi G. Takaoka    public void set(@Nonnull final ResizableIntArray ip) {
1039370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka        // TODO: Implement primitive array pool.
1049370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka        mArray = ip.mArray;
1059370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka        mLength = ip.mLength;
1069370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka    }
1079370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka
108519df535996427c87242f8dbdd5993c6ab5a87d0Tadashi G. Takaoka    public void copy(@Nonnull final ResizableIntArray ip) {
1097abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka        final int newCapacity = calculateCapacity(ip.mLength);
1107abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka        if (newCapacity > 0) {
1117abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka            // TODO: Implement primitive array pool.
1127abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka            mArray = new int[newCapacity];
1137abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka        }
1149370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka        System.arraycopy(ip.mArray, 0, mArray, 0, ip.mLength);
1159370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka        mLength = ip.mLength;
1169370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka    }
1179370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka
118519df535996427c87242f8dbdd5993c6ab5a87d0Tadashi G. Takaoka    public void append(@Nonnull final ResizableIntArray src, final int startPos, final int length) {
1197abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka        if (length == 0) {
1207abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka            return;
1217abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka        }
1229370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka        final int currentLength = mLength;
1239370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka        final int newLength = currentLength + length;
1249370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka        ensureCapacity(newLength);
1259370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka        System.arraycopy(src.mArray, startPos, mArray, currentLength, length);
1269370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka        mLength = newLength;
1279370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka    }
1287abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka
1297abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka    public void fill(final int value, final int startPos, final int length) {
1307abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka        if (startPos < 0 || length < 0) {
1317abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka            throw new IllegalArgumentException("startPos=" + startPos + "; length=" + length);
1327abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka        }
1337abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka        final int endPos = startPos + length;
1347abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka        ensureCapacity(endPos);
1357abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka        Arrays.fill(mArray, startPos, endPos, value);
1367abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka        if (mLength < endPos) {
1377abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka            mLength = endPos;
1387abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka        }
1397abdcf1ed3113d3c121f6ff1b87a7464f079e141Tadashi G. Takaoka    }
14064ee09610024eb1436c51f9c9ef9fc3f77239d73Tadashi G. Takaoka
141e8754aba1c8f217e7ca828de25e0506ac58daa99Keisuke Kuroyanagi    /**
142e8754aba1c8f217e7ca828de25e0506ac58daa99Keisuke Kuroyanagi     * Shift to the left by elementCount, discarding elementCount pointers at the start.
143e8754aba1c8f217e7ca828de25e0506ac58daa99Keisuke Kuroyanagi     * @param elementCount how many elements to shift.
144e8754aba1c8f217e7ca828de25e0506ac58daa99Keisuke Kuroyanagi     */
14554bf24f64b9bbd4c5e4b6d4c3c6144c047d6ddc6Mohammadinamul Sheik    @UsedForTesting
146e8754aba1c8f217e7ca828de25e0506ac58daa99Keisuke Kuroyanagi    public void shift(final int elementCount) {
147e8754aba1c8f217e7ca828de25e0506ac58daa99Keisuke Kuroyanagi        System.arraycopy(mArray, elementCount, mArray, 0, mLength - elementCount);
148e8754aba1c8f217e7ca828de25e0506ac58daa99Keisuke Kuroyanagi        mLength -= elementCount;
149e8754aba1c8f217e7ca828de25e0506ac58daa99Keisuke Kuroyanagi    }
150e8754aba1c8f217e7ca828de25e0506ac58daa99Keisuke Kuroyanagi
15164ee09610024eb1436c51f9c9ef9fc3f77239d73Tadashi G. Takaoka    @Override
15264ee09610024eb1436c51f9c9ef9fc3f77239d73Tadashi G. Takaoka    public String toString() {
15364ee09610024eb1436c51f9c9ef9fc3f77239d73Tadashi G. Takaoka        final StringBuilder sb = new StringBuilder();
15464ee09610024eb1436c51f9c9ef9fc3f77239d73Tadashi G. Takaoka        for (int i = 0; i < mLength; i++) {
15564ee09610024eb1436c51f9c9ef9fc3f77239d73Tadashi G. Takaoka            if (i != 0) {
15664ee09610024eb1436c51f9c9ef9fc3f77239d73Tadashi G. Takaoka                sb.append(",");
15764ee09610024eb1436c51f9c9ef9fc3f77239d73Tadashi G. Takaoka            }
15864ee09610024eb1436c51f9c9ef9fc3f77239d73Tadashi G. Takaoka            sb.append(mArray[i]);
15964ee09610024eb1436c51f9c9ef9fc3f77239d73Tadashi G. Takaoka        }
16064ee09610024eb1436c51f9c9ef9fc3f77239d73Tadashi G. Takaoka        return "[" + sb + "]";
16164ee09610024eb1436c51f9c9ef9fc3f77239d73Tadashi G. Takaoka    }
1629370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka}
163