io.opentelemetry.sdk.internal.DynamicPrimitiveLongList Maven / Gradle / Ivy
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.sdk.internal;
import java.util.AbstractList;
/**
* A resizable list for storing primitive `long` values.
*
* This class implements a dynamically resizable list specifically for primitive long values. The
* values are stored in a chain of arrays (named sub-array), so it can grow efficiently, by adding
* more sub-arrays per its defined size. The backing array also helps avoid auto-boxing and helps
* provide access to values as primitives without boxing.
*
*
The list is designed to minimize memory allocations, by:
*
*
* - Adding sub-arrays and not creating new arrays and copying.
*
- When the size is changing to a smaller size, arrays are not removed.
*
*
* Supported {@code List} methods:
*
*
* - {@link #get(int)} - Retrieves the element at the specified position in this list as a
* {@code Long} object.
*
- {@link #set(int, Long)} - Replaces the element at the specified position in this list with
* the specified {@code Long} object.
*
- {@link #size()} - Returns the number of elements in this list.
*
*
* Additional utility methods:
*
*
* - {@link #getLong(int)} - Retrieves the element at the specified position in this list as a
* primitive long.
*
- {@link #setLong(int, long)} - Replaces the element at the specified position in this list
* with the specified primitive long element.
*
- {@link #resizeAndClear(int)} - Resizes the list to the specified size, resetting all
* elements to zero.
*
*
* This class is internal and is hence not for public use. Its APIs are unstable and can change
* at any time.
*
*
This class is not thread-safe.
*/
public class DynamicPrimitiveLongList extends AbstractList {
private static final int DEFAULT_SUBARRAY_CAPACITY = 10;
private final int subarrayCapacity;
private long[][] arrays;
private int size;
private int arrayCount;
public static DynamicPrimitiveLongList of(long... values) {
DynamicPrimitiveLongList list = new DynamicPrimitiveLongList();
list.resizeAndClear(values.length);
for (int i = 0; i < values.length; i++) {
list.setLong(i, values[i]);
}
return list;
}
public static DynamicPrimitiveLongList ofSubArrayCapacity(int subarrayCapacity) {
return new DynamicPrimitiveLongList(subarrayCapacity);
}
public static DynamicPrimitiveLongList empty() {
return new DynamicPrimitiveLongList();
}
DynamicPrimitiveLongList() {
this(DEFAULT_SUBARRAY_CAPACITY);
}
DynamicPrimitiveLongList(int subarrayCapacity) {
if (subarrayCapacity <= 0) {
throw new IllegalArgumentException("Subarray capacity must be positive");
}
this.subarrayCapacity = subarrayCapacity;
arrays = new long[0][subarrayCapacity];
arrayCount = 0;
size = 0;
}
@Override
public Long get(int index) {
return getLong(index);
}
public long getLong(int index) {
rangeCheck(index);
return arrays[index / subarrayCapacity][index % subarrayCapacity];
}
@Override
public Long set(int index, Long element) {
return setLong(index, element);
}
public long setLong(int index, long element) {
rangeCheck(index);
long oldValue = arrays[index / subarrayCapacity][index % subarrayCapacity];
arrays[index / subarrayCapacity][index % subarrayCapacity] = element;
return oldValue;
}
@Override
public int size() {
return size;
}
public void resizeAndClear(int newSize) {
if (newSize < 0) {
throw new IllegalArgumentException("New size must be non-negative");
}
ensureCapacity(newSize);
size = newSize;
for (int i = 0; i < newSize; i++) {
setLong(i, 0);
}
}
private void ensureCapacity(int minCapacity) {
// A faster way to do ceil(minCapacity/subArrayCapacity)
int requiredArrays = (minCapacity + subarrayCapacity - 1) / subarrayCapacity;
if (requiredArrays > arrayCount) {
arrays = java.util.Arrays.copyOf(arrays, /* newLength= */ requiredArrays);
for (int i = arrayCount; i < requiredArrays; i++) {
arrays[i] = new long[subarrayCapacity];
}
arrayCount = requiredArrays;
}
}
private void rangeCheck(int index) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
}
private String outOfBoundsMsg(int index) {
return "Index: " + index + ", Size: " + size;
}
}