
javaslang.collection.LinearSeq Maven / Gradle / Ivy
/* / \____ _ _ ____ ______ / \ ____ __ _______
* / / \/ \ / \/ \ / /\__\/ // \/ \ // /\__\ JΛVΛSLΛNG
* _/ / /\ \ \/ / /\ \\__\\ \ // /\ \ /\\/ \ /__\ \ Copyright 2014-2016 Javaslang, http://javaslang.io
* /___/\_/ \_/\____/\_/ \_/\__\/__/\__\_/ \_// \__/\_____/ Licensed under the Apache License, Version 2.0
*/
package javaslang.collection;
import javaslang.Tuple;
import javaslang.Tuple2;
import javaslang.control.Option;
import java.util.Comparator;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.ToIntFunction;
/**
* Interface for immutable, linear sequences.
*
* Efficient {@code head()}, {@code tail()}, and {@code isEmpty()} methods are characteristic for linear sequences.
*
* @param component type
* @author Daniel Dietrich
* @since 2.0.0
*/
public interface LinearSeq extends Seq {
long serialVersionUID = 1L;
/**
* Narrows a widened {@code LinearSeq extends T>} to {@code LinearSeq}
* by performing a type safe-cast. This is eligible because immutable/read-only
* collections are covariant.
*
* @param linearSeq A {@code LinearSeq}.
* @param Component type of the {@code LinearSeq}.
* @return the given {@code linearSeq} instance as narrowed type {@code LinearSeq}.
*/
@SuppressWarnings("unchecked")
static LinearSeq narrow(LinearSeq extends T> linearSeq) {
return (LinearSeq) linearSeq;
}
// -- Adjusted return types of Seq methods
@Override
LinearSeq append(T element);
@Override
LinearSeq appendAll(Iterable extends T> elements);
@Override
LinearSeq extends LinearSeq> combinations();
@Override
LinearSeq extends LinearSeq> combinations(int k);
@Override
Iterator extends LinearSeq> crossProduct(int power);
@Override
LinearSeq distinct();
@Override
LinearSeq distinctBy(Comparator super T> comparator);
@Override
LinearSeq distinctBy(Function super T, ? extends U> keyExtractor);
@Override
LinearSeq drop(long n);
@Override
LinearSeq dropRight(long n);
@Override
LinearSeq dropUntil(Predicate super T> predicate);
@Override
LinearSeq dropWhile(Predicate super T> predicate);
@Override
LinearSeq filter(Predicate super T> predicate);
@Override
LinearSeq flatMap(Function super T, ? extends Iterable extends U>> mapper);
@Override
Map> groupBy(Function super T, ? extends C> classifier);
@Override
Iterator extends LinearSeq> grouped(long size);
@Override
default int indexWhere(Predicate super T> predicate, int from) {
Objects.requireNonNull(predicate, "predicate is null");
int i = from;
LinearSeq these = drop(from);
while (!these.isEmpty()) {
if (predicate.test(these.head())) {
return i;
}
i++;
these = these.tail();
}
return -1;
}
@Override
LinearSeq init();
@Override
Option extends LinearSeq> initOption();
@Override
LinearSeq insert(int index, T element);
@Override
LinearSeq insertAll(int index, Iterable extends T> elements);
@Override
LinearSeq intersperse(T element);
@Override
default int lastIndexOfSlice(Iterable extends T> that, int end) {
return LinearSeqModule.LastIndexOfSlice.lastIndexOfSlice(this, unit(that), end);
}
@Override
default int lastIndexWhere(Predicate super T> predicate, int end) {
Objects.requireNonNull(predicate, "predicate is null");
int i = 0;
LinearSeq these = this;
int last = -1;
while (!these.isEmpty() && i <= end) {
if (predicate.test(these.head())) {
last = i;
}
these = these.tail();
i++;
}
return last;
}
@Override
LinearSeq map(Function super T, ? extends U> mapper);
@Override
LinearSeq padTo(int length, T element);
@Override
LinearSeq patch(int from, Iterable extends T> that, int replaced);
@Override
Tuple2 extends LinearSeq, ? extends LinearSeq> partition(Predicate super T> predicate);
@Override
LinearSeq peek(Consumer super T> action);
@Override
LinearSeq extends LinearSeq> permutations();
@Override
LinearSeq prepend(T element);
@Override
LinearSeq prependAll(Iterable extends T> elements);
@Override
LinearSeq remove(T element);
@Override
LinearSeq removeFirst(Predicate predicate);
@Override
LinearSeq removeLast(Predicate predicate);
@Override
LinearSeq removeAt(int index);
@Override
LinearSeq removeAll(T element);
@Override
LinearSeq removeAll(Iterable extends T> elements);
@Override
LinearSeq replace(T currentElement, T newElement);
@Override
LinearSeq replaceAll(T currentElement, T newElement);
@Override
LinearSeq retainAll(Iterable extends T> elements);
@Override
LinearSeq reverse();
@Override
default Iterator reverseIterator() {
return reverse().iterator();
}
@Override
LinearSeq scan(T zero, BiFunction super T, ? super T, ? extends T> operation);
@Override
LinearSeq scanLeft(U zero, BiFunction super U, ? super T, ? extends U> operation);
@Override
LinearSeq 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 i = 0;
LinearSeq these = this.drop(from);
while (!these.isEmpty() && predicate.test(these.head())) {
i++;
these = these.tail();
}
return i;
}
@Override
LinearSeq slice(long beginIndex, long endIndex);
@Override
Iterator extends LinearSeq> sliding(long size);
@Override
Iterator extends LinearSeq> sliding(long size, long step);
@Override
LinearSeq sorted();
@Override
LinearSeq sorted(Comparator super T> comparator);
@Override
> LinearSeq sortBy(Function super T, ? extends U> mapper);
@Override
LinearSeq sortBy(Comparator super U> comparator, Function super T, ? extends U> mapper);
@Override
Tuple2 extends LinearSeq, ? extends LinearSeq> span(Predicate super T> predicate);
@Override
LinearSeq subSequence(int beginIndex);
@Override
LinearSeq subSequence(int beginIndex, int endIndex);
@Override
LinearSeq tail();
@Override
Option extends LinearSeq> tailOption();
@Override
LinearSeq take(long n);
@Override
LinearSeq takeRight(long n);
@Override
LinearSeq takeUntil(Predicate super T> predicate);
@Override
LinearSeq takeWhile(Predicate super T> predicate);
@Override
LinearSeq unit(Iterable extends U> iterable);
@Override
Tuple2 extends LinearSeq, ? extends LinearSeq> unzip(Function super T, Tuple2 extends T1, ? extends T2>> unzipper);
@Override
LinearSeq update(int index, T element);
@Override
LinearSeq> zip(Iterable extends U> that);
@Override
LinearSeq> zipAll(Iterable extends U> that, T thisElem, U thatElem);
@Override
LinearSeq> zipWithIndex();
/**
* Searches this sequence for a specific element using a linear 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, (-(insertion point) - 1). The
* insertion point 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) {
ToIntFunction comparison = current -> {
Comparable comparable = (Comparable) element;
return comparable.compareTo(current);
};
return LinearSeqModule.Search.linearSearch(this, comparison);
}
/**
* Searches this sequence for a specific element using a linear 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, (-(insertion point) - 1). The
* insertion point 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");
ToIntFunction comparison = current -> comparator.compare(element, current);
return LinearSeqModule.Search.linearSearch(this, comparison);
}
}
interface LinearSeqModule {
interface LastIndexOfSlice {
static int lastIndexOfSlice(LinearSeq t, LinearSeq slice, int end) {
if (end < 0) {
return -1;
}
if (t.isEmpty()) {
return slice.isEmpty() ? 0 : -1;
}
if (slice.isEmpty()) {
int len = t.length();
return len < end ? len : end;
}
int p = 0;
int result = -1;
while (t.length() >= slice.length()) {
Tuple2, Integer> r = findSlice(t, slice);
if (r == null) {
return result;
}
if (p + r._2 <= end) {
result = p + r._2;
p += r._2 + 1;
t = r._1.tail();
} else {
return result;
}
}
return result;
}
static Tuple2, Integer> findSlice(LinearSeq t, LinearSeq slice) {
int p = 0;
while (t.length() >= slice.length()) {
if (t.startsWith(slice)) {
return Tuple.of(t, p);
}
p++;
t = t.tail();
}
return null;
}
}
interface Search {
static int linearSearch(LinearSeq seq, ToIntFunction comparison) {
int idx = 0;
for (T current : seq) {
int cmp = comparison.applyAsInt(current);
if (cmp == 0) {
return idx;
} else if (cmp < 0) {
return -(idx + 1);
}
idx += 1;
}
return -(idx + 1);
}
}
}