Skip to content

Commit

Permalink
Merge pull request #42982 from mkouba/qute-jdk-lists
Browse files Browse the repository at this point in the history
Use JDK immutable lists to reduce arity of List invokeInterface
  • Loading branch information
mkouba authored Sep 3, 2024
2 parents 839d999 + da7c0ad commit 2539288
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 278 deletions.
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
package io.quarkus.qute;

import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import java.util.Spliterator;
import java.util.Spliterators;

/**
* Immutable lists.
Expand All @@ -26,14 +18,18 @@ private ImmutableList() {
* @return an immutable copy of the given list
*/
public static <T> List<T> copyOf(List<T> list) {
if (list.isEmpty()) {
return Collections.emptyList();
} else if (list.size() == 1) {
return of(list.get(0));
} else if (list.size() == 2) {
return of(list.get(0), list.get(1));
}
return new ImmutableArrayList<>(list.toArray());
final int size;
if (list instanceof ArrayList<T> && (size = list.size()) <= 2) {
switch (size) {
case 0:
return List.of();
case 1:
return List.of(list.get(0));
case 2:
return List.of(list.get(0), list.get(1));
}
}
return List.copyOf(list);
}

/**
Expand All @@ -43,16 +39,12 @@ public static <T> List<T> copyOf(List<T> list) {
*/
@SafeVarargs
public static <T> List<T> of(T... elements) {
switch (elements.length) {
case 0:
return Collections.emptyList();
case 1:
return of(elements[0]);
case 2:
return of(elements[0], elements[1]);
default:
return new ImmutableArrayList<>(elements);
}
return switch (elements.length) {
case 0 -> List.of();
case 1 -> List.of(elements[0]);
case 2 -> List.of(elements[0], elements[1]);
default -> List.of(elements);
};
}

/**
Expand All @@ -62,7 +54,7 @@ public static <T> List<T> of(T... elements) {
* @return an immutable list
*/
public static <E> List<E> of(E element) {
return Collections.singletonList(element);
return List.of(element);
}

/**
Expand All @@ -73,7 +65,7 @@ public static <E> List<E> of(E element) {
* @return an immutable list
*/
public static <E> List<E> of(E e1, E e2) {
return new ImmutableList2<>(e1, e2);
return List.of(e1, e2);
}

/**
Expand Down Expand Up @@ -105,253 +97,6 @@ public Builder<T> addAll(Collection<T> elements) {
public List<T> build() {
return copyOf(elements);
}

}

static class ImmutableList2<E> extends AbstractList<E> {

private final E e0;
private final E e1;

ImmutableList2(E e0, E e1) {
this.e0 = e0;
this.e1 = e1;
}

@Override
public E get(int index) {
if (index == 0) {
return e0;
} else if (index == 1) {
return e1;
}
throw indexOutOfBound(index, 2);
}

@Override
public int size() {
return 2;
}

@Override
public boolean isEmpty() {
return false;
}

@Override
public Iterator<E> iterator() {
return new Itr();
}

@Override
public ListIterator<E> listIterator() {
return new Itr();
}

private final class Itr implements ListIterator<E> {

private byte cursor = 0;

@Override
public boolean hasNext() {
return cursor < 2;
}

@Override
public E next() {
if (cursor == 0) {
cursor++;
return e0;
} else if (cursor == 1) {
cursor++;
return e1;
}
throw new NoSuchElementException();
}

@Override
public boolean hasPrevious() {
return cursor > 0;
}

@Override
public E previous() {
if (cursor == 2) {
cursor--;
return e1;
} else if (cursor == 1) {
cursor--;
return e0;
}
throw new NoSuchElementException();
}

@Override
public int nextIndex() {
return cursor;
}

@Override
public int previousIndex() {
return cursor - 1;
}

@Override
public void remove() {
throw new UnsupportedOperationException();
}

@Override
public void set(E e) {
throw new UnsupportedOperationException();
}

@Override
public void add(E e) {
throw new UnsupportedOperationException();
}
}

}

static class ImmutableArrayList<E> extends AbstractList<E> {

private final Object[] elements;

ImmutableArrayList(Object[] elements) {
this.elements = elements;
}

@SuppressWarnings("unchecked")
@Override
public E get(int index) {
if (index < 0 || index >= elements.length) {
throw indexOutOfBound(index, size());
}
return (E) elements[index];
}

@Override
public int size() {
return elements.length;
}

@Override
public Iterator<E> iterator() {
return new Itr(elements.length, 0);
}

@Override
public ListIterator<E> listIterator() {
return new Itr(elements.length, 0);
}

@Override
public ListIterator<E> listIterator(int index) {
return new Itr(elements.length, index);
}

@Override
public List<E> subList(int fromIndex, int toIndex) {
if (fromIndex < 0 || fromIndex > toIndex) {
throw indexOutOfBound(fromIndex, size());
}
if (toIndex > elements.length) {
throw indexOutOfBound(toIndex, size());
}
if (fromIndex == toIndex) {
return Collections.emptyList();
}
return new ImmutableArrayList<>(
Arrays.copyOfRange(this.elements, fromIndex, toIndex));
}

@Override
public String toString() {
return Arrays.toString(elements);
}

@Override
public boolean isEmpty() {
return elements.length == 0;
}

@Override
public Spliterator<E> spliterator() {
return Spliterators.spliterator(this, Spliterator.ORDERED
| Spliterator.IMMUTABLE | Spliterator.NONNULL);
}

private final class Itr implements ListIterator<E> {

private int cursor;

private final int size;

Itr(int size, int position) {
this.size = size;
this.cursor = position;
}

@Override
public boolean hasNext() {
return cursor < size;
}

@SuppressWarnings("unchecked")
@Override
public E next() {
if (hasNext()) {
return (E) elements[cursor++];
}
throw new NoSuchElementException();
}

@Override
public boolean hasPrevious() {
return cursor > 0;
}

@SuppressWarnings("unchecked")
@Override
public E previous() {
if (hasPrevious()) {
return (E) elements[--cursor];
}
throw new NoSuchElementException();
}

@Override
public int nextIndex() {
return cursor;
}

@Override
public int previousIndex() {
return cursor - 1;
}

@Override
public void remove() {
throw new UnsupportedOperationException();
}

@Override
public void set(E e) {
throw new UnsupportedOperationException();
}

@Override
public void add(E e) {
throw new UnsupportedOperationException();
}
}

}

private static IndexOutOfBoundsException indexOutOfBound(int index, int size) {
return new IndexOutOfBoundsException("Index " + index
+ " is out of bounds, list size: " + size);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,7 @@ public void testListOfTwo() {
assertThatExceptionOfType(NoSuchElementException.class)
.isThrownBy(() -> it.next());
assertThatExceptionOfType(IndexOutOfBoundsException.class)
.isThrownBy(() -> list.get(5))
.withMessage(
"Index 5 is out of bounds, list size: 2");
.isThrownBy(() -> list.get(5));
}

}

0 comments on commit 2539288

Please sign in to comment.