Loading java/src/com/android/inputmethod/latin/ResizableIntArray.java +49 −20 Original line number Original line Diff line number Diff line Loading @@ -28,38 +28,49 @@ public class ResizableIntArray { } } public int get(final int index) { public int get(final int index) { if (index < 0 || index >= mLength) { if (index < mLength) { throw new ArrayIndexOutOfBoundsException("length=" + mLength + "; index=" + index); } return mArray[index]; return mArray[index]; } } throw new ArrayIndexOutOfBoundsException("length=" + mLength + "; index=" + index); } public void add(final int index, final int val) { public void add(final int index, final int val) { if (mLength < index + 1) { if (index < mLength) { mArray[index] = val; } else { mLength = index; mLength = index; add(val); add(val); } else { mArray[index] = val; } } } } public void add(final int val) { public void add(final int val) { final int nextLength = mLength + 1; final int currentLength = mLength; ensureCapacity(nextLength); ensureCapacity(currentLength + 1); mArray[mLength] = val; mArray[currentLength] = val; mLength = nextLength; mLength = currentLength + 1; } /** * Calculate the new capacity of {@code mArray}. * @param minimumCapacity the minimum capacity that the {@code mArray} should have. * @return the new capacity that the {@code mArray} should have. Returns zero when there is no * need to expand {@code mArray}. */ private int calculateCapacity(final int minimumCapacity) { final int currentCapcity = mArray.length; if (currentCapcity < minimumCapacity) { final int nextCapacity = currentCapcity * 2; // The following is the same as return Math.max(minimumCapacity, nextCapacity); return minimumCapacity > nextCapacity ? minimumCapacity : nextCapacity; } return 0; } } private void ensureCapacity(final int minimumCapacity) { private void ensureCapacity(final int minimumCapacity) { if (mArray.length < minimumCapacity) { final int newCapacity = calculateCapacity(minimumCapacity); final int nextCapacity = mArray.length * 2; if (newCapacity > 0) { // The following is the same as newLength = // Math.max(minimumCapacity, nextCapacity); final int newLength = minimumCapacity > nextCapacity ? minimumCapacity : nextCapacity; // TODO: Implement primitive array pool. // TODO: Implement primitive array pool. mArray = Arrays.copyOf(mArray, newLength); mArray = Arrays.copyOf(mArray, newCapacity); } } } } Loading Loading @@ -89,17 +100,35 @@ public class ResizableIntArray { } } public void copy(final ResizableIntArray ip) { public void copy(final ResizableIntArray ip) { // TODO: Avoid useless coping of values. final int newCapacity = calculateCapacity(ip.mLength); ensureCapacity(ip.mLength); if (newCapacity > 0) { // TODO: Implement primitive array pool. mArray = new int[newCapacity]; } System.arraycopy(ip.mArray, 0, mArray, 0, ip.mLength); System.arraycopy(ip.mArray, 0, mArray, 0, ip.mLength); mLength = ip.mLength; mLength = ip.mLength; } } public void append(final ResizableIntArray src, final int startPos, final int length) { public void append(final ResizableIntArray src, final int startPos, final int length) { if (length == 0) { return; } final int currentLength = mLength; final int currentLength = mLength; final int newLength = currentLength + length; final int newLength = currentLength + length; ensureCapacity(newLength); ensureCapacity(newLength); System.arraycopy(src.mArray, startPos, mArray, currentLength, length); System.arraycopy(src.mArray, startPos, mArray, currentLength, length); mLength = newLength; mLength = newLength; } } public void fill(final int value, final int startPos, final int length) { if (startPos < 0 || length < 0) { throw new IllegalArgumentException("startPos=" + startPos + "; length=" + length); } final int endPos = startPos + length; ensureCapacity(endPos); Arrays.fill(mArray, startPos, endPos, value); if (mLength < endPos) { mLength = endPos; } } } } tests/src/com/android/inputmethod/latin/ResizableIntArrayTests.java +89 −8 Original line number Original line Diff line number Diff line Loading @@ -37,8 +37,12 @@ public class ResizableIntArrayTests extends AndroidTestCase { for (int i = 0; i < limit; i++) { for (int i = 0; i < limit; i++) { src.add(i); src.add(i); assertEquals("length after add " + i, i + 1, src.getLength()); assertEquals("length after add " + i, i + 1, src.getLength()); if (i == DEFAULT_CAPACITY) array2 = src.getPrimitiveArray(); if (i == DEFAULT_CAPACITY) { if (i == DEFAULT_CAPACITY * 2) array3 = src.getPrimitiveArray(); array2 = src.getPrimitiveArray(); } if (i == DEFAULT_CAPACITY * 2) { array3 = src.getPrimitiveArray(); } if (i < DEFAULT_CAPACITY) { if (i < DEFAULT_CAPACITY) { assertSame("array after add " + i, array, src.getPrimitiveArray()); assertSame("array after add " + i, array, src.getPrimitiveArray()); } else if (i < DEFAULT_CAPACITY * 2) { } else if (i < DEFAULT_CAPACITY * 2) { Loading Loading @@ -110,7 +114,9 @@ public class ResizableIntArrayTests extends AndroidTestCase { for (int i = 0; i < DEFAULT_CAPACITY; i++) { for (int i = 0; i < DEFAULT_CAPACITY; i++) { src.add(i); src.add(i); assertEquals("length after add " + i, i + 1, src.getLength()); assertEquals("length after add " + i, i + 1, src.getLength()); if (i == smallerLength) array3 = src.getPrimitiveArray(); if (i == smallerLength) { array3 = src.getPrimitiveArray(); } if (i < smallerLength) { if (i < smallerLength) { assertSame("array after add " + i, array2, src.getPrimitiveArray()); assertSame("array after add " + i, array2, src.getPrimitiveArray()); } else if (i < smallerLength * 2) { } else if (i < smallerLength * 2) { Loading @@ -133,11 +139,13 @@ public class ResizableIntArrayTests extends AndroidTestCase { assertEquals("length after larger setLength", largerLength, src.getLength()); assertEquals("length after larger setLength", largerLength, src.getLength()); assertNotSame("array after larger setLength", array, array2); assertNotSame("array after larger setLength", array, array2); assertEquals("array length after larger setLength", largerLength, array2.length); assertEquals("array length after larger setLength", largerLength, array2.length); for (int i = 0; i < DEFAULT_CAPACITY; i++) { for (int i = 0; i < largerLength; i++) { assertEquals("value at " + i, i, src.get(i)); final int v = src.get(i); if (i < DEFAULT_CAPACITY) { assertEquals("value at " + i, i, v); } else { assertEquals("value at " + i, 0, v); } } for (int i = DEFAULT_CAPACITY; i < largerLength; i++) { assertEquals("value at " + i, 0, src.get(i)); } } final int smallerLength = DEFAULT_CAPACITY / 2; final int smallerLength = DEFAULT_CAPACITY / 2; Loading Loading @@ -236,6 +244,79 @@ public class ResizableIntArrayTests extends AndroidTestCase { src.getPrimitiveArray(), 0, dst.getPrimitiveArray(), dstLen + srcLen, srcLen); src.getPrimitiveArray(), 0, dst.getPrimitiveArray(), dstLen + srcLen, srcLen); } } public void testFill() { final int srcLen = DEFAULT_CAPACITY; final ResizableIntArray src = new ResizableIntArray(srcLen); for (int i = 0; i < srcLen; i++) { src.add(i); } final int[] array = src.getPrimitiveArray(); final int startPos = srcLen / 3; final int length = srcLen / 3; final int endPos = startPos + length; assertTrue(startPos >= 1); final int value = 123; try { src.fill(value, -1, length); fail("fill from -1 shouldn't succeed"); } catch (IllegalArgumentException e) { // success } try { src.fill(value, startPos, -1); fail("fill negative length shouldn't succeed"); } catch (IllegalArgumentException e) { // success } src.fill(value, startPos, length); assertEquals("length after fill", srcLen, src.getLength()); assertSame("array after fill", array, src.getPrimitiveArray()); for (int i = 0; i < srcLen; i++) { final int v = src.get(i); if (i >= startPos && i < endPos) { assertEquals("new values after fill at " + i, value, v); } else { assertEquals("unmodified values after fill at " + i, i, v); } } final int length2 = srcLen * 2 - startPos; final int largeEnd = startPos + length2; assertTrue(largeEnd > srcLen); final int value2 = 456; src.fill(value2, startPos, length2); assertEquals("length after large fill", largeEnd, src.getLength()); assertNotSame("array after large fill", array, src.getPrimitiveArray()); for (int i = 0; i < largeEnd; i++) { final int v = src.get(i); if (i >= startPos && i < largeEnd) { assertEquals("new values after large fill at " + i, value2, v); } else { assertEquals("unmodified values after large fill at " + i, i, v); } } final int startPos2 = largeEnd + length2; final int endPos2 = startPos2 + length2; final int value3 = 789; src.fill(value3, startPos2, length2); assertEquals("length after disjoint fill", endPos2, src.getLength()); for (int i = 0; i < endPos2; i++) { final int v = src.get(i); if (i >= startPos2 && i < endPos2) { assertEquals("new values after disjoint fill at " + i, value3, v); } else if (i >= startPos && i < largeEnd) { assertEquals("unmodified values after disjoint fill at " + i, value2, v); } else if (i < startPos) { assertEquals("unmodified values after disjoint fill at " + i, i, v); } else { assertEquals("gap values after disjoint fill at " + i, 0, v); } } } private static void assertArrayEquals(String message, int[] expecteds, int expectedPos, private static void assertArrayEquals(String message, int[] expecteds, int expectedPos, int[] actuals, int actualPos, int length) { int[] actuals, int actualPos, int length) { if (expecteds == null && actuals == null) { if (expecteds == null && actuals == null) { Loading Loading
java/src/com/android/inputmethod/latin/ResizableIntArray.java +49 −20 Original line number Original line Diff line number Diff line Loading @@ -28,38 +28,49 @@ public class ResizableIntArray { } } public int get(final int index) { public int get(final int index) { if (index < 0 || index >= mLength) { if (index < mLength) { throw new ArrayIndexOutOfBoundsException("length=" + mLength + "; index=" + index); } return mArray[index]; return mArray[index]; } } throw new ArrayIndexOutOfBoundsException("length=" + mLength + "; index=" + index); } public void add(final int index, final int val) { public void add(final int index, final int val) { if (mLength < index + 1) { if (index < mLength) { mArray[index] = val; } else { mLength = index; mLength = index; add(val); add(val); } else { mArray[index] = val; } } } } public void add(final int val) { public void add(final int val) { final int nextLength = mLength + 1; final int currentLength = mLength; ensureCapacity(nextLength); ensureCapacity(currentLength + 1); mArray[mLength] = val; mArray[currentLength] = val; mLength = nextLength; mLength = currentLength + 1; } /** * Calculate the new capacity of {@code mArray}. * @param minimumCapacity the minimum capacity that the {@code mArray} should have. * @return the new capacity that the {@code mArray} should have. Returns zero when there is no * need to expand {@code mArray}. */ private int calculateCapacity(final int minimumCapacity) { final int currentCapcity = mArray.length; if (currentCapcity < minimumCapacity) { final int nextCapacity = currentCapcity * 2; // The following is the same as return Math.max(minimumCapacity, nextCapacity); return minimumCapacity > nextCapacity ? minimumCapacity : nextCapacity; } return 0; } } private void ensureCapacity(final int minimumCapacity) { private void ensureCapacity(final int minimumCapacity) { if (mArray.length < minimumCapacity) { final int newCapacity = calculateCapacity(minimumCapacity); final int nextCapacity = mArray.length * 2; if (newCapacity > 0) { // The following is the same as newLength = // Math.max(minimumCapacity, nextCapacity); final int newLength = minimumCapacity > nextCapacity ? minimumCapacity : nextCapacity; // TODO: Implement primitive array pool. // TODO: Implement primitive array pool. mArray = Arrays.copyOf(mArray, newLength); mArray = Arrays.copyOf(mArray, newCapacity); } } } } Loading Loading @@ -89,17 +100,35 @@ public class ResizableIntArray { } } public void copy(final ResizableIntArray ip) { public void copy(final ResizableIntArray ip) { // TODO: Avoid useless coping of values. final int newCapacity = calculateCapacity(ip.mLength); ensureCapacity(ip.mLength); if (newCapacity > 0) { // TODO: Implement primitive array pool. mArray = new int[newCapacity]; } System.arraycopy(ip.mArray, 0, mArray, 0, ip.mLength); System.arraycopy(ip.mArray, 0, mArray, 0, ip.mLength); mLength = ip.mLength; mLength = ip.mLength; } } public void append(final ResizableIntArray src, final int startPos, final int length) { public void append(final ResizableIntArray src, final int startPos, final int length) { if (length == 0) { return; } final int currentLength = mLength; final int currentLength = mLength; final int newLength = currentLength + length; final int newLength = currentLength + length; ensureCapacity(newLength); ensureCapacity(newLength); System.arraycopy(src.mArray, startPos, mArray, currentLength, length); System.arraycopy(src.mArray, startPos, mArray, currentLength, length); mLength = newLength; mLength = newLength; } } public void fill(final int value, final int startPos, final int length) { if (startPos < 0 || length < 0) { throw new IllegalArgumentException("startPos=" + startPos + "; length=" + length); } final int endPos = startPos + length; ensureCapacity(endPos); Arrays.fill(mArray, startPos, endPos, value); if (mLength < endPos) { mLength = endPos; } } } }
tests/src/com/android/inputmethod/latin/ResizableIntArrayTests.java +89 −8 Original line number Original line Diff line number Diff line Loading @@ -37,8 +37,12 @@ public class ResizableIntArrayTests extends AndroidTestCase { for (int i = 0; i < limit; i++) { for (int i = 0; i < limit; i++) { src.add(i); src.add(i); assertEquals("length after add " + i, i + 1, src.getLength()); assertEquals("length after add " + i, i + 1, src.getLength()); if (i == DEFAULT_CAPACITY) array2 = src.getPrimitiveArray(); if (i == DEFAULT_CAPACITY) { if (i == DEFAULT_CAPACITY * 2) array3 = src.getPrimitiveArray(); array2 = src.getPrimitiveArray(); } if (i == DEFAULT_CAPACITY * 2) { array3 = src.getPrimitiveArray(); } if (i < DEFAULT_CAPACITY) { if (i < DEFAULT_CAPACITY) { assertSame("array after add " + i, array, src.getPrimitiveArray()); assertSame("array after add " + i, array, src.getPrimitiveArray()); } else if (i < DEFAULT_CAPACITY * 2) { } else if (i < DEFAULT_CAPACITY * 2) { Loading Loading @@ -110,7 +114,9 @@ public class ResizableIntArrayTests extends AndroidTestCase { for (int i = 0; i < DEFAULT_CAPACITY; i++) { for (int i = 0; i < DEFAULT_CAPACITY; i++) { src.add(i); src.add(i); assertEquals("length after add " + i, i + 1, src.getLength()); assertEquals("length after add " + i, i + 1, src.getLength()); if (i == smallerLength) array3 = src.getPrimitiveArray(); if (i == smallerLength) { array3 = src.getPrimitiveArray(); } if (i < smallerLength) { if (i < smallerLength) { assertSame("array after add " + i, array2, src.getPrimitiveArray()); assertSame("array after add " + i, array2, src.getPrimitiveArray()); } else if (i < smallerLength * 2) { } else if (i < smallerLength * 2) { Loading @@ -133,11 +139,13 @@ public class ResizableIntArrayTests extends AndroidTestCase { assertEquals("length after larger setLength", largerLength, src.getLength()); assertEquals("length after larger setLength", largerLength, src.getLength()); assertNotSame("array after larger setLength", array, array2); assertNotSame("array after larger setLength", array, array2); assertEquals("array length after larger setLength", largerLength, array2.length); assertEquals("array length after larger setLength", largerLength, array2.length); for (int i = 0; i < DEFAULT_CAPACITY; i++) { for (int i = 0; i < largerLength; i++) { assertEquals("value at " + i, i, src.get(i)); final int v = src.get(i); if (i < DEFAULT_CAPACITY) { assertEquals("value at " + i, i, v); } else { assertEquals("value at " + i, 0, v); } } for (int i = DEFAULT_CAPACITY; i < largerLength; i++) { assertEquals("value at " + i, 0, src.get(i)); } } final int smallerLength = DEFAULT_CAPACITY / 2; final int smallerLength = DEFAULT_CAPACITY / 2; Loading Loading @@ -236,6 +244,79 @@ public class ResizableIntArrayTests extends AndroidTestCase { src.getPrimitiveArray(), 0, dst.getPrimitiveArray(), dstLen + srcLen, srcLen); src.getPrimitiveArray(), 0, dst.getPrimitiveArray(), dstLen + srcLen, srcLen); } } public void testFill() { final int srcLen = DEFAULT_CAPACITY; final ResizableIntArray src = new ResizableIntArray(srcLen); for (int i = 0; i < srcLen; i++) { src.add(i); } final int[] array = src.getPrimitiveArray(); final int startPos = srcLen / 3; final int length = srcLen / 3; final int endPos = startPos + length; assertTrue(startPos >= 1); final int value = 123; try { src.fill(value, -1, length); fail("fill from -1 shouldn't succeed"); } catch (IllegalArgumentException e) { // success } try { src.fill(value, startPos, -1); fail("fill negative length shouldn't succeed"); } catch (IllegalArgumentException e) { // success } src.fill(value, startPos, length); assertEquals("length after fill", srcLen, src.getLength()); assertSame("array after fill", array, src.getPrimitiveArray()); for (int i = 0; i < srcLen; i++) { final int v = src.get(i); if (i >= startPos && i < endPos) { assertEquals("new values after fill at " + i, value, v); } else { assertEquals("unmodified values after fill at " + i, i, v); } } final int length2 = srcLen * 2 - startPos; final int largeEnd = startPos + length2; assertTrue(largeEnd > srcLen); final int value2 = 456; src.fill(value2, startPos, length2); assertEquals("length after large fill", largeEnd, src.getLength()); assertNotSame("array after large fill", array, src.getPrimitiveArray()); for (int i = 0; i < largeEnd; i++) { final int v = src.get(i); if (i >= startPos && i < largeEnd) { assertEquals("new values after large fill at " + i, value2, v); } else { assertEquals("unmodified values after large fill at " + i, i, v); } } final int startPos2 = largeEnd + length2; final int endPos2 = startPos2 + length2; final int value3 = 789; src.fill(value3, startPos2, length2); assertEquals("length after disjoint fill", endPos2, src.getLength()); for (int i = 0; i < endPos2; i++) { final int v = src.get(i); if (i >= startPos2 && i < endPos2) { assertEquals("new values after disjoint fill at " + i, value3, v); } else if (i >= startPos && i < largeEnd) { assertEquals("unmodified values after disjoint fill at " + i, value2, v); } else if (i < startPos) { assertEquals("unmodified values after disjoint fill at " + i, i, v); } else { assertEquals("gap values after disjoint fill at " + i, 0, v); } } } private static void assertArrayEquals(String message, int[] expecteds, int expectedPos, private static void assertArrayEquals(String message, int[] expecteds, int expectedPos, int[] actuals, int actualPos, int length) { int[] actuals, int actualPos, int length) { if (expecteds == null && actuals == null) { if (expecteds == null && actuals == null) { Loading