package org.osgl.util;
import org.osgl.$;
import java.util.EnumSet;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* Provide default implementation to some {@link C.Sequence} interface.
*
* <p>The most of the method of this implementation is lazy without
* regarding to the {@link C.Feature#LAZY} setting of this
* sequence instance</p>
*/
public abstract class SequenceBase<T>
extends TraversableBase<T> implements C.Sequence<T> {
// utilities
protected final boolean isLazy() {
return is(C.Feature.LAZY);
}
protected final boolean isImmutable() {
return is(C.Feature.IMMUTABLE);
}
protected final boolean isReadOnly() {
return is(C.Feature.READONLY);
}
protected final boolean isMutable() {
return !isImmutable() && !isReadOnly();
}
protected final boolean isLimited() {
return is(C.Feature.LIMITED);
}
@Override
public C.Sequence<T> lazy() {
return (C.Sequence<T>)super.lazy();
}
@Override
public C.Sequence<T> eager() {
return (C.Sequence<T>)super.eager();
}
@Override
public C.Sequence<T> parallel() {
return (C.Sequence<T>)super.parallel();
}
@Override
public C.Sequence<T> sequential() {
return (C.Sequence<T>)super.sequential();
}
@Override
protected EnumSet<C.Feature> initFeatures() {
return EnumSet.of(C.Feature.LAZY, C.Feature.READONLY);
}
@Override
public SequenceBase<T> accept($.Function<? super T, ?> visitor) {
C.forEach(this, visitor);
return this;
}
@Override
public SequenceBase<T> forEach($.Function<? super T, ?> visitor) {
return accept(visitor);
}
@Override
public C.Sequence<T> each($.Function<? super T, ?> visitor) {
return accept(visitor);
}
protected void forEachLeft($.Function<? super T, ?> visitor) {
forEach(visitor);
}
@Override
public T first() throws NoSuchElementException {
return iterator().next();
}
@Override
public final T head() throws NoSuchElementException {
return first();
}
@Override
@SuppressWarnings("unchecked")
public C.Sequence<T> acceptLeft($.Function<? super T, ?> visitor) {
forEachLeft(visitor);
return this;
}
/**
* Delegate to {@link TraversableBase#reduce(Object, org.osgl.Osgl.Func2)}
* @param identity {@inheritDoc}
* @param accumulator {@inheritDoc}
* @param <R> {@inheritDoc}
* @return {@inheritDoc}
*/
@Override
public <R> R reduceLeft(R identity, $.Func2<R, T, R> accumulator) {
return reduce(identity, accumulator);
}
/**
* Delegate to {@link TraversableBase#reduce(org.osgl.Osgl.Func2)}
* @param accumulator {@inheritDoc}
* @return {@inheritDoc}
*/
@Override
public $.Option<T> reduceLeft($.Func2<T, T, T> accumulator) {
return reduce(accumulator);
}
/**
* Delegate to {@link TraversableBase#findOne(org.osgl.Osgl.Function)}
* @param predicate the function map the element to Boolean
* @return {@inheritDoc}
*/
@Override
public $.Option<T> findFirst($.Function<? super T, Boolean> predicate) {
return findOne(predicate);
}
@Override
public C.Sequence<T> head(int n) {
if (n == 0) {
return Nil.seq();
} else if (n < 0) {
if (isLimited()) {
return drop(size() + n);
} else {
throw new UnsupportedOperationException();
}
} else {
if (isLimited() && n >= size()) {
return this;
}
return IndexFilteredSeq.of(this, $.F.lessThan(n));
}
}
@Override
public C.Sequence<T> tail() throws UnsupportedOperationException {
return IndexFilteredSeq.of(this, $.F.greaterThan(0));
}
@Override
public C.Sequence<T> take(int n) {
return head(n);
}
@Override
public C.Sequence<T> takeWhile($.Function<? super T, Boolean> predicate) {
return FilteredSeq.of(this, predicate, FilteredIterator.Type.WHILE);
}
@Override
public C.Sequence<T> drop(int n) throws IllegalArgumentException {
if (n < 0) {
throw new IndexOutOfBoundsException();
}
if (n == 0) {
return this;
}
return IndexFilteredSeq.of(this, $.F.gte(n));
}
@Override
public C.Sequence<T> dropWhile($.Function<? super T, Boolean> predicate) {
return FilteredSeq.of(this, $.F.negate(predicate), FilteredIterator.Type.UNTIL);
}
@Override
public C.Sequence<T> append(Iterable<? extends T> iterable) {
return append(C.seq(iterable));
}
@Override
public C.Sequence<T> append(C.Sequence<? extends T> seq) {
if (seq.isEmpty()) {
return this;
}
return CompositeSeq.of(this, seq);
}
@Override
public C.Sequence<T> append(Iterator<? extends T> iterator) {
if (!iterator.hasNext()) {
return this;
}
return CompositeSeq.of(this, C.seq(iterator));
}
@Override
public C.Sequence<T> append(Enumeration<? extends T> enumeration) {
if (!enumeration.hasMoreElements()) {
return this;
}
return CompositeSeq.of(this, C.seq(enumeration));
}
@Override
public C.Sequence<T> append(T t) {
return CompositeSeq.of(this, $.val(t));
}
@Override
public C.Sequence<T> prepend(Iterable<? extends T> iterable) {
if (!iterable.iterator().hasNext()) {
return this;
}
return prepend(C.seq(iterable));
}
@Override
public C.Sequence<T> prepend(Iterator<? extends T> iterator) {
if (!iterator.hasNext()) {
return this;
}
return prepend(C.seq(iterator));
}
@Override
public C.Sequence<T> prepend(Enumeration<? extends T> enumeration) {
if (!enumeration.hasMoreElements()) {
return this;
}
return prepend(C.seq(enumeration));
}
@Override
public C.Sequence<T> prepend(C.Sequence<? extends T> seq) {
if (seq.isEmpty()) {
return this;
}
C.Sequence<T> casted = $.cast(seq);
return casted.append(this);
}
@Override
public C.Sequence<T> prepend(T t) {
return CompositeSeq.of(C.singletonList(t), this);
}
@Override
public C.Sequence<T> filter($.Function<? super T, Boolean> predicate) {
return FilteredSeq.of(this, predicate);
}
@Override
public <R> C.Sequence<R> map($.Function<? super T, ? extends R> mapper) {
return MappedSeq.of(this, mapper);
}
@Override
public <R> C.Sequence<R> flatMap($.Function<? super T, ? extends Iterable<? extends R>> mapper
) {
return FlatMappedSeq.of(this, mapper);
}
@Override
public <T2> C.Sequence<$.T2<T, T2>> zip(Iterable<T2> iterable) {
return new ZippedSeq<T, T2>(this, iterable);
}
@Override
public <T2> C.Sequence<$.T2<T, T2>> zipAll(Iterable<T2> iterable, T def1, T2 def2) {
return new ZippedSeq<T, T2>(this, iterable, def1, def2);
}
@Override
public C.Sequence<$.T2<T, Integer>> zipWithIndex() {
return new ZippedSeq<T, Integer>(this, new IndexIterable(this));
}
@Override
public int count(T t) {
return count(this, t);
}
public static <T> int count(C.Sequence<T> sequence, T element) {
int n = 0;
for (T t : sequence) {
if ($.eq(t, element)) {
n++;
}
}
return n;
}
}