From 3c072e6fe6db9650f0a160647e8c90ab0db42fea Mon Sep 17 00:00:00 2001 From: Al Sutton Date: Wed, 24 Jul 2019 21:27:44 +0100 Subject: [PATCH] Support varargs for concatElements concatElements currently can only support two arrays, this CL changes it to use varargs so we can make use of it in an upcomming change which needs a three way merge. I've replaced the two way method with the varargs version, but I'm open to discussion around keeping them both if the optimisations we can do for a two way merge are seen as more valuable than the space saving from having only one concatElements method. Bug: 28437818 Test: atest ArrayUtilsTest Change-Id: I634d279ceef7cd620efaf5a2c566e3ebadf6738e --- .../com/android/internal/util/ArrayUtils.java | 64 +++++++++++++++---- .../android/internal/util/ArrayUtilsTest.java | 36 +++++++++++ 2 files changed, 88 insertions(+), 12 deletions(-) diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java index b73ecd1974aa8..e3264a054a437 100644 --- a/core/java/com/android/internal/util/ArrayUtils.java +++ b/core/java/com/android/internal/util/ArrayUtils.java @@ -320,23 +320,63 @@ public class ArrayUtils { return array; } + /** + * Combine multiple arrays into a single array. + * + * @param kind The class of the array elements + * @param arrays The arrays to combine + * @param The class of the array elements (inferred from kind). + * @return A single array containing all the elements of the parameter arrays. + */ @SuppressWarnings("unchecked") - public static @NonNull T[] concatElements(Class kind, @Nullable T[] a, @Nullable T[] b) { - final int an = (a != null) ? a.length : 0; - final int bn = (b != null) ? b.length : 0; - if (an == 0 && bn == 0) { - if (kind == String.class) { - return (T[]) EmptyArray.STRING; - } else if (kind == Object.class) { - return (T[]) EmptyArray.OBJECT; + public static @NonNull T[] concatElements(Class kind, @Nullable T[]... arrays) { + if (arrays == null || arrays.length == 0) { + return createEmptyArray(kind); + } + + int totalLength = 0; + int maxLength = 0; + T[] maxLengthArray = arrays[0]; + for (T[] item : arrays) { + if (item == null) { + continue; + } + + totalLength += item.length; + if (item.length > maxLength) { + maxLengthArray = item; + maxLength = item.length; } } - final T[] res = (T[]) Array.newInstance(kind, an + bn); - if (an > 0) System.arraycopy(a, 0, res, 0, an); - if (bn > 0) System.arraycopy(b, 0, res, an, bn); - return res; + + // Optimization for entirely empty arrays. + if (totalLength == 0) { + return createEmptyArray(kind); + } + + final T[] all = (T[]) Array.newInstance(kind, totalLength); + int pos = 0; + for (T[] item : arrays) { + if (item == null || item.length == 0) { + continue; + } + System.arraycopy(item, 0, all, pos, item.length); + pos += item.length; + } + return all; } + private static @NonNull T[] createEmptyArray(Class kind) { + if (kind == String.class) { + return (T[]) EmptyArray.STRING; + } else if (kind == Object.class) { + return (T[]) EmptyArray.OBJECT; + } + + return (T[]) Array.newInstance(kind, 0); + } + + /** * Adds value to given array if not already present, providing set-like * behavior. diff --git a/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java index 39bb84a20d7a5..cb30b3fe5b826 100644 --- a/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java +++ b/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java @@ -177,4 +177,40 @@ public class ArrayUtilsTest extends TestCase { assertArrayEquals(new Long[] { 1L, 2L, 3L, 4L }, concatElements(Long.class, new Long[] { 1L, 2L }, new Long[] { 3L, 4L })); } + + public void testConcatElements_threeWay() { + String[] array1 = { "1", "2" }; + String[] array2 = { "3", "4" }; + String[] array3 = { "5", "6" }; + String[] expectation = {"1", "2", "3", "4", "5", "6"}; + + String[] concatResult = ArrayUtils.concatElements(String.class, array1, array2, array3); + assertArrayEquals(expectation, concatResult); + } + + + public void testConcatElements_threeWayWithNull() { + String[] array1 = { "1", "2" }; + String[] array2 = null; + String[] array3 = { "5", "6" }; + String[] expectation = {"1", "2", "5", "6"}; + + String[] concatResult = ArrayUtils.concatElements(String.class, array1, array2, array3); + assertArrayEquals(expectation, concatResult); + } + + public void testConcatElements_zeroElements() { + String[] expectation = new String[0]; + + String[] concatResult = ArrayUtils.concatElements(String.class); + assertArrayEquals(expectation, concatResult); + } + + public void testConcatElements_oneNullElement() { + String[] expectation = new String[0]; + + String[] concatResult = ArrayUtils.concatElements(String.class, null); + assertArrayEquals(expectation, concatResult); + } + }