package com.nurkiewicz.lazyseq; import java.util.ArrayList; import java.util.Objects; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; /** * @author Tomasz Nurkiewicz * @since 5/8/13, 9:08 PM */ class Cons<E> extends LazySeq<E> { private final E head; private volatile LazySeq<E> tailOrNull; private final Supplier<LazySeq<E>> tailFun; Cons(E head, Supplier<LazySeq<E>> tailFun) { this.head = Objects.requireNonNull(head); this.tailFun = Objects.requireNonNull(tailFun); } @Override public E head() { return head; } @Override public LazySeq<E> tail() { if (!isTailDefined()) { synchronized (this) { if (!isTailDefined()) { tailOrNull = tailFun.get(); } } } return tailOrNull; } @Override protected boolean isTailDefined() { return tailOrNull != null; } public <R> LazySeq<R> map(Function<? super E, ? extends R> mapper) { return cons(mapper.apply(head()), () -> tail().map(mapper)); } @Override public LazySeq<E> filter(Predicate<? super E> predicate) { if (predicate.test(head)) { return cons(head, () -> tail().filter(predicate)); } else { return tail().filter(predicate); } } @Override public <R> LazySeq<R> flatMap(Function<? super E, ? extends Iterable<? extends R>> mapper) { final ArrayList<R> result = new ArrayList<>(); mapper.apply(head).forEach(result::add); return concat(result, () -> tail().flatMap(mapper)); } @Override protected LazySeq<E> takeUnsafe(long maxSize) { if (maxSize > 1) { return cons(head, () -> tail().takeUnsafe(maxSize - 1)); } else { return LazySeq.of(head); } } @Override public boolean isEmpty() { return false; } }