blob: 0236b323b97131c3694920a2d8bac06bd2adb063 [file] [log] [blame]
import java.util.AbstractList;
import java.util.Collections;
import java.util.List;
import org.checkerframework.checker.index.qual.HasSubsequence;
import org.checkerframework.checker.index.qual.IndexFor;
import org.checkerframework.checker.index.qual.IndexOrHigh;
import org.checkerframework.checker.index.qual.IndexOrLow;
import org.checkerframework.checker.index.qual.LTEqLengthOf;
import org.checkerframework.checker.index.qual.LTLengthOf;
import org.checkerframework.checker.index.qual.LessThan;
import org.checkerframework.checker.index.qual.Positive;
import org.checkerframework.common.value.qual.MinLen;
/**
* A simplified version of the Guava primitives classes (such as Bytes, Longs, Shorts, etc.) with
* all expected warnings suppressed.
*/
public class GuavaPrimitives extends AbstractList<Short> {
@HasSubsequence(subsequence = "this", from = "this.start", to = "this.end")
final short @MinLen(1) [] array;
final @IndexFor("array") @LessThan("end") int start;
final @Positive @LTEqLengthOf("array") int end;
public static @IndexOrLow("#1") int indexOf(short[] array, short target) {
return indexOf(array, target, 0, array.length);
}
private static @IndexOrLow("#1") @LessThan("#4") int indexOf(
short[] array, short target, @IndexOrHigh("#1") int start, @IndexOrHigh("#1") int end) {
for (int i = start; i < end; i++) {
if (array[i] == target) {
return i;
}
}
return -1;
}
private static @IndexOrLow("#1") @LessThan("#4") int lastIndexOf(
short[] array, short target, @IndexOrHigh("#1") int start, @IndexOrHigh("#1") int end) {
for (int i = end - 1; i >= start; i--) {
if (array[i] == target) {
return i;
}
}
return -1;
}
GuavaPrimitives(short @MinLen(1) [] array) {
this(array, 0, array.length);
}
@SuppressWarnings(
"index" // these three fields need to be initialized in some order, and any ordering leads to
// the first two issuing errors - since each field is dependent on at least one of the others
)
GuavaPrimitives(
short @MinLen(1) [] array,
@IndexFor("#1") @LessThan("#3") int start,
@Positive @LTEqLengthOf("#1") int end) {
// warnings in here might just need to be suppressed. A single @SuppressWarnings("index") to
// establish rep. invariant might be okay?
this.array = array;
this.start = start;
this.end = end;
}
public @Positive @LTLengthOf(
value = {"this", "array"},
offset = {"-1", "start - 1"}) int
size() { // INDEX: Annotation on a public method refers to private member.
return end - start;
}
public boolean isEmpty() {
return false;
}
public Short get(@IndexFor("this") int index) {
return array[start + index];
}
@SuppressWarnings(
"lowerbound") // https://github.com/kelloggm/checker-framework/issues/227 indexOf()
public @IndexOrLow("this") int indexOf(Object target) {
// Overridden to prevent a ton of boxing
if (target instanceof Short) {
int i = GuavaPrimitives.indexOf(array, (Short) target, start, end);
if (i >= 0) {
return i - start;
}
}
return -1;
}
@SuppressWarnings(
"lowerbound") // https://github.com/kelloggm/checker-framework/issues/227 lastIndexOf()
public @IndexOrLow("this") int lastIndexOf(Object target) {
// Overridden to prevent a ton of boxing
if (target instanceof Short) {
int i = GuavaPrimitives.lastIndexOf(array, (Short) target, start, end);
if (i >= 0) {
return i - start;
}
}
return -1;
}
public Short set(@IndexFor("this") int index, Short element) {
short oldValue = array[start + index];
// checkNotNull for GWT (do not optimize)
array[start + index] = element;
return oldValue;
}
@SuppressWarnings("index") // needs https://github.com/kelloggm/checker-framework/issues/229
public List<Short> subList(
@IndexOrHigh("this") @LessThan("#2") int fromIndex, @IndexOrHigh("this") int toIndex) {
int size = size();
if (fromIndex == toIndex) {
return Collections.emptyList();
}
return new GuavaPrimitives(array, start + fromIndex, start + toIndex);
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder(size() * 6);
builder.append('[').append(array[start]);
for (int i = start + 1; i < end; i++) {
builder.append(", ").append(array[i]);
}
return builder.append(']').toString();
}
}