Add LongArrayMultiStateCounter.combineValues

This method combines values into a smaller array
by using an index map.

Bug: 244623253
Test: atest com.android.internal.os.LongArrayMultiStateCounterTest
Change-Id: Ic35d30cc1f8765cd4e21366943da8291355a0047
This commit is contained in:
Dmitri Plotnikov
2022-09-09 15:27:30 -07:00
parent 955425bdf1
commit bb76e0fe02
3 changed files with 79 additions and 0 deletions

View File

@@ -98,6 +98,18 @@ public final class LongArrayMultiStateCounter implements Parcelable {
native_getValues(mNativeObject, array);
}
/**
* Combines contained values into a smaller array by aggregating them
* according to an index map.
*/
public boolean combineValues(long[] array, int[] indexMap) {
if (indexMap.length != mLength) {
throw new IllegalArgumentException(
"Wrong index map size " + indexMap.length + ", expected " + mLength);
}
return native_combineValues(mNativeObject, array, indexMap);
}
@Override
public String toString() {
final long[] array = new long[mLength];
@@ -116,6 +128,10 @@ public final class LongArrayMultiStateCounter implements Parcelable {
@FastNative
private native void native_getValues(long nativeObject, long[] array);
@FastNative
private native boolean native_combineValues(long nativeObject, long[] array,
int[] indexMap);
}
private static final NativeAllocationRegistry sRegistry =

View File

@@ -244,6 +244,38 @@ static void native_getValues_LongArrayContainer(JNIEnv *env, jobject self, jlong
std::copy(vector->data(), vector->data() + vector->size(), scopedArray.get());
}
static jboolean native_combineValues_LongArrayContainer(JNIEnv *env, jobject self, jlong nativePtr,
jlongArray jarray, jintArray jindexMap) {
std::vector<uint64_t> *vector = reinterpret_cast<std::vector<uint64_t> *>(nativePtr);
ScopedLongArrayRW scopedArray(env, jarray);
ScopedIntArrayRO scopedIndexMap(env, jindexMap);
const uint64_t *data = vector->data();
uint64_t *array = reinterpret_cast<uint64_t *>(scopedArray.get());
const uint8_t size = scopedArray.size();
for (int i = 0; i < size; i++) {
array[i] = 0;
}
bool nonZero = false;
for (int i = 0; i < vector->size(); i++) {
jint index = scopedIndexMap[i];
if (index < 0 || index >= size) {
jniThrowExceptionFmt(env, "java/lang/IndexOutOfBoundsException",
"Index %d is out of bounds: [0, %d]", index, size - 1);
return false;
}
if (data[i] != 0L) {
array[index] += data[i];
nonZero = true;
}
}
return nonZero;
}
static const JNINativeMethod g_LongArrayContainer_methods[] = {
// @CriticalNative
{"native_init", "(I)J", (void *)native_init_LongArrayContainer},
@@ -253,6 +285,8 @@ static const JNINativeMethod g_LongArrayContainer_methods[] = {
{"native_setValues", "(J[J)V", (void *)native_setValues_LongArrayContainer},
// @FastNative
{"native_getValues", "(J[J)V", (void *)native_getValues_LongArrayContainer},
// @FastNative
{"native_combineValues", "(J[J[I)Z", (void *)native_combineValues_LongArrayContainer},
};
int register_com_android_internal_os_LongArrayMultiStateCounter(JNIEnv *env) {

View File

@@ -161,4 +161,33 @@ public class LongArrayMultiStateCounterTest {
assertThrows(RuntimeException.class,
() -> LongArrayMultiStateCounter.CREATOR.createFromParcel(parcel));
}
@Test
public void combineValues() {
long[] values = new long[] {0, 1, 2, 3, 42};
LongArrayMultiStateCounter.LongArrayContainer container =
new LongArrayMultiStateCounter.LongArrayContainer(values.length);
container.setValues(values);
long[] out = new long[3];
int[] indexes = {2, 1, 1, 0, 0};
boolean nonZero = container.combineValues(out, indexes);
assertThat(nonZero).isTrue();
assertThat(out).isEqualTo(new long[]{45, 3, 0});
// All zeros
container.setValues(new long[]{0, 0, 0, 0, 0});
nonZero = container.combineValues(out, indexes);
assertThat(nonZero).isFalse();
assertThat(out).isEqualTo(new long[]{0, 0, 0});
// Index out of range
IndexOutOfBoundsException e1 = assertThrows(
IndexOutOfBoundsException.class,
() -> container.combineValues(out, new int[]{0, 1, -1, 0, 0}));
assertThat(e1.getMessage()).isEqualTo("Index -1 is out of bounds: [0, 2]");
IndexOutOfBoundsException e2 = assertThrows(IndexOutOfBoundsException.class,
() -> container.combineValues(out, new int[]{0, 1, 4, 0, 0}));
assertThat(e2.getMessage()).isEqualTo("Index 4 is out of bounds: [0, 2]");
}
}