/* __ __ __ __ __ ___
* \ \ / / \ \ / / __/
* \ \/ / /\ \ \/ / /
* \____/__/ \__\____/__/.ɪᴏ
* ᶜᵒᵖʸʳᶦᵍʰᵗ ᵇʸ ᵛᵃᵛʳ ⁻ ˡᶦᶜᵉⁿˢᵉᵈ ᵘⁿᵈᵉʳ ᵗʰᵉ ᵃᵖᵃᶜʰᵉ ˡᶦᶜᵉⁿˢᵉ ᵛᵉʳˢᶦᵒⁿ ᵗʷᵒ ᵈᵒᵗ ᶻᵉʳᵒ
*/
package io.vavr.collection;
import io.vavr.PartialFunction;
import io.vavr.Tuple3;
import io.vavr.Tuple2;
import io.vavr.control.Option;
import java.util.Comparator;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.function.*;
/**
* Interface for immutable, indexed sequences.
* <p>
* Efficient random access is characteristic for indexed sequences.
*
* @param <T> component type
* @author Daniel Dietrich
*/
public interface IndexedSeq<T> extends Seq<T> {
long serialVersionUID = 1L;
/**
* Narrows a widened {@code IndexedSeq<? extends T>} to {@code IndexedSeq<T>}
* by performing a type-safe cast. This is eligible because immutable/read-only
* collections are covariant.
*
* @param indexedSeq An {@code IndexedSeq}.
* @param <T> Component type of the {@code IndexedSeq}.
* @return the given {@code indexedSeq} instance as narrowed type {@code IndexedSeq<T>}.
*/
@SuppressWarnings("unchecked")
static <T> IndexedSeq<T> narrow(IndexedSeq<? extends T> indexedSeq) {
return (IndexedSeq<T>) indexedSeq;
}
// -- Adjusted return types of Seq methods
@Override
IndexedSeq<T> append(T element);
@Override
IndexedSeq<T> appendAll(Iterable<? extends T> elements);
@GwtIncompatible
@Override
IndexedSeq<T> asJava(Consumer<? super java.util.List<T>> action);
@GwtIncompatible
@Override
IndexedSeq<T> asJavaMutable(Consumer<? super java.util.List<T>> action);
@Override
<R> IndexedSeq<R> collect(PartialFunction<? super T, ? extends R> partialFunction);
@Override
IndexedSeq<? extends IndexedSeq<T>> combinations();
@Override
IndexedSeq<? extends IndexedSeq<T>> combinations(int k);
@Override
Iterator<? extends IndexedSeq<T>> crossProduct(int power);
@Override
IndexedSeq<T> distinct();
@Override
IndexedSeq<T> distinctBy(Comparator<? super T> comparator);
@Override
<U> IndexedSeq<T> distinctBy(Function<? super T, ? extends U> keyExtractor);
@Override
IndexedSeq<T> drop(int n);
@Override
IndexedSeq<T> dropUntil(Predicate<? super T> predicate);
@Override
IndexedSeq<T> dropWhile(Predicate<? super T> predicate);
@Override
IndexedSeq<T> dropRight(int n);
@Override
IndexedSeq<T> dropRightUntil(Predicate<? super T> predicate);
@Override
IndexedSeq<T> dropRightWhile(Predicate<? super T> predicate);
@Override
default boolean endsWith(Seq<? extends T> that) {
Objects.requireNonNull(that, "that is null");
if (that instanceof IndexedSeq) {
int i = length() - 1;
int j = that.length() - 1;
if (j > i) {
return false;
} else {
while (j >= 0) {
if (!Objects.equals(this.get(i), that.get(j))) {
return false;
}
i--;
j--;
}
return true;
}
} else {
return Seq.super.endsWith(that);
}
}
@Override
IndexedSeq<T> filter(Predicate<? super T> predicate);
@Override
<U> IndexedSeq<U> flatMap(Function<? super T, ? extends Iterable<? extends U>> mapper);
@Override
<C> Map<C, ? extends IndexedSeq<T>> groupBy(Function<? super T, ? extends C> classifier);
@Override
default int indexWhere(Predicate<? super T> predicate, int from) {
Objects.requireNonNull(predicate, "predicate is null");
int start = Math.max(from, 0);
int n = start + segmentLength(predicate.negate(), start);
return (n >= length()) ? -1 : n;
}
@Override
Iterator<? extends IndexedSeq<T>> grouped(int size);
@Override
default int indexOfSlice(Iterable<? extends T> that, int from) {
Objects.requireNonNull(that, "that is null");
return IndexedSeqModule.Slice.indexOfSlice(this, that, from);
}
@Override
IndexedSeq<T> init();
@Override
Option<? extends IndexedSeq<T>> initOption();
@Override
IndexedSeq<T> insert(int index, T element);
@Override
IndexedSeq<T> insertAll(int index, Iterable<? extends T> elements);
@Override
IndexedSeq<T> intersperse(T element);
@Override
default T last() {
if (isEmpty()) {
throw new NoSuchElementException("last of empty IndexedSeq");
} else {
return get(length() - 1);
}
}
@Override
default int lastIndexOfSlice(Iterable<? extends T> that, int end) {
Objects.requireNonNull(that, "that is null");
return IndexedSeqModule.Slice.lastIndexOfSlice(this, that, end);
}
@Override
default int lastIndexWhere(Predicate<? super T> predicate, int end) {
Objects.requireNonNull(predicate, "predicate is null");
int i = Math.min(end, length() - 1);
while (i >= 0 && !predicate.test(this.get(i))) {
i--;
}
return i;
}
@Override
<U> IndexedSeq<U> map(Function<? super T, ? extends U> mapper);
@Override
IndexedSeq<T> orElse(Iterable<? extends T> other);
@Override
IndexedSeq<T> orElse(Supplier<? extends Iterable<? extends T>> supplier);
@Override
IndexedSeq<T> padTo(int length, T element);
@Override
IndexedSeq<T> patch(int from, Iterable<? extends T> that, int replaced);
@Override
Tuple2<? extends IndexedSeq<T>, ? extends IndexedSeq<T>> partition(Predicate<? super T> predicate);
@Override
IndexedSeq<T> peek(Consumer<? super T> action);
@Override
IndexedSeq<? extends IndexedSeq<T>> permutations();
@Override
IndexedSeq<T> prepend(T element);
@Override
IndexedSeq<T> prependAll(Iterable<? extends T> elements);
@Override
IndexedSeq<T> remove(T element);
@Override
IndexedSeq<T> removeFirst(Predicate<T> predicate);
@Override
IndexedSeq<T> removeLast(Predicate<T> predicate);
@Override
IndexedSeq<T> removeAt(int index);
@Override
IndexedSeq<T> removeAll(T element);
@Override
IndexedSeq<T> removeAll(Iterable<? extends T> elements);
@Override
IndexedSeq<T> removeAll(Predicate<? super T> predicate);
@Override
IndexedSeq<T> replace(T currentElement, T newElement);
@Override
IndexedSeq<T> replaceAll(T currentElement, T newElement);
@Override
IndexedSeq<T> retainAll(Iterable<? extends T> elements);
@Override
IndexedSeq<T> reverse();
@Override
default Iterator<T> reverseIterator() {
return new AbstractIterator<T>() {
private int i = IndexedSeq.this.length();
@Override
public boolean hasNext() {
return i > 0;
}
@Override
public T getNext() {
return IndexedSeq.this.get(--i);
}
};
}
@Override
IndexedSeq<T> scan(T zero, BiFunction<? super T, ? super T, ? extends T> operation);
@Override
<U> IndexedSeq<U> scanLeft(U zero, BiFunction<? super U, ? super T, ? extends U> operation);
@Override
<U> IndexedSeq<U> scanRight(U zero, BiFunction<? super T, ? super U, ? extends U> operation);
@Override
default int segmentLength(Predicate<? super T> predicate, int from) {
Objects.requireNonNull(predicate, "predicate is null");
int len = length();
int i = from;
while (i < len && predicate.test(this.get(i))) {
i++;
}
return i - from;
}
@Override
IndexedSeq<T> shuffle();
@Override
IndexedSeq<T> slice(int beginIndex, int endIndex);
@Override
Iterator<? extends IndexedSeq<T>> slideBy(Function<? super T, ?> classifier);
@Override
Iterator<? extends IndexedSeq<T>> sliding(int size);
@Override
Iterator<? extends IndexedSeq<T>> sliding(int size, int step);
@Override
IndexedSeq<T> sorted();
@Override
IndexedSeq<T> sorted(Comparator<? super T> comparator);
@Override
<U extends Comparable<? super U>> IndexedSeq<T> sortBy(Function<? super T, ? extends U> mapper);
@Override
<U> IndexedSeq<T> sortBy(Comparator<? super U> comparator, Function<? super T, ? extends U> mapper);
@Override
Tuple2<? extends IndexedSeq<T>, ? extends IndexedSeq<T>> span(Predicate<? super T> predicate);
@Override
default boolean startsWith(Iterable<? extends T> that, int offset) {
Objects.requireNonNull(that, "that is null");
if (offset < 0) { return false; }
if (that instanceof IndexedSeq) {
IndexedSeq<? extends T> thatIndexedSeq = (IndexedSeq<? extends T>) that;
int i = offset;
int j = 0;
int thisLen = length();
int thatLen = thatIndexedSeq.length();
while (i < thisLen && j < thatLen && Objects.equals(this.get(i), thatIndexedSeq.get(j))) {
i++;
j++;
}
return j == thatLen;
} else {
int i = offset;
int thisLen = length();
java.util.Iterator<? extends T> thatElems = that.iterator();
while (i < thisLen && thatElems.hasNext()) {
if (!Objects.equals(this.get(i), thatElems.next())) {
return false;
}
i++;
}
return !thatElems.hasNext();
}
}
@Override
IndexedSeq<T> subSequence(int beginIndex);
@Override
IndexedSeq<T> subSequence(int beginIndex, int endIndex);
@Override
IndexedSeq<T> tail();
@Override
Option<? extends IndexedSeq<T>> tailOption();
@Override
IndexedSeq<T> take(int n);
@Override
IndexedSeq<T> takeRight(int n);
@Override
IndexedSeq<T> takeUntil(Predicate<? super T> predicate);
@Override
IndexedSeq<T> takeWhile(Predicate<? super T> predicate);
@Override
<T1, T2> Tuple2<? extends IndexedSeq<T1>, ? extends IndexedSeq<T2>> unzip(Function<? super T, Tuple2<? extends T1, ? extends T2>> unzipper);
@Override
<T1, T2, T3> Tuple3<? extends IndexedSeq<T1>, ? extends IndexedSeq<T2>, ? extends IndexedSeq<T3>> unzip3(Function<? super T, Tuple3<? extends T1, ? extends T2, ? extends T3>> unzipper);
@Override
IndexedSeq<T> update(int index, T element);
@Override
IndexedSeq<T> update(int index, Function<? super T, ? extends T> updater);
@Override
<U> IndexedSeq<Tuple2<T, U>> zip(Iterable<? extends U> that);
@Override
<U, R> IndexedSeq<R> zipWith(Iterable<? extends U> that, BiFunction<? super T, ? super U, ? extends R> mapper);
@Override
<U> IndexedSeq<Tuple2<T, U>> zipAll(Iterable<? extends U> that, T thisElem, U thatElem);
@Override
IndexedSeq<Tuple2<T, Integer>> zipWithIndex();
@Override
<U> IndexedSeq<U> zipWithIndex(BiFunction<? super T, ? super Integer, ? extends U> mapper);
/**
* Searches this sequence for a specific element using a binary search. The sequence must already be sorted into
* ascending natural order. If it is not sorted, the results are undefined.
*
* @param element the element to find
* @return the index of the search element, if it is contained in the sequence;
* otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>. The
* <i>insertion point</i> is defined as the point at which the
* element would be inserted into the sequence. Note that this guarantees that
* the return value will be >= 0 if and only if the element is found.
* @throws ClassCastException if T cannot be cast to {@code Comparable<? super T>}
*/
@Override
@SuppressWarnings("unchecked")
default int search(T element) {
IntUnaryOperator comparison = midIndex -> {
Comparable<? super T> midVal = (Comparable<? super T>) get(midIndex);
return midVal.compareTo(element);
};
return IndexedSeqModule.Search.binarySearch(this, comparison);
}
/**
* Searches this sequence for a specific element using a binary search. The sequence must already be sorted into
* ascending order according to the specified comparator. If it is not sorted, the results are undefined.
*
* @param element the element to find
* @param comparator the comparator by which this sequence is ordered
* @return the index of the search element, if it is contained in the sequence;
* otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>. The
* <i>insertion point</i> is defined as the point at which the
* element would be inserted into the sequence. Note that this guarantees that
* the return value will be >= 0 if and only if the element is found.
*/
@Override
default int search(T element, Comparator<? super T> comparator) {
Objects.requireNonNull(comparator, "comparator is null");
IntUnaryOperator comparison = midIndex -> {
T midVal = get(midIndex);
return comparator.compare(midVal, element);
};
return IndexedSeqModule.Search.binarySearch(this, comparison);
}
}
interface IndexedSeqModule {
class Slice {
static <T> int indexOfSlice(IndexedSeq<T> source, Iterable<? extends T> slice, int from) {
if (source.isEmpty()) {
return from == 0 && Collections.isEmpty(slice) ? 0 : -1;
}
final IndexedSeq<T> _slice = toIndexedSeq(slice);
final int maxIndex = source.length() - _slice.length();
return findSlice(source, _slice, Math.max(from, 0), maxIndex);
}
static <T> int lastIndexOfSlice(IndexedSeq<T> source, Iterable<? extends T> slice, int end) {
if (end < 0) {
return -1;
} else if (source.isEmpty()) {
return Collections.isEmpty(slice) ? 0 : -1;
} else if (Collections.isEmpty(slice)) {
final int len = source.length();
return len < end ? len : end;
}
int index = 0;
int result = -1;
final IndexedSeq<T> _slice = toIndexedSeq(slice);
final int maxIndex = source.length() - _slice.length();
while (index <= maxIndex) {
int indexOfSlice = findSlice(source, _slice, index, maxIndex);
if (indexOfSlice < 0) {
return result;
}
if (indexOfSlice <= end) {
result = indexOfSlice;
index = indexOfSlice + 1;
} else {
return result;
}
}
return result;
}
private static <T> int findSlice(IndexedSeq<T> source, IndexedSeq<T> slice, int index, int maxIndex) {
while (index <= maxIndex) {
if (source.startsWith(slice, index)) {
return index;
}
index++;
}
return -1;
}
@SuppressWarnings("unchecked")
private static <T> IndexedSeq<T> toIndexedSeq(Iterable<? extends T> iterable) {
return (iterable instanceof IndexedSeq) ? (IndexedSeq<T>) iterable : Vector.ofAll(iterable);
}
}
interface Search {
static <T> int binarySearch(IndexedSeq<T> seq, IntUnaryOperator comparison) {
int low = 0;
int high = seq.size() - 1;
while (low <= high) {
final int mid = (low + high) >>> 1;
final int cmp = comparison.applyAsInt(mid);
if (cmp < 0) {
low = mid + 1;
} else if (cmp > 0) {
high = mid - 1;
} else {
return mid;
}
}
return -(low + 1);
}
}
}