Skip to content

Commit

Permalink
[CALCITE-4199] Add nullability annotations to ChunkList
Browse files Browse the repository at this point in the history
  • Loading branch information
vlsi committed Oct 1, 2020
1 parent 8a7af5a commit 54da180
Showing 1 changed file with 50 additions and 34 deletions.
84 changes: 50 additions & 34 deletions core/src/main/java/org/apache/calcite/util/ChunkList.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,17 @@
*/
package org.apache.calcite.util;

import org.checkerframework.checker.nullness.qual.Nullable;

import java.util.AbstractSequentialList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.NoSuchElementException;

import static org.apache.calcite.linq4j.Nullness.castNonNull;

/**
* Implementation of list similar to {@link LinkedList}, but stores elements
* in chunks of 32 elements.
Expand All @@ -44,8 +48,8 @@ public class ChunkList<E> extends AbstractSequentialList<E> {
}

private int size;
private Object[] first;
private Object[] last;
private E @Nullable [] first;
private E @Nullable [] last;

/**
* Creates an empty ChunkList.
Expand Down Expand Up @@ -113,15 +117,17 @@ boolean isValid(boolean fail) {
}

@Override public boolean add(E element) {
Object[] chunk = last;
E[] chunk = last;
int occupied;
if (chunk == null) {
chunk = first = last = new Object[CHUNK_SIZE + HEADER_SIZE];
//noinspection unchecked
chunk = first = last = (E[]) new Object[CHUNK_SIZE + HEADER_SIZE];
occupied = 0;
} else {
occupied = occupied(chunk);
if (occupied == CHUNK_SIZE) {
chunk = new Object[CHUNK_SIZE + HEADER_SIZE];
//noinspection unchecked
chunk = (E[]) new Object[CHUNK_SIZE + HEADER_SIZE];
setNext(last, chunk);
setPrev(chunk, last);
occupied = 0;
Expand All @@ -142,21 +148,25 @@ boolean isValid(boolean fail) {
}
}

private static Object[] prev(Object[] chunk) {
return (Object[]) chunk[0];
private static <E> E @Nullable [] prev(E[] chunk) {
//noinspection unchecked
return (E @Nullable []) chunk[0];
}

private static void setPrev(Object[] chunk, Object[] prev) {
chunk[0] = prev;
private static <E> void setPrev(E[] chunk, E @Nullable [] prev) {
//noinspection unchecked
chunk[0] = (E) prev;
}

private static Object[] next(Object[] chunk) {
return (Object[]) chunk[1];
private static <E> E @Nullable [] next(E[] chunk) {
//noinspection unchecked
return (E @Nullable []) chunk[1];
}

private static void setNext(Object[] chunk, Object[] next) {
private static <E> void setNext(E[] chunk, E @Nullable [] next) {
assert chunk != next;
chunk[1] = next;
//noinspection unchecked
chunk[1] = (E) next;
}

private static int occupied(Object[] chunk) {
Expand All @@ -167,12 +177,12 @@ private static void setOccupied(Object[] chunk, int size) {
chunk[2] = INTEGERS[size];
}

private static Object element(Object[] chunk, int index) {
private static <E> E element(E[] chunk, int index) {
return chunk[index];
}

private static void setElement(Object[] chunk, int index, Object element) {
chunk[index] = element;
private static <E> void setElement(E[] chunk, int index, @Nullable E element) {
chunk[index] = castNonNull(element);
}

private ChunkListIterator locate(int index) {
Expand All @@ -184,10 +194,10 @@ private ChunkListIterator locate(int index) {
return new ChunkListIterator(null, 0, 0, -1, 0);
}
int n = 0;
for (Object[] chunk = first;;) {
for (E[] chunk = first;;) {
final int occupied = occupied(chunk);
final int nextN = n + occupied;
final Object[] next = next(chunk);
final E[] next = next(chunk);
if (nextN >= index || next == null) {
return new ChunkListIterator(chunk, n, index, -1, n + occupied);
}
Expand All @@ -198,7 +208,7 @@ private ChunkListIterator locate(int index) {

/** Iterator over a {@link ChunkList}. */
private class ChunkListIterator implements ListIterator<E> {
private Object[] chunk;
private E @Nullable [] chunk;
/** Offset in the list of the first element of this chunk. */
private int start;
/** Offset within current chunk of the next element to return. */
Expand All @@ -209,7 +219,7 @@ private class ChunkListIterator implements ListIterator<E> {
/** Offset of the first unoccupied location in the current chunk. */
private int end;

ChunkListIterator(Object[] chunk, int start, int cursor, int lastRet,
ChunkListIterator(E @Nullable [] chunk, int start, int cursor, int lastRet,
int end) {
this.chunk = chunk;
this.start = start;
Expand All @@ -218,6 +228,10 @@ private class ChunkListIterator implements ListIterator<E> {
this.end = end;
}

private E[] currentChunk() {
return castNonNull(chunk);
}

@Override public boolean hasNext() {
return cursor < size;
}
Expand All @@ -240,7 +254,7 @@ private class ChunkListIterator implements ListIterator<E> {
}
}
@SuppressWarnings("unchecked")
final E element = (E) element(chunk,
final E element = (E) element(currentChunk(),
HEADER_SIZE + (lastRet = cursor++) - start);
return element;
}
Expand All @@ -262,7 +276,7 @@ private class ChunkListIterator implements ListIterator<E> {
assert cursor == end - 1;
}
//noinspection unchecked
return (E) element(chunk, cursor - start);
return (E) element(currentChunk(), cursor - start);
}

@Override public int nextIndex() {
Expand All @@ -281,8 +295,8 @@ private class ChunkListIterator implements ListIterator<E> {
--cursor;
if (end == start + 1) {
// Chunk is now empty.
final Object[] prev = prev(chunk);
final Object[] next = ChunkList.next(chunk);
final E[] prev = prev(currentChunk());
final E[] next = ChunkList.next(currentChunk());
if (next == null) {
last = prev;
if (prev == null) {
Expand Down Expand Up @@ -317,7 +331,7 @@ private class ChunkListIterator implements ListIterator<E> {
if (c == null) {
c = last;
}
int o = occupied(c);
int o = occupied(castNonNull(c));
if (o == 1) {
// Block is now empty; remove it
final Object[] prev = prev(c);
Expand All @@ -339,33 +353,34 @@ private class ChunkListIterator implements ListIterator<E> {
}
} else {
// Move existing contents down one.
System.arraycopy(chunk, HEADER_SIZE + r - start + 1,
chunk, HEADER_SIZE + r - start, end - r - 1);
System.arraycopy(currentChunk(), HEADER_SIZE + r - start + 1,
currentChunk(), HEADER_SIZE + r - start, end - r - 1);
--end;
final int o = end - start;
setElement(chunk, HEADER_SIZE + o, null); // allow gc
setOccupied(chunk, o);
setElement(currentChunk(), HEADER_SIZE + o, null); // allow gc
setOccupied(currentChunk(), o);
}
}

@Override public void set(E e) {
if (lastRet < 0) {
throw new IllegalStateException();
}
Object[] c = chunk;
Object[] c = currentChunk();
int p = lastRet;
int s = start;
if (p < start) {
// The element is at the end of the previous chunk
c = prev(c);
s -= occupied(c);
s -= occupied(castNonNull(c));
}
setElement(c, HEADER_SIZE + p - s, e);
}

@Override public void add(E e) {
if (chunk == null) {
Object[] newChunk = new Object[CHUNK_SIZE + HEADER_SIZE];
//noinspection unchecked
E[] newChunk = (E[]) new Object[CHUNK_SIZE + HEADER_SIZE];
if (first != null) {
setNext(newChunk, first);
setPrev(first, newChunk);
Expand All @@ -379,8 +394,9 @@ private class ChunkListIterator implements ListIterator<E> {
} else if (end == start + CHUNK_SIZE) {
// FIXME We create a new chunk, but the next chunk might be
// less than half full. We should consider using it.
Object[] newChunk = new Object[CHUNK_SIZE + HEADER_SIZE];
final Object[] next = ChunkList.next(chunk);
//noinspection unchecked
E[] newChunk = (E[]) new Object[CHUNK_SIZE + HEADER_SIZE];
final E[] next = ChunkList.next(chunk);
setPrev(newChunk, chunk);
setNext(chunk, newChunk);

Expand Down

0 comments on commit 54da180

Please sign in to comment.