
com.simplaex.bedrock.Seq Maven / Gradle / Ivy
package com.simplaex.bedrock;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import java.io.Serializable;
import java.util.*;
import java.util.function.*;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import static com.simplaex.bedrock.Control.swap;
/**
* An immutable sequence.
*
* @param The type of the Elements contained in this Sequence.
*/
@Immutable
@SuppressWarnings({"unused"})
public abstract class Seq implements
Serializable,
RandomAccess,
SequenceMethods, BiPredicate super E, ? super E>, Seq>,
Container,
IntFunction {
private int hashCode = 0;
public abstract E get(@Nonnegative final int index);
@Override
public E apply(@Nonnegative final int index) {
return get(index);
}
@Override
public boolean isEmpty() {
return length() == 0;
}
@Override
@Nonnull
public Seq shuffled(@Nonnull final Random random) {
Objects.requireNonNull(random, "the supplied 'random' generator must not be null");
final Object[] array = toArray();
final int len = array.length;
for (int i = 0; i < len; i += 1) {
swap(array, i, random.nextInt(len));
}
return new SeqSimple<>(array);
}
@Override
public E draw(@Nonnull final Random random) throws NoSuchElementException {
Objects.requireNonNull(random, "the supplied 'random' generator must not be null");
if (isEmpty()) {
throw new NoSuchElementException("drawing from an empty set");
}
final int ix = random.nextInt(size());
return get(ix);
}
@Nonnull
public abstract Seq sortedBy(@Nonnull final Comparator super E> comparator);
@Nonnull
public > Seq sortedOn(@Nonnull final Function super E, ? extends F> function) {
Objects.requireNonNull(function, "'function' must not be null");
return sortedBy(Comparator.comparing(function));
}
@Nonnull
public abstract E[] toArray(@Nonnull final Class clazz);
@Nonnull
public abstract Object[] toArray();
@Override
@Nonnull
public String asString(@Nonnull final String delimiter) {
return stream().map(Objects::toString).collect(Collectors.joining(delimiter));
}
@Nonnegative
public int count(@Nullable final E e) {
final int len = length();
int c = 0;
for (int i = 0; i < len; i += 1) {
final E el = get(i);
if (Objects.equals(el, e)) {
c += 1;
}
}
return c;
}
@Nonnegative
public int countBy(@Nonnull final Predicate super E> predicate) {
Objects.requireNonNull(predicate, "'predicate' must not be null");
final int len = length();
int c = 0;
for (int i = 0; i < len; i += 1) {
final E el = get(i);
if (predicate.test(el)) {
c += 1;
}
}
return c;
}
public int find(@Nullable final E e) {
final int len = length();
for (int i = 0; i < len; i += 1) {
final E el = get(i);
if (el == e || el != null && el.equals(e)) {
return i;
}
}
return -1;
}
public int findBy(@Nonnull final Predicate super E> predicate) {
Objects.requireNonNull(predicate, "'predicate' must not be null");
final int len = length();
for (int i = 0; i < len; i += 1) {
final E element = get(i);
if (predicate.test(element)) {
return i;
}
}
return -1;
}
public Optional findFirst(@Nonnull final Predicate super E> predicate) {
Objects.requireNonNull(predicate, "'predicate' must not be null");
final int len = length();
for (int i = 0; i < len; i += 1) {
final E element = get(i);
if (predicate.test(element)) {
return Optional.ofNullable(element);
}
}
return Optional.empty();
}
@Override
public boolean contains(@Nullable final E e) {
return find(e) > -1;
}
@Override
public boolean exists(@Nonnull final Predicate super E> predicate) {
return findBy(predicate) > -1;
}
@Override
public boolean forAll(@Nonnull final Predicate super E> predicate) {
return countBy(predicate) == length();
}
void checkBounds(final int index) {
if (index >= length() || index < 0) {
throw new IndexOutOfBoundsException();
}
}
@Nonnull
public Seq map(@Nonnull final Function super E, ? extends F> function) {
Objects.requireNonNull(function, "'function' must not be null");
final Object[] array = new Object[length()];
int i = 0;
for (final E e : this) {
array[i++] = function.apply(e);
}
return new SeqSimple<>(array);
}
@Nonnull
public Seq flatMap(@Nonnull final Function super E, Seq> function) {
Objects.requireNonNull(function, "'function' must not be null");
@SuppressWarnings("unchecked") final Seq[] array = (Seq[]) new Seq[length()];
int i = 0;
int c = 0;
for (final E e : this) {
final Seq result = function.apply(e);
c += result.length();
array[i++] = result;
}
final Object[] resultArray = new Object[c];
i = 0;
for (final Seq s : array) {
for (final F e : s) {
resultArray[i++] = e;
}
}
return new SeqSimple<>(resultArray);
}
@Nonnull
public Seq flatMapOptional(@Nonnull final Function super E, Optional> function) {
Objects.requireNonNull(function, "'function' must not be null");
@SuppressWarnings("unchecked") final Seq[] array = (Seq[]) new Seq[length()];
final SeqBuilder resultBuilder = Seq.builder();
for (final E e : this) {
final Optional result = function.apply(e);
result.ifPresent(resultBuilder::add);
}
return resultBuilder.build();
}
@Nonnull
public Seq flatMapIterable(@Nonnull final Function super E, ? extends Iterable> function) {
Objects.requireNonNull(function, "'function' must not be null");
@SuppressWarnings("unchecked") final Seq[] array = (Seq[]) new Seq[length()];
final SeqBuilder resultBuilder = Seq.builder();
for (final E e : this) {
resultBuilder.addElements(function.apply(e));
}
return resultBuilder.build();
}
@Nonnull
public Seq> zip(@Nonnull final Seq a) {
return zipWith(Pair::new, a);
}
@Nonnull
public Seq zipWith(
final @Nonnull BiFunction super E, ? super A, ? extends C> function,
final @Nonnull Seq sequence
) {
Objects.requireNonNull(function, "'function' must not be null");
Objects.requireNonNull(sequence, "'sequence' must not be null");
final int len = Math.min(length(), sequence.length());
final Object[] arr = new Object[len];
for (int i = 0; i < len; i += 1) {
arr[i] = function.apply(get(i), sequence.get(i));
}
return new SeqSimple<>(arr);
}
@Nonnull
public Seq> zipWithIndex() {
return Seq.rangeExclusive(0, length()).zip(this);
}
public A foldl(@Nonnull final BiFunction super A, ? super E, ? extends A> function, final A startValue) {
Objects.requireNonNull(function, "'function' must not be null");
A acc = startValue;
for (int i = 0; i < length(); i += 1) {
acc = function.apply(acc, get(i));
}
return acc;
}
public E foldl1(@Nonnull final BiFunction super E, ? super E, ? extends E> function) {
return foldl(function, head());
}
public A foldr(@Nonnull final BiFunction super E, ? super A, ? extends A> function, final A startValue) {
Objects.requireNonNull(function, "'function' must not be null");
A acc = startValue;
for (int i = length() - 1; i >= 0; i -= 1) {
acc = function.apply(get(i), acc);
}
return acc;
}
public E foldr1(@Nonnull final BiFunction super E, ? super E, ? extends E> function) {
return foldr(function, last());
}
@Override
@Nonnull
public Pair, Seq> partitionBy(@Nonnull final Predicate super E> predicate) {
Objects.requireNonNull(predicate, "'predicate' must not be null");
final int sizeHint = length() / 2 + 1;
final SeqBuilder b1 = Seq.builder(sizeHint);
final SeqBuilder b2 = Seq.builder(sizeHint);
forEach(x -> {
if (predicate.test(x)) {
b1.add(x);
} else {
b2.add(x);
}
});
return Pair.of(b1.result(), b2.result());
}
@SuppressWarnings("unchecked")
public E maximum() {
try {
return (E) maximum((Seq) this);
} catch (final ClassCastException exc) {
return null;
}
}
@SuppressWarnings("unchecked")
public E minimum() {
try {
return (E) minimum((Seq) this);
} catch (final ClassCastException exc) {
return null;
}
}
public E maximumBy(final Comparator super E> comparator) {
return foldl1((left, right) -> comparator.compare(left, right) < 0 ? right : left);
}
public E minimumBy(final Comparator super E> comparator) {
return foldl1((left, right) -> comparator.compare(left, right) > 0 ? right : left);
}
@Override
@Nonnull
public Seq> group() {
return groupBy(Objects::equals);
}
@Override
@Nonnull
public Seq> groupBy(@Nonnull final BiPredicate super E, ? super E> operator) {
Objects.requireNonNull(operator, "'operator' must not be null");
if (isEmpty()) {
return Seq.empty();
}
final SeqBuilder> b1 = Seq.builder();
final SeqBuilder b2 = Seq.builder();
E previous = head();
b2.add(previous);
for (int i = 1; i < size(); i += 1) {
final E current = get(i);
if (!operator.test(previous, current)) {
b1.add(b2.result());
b2.clear();
}
b2.add(current);
previous = current;
}
if (!b2.isEmpty()) {
b1.add(b2.result());
}
return b1.result();
}
@Nonnull
@SuppressWarnings("unchecked")
public Seq filter(@Nonnull final Class clazz) {
final Seq res = filter(element -> element != null && clazz.isAssignableFrom(element.getClass()));
return (Seq) res;
}
@Override
@Nonnull
public Seq filter(@Nonnull final Predicate super E> predicate) {
Objects.requireNonNull(predicate, "'predicate' must not be null");
final int sizeHint = length() / 2;
final SeqBuilder b = Seq.builder(sizeHint);
forEach(x -> {
if (predicate.test(x)) {
b.add(x);
}
});
return b.result();
}
@Override
@Nonnull
public Seq filterNot(@Nonnull final Predicate super E> predicate) {
Objects.requireNonNull(predicate, "'predicate' must not be null");
return filter(predicate.negate());
}
@Override
@Nonnull
public Seq takeWhile(@Nonnull final Predicate super E> predicate) {
Objects.requireNonNull(predicate, "'predicate' must not be null");
int i = 0;
while (i < length() && predicate.test(get(i))) {
i += 1;
}
return take(i);
}
@Override
@Nonnull
public Seq takeWhileView(@Nonnull final Predicate super E> predicate) {
Objects.requireNonNull(predicate, "'predicate' must not be null");
int i = 0;
while (i < length() && predicate.test(get(i))) {
i += 1;
}
return takeView(i);
}
@Override
@Nonnull
public Seq dropWhile(@Nonnull final Predicate super E> predicate) {
Objects.requireNonNull(predicate, "'predicate' must not be null");
int i = 0;
while (i < length() && predicate.test(get(i))) {
i += 1;
}
return drop(i);
}
@Override
@Nonnull
public Seq dropWhileView(@Nonnull final Predicate super E> predicate) {
Objects.requireNonNull(predicate, "'predicate' must not be null");
int i = 0;
while (i < length() && predicate.test(get(i))) {
i += 1;
}
return dropView(i);
}
@Override
@Nonnull
public Pair, Seq> breakBy(@Nonnull final Predicate super E> predicate) {
Objects.requireNonNull(predicate, "'predicate' must not be null");
final int ix = findBy(predicate);
if (ix < 0) {
return Pair.of(this, Seq.empty());
} else if (ix == 0) {
return Pair.of(Seq.empty(), this);
} else {
return Pair.of(subSequence(0, ix), subSequence(ix, length()));
}
}
@Override
@Nonnull
public Pair, Seq> breakByView(@Nonnull final Predicate super E> predicate) {
Objects.requireNonNull(predicate, "'predicate' must not be null");
final int ix = findBy(predicate);
if (ix < 0) {
return Pair.of(this, Seq.empty());
} else if (ix == 0) {
return Pair.of(Seq.empty(), this);
} else {
return Pair.of(subSequenceView(0, ix), subSequenceView(ix, length()));
}
}
@Override
@Nonnull
public Pair, Seq> spanBy(@Nonnull final Predicate super E> predicate) {
Objects.requireNonNull(predicate, "'predicate' must not be null");
return breakBy(predicate.negate());
}
@Override
@Nonnull
public Pair, Seq> spanByView(@Nonnull final Predicate super E> predicate) {
Objects.requireNonNull(predicate, "'predicate' must not be null");
return breakByView(predicate.negate());
}
@Override
@Nonnull
public Seq> inits() {
final int len = length();
@SuppressWarnings("unchecked") final Seq[] seqs = (Seq[]) new Seq[len];
for (int i = 0; i < len; i += 1) {
seqs[i] = take(i + 1);
}
return new SeqSimple<>(seqs);
}
@Override
@Nonnull
public Seq> initsView() {
final int len = length();
@SuppressWarnings("unchecked") final Seq[] seqs = (Seq[]) new Seq[len];
for (int i = 0; i < len; i += 1) {
seqs[i] = takeView(i + 1);
}
return new SeqSimple<>(seqs);
}
@Override
@Nonnull
public Seq> tails() {
final int len = length();
@SuppressWarnings("unchecked") final Seq[] seqs = (Seq[]) new Seq[len];
for (int i = 0; i < len; i += 1) {
seqs[i] = takeRight(i + 1);
}
return new SeqSimple<>(seqs);
}
@Override
@Nonnull
public Seq> tailsView() {
final int len = length();
@SuppressWarnings("unchecked") final Seq[] seqs = (Seq[]) new Seq[len];
for (int i = 0; i < len; i += 1) {
seqs[i] = takeRightView(i + 1);
}
return new SeqSimple<>(seqs);
}
public E head() {
return get(0);
}
public E last() {
return get(length() - 1);
}
@Nonnull
public Optional headOptional() {
if (isEmpty()) {
return Optional.empty();
}
return Optional.of(head());
}
@Nonnull
public Optional lastOptional() {
if (isEmpty()) {
return Optional.empty();
}
return Optional.of(last());
}
@Nonnull
public Seq intercalate(@Nonnull final Seq seq) {
if (isEmpty()) {
return this;
}
final int targetSize = (seq.size() + 1) * size() - seq.size();
final Object[] targetArray = new Object[targetSize];
targetArray[0] = head();
int targetIndex = 1;
for (int i = 1; i < size(); i += 1) {
for (int j = 0; j < seq.size(); j += 1) {
targetArray[targetIndex++] = seq.get(j);
}
targetArray[targetIndex++] = get(i);
}
return new SeqSimple<>(targetArray);
}
@Nonnull
public Seq intersperse(final E e) {
if (isEmpty()) {
return this;
}
final int targetSize = size() * 2 - 1;
final Object[] targetArray = new Object[targetSize];
targetArray[0] = head();
int targetIndex = 1;
for (int i = 1; i < size(); i += 1) {
targetArray[targetIndex++] = e;
targetArray[targetIndex++] = get(i);
}
return new SeqSimple<>(targetArray);
}
/**
* Returns a copy of this Seq with no duplicates.
*
* Order is maintained.
*/
@Nonnull
@Override
public Seq distinct() {
final HashSet elements = new HashSet<>();
final SeqBuilder builder = Seq.builder(size());
forEach(element -> {
if (!elements.contains(element)) {
builder.add(element);
elements.add(element);
}
});
return builder.result();
}
/**
* Returns a Seq with the elements from the given Seq removed.
*
* Order is maintained, but the resuling Seq is not distinct; if this Seq contains duplicates then the result
* may contain duplicates too.
*/
public Seq without(final Seq seq) {
return filter(element -> !seq.contains(element));
}
/**
* Returns a distinct Seq that contains the elements from both this Seq and the given Seq.
*
* Order is maintained, but there are no duplicates.
*/
public Seq union(final Seq seq) {
final HashSet elements = new HashSet<>();
final SeqBuilder builder = Seq.builder(size());
final Consumer appender = element -> {
if (!elements.contains(element)) {
builder.add(element);
elements.add(element);
}
};
forEach(appender);
seq.forEach(appender);
return builder.result();
}
/**
* Returns a distinct Seq that contains only the elements that occur in both sets.
*
* Order is maintained.
*/
public Seq intersect(final Seq seq) {
return union(seq).filter(e -> contains(e) && seq.contains(e));
}
@Override
public boolean equals(final @Nullable Object that) {
if (this == that) {
return true;
}
if (!(that instanceof Seq)) {
return false;
}
final int len = length();
@SuppressWarnings("unchecked") final Seq thatSeq = (Seq) that;
if (len != thatSeq.length()) {
return false;
}
final Iterator thisIterator = iterator();
final Iterator thatIterator = thatSeq.iterator();
while (thisIterator.hasNext() && thatIterator.hasNext()) {
final E thisElement = thisIterator.next();
final E thatElement = thatIterator.next();
if (!(thisElement == thatElement || thisElement != null && thisElement.equals(thatElement))) {
return false;
}
}
return true;
}
@Override
public final int hashCode() {
if (hashCode == 0) {
hashCode = calculateHashCode();
}
return hashCode;
}
int calculateHashCode() {
int result = 1;
for (final E element : this) {
result = 31 * result + (element == null ? 0 : element.hashCode());
}
return result;
}
@Override
public String toString() {
return stream().map(Objects::toString).collect(Collectors.joining(", ", "[", "]"));
}
static void reverse(final @Nonnull E[] array) {
final int len = array.length;
final int halfLen = len / 2;
for (int i = 0, j = len - 1; i < halfLen; i += 1, j -= 1) {
swap(array, i, j);
}
}
/**
* Rotates the list by amount positions.
*
* Positive values rotate items to the right, negative values to the left.
*
* Seq.of(1, 2, 3).rotated(1).equals(Seq.of(3, 1, 2))
* Seq.of(1, 2, 3).rotated(-1).equals(Seq.of(2, 3, 1))
*
* @param amount The amount of positions to rotate, positive values to the right, negative values to the left.
* @return The rotated sequence.
*/
@Nonnull
@Override
public Seq rotated(final int amount) {
final Object[] array = new Object[size()];
if (amount == 0) {
return this;
}
if (amount < 0) {
return leftRotated(-amount);
}
for (int i = 0; i < size(); i += 1) {
array[(i + amount) % size()] = get(i);
}
return ofArrayZeroCopyInternal(array);
}
@Nonnull
private Seq leftRotated(final int amount) {
final Object[] array = new Object[size()];
for (int i = 0; i < size(); i += 1) {
array[i] = get((i + amount) % size());
}
return ofArrayZeroCopyInternal(array);
}
@Nonnull
@Override
public Iterator> permutationsIterator() {
return new PermutationIterator<>(this);
}
@Nonnull
@Override
public Seq> permutations() {
return permutationsStream().collect(collector());
}
@Nonnull
@Override
public Iterator iterator() {
return new Iterator() {
private int current = 0;
@Override
public boolean hasNext() {
return current < length();
}
@Override
public E next() {
return get(current++);
}
};
}
@Nonnull
public Iterator reverseIterator() {
return reversed().iterator();
}
/**
* Create a java.util.List
that contains the elements of this sequence.
*
* This action does not copy any data.
*
* @return An unmodifiable list that is backed by this Sequence.
*/
@Nonnull
public List toList() {
return new AbstractList() {
@Override
public E get(final int index) {
return Seq.this.get(index);
}
@Override
public int size() {
return length();
}
};
}
public static Collector, Seq> collector() {
return new Collector, Seq>() {
@Override
public Supplier> supplier() {
return Seq::builder;
}
@Override
public BiConsumer, T> accumulator() {
return SeqBuilder::add;
}
@Override
public BinaryOperator> combiner() {
return SeqBuilder::addElements;
}
@Override
public Function, Seq> finisher() {
return SeqBuilder::result;
}
@Override
public java.util.Set characteristics() {
return Collections.emptySet();
}
};
}
@Nonnull
public Mapping> toMap(@Nonnull final Function super E, ? extends K> groupingFunction) {
Objects.requireNonNull(groupingFunction, "'groupingFunction' must not be null");
final Map> map = new HashMap<>();
boolean allComparable = true;
for (final E element : this) {
final K key = groupingFunction.apply(element);
allComparable = allComparable && key instanceof Comparable;
if (!map.containsKey(key)) {
map.put(key, Seq.builder());
}
map.get(key).add(element);
}
if (map.isEmpty()) {
return Mapping.empty();
}
final Map> finalMap = new HashMap<>();
map.forEach((key, builder) -> finalMap.put(key, builder.result()));
return Mapping.wrap(finalMap);
}
@Nonnull
public > ArrayMap> toArrayMap(@Nonnull final Function super E, ? extends K> groupingFunction) {
Objects.requireNonNull(groupingFunction, "'groupingFunction' must not be null");
final TreeMap> map = new TreeMap<>();
for (final E element : this) {
final K key = groupingFunction.apply(element);
if (!map.containsKey(key)) {
map.put(key, Seq.builder());
}
map.get(key).add(element);
}
if (map.isEmpty()) {
return ArrayMap.empty();
}
final Object[] keys = Seq.ofCollectionInternal(map.keySet()).backingArray;
final Object[] values = new Object[keys.length];
for (int i = 0; i < keys.length; i += 1) {
//noinspection SuspiciousMethodCalls
values[i] = map.get(keys[i]).result();
}
return new ArrayMap<>(keys, values);
}
@SuppressWarnings("unchecked")
@Nonnull
public static Seq empty() {
return (Seq) SeqEmpty.EMPTY;
}
@SafeVarargs
@Nonnull
public static Seq of(@Nonnull final E... es) {
Objects.requireNonNull(es);
if (es.length == 0) {
return empty();
}
return new SeqSimple<>(es);
}
@SafeVarargs
@Nonnull
public static Seq seq(@Nonnull final E... es) {
return ofArray(es);
}
@Nonnull
public static Seq ofArray(@Nonnull final E[] array) {
Objects.requireNonNull(array);
if (array.length == 0) {
return empty();
}
return new SeqSimple<>(array.clone());
}
@Nonnull
static SeqSimple ofArrayZeroCopyInternal(@Nonnull final Object[] array) {
return new SeqSimple<>(array);
}
@Nonnull
public static Seq ofCollection(@Nonnull final Collection extends E> collection) {
Objects.requireNonNull(collection);
if (collection.isEmpty()) {
return empty();
}
return ofCollectionInternal(collection);
}
@Nonnull
static SeqSimple ofCollectionInternal(@Nonnull final Collection extends E> collection) {
final Object[] array = new Object[collection.size()];
int i = 0;
for (final E e : collection) {
array[i++] = e;
}
return new SeqSimple<>(array);
}
@Nonnull
public static Seq ofIterable(@Nonnull final Iterable extends E> iterable) {
Objects.requireNonNull(iterable);
final SeqBuilder builder = new SeqBuilder<>();
iterable.forEach(builder::add);
return builder.result();
}
@Nonnull
public static Seq ofIterator(@Nonnull final Iterator extends E> iterator) {
Objects.requireNonNull(iterator);
final SeqBuilder builder = new SeqBuilder<>();
while (iterator.hasNext()) {
builder.add(iterator.next());
}
return builder.result();
}
@Nonnull
public static Seq ofPair(@Nonnull final Pair pair) {
Objects.requireNonNull(pair, "'pair' must not be null");
return Seq.builder().addAll(pair.fst(), pair.snd()).result();
}
@Nonnull
public static Seq ofString(@Nonnull final String string) {
Objects.requireNonNull(string);
final Character[] array = new Character[string.length()];
for (int i = 0; i < array.length; i += 1) {
array[i] = string.charAt(i);
}
return new SeqSimple<>(array);
}
@FunctionalInterface
@Deprecated
public interface WithIndexConsumer {
void consume(int index, E element);
}
@Deprecated
public void forEach(@Nonnull final WithIndexConsumer consumer) {
Objects.requireNonNull(consumer, "'consumer' must not be null");
for (int i = 0; i < size(); i += 1) {
consumer.consume(i, get(i));
}
}
@Nonnull
public static Seq codepointsOfString(@Nonnull final String string) {
final SeqBuilder b = builder();
Strings.forEachCodepoint(string, b::add);
return b.result();
}
@SafeVarargs
@Nonnull
public static Seq concatView(@Nonnull final Seq... seqs) {
Objects.requireNonNull(seqs);
if (seqs.length == 0) {
return Seq.empty();
}
int size = 0;
for (final Seq seq : seqs) {
size += seq.length();
}
if (size == 0) {
return Seq.empty();
}
return new SeqGenerated(
ix -> {
Seq seq = seqs[0];
int i = 1;
while (ix >= seq.length() && i < seqs.length) {
ix -= seq.length();
seq = seqs[i];
i += 1;
}
return seq.get(ix);
},
size
) {
@Nonnull
@Override
public Iterator iterator() {
return new Iterator() {
private int i = 0;
private int j = 0;
@Override
public boolean hasNext() {
return i < seqs.length && j < seqs[i].length();
}
@Override
public E next() {
final E elem = seqs[i].get(j);
j += 1;
if (j == seqs[i].length()) {
j = 0;
i += 1;
}
return elem;
}
};
}
};
}
@SafeVarargs
@Nonnull
public static Seq concat(@Nonnull final Seq... seqs) {
Objects.requireNonNull(seqs);
int size = 0;
for (final Seq seq : seqs) {
size += seq.length();
}
if (size == 0) {
return Seq.empty();
}
final Object[] array = new Object[size];
int i = 0;
for (final Seq seq : seqs) {
for (final E elem : seq) {
array[i++] = elem;
}
}
return new SeqSimple<>(array);
}
@Nonnull
public static SeqBuilder builder() {
return new SeqBuilder<>();
}
@Nonnull
public static SeqBuilder builder(final int sizeHint) {
return new SeqBuilder<>(sizeHint);
}
@Nonnull
public static Seq ofGenerator(@Nonnull final IntFunction function, @Nonnegative final int length) {
Objects.requireNonNull(function, "'function' must not be null.");
return new SeqGenerated<>(function, length);
}
@Nonnull
public static Seq ofGeneratorMemoizing(@Nonnull final IntFunction function, @Nonnegative final int length) {
Objects.requireNonNull(function, "'function' must not be null.");
return new SeqGenerated<>(Control.memoizing(function), length);
}
@Nonnull
public static Seq wrap(@Nonnull final char[] array) {
if (array.length == 0) {
return Seq.empty();
}
return ofGenerator(ix -> array[ix], array.length);
}
@Nonnull
public static Seq wrap(@Nonnull final boolean[] array) {
if (array.length == 0) {
return Seq.empty();
}
return ofGenerator(ix -> array[ix], array.length);
}
@Nonnull
public static Seq wrap(@Nonnull final byte[] array) {
if (array.length == 0) {
return Seq.empty();
}
return ofGenerator(ix -> array[ix], array.length);
}
@Nonnull
public static Seq wrap(@Nonnull final short[] array) {
if (array.length == 0) {
return Seq.empty();
}
return ofGenerator(ix -> array[ix], array.length);
}
@Nonnull
public static Seq wrap(@Nonnull final int[] array) {
if (array.length == 0) {
return Seq.empty();
}
return ofGenerator(ix -> array[ix], array.length);
}
@Nonnull
public static Seq wrap(@Nonnull final long[] array) {
if (array.length == 0) {
return Seq.empty();
}
return ofGenerator(ix -> array[ix], array.length);
}
@Nonnull
public static Seq wrap(@Nonnull final float[] array) {
if (array.length == 0) {
return Seq.empty();
}
return ofGenerator(ix -> array[ix], array.length);
}
@Nonnull
public static Seq wrap(@Nonnull final double[] array) {
if (array.length == 0) {
return Seq.empty();
}
return ofGenerator(ix -> array[ix], array.length);
}
@Nonnull
public static Seq wrap(@Nonnull final Character[] array) {
if (array.length == 0) {
return Seq.empty();
}
return ofGenerator(ix -> array[ix], array.length);
}
@Nonnull
public static Seq wrap(@Nonnull final Boolean[] array) {
if (array.length == 0) {
return Seq.empty();
}
return ofGenerator(ix -> array[ix], array.length);
}
@Nonnull
public static Seq wrap(@Nonnull final Byte[] array) {
if (array.length == 0) {
return Seq.empty();
}
return ofGenerator(ix -> array[ix], array.length);
}
@Nonnull
public static Seq wrap(@Nonnull final Short[] array) {
if (array.length == 0) {
return Seq.empty();
}
return ofGenerator(ix -> array[ix], array.length);
}
@Nonnull
public static Seq wrap(@Nonnull final Integer[] array) {
if (array.length == 0) {
return Seq.empty();
}
return ofGenerator(ix -> array[ix], array.length);
}
@Nonnull
public static Seq wrap(@Nonnull final Long[] array) {
if (array.length == 0) {
return Seq.empty();
}
return ofGenerator(ix -> array[ix], array.length);
}
@Nonnull
public static Seq wrap(@Nonnull final Float[] array) {
if (array.length == 0) {
return Seq.empty();
}
return ofGenerator(ix -> array[ix], array.length);
}
@Nonnull
public static Seq wrap(@Nonnull final Double[] array) {
if (array.length == 0) {
return Seq.empty();
}
return ofGenerator(ix -> array[ix], array.length);
}
@Nonnull
public static Seq wrap(@Nonnull final E[] array) {
if (array.length == 0) {
return Seq.empty();
}
return ofGenerator(ix -> array[ix], array.length);
}
@Nonnull
public static Seq wrap(@Nonnull final List list) {
if (list.isEmpty()) {
return Seq.empty();
}
return ofGenerator(list::get, list.size());
}
@Nonnull
public static Seq wrap(@Nonnull final BitSet bitSet) {
if (bitSet.isEmpty()) {
return Seq.empty();
}
return ofGenerator(bitSet::get, bitSet.length());
}
@Nonnull
public static Seq wrap(@Nonnull final String string) {
if (string.isEmpty()) {
return Seq.empty();
}
return ofGenerator(string::charAt, string.length());
}
public static > E minimum(final Seq seq) {
if (seq instanceof SeqSimpleSorted) {
return seq.head();
}
Objects.requireNonNull(seq, "'seq' must not be null");
return seq.minimumBy(Comparable::compareTo);
}
public static > E maximum(final Seq seq) {
if (seq instanceof SeqSimpleSorted) {
return seq.last();
}
Objects.requireNonNull(seq, "'seq' must not be null");
return seq.maximumBy(Comparable::compareTo);
}
public static boolean any(@Nonnull final Seq seq) {
Objects.requireNonNull(seq, "the supplied sequence must not be null");
for (final Boolean e : seq) {
if (Boolean.TRUE.equals(e)) {
return true;
}
}
return false;
}
public static boolean all(@Nonnull final Seq seq) {
Objects.requireNonNull(seq, "the supplied sequence must not be null");
for (final Boolean e : seq) {
if (!Boolean.TRUE.equals(e)) {
return false;
}
}
return true;
}
public static int intSum(final Seq seq) {
Objects.requireNonNull(seq, "'seq' must not be null");
return seq.foldl(Operators::plus, 0);
}
public static long longSum(final Seq seq) {
Objects.requireNonNull(seq, "'seq' must not be null");
return seq.foldl(Operators::plus, 0L);
}
public static double doubleSum(final Seq seq) {
Objects.requireNonNull(seq, "'seq' must not be null");
return seq.foldl(Operators::plus, 0.0);
}
public static int intProduct(final Seq seq) {
Objects.requireNonNull(seq, "'seq' must not be null");
return seq.foldl(Operators::times, 1);
}
public static long longProduct(final Seq seq) {
Objects.requireNonNull(seq, "'seq' must not be null");
return seq.foldl(Operators::times, 1L);
}
public static double doubleProduct(final Seq seq) {
Objects.requireNonNull(seq, "'seq' must not be null");
return seq.foldl(Operators::times, 1.0);
}
public static boolean and(final Seq seq) {
return all(seq);
}
public static boolean or(final Seq seq) {
return any(seq);
}
public static int commonPrefixLength(final Seq as, final Seq bs) {
Objects.requireNonNull(as, "'as' must not be null");
Objects.requireNonNull(bs, "'bs' must not be null");
final int length = Math.min(as.size(), bs.size());
int commonPrefixLength = 0;
for (int i = 0; i < length; i += 1) {
final A a = as.get(i);
final B b = bs.get(i);
if (a == null) {
if (b == null) {
commonPrefixLength += 1;
continue;
}
break;
}
if (a.equals(b)) {
commonPrefixLength += 1;
continue;
}
break;
}
return commonPrefixLength;
}
public static Seq commonPrefix(final Seq as, final Seq bs) {
final int commonPrefixLength = commonPrefixLength(as, bs);
return as.subSequence(0, commonPrefixLength);
}
public static Seq commonPrefixView(final Seq as, final Seq bs) {
final int commonPrefixLength = commonPrefixLength(as, bs);
return as.subSequenceView(0, commonPrefixLength);
}
public static Seq rangeInclusive(final int from, final int to) {
if (from <= to) {
return ofGenerator(index -> from + index, to - from + 1);
}
final int length = from - to;
return ofGenerator(index -> to + (length - index), length + 1);
}
public static Seq rangeExclusive(final int from, final int to) {
if (from == to) {
return empty();
}
if (from < to) {
return ofGenerator(index -> from + index, to - from);
}
final int length = from - to;
return ofGenerator(index -> to + (length - index), length);
}
public static Seq> zip(
final Seq as,
final Seq bs,
final Seq cs,
final Seq ds
) {
final int length = Arithmetic.minimum(as.length(), bs.length(), cs.length(), ds.length());
final SeqBuilder> builder = Seq.builder(length);
for (int i = 0; i < length; i += 1) {
builder.add(Quadruple.of(as.get(i), bs.get(i), cs.get(i), ds.get(i)));
}
return builder.result();
}
public static Seq> zip(
final Seq as,
final Seq bs,
final Seq cs
) {
final int length = Arithmetic.minimum(as.length(), bs.length(), cs.length());
final SeqBuilder> builder = Seq.builder(length);
for (int i = 0; i < length; i += 1) {
builder.add(Triple.of(as.get(i), bs.get(i), cs.get(i)));
}
return builder.result();
}
public static Seq> zip(
final Seq