Skip to content

Commit

Permalink
Fix [Type]ArrayList elements() method usage (apache#13354)
Browse files Browse the repository at this point in the history
  • Loading branch information
xiangfu0 authored Jun 11, 2024
1 parent d09cd0c commit 5ca1d97
Show file tree
Hide file tree
Showing 7 changed files with 309 additions and 26 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.pinot.common.utils;

import it.unimi.dsi.fastutil.doubles.DoubleArrayList;
import it.unimi.dsi.fastutil.floats.FloatArrayList;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.longs.LongArrayList;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;


/**
* Utility class for {@link IntArrayList}, {@link LongArrayList}, {@link FloatArrayList}, {@link DoubleArrayList},
* {@link ObjectArrayList}.
*/
public class ArrayListUtils {
private ArrayListUtils() {
}

/**
* Best effort extract the given {@link IntArrayList} to an int array without copying the elements.
* The {@link IntArrayList#elements()} returned int array may be longer than the actual size of the
* {@link IntArrayList}, and the actual size of the {@link IntArrayList} can be retrieved using
* {@link IntArrayList#size()}.
* This method checks the length of the returned int array and returns the same if it is equal to the size of the
* {@link IntArrayList}, otherwise, it copies the elements to a new int array and returns it.
*
* <p>Use this method only if you are sure that the returned int array will not be modified.
* <p>Otherwise, use {@link IntArrayList#toIntArray()}.
*
* @param intArrayList Input {@link IntArrayList}
* @return Best effort extracted int array without copying the elements
*/
public static int[] toIntArray(IntArrayList intArrayList) {
int[] intArrayListElements = intArrayList.elements();
return intArrayListElements.length == intArrayList.size() ? intArrayListElements : intArrayList.toIntArray();
}

/**
* Best effort extract the given {@link LongArrayList} to a long array without copying the elements.
* The {@link LongArrayList#elements()} returned long array may be longer than the actual size of the
* {@link LongArrayList}, and the actual size of the {@link LongArrayList} can be retrieved using
* {@link LongArrayList#size()}.
* This method checks the length of the returned long array and returns the same if it is equal to the size of the
* {@link LongArrayList}, otherwise, it copies the elements to a new long array and returns it.
*
* <p>Use this method only if you are sure that the returned long array will not be modified.
* <p>Otherwise, use {@link LongArrayList#toLongArray()}.
*
* @param longArrayList Input {@link LongArrayList}
* @return Best effort extracted long array without copying the elements
*/
public static long[] toLongArray(LongArrayList longArrayList) {
long[] longArrayListElements = longArrayList.elements();
return longArrayListElements.length == longArrayList.size() ? longArrayListElements : longArrayList.toLongArray();
}

/**
* Best effort extract the given {@link FloatArrayList} to a float array without copying the elements.
* The {@link FloatArrayList#elements()} returned float array may be longer than the actual size of the
* {@link FloatArrayList}, and the actual size of the {@link FloatArrayList} can be retrieved using
* {@link FloatArrayList#size()}.
* This method checks the length of the returned float array and returns the same if it is equal to the size of the
* {@link FloatArrayList}, otherwise, it copies the elements to a new float array and returns it.
*
* <p>Use this method only if you are sure that the returned float array will not be modified.
* <p>Otherwise, use {@link FloatArrayList#toFloatArray()}.
*
* @param floatArrayList Input {@link FloatArrayList}
* @return Best effort extracted float array without copying the elements
*/
public static float[] toFloatArray(FloatArrayList floatArrayList) {
float[] floatArrayListElements = floatArrayList.elements();
return floatArrayListElements.length == floatArrayList.size() ? floatArrayListElements
: floatArrayList.toFloatArray();
}

/**
* Best effort extract the given {@link DoubleArrayList} to a double array without copying the elements.
* The {@link DoubleArrayList#elements()} returned double array may be longer than the actual size of the
* {@link DoubleArrayList}, and the actual size of the {@link DoubleArrayList} can be retrieved using
* {@link DoubleArrayList#size()}.
* This method checks the length of the returned double array and returns the same if it is equal to the size of the
* {@link DoubleArrayList}, otherwise, it copies the elements to a new double array and returns it.
*
* <p>Use this method only if you are sure that the returned double array will not be modified.
* <p>Otherwise, use {@link DoubleArrayList#toDoubleArray()}.
*
* @param doubleArrayList Input {@link DoubleArrayList}
* @return Best effort extracted double array without copying the elements
*/
public static double[] toDoubleArray(DoubleArrayList doubleArrayList) {
double[] doubleArrayListElements = doubleArrayList.elements();
return doubleArrayListElements.length == doubleArrayList.size() ? doubleArrayListElements
: doubleArrayList.toDoubleArray();
}

/**
* Convert the given {@link ObjectArrayList} to a string array.
* The method {@link ObjectArrayList#elements()} could return either Object[] or String[]. The casting to String[]
* is not guaranteed to work, and it may throw {@link ClassCastException} if the internal object is not a String
* array.
* <p>
* This method first get `elements` as Object, then check if it's instance of String[].
* Only return the reference when the internal object is a String array and the length equals to ObjectArrayList
* size.
* For all the other scenarios, just copy the elements to a new string array and returns it.
* <p>
*
* @param stringArrayList Input {@link ObjectArrayList}
* @return Copied string array
*/
public static String[] toStringArray(ObjectArrayList<String> stringArrayList) {
Object elements = stringArrayList.elements();
if (elements instanceof String[]) {
String[] stringArrayListElements = (String[]) elements;
if (stringArrayListElements.length == stringArrayList.size()) {
return stringArrayListElements;
}
}
return stringArrayList.toArray(new String[0]);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,7 @@ private static int[] toIntArray(Object value) {
return (int[]) value;
} else if (value instanceof IntArrayList) {
// For ArrayAggregationFunction
return ((IntArrayList) value).elements();
return ArrayListUtils.toIntArray((IntArrayList) value);
}
throw new IllegalStateException(String.format("Cannot convert: '%s' to int[]", value));
}
Expand All @@ -533,7 +533,7 @@ private static float[] toFloatArray(Object value) {
return (float[]) value;
} else if (value instanceof FloatArrayList) {
// For ArrayAggregationFunction
return ((FloatArrayList) value).elements();
return ArrayListUtils.toFloatArray((FloatArrayList) value);
}
throw new IllegalStateException(String.format("Cannot convert: '%s' to float[]", value));
}
Expand All @@ -543,7 +543,7 @@ private static double[] toDoubleArray(Object value) {
return (double[]) value;
} else if (value instanceof DoubleArrayList) {
// For HistogramAggregationFunction and ArrayAggregationFunction
return ((DoubleArrayList) value).elements();
return ArrayListUtils.toDoubleArray((DoubleArrayList) value);
} else if (value instanceof int[]) {
int[] intValues = (int[]) value;
int length = intValues.length;
Expand Down Expand Up @@ -576,7 +576,7 @@ private static long[] toLongArray(Object value) {
return (long[]) value;
} else if (value instanceof LongArrayList) {
// For FunnelCountAggregationFunction and ArrayAggregationFunction
return ((LongArrayList) value).elements();
return ArrayListUtils.toLongArray((LongArrayList) value);
} else {
int[] intValues = (int[]) value;
int length = intValues.length;
Expand All @@ -593,7 +593,7 @@ private static String[] toStringArray(Object value) {
return (String[]) value;
} else if (value instanceof ObjectArrayList) {
// For ArrayAggregationFunction
return ((ObjectArrayList<String>) value).toArray(new String[0]);
return ArrayListUtils.toStringArray((ObjectArrayList<String>) value);
}
throw new IllegalStateException(String.format("Cannot convert: '%s' to String[]", value));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.pinot.common.utils;

import it.unimi.dsi.fastutil.doubles.DoubleArrayList;
import it.unimi.dsi.fastutil.floats.FloatArrayList;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.longs.LongArrayList;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import org.testng.annotations.Test;

import static org.testng.Assert.assertEquals;


public class ArrayListUtilsTest {
@Test
public void testToIntArray() {
// Test empty list
IntArrayList intArrayList = new IntArrayList();
int[] intArray = ArrayListUtils.toIntArray(intArrayList);
assertEquals(intArray.length, 0);

// Test list with one element
intArrayList.add(1);
intArray = ArrayListUtils.toIntArray(intArrayList);
assertEquals(intArray.length, 1);
assertEquals(intArray[0], 1);

// Test list with multiple elements
intArrayList.add(2);
intArrayList.add(3);
intArray = ArrayListUtils.toIntArray(intArrayList);
assertEquals(intArray.length, 3);
assertEquals(intArray[0], 1);
assertEquals(intArray[1], 2);
assertEquals(intArray[2], 3);
}

@Test
public void testToLongArray() {
// Test empty list
LongArrayList longArrayList = new LongArrayList();
long[] longArray = ArrayListUtils.toLongArray(longArrayList);
assertEquals(longArray.length, 0);

// Test list with one element
longArrayList.add(1L);
longArray = ArrayListUtils.toLongArray(longArrayList);
assertEquals(longArray.length, 1);
assertEquals(longArray[0], 1L);

// Test list with multiple elements
longArrayList.add(2L);
longArrayList.add(3L);
longArray = ArrayListUtils.toLongArray(longArrayList);
assertEquals(longArray.length, 3);
assertEquals(longArray[0], 1L);
assertEquals(longArray[1], 2L);
assertEquals(longArray[2], 3L);
}

@Test
public void testToFloatArray() {
// Test empty list
FloatArrayList floatArrayList = new FloatArrayList();
float[] floatArray = ArrayListUtils.toFloatArray(floatArrayList);
assertEquals(floatArray.length, 0);

// Test list with one element
floatArrayList.add(1.0f);
floatArray = ArrayListUtils.toFloatArray(floatArrayList);
assertEquals(floatArray.length, 1);
assertEquals(floatArray[0], 1.0f);

// Test list with multiple elements
floatArrayList.add(2.0f);
floatArrayList.add(3.0f);
floatArray = ArrayListUtils.toFloatArray(floatArrayList);
assertEquals(floatArray.length, 3);
assertEquals(floatArray[0], 1.0f);
assertEquals(floatArray[1], 2.0f);
assertEquals(floatArray[2], 3.0f);
}

@Test
public void testToDoubleArray() {
// Test empty list
DoubleArrayList doubleArrayList = new DoubleArrayList();
double[] doubleArray = ArrayListUtils.toDoubleArray(doubleArrayList);
assertEquals(doubleArray.length, 0);

// Test list with one element
doubleArrayList.add(1.0);
doubleArray = ArrayListUtils.toDoubleArray(doubleArrayList);
assertEquals(doubleArray.length, 1);
assertEquals(doubleArray[0], 1.0);

// Test list with multiple elements
doubleArrayList.add(2.0);
doubleArrayList.add(3.0);
doubleArray = ArrayListUtils.toDoubleArray(doubleArrayList);
assertEquals(doubleArray.length, 3);
assertEquals(doubleArray[0], 1.0);
assertEquals(doubleArray[1], 2.0);
assertEquals(doubleArray[2], 3.0);
}

@Test
public void testToStringArray() {
// Test empty list
ObjectArrayList<String> stringArrayList = new ObjectArrayList<String>();
String[] stringArray = ArrayListUtils.toStringArray(stringArrayList);
assertEquals(stringArray.length, 0);

// Test list with one element
stringArrayList.add("1");
stringArray = ArrayListUtils.toStringArray(stringArrayList);
assertEquals(stringArray.length, 1);
assertEquals(stringArray[0], "1");

// Test list with multiple elements
stringArrayList.add("2");
stringArrayList.add("3");
stringArray = ArrayListUtils.toStringArray(stringArrayList);
assertEquals(stringArray.length, 3);
assertEquals(stringArray[0], "1");
assertEquals(stringArray[1], "2");
assertEquals(stringArray[2], "3");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.apache.commons.lang3.tuple.Pair;
import org.apache.pinot.common.datatable.DataTable;
import org.apache.pinot.common.request.context.FilterContext;
import org.apache.pinot.common.utils.ArrayListUtils;
import org.apache.pinot.common.utils.DataSchema;
import org.apache.pinot.common.utils.DataSchema.ColumnDataType;
import org.apache.pinot.core.common.datatable.DataTableBuilder;
Expand Down Expand Up @@ -195,19 +196,19 @@ private void setFinalResult(DataTableBuilder dataTableBuilder, ColumnDataType[]
dataTableBuilder.setColumn(index, (ByteArray) result);
break;
case INT_ARRAY:
dataTableBuilder.setColumn(index, ((IntArrayList) result).elements());
dataTableBuilder.setColumn(index, ArrayListUtils.toIntArray((IntArrayList) result));
break;
case LONG_ARRAY:
dataTableBuilder.setColumn(index, ((LongArrayList) result).elements());
dataTableBuilder.setColumn(index, ArrayListUtils.toLongArray((LongArrayList) result));
break;
case FLOAT_ARRAY:
dataTableBuilder.setColumn(index, ((FloatArrayList) result).elements());
dataTableBuilder.setColumn(index, ArrayListUtils.toFloatArray((FloatArrayList) result));
break;
case DOUBLE_ARRAY:
dataTableBuilder.setColumn(index, ((DoubleArrayList) result).elements());
dataTableBuilder.setColumn(index, ArrayListUtils.toDoubleArray((DoubleArrayList) result));
break;
case STRING_ARRAY:
dataTableBuilder.setColumn(index, ((ObjectArrayList<String>) result).elements());
dataTableBuilder.setColumn(index, ArrayListUtils.toStringArray((ObjectArrayList<String>) result));
break;
default:
throw new IllegalStateException("Illegal column data type in final result: " + columnDataType);
Expand Down
Loading

0 comments on commit 5ca1d97

Please sign in to comment.