diff --git a/src/main/java/org/jayield/Advancer.java b/src/main/java/org/jayield/Advancer.java index 50c783e..9f11626 100644 --- a/src/main/java/org/jayield/Advancer.java +++ b/src/main/java/org/jayield/Advancer.java @@ -16,34 +16,20 @@ package org.jayield; -import java.util.Iterator; -import java.util.NoSuchElementException; - /** - * Sequential traverser with both internal and external iteration approach. + * Sequential traverser with internal and individually step approach. */ -public interface Advancer extends Iterator, Traverser { +public interface Advancer { + /** + * If a remaining element exists, yields that element through + * the given action. + */ + boolean tryAdvance(Yield yield); + /** * An Advancer object without elements. */ static Advancer empty() { - return new Advancer() { - @Override - public boolean hasNext() { - return false; - } - - @Override - public R next() { - throw new NoSuchElementException("No such elements available for iteration!"); - } - - @Override - public void traverse(Yield yield) { - /* Do nothing. Since there are no elements, thus there is nothing to do. */ - } - }; + return action -> false; } - - } diff --git a/src/main/java/org/jayield/Query.java b/src/main/java/org/jayield/Query.java index 1522f37..3594eea 100644 --- a/src/main/java/org/jayield/Query.java +++ b/src/main/java/org/jayield/Query.java @@ -16,30 +16,6 @@ package org.jayield; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Comparator; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.Spliterator; -import java.util.Spliterators.AbstractSpliterator; -import java.util.function.BiConsumer; -import java.util.function.BiFunction; -import java.util.function.BinaryOperator; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.IntFunction; -import java.util.function.Predicate; -import java.util.function.Supplier; -import java.util.function.ToDoubleFunction; -import java.util.function.ToIntFunction; -import java.util.function.ToLongFunction; -import java.util.function.UnaryOperator; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; - import org.jayield.advs.AdvancerArray; import org.jayield.advs.AdvancerConcat; import org.jayield.advs.AdvancerDistinct; @@ -55,16 +31,42 @@ import org.jayield.advs.AdvancerSkip; import org.jayield.advs.AdvancerStream; import org.jayield.advs.AdvancerTakeWhile; -import org.jayield.advs.AdvancerThen; import org.jayield.advs.AdvancerZip; import org.jayield.boxes.BoolBox; import org.jayield.boxes.Box; import org.jayield.primitives.dbl.DoubleAdvancer; import org.jayield.primitives.dbl.DoubleQuery; +import org.jayield.primitives.dbl.DoubleTraverser; import org.jayield.primitives.intgr.IntAdvancer; import org.jayield.primitives.intgr.IntQuery; +import org.jayield.primitives.intgr.IntTraverser; import org.jayield.primitives.lng.LongAdvancer; import org.jayield.primitives.lng.LongQuery; +import org.jayield.primitives.lng.LongTraverser; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.Spliterator; +import java.util.Spliterators.AbstractSpliterator; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.BinaryOperator; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.IntFunction; +import java.util.function.Predicate; +import java.util.function.Supplier; +import java.util.function.ToDoubleFunction; +import java.util.function.ToIntFunction; +import java.util.function.ToLongFunction; +import java.util.function.UnaryOperator; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; /** * A sequence of elements supporting sequential operations. @@ -77,9 +79,11 @@ public class Query { private final Advancer adv; + private final Traverser trav; - public Query(Advancer adv) { + public Query(Advancer adv, Traverser trav) { this.adv = adv; + this.trav = trav; } /** @@ -88,23 +92,17 @@ public Query(Advancer adv) { * exception is thrown. */ public final void traverse(Yield yield) { - this.adv.traverse(yield); + this.trav.traverse(yield); } /** - * Returns {@code true} if the iteration has more elements. - * (In other words, returns {@code true} if {@link #next} would - * return an element rather than throwing an exception.) + * If a remaining element exists, yields that element through + * the given action. */ - public final boolean hasNext() { - return this.adv.hasNext(); - } - /** - * Returns the next element in the iteration. - */ - public final T next() { - return this.adv.next(); + public boolean tryAdvance(Yield action) { + return this.adv.tryAdvance(action); } + /** * Yields elements sequentially in the current thread, * until all elements have been processed or the traversal @@ -112,7 +110,7 @@ public final T next() { */ public final void shortCircuit(Yield yield) { try{ - this.adv.traverse(yield); + this.trav.traverse(yield); }catch(TraversableFinishError e){ /* Proceed */ } @@ -123,7 +121,8 @@ public final void shortCircuit(Yield yield) { * are the specified values in data parameter. */ public static Query of(U...data) { - return new Query<>(new AdvancerArray<>(data)); + AdvancerArray adv = new AdvancerArray<>(data); + return new Query<>(adv, adv); } /** @@ -131,7 +130,8 @@ public static Query of(U...data) { * from the provided List data. */ public static Query fromList(List data) { - return new Query<>(new AdvancerList<>(data)); + AdvancerList adv = new AdvancerList<>(data); + return new Query<>(adv, adv); } /** @@ -139,7 +139,8 @@ public static Query fromList(List data) { * from the provided stream data. */ public static Query fromStream(Stream data) { - return new Query<>(new AdvancerStream<>(data)); + AdvancerStream adv = new AdvancerStream<>(data); + return new Query<>(adv, adv); } /** @@ -150,7 +151,8 @@ public static Query fromStream(Stream data) { * */ public static Query iterate(U seed, UnaryOperator f) { - return new Query<>(new AdvancerIterate<>(seed, f)); + AdvancerIterate iter = new AdvancerIterate<>(seed, f); + return new Query<>(iter, iter); } /** @@ -158,7 +160,8 @@ public static Query iterate(U seed, UnaryOperator f) { * function to the elements of this query. */ public final Query map(Function mapper) { - return new Query<>(new AdvancerMap<>(adv, mapper)); + AdvancerMap map = new AdvancerMap<>(this, mapper); + return new Query<>(map, map); } /** @@ -166,7 +169,8 @@ public final Query map(Function mapper) { * sequences, producing a sequence of the results. */ public final Query zip(Query other, BiFunction zipper) { - return new Query<>(new AdvancerZip<>(this.adv, other.adv, zipper)); + AdvancerZip zip = new AdvancerZip<>(this, other, zipper); + return new Query<>(zip, zip); } /** @@ -177,7 +181,7 @@ public final Query zip(Query other, BiFunction mapper) { - return new IntQuery(IntAdvancer.from(adv, mapper)); + return new IntQuery(IntAdvancer.from(adv, mapper), IntTraverser.from(trav, mapper)); } /** @@ -188,7 +192,7 @@ public final IntQuery mapToInt(ToIntFunction mapper) { * ToLongFunction used to map elements of this {@code Query} to long */ public final LongQuery mapToLong(ToLongFunction mapper) { - return new LongQuery(LongAdvancer.from(adv, mapper)); + return new LongQuery(LongAdvancer.from(adv, mapper), LongTraverser.from(trav, mapper)); } /** @@ -199,7 +203,7 @@ public final LongQuery mapToLong(ToLongFunction mapper) { * ToLongFunction used to map elements of this {@code Query} to double */ public final DoubleQuery mapToDouble(ToDoubleFunction mapper) { - return new DoubleQuery(DoubleAdvancer.from(adv, mapper)); + return new DoubleQuery(DoubleAdvancer.from(adv, mapper), DoubleTraverser.from(trav, mapper)); } /** @@ -207,7 +211,8 @@ public final DoubleQuery mapToDouble(ToDoubleFunction mapper) { * the given predicate. */ public final Query filter(Predicate p) { - return new Query<>(new AdvancerFilter<>(adv, p)); + AdvancerFilter filter = new AdvancerFilter<>(this, p); + return new Query<>(filter, filter); } /** @@ -215,7 +220,8 @@ public final Query filter(Predicate p) { * after discarding the first {@code n} elements of the query. */ public final Query skip(int n){ - return new Query<>(new AdvancerSkip<>(adv, n)); + AdvancerSkip skip = new AdvancerSkip<>(this, n); + return new Query<>(skip, skip); } /** @@ -223,7 +229,8 @@ public final Query skip(int n){ * to be no longer than {@code n} in length. */ public final Query limit(int n){ - return new Query<>(new AdvancerLimit<>(this, n)); + AdvancerLimit limit = new AdvancerLimit<>(this, n); + return new Query<>(limit, limit); } /** @@ -231,7 +238,8 @@ public final Query limit(int n){ * {@link Object#equals(Object)}) of this query. */ public final Query distinct(){ - return new Query<>(new AdvancerDistinct<>(adv)); + AdvancerDistinct dis = new AdvancerDistinct<>(this); + return new Query<>(dis, dis); } /** @@ -240,7 +248,8 @@ public final Query distinct(){ * the provided mapping function to each element. */ public final Query flatMap(Function> mapper){ - return new Query<>(new AdvancerFlatMap<>(this, mapper)); + AdvancerFlatMap map = new AdvancerFlatMap<>(this, mapper); + return new Query<>(map, map); } /** @@ -249,7 +258,8 @@ public final Query flatMap(Function peek(Consumer action) { - return new Query<>(new AdvancerPeek<>(adv, action)); + AdvancerPeek peek = new AdvancerPeek<>(this, action); + return new Query<>(peek, peek); } /** @@ -257,9 +267,21 @@ public final Query peek(Consumer action) { * this query that match the given predicate. */ public final Query takeWhile(Predicate predicate){ - return new Query<>(new AdvancerTakeWhile<>(this, predicate)); + AdvancerTakeWhile take = new AdvancerTakeWhile<>(this, predicate); + return new Query<>(take, take); } + /** + * The {@code then} operator lets you encapsulate a piece of an operator + * chain into a function. + * That function {@code next} is applied to this query to produce a new + * {@code Traverser} object that is encapsulated in the resulting query. + * On the other hand, the {@code nextAdv} is applied to this query to produce a new + * {@code Advancer} object that is encapsulated in the resulting query. + */ + public final Query then(Function, Advancer> nextAdv, Function, Traverser> next) { + return new Query<>(nextAdv.apply(this), next.apply(this)); + } /** * The {@code then} operator lets you encapsulate a piece of an operator * chain into a function. @@ -267,7 +289,10 @@ public final Query takeWhile(Predicate predicate){ * {@code Traverser} object that is encapsulated in the resulting query. */ public final Query then(Function, Traverser> next) { - return new Query<>(new AdvancerThen<>(this, next)); + Advancer nextAdv = item -> { throw new UnsupportedOperationException( + "Missing tryAdvance() implementation! Use the overloaded then() providing both Advancer and Traverser!"); + }; + return new Query<>(nextAdv, next.apply(this)); } /** @@ -290,14 +315,12 @@ public final Stream toStream() { Spliterator iter = new AbstractSpliterator(Long.MAX_VALUE, Spliterator.ORDERED) { @Override public boolean tryAdvance(Consumer action) { - if(!adv.hasNext()) return false; - action.accept(adv.next()); - return true; + return adv.tryAdvance(action::accept); } @Override public void forEachRemaining(Consumer action) { - adv.traverse(action::accept); + trav.traverse(action::accept); } }; return StreamSupport.stream(iter, false); @@ -309,10 +332,7 @@ public void forEachRemaining(Consumer action) { */ public final Optional findFirst(){ Box box = new Box<>(); - this.shortCircuit(item -> { - box.turnPresent(item); - Yield.bye(); - }); + this.tryAdvance(box::turnPresent); return box.isPresent() ? Optional.of(box.getValue()) : Optional.empty(); @@ -323,11 +343,15 @@ public final Optional findFirst(){ * {@code Comparator}. This is a special case of a reduction. */ public final Optional max(Comparator cmp){ - Box b = new Box<>(); - this.traverse(e -> { - if(!b.isPresent()) b.turnPresent(e); - else if(cmp.compare(e, b.getValue()) > 0) b.setValue(e); - }); + class BoxMax extends Box implements Yield { + @Override + public final void ret(T item) { + if(!isPresent()) turnPresent(item); + else if(cmp.compare(item, value) > 0) value = item; + } + } + BoxMax b = new BoxMax(); + this.traverse(b); return b.isPresent() ? Optional.of(b.getValue()) : Optional.empty(); } @@ -370,7 +394,6 @@ public final boolean allMatch(Predicate p) { public final long count() { class Counter implements Yield { long n = 0; - @Override public void ret(T item) { ++n; @@ -382,12 +405,13 @@ public void ret(T item) { } /** - * Returns an optional with the resulting reduction of the elements of this query, + * Returns an {@link Optional} with the resulting reduction of the elements of this {@code Query}, * if a reduction can be made, using the provided accumulator. */ public Optional reduce(BinaryOperator accumulator) { - if (this.hasNext()) { - return Optional.ofNullable(this.reduce(this.next(), accumulator)); + Box box = new Box<>(); + if(this.tryAdvance(box::setValue)) { + return Optional.of(this.reduce(box.getValue(), accumulator)); } else { return Optional.empty(); } @@ -398,10 +422,18 @@ public Optional reduce(BinaryOperator accumulator) { * using the provided identity value and accumulator. */ public T reduce(T identity, BinaryOperator accumulator) { - Box result = new Box<>(); - result.setValue(identity); - this.traverse(elem -> result.setValue(accumulator.apply(result.getValue(), elem))); - return result.getValue(); + class BoxAccumulator extends Box implements Yield { + public BoxAccumulator(T identity) { + super(identity); + } + @Override + public final void ret(T item) { + this.value = accumulator.apply(value, item); + } + } + BoxAccumulator box = new BoxAccumulator(identity); + this.traverse(box); + return box.getValue(); } /** @@ -469,7 +501,8 @@ public final boolean noneMatch(Predicate p) { * where each element is generated by the provided Supplier. */ public static Query generate(Supplier s) { - return new Query<>(new AdvancerGenerate<>(s)); + AdvancerGenerate gen = new AdvancerGenerate<>(s); + return new Query<>(gen, gen); } /** @@ -489,7 +522,8 @@ public R collect(Supplier supplier, BiConsumer accumulator) * elements of the other {@code Query}. */ public final Query concat(Query other) { - return new Query<>(new AdvancerConcat<>(this, other)); + AdvancerConcat con = new AdvancerConcat<>(this, other); + return new Query<>(con, con); } /** @@ -501,7 +535,8 @@ public final Query concat(Query other) { public final Query sorted(Comparator comparator) { T[] state = (T[]) this.toArray(); Arrays.sort(state, comparator); - return new Query<>(new AdvancerArray<>(state)); + AdvancerArray sorted = new AdvancerArray<>(state); + return new Query<>(sorted, sorted); } /** @@ -509,7 +544,8 @@ public final Query sorted(Comparator comparator) { * after discarding the first sequence of elements that match the given Predicate. */ public final Query dropWhile(Predicate predicate) { - return new Query<>(new AdvancerDropWhile<>(this, predicate)); + AdvancerDropWhile drop = new AdvancerDropWhile<>(this, predicate); + return new Query<>(drop, drop); } } diff --git a/src/main/java/org/jayield/Traverser.java b/src/main/java/org/jayield/Traverser.java index dc32bbf..bbe4cca 100644 --- a/src/main/java/org/jayield/Traverser.java +++ b/src/main/java/org/jayield/Traverser.java @@ -29,4 +29,12 @@ public interface Traverser { * exception is thrown. */ void traverse(Yield yield); + + /** + * A Traverser object without elements. + */ + static Traverser empty() { + return action -> { }; + } + } diff --git a/src/main/java/org/jayield/advs/AbstractAdvancer.java b/src/main/java/org/jayield/advs/AbstractAdvancer.java deleted file mode 100644 index 6a28346..0000000 --- a/src/main/java/org/jayield/advs/AbstractAdvancer.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2020, Fernando Miguel Carvalho, mcarvalho@cc.isel.ipl.pt - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jayield.advs; - -import java.util.NoSuchElementException; - -import org.jayield.Advancer; - -public abstract class AbstractAdvancer implements Advancer { - boolean moved; - boolean finished; - T curr; - - @Override - public final boolean hasNext() { - if(finished) return false; // It has finished thus return false. - if(moved) return true; // It has not finished and has already moved forward, thus there is next. - finished = !advance(); // If tryAdvance returns true then it has not finished yet. - return !finished; - } - - private final boolean advance() { - moved = true; - return move(); - } - - /** - * Return true if it advances successfully and put the current item in curr field. - */ - protected abstract boolean move(); - - @Override - public final T next() { - if (!hasNext()) { - throw new NoSuchElementException("No more elements available on iteration!"); - } - prepareIteration(); - return curr; - } - - protected void prepareIteration() { - moved = false; - } - -} diff --git a/src/main/java/org/jayield/advs/AdvancerArray.java b/src/main/java/org/jayield/advs/AdvancerArray.java index 9b228be..a427f20 100644 --- a/src/main/java/org/jayield/advs/AdvancerArray.java +++ b/src/main/java/org/jayield/advs/AdvancerArray.java @@ -16,12 +16,11 @@ package org.jayield.advs; -import java.util.NoSuchElementException; - import org.jayield.Advancer; +import org.jayield.Traverser; import org.jayield.Yield; -public class AdvancerArray implements Advancer { +public class AdvancerArray implements Advancer, Traverser { private final U[] data; private int current; @@ -30,13 +29,6 @@ public AdvancerArray(U... data) { this.current = 0; } - @Override - public U next() { - if(!hasNext()) throw new NoSuchElementException("No more elements available on iteration!"); - return data[current++]; - } - - @Override public boolean hasNext() { return current < data.length; } @@ -52,4 +44,11 @@ public void traverse(Yield yield) { yield.ret(data[i]); } } -} + + @Override + public boolean tryAdvance(Yield yield) { + if(!hasNext()) return false; + yield.ret(data[current++]); + return true; + } +} \ No newline at end of file diff --git a/src/main/java/org/jayield/advs/AdvancerConcat.java b/src/main/java/org/jayield/advs/AdvancerConcat.java index 271a4a4..c71610a 100644 --- a/src/main/java/org/jayield/advs/AdvancerConcat.java +++ b/src/main/java/org/jayield/advs/AdvancerConcat.java @@ -1,12 +1,11 @@ package org.jayield.advs; -import java.util.NoSuchElementException; - import org.jayield.Advancer; import org.jayield.Query; +import org.jayield.Traverser; import org.jayield.Yield; -public class AdvancerConcat implements Advancer { +public class AdvancerConcat implements Advancer, Traverser { private final Query first; private final Query second; @@ -15,24 +14,14 @@ public AdvancerConcat(Query first, Query second) { this.second = second; } - @Override - public boolean hasNext() { - return first.hasNext() || second.hasNext(); - } - - @Override - public T next() { - if(first.hasNext()) { - return first.next(); - } else if(second.hasNext()) { - return second.next(); - } - throw new NoSuchElementException("No more elements available on iteration!"); - } - @Override public void traverse(Yield yield) { this.first.traverse(yield); this.second.traverse(yield); } + + @Override + public boolean tryAdvance(Yield yield) { + return first.tryAdvance(yield) || second.tryAdvance(yield); + } } diff --git a/src/main/java/org/jayield/advs/AdvancerDistinct.java b/src/main/java/org/jayield/advs/AdvancerDistinct.java index 4874085..c8a8904 100644 --- a/src/main/java/org/jayield/advs/AdvancerDistinct.java +++ b/src/main/java/org/jayield/advs/AdvancerDistinct.java @@ -16,36 +16,38 @@ package org.jayield.advs; -import java.util.HashSet; - import org.jayield.Advancer; +import org.jayield.Query; +import org.jayield.Traverser; import org.jayield.Yield; +import org.jayield.boxes.BoolBox; -public class AdvancerDistinct extends AbstractAdvancer { - private final Advancer upstream; +import java.util.HashSet; + +public class AdvancerDistinct implements Advancer, Traverser { + private final Query upstream; final HashSet mem = new HashSet<>(); - public AdvancerDistinct(Advancer adv) { + public AdvancerDistinct(Query adv) { this.upstream = adv; } - /** - * Returns true if it moves successfully. Otherwise returns false - * signaling it has finished. - */ - public boolean move() { - while(upstream.hasNext()) { - curr = upstream.next(); - if(mem.add(curr)) - return true; - } - return false; - } - @Override public void traverse(Yield yield) { upstream.traverse(item -> { if(mem.add(item)) yield.ret(item); }); } + + @Override + public boolean tryAdvance(Yield yield) { + final BoolBox found = new BoolBox(); + while(found.isFalse() && upstream.tryAdvance(item -> { + if(mem.add(item)) { + yield.ret(item); + found.set(); + } + })); + return found.isTrue(); + } } diff --git a/src/main/java/org/jayield/advs/AdvancerDropWhile.java b/src/main/java/org/jayield/advs/AdvancerDropWhile.java index 6cc2d78..dc0556a 100644 --- a/src/main/java/org/jayield/advs/AdvancerDropWhile.java +++ b/src/main/java/org/jayield/advs/AdvancerDropWhile.java @@ -1,48 +1,49 @@ package org.jayield.advs; -import java.util.function.Predicate; - +import org.jayield.Advancer; import org.jayield.Query; +import org.jayield.Traverser; import org.jayield.Yield; -import org.jayield.boxes.BoolBox; -public class AdvancerDropWhile extends AbstractAdvancer { +import java.util.function.Predicate; + +public class AdvancerDropWhile implements Advancer, Traverser { private final Query upstream; private final Predicate predicate; - private final BoolBox dropped; + private boolean dropped; public AdvancerDropWhile(Query upstream, Predicate predicate) { this.upstream = upstream; this.predicate = predicate; - this.dropped = new BoolBox(); } @Override public void traverse(Yield yield) { upstream.traverse(item -> { - if (!dropped.isTrue() && !predicate.test(item)) { - dropped.set(); + if (!dropped && !predicate.test(item)) { + dropped = true; } - if (dropped.isTrue()) { + if (dropped) { yield.ret(item); } }); } @Override - protected boolean move() { - while (!dropped.isTrue() && this.upstream.hasNext()) { - curr = upstream.next(); - if (!predicate.test(curr)) { - this.dropped.set(); - return true; + public boolean tryAdvance(Yield yield) { + if (dropped) { + return upstream.tryAdvance(yield); + } else { + while(!dropped && upstream.tryAdvance(item -> { + if(!predicate.test(item)){ + dropped = true; + yield.ret(item); + } + })) { + // Intentionally empty. Action specified on yield statement of tryAdvance(). } + return dropped; } - if (dropped.isTrue() && upstream.hasNext()) { - curr = upstream.next(); - return true; - } - return false; } } diff --git a/src/main/java/org/jayield/advs/AdvancerFilter.java b/src/main/java/org/jayield/advs/AdvancerFilter.java index 29e6511..383397d 100644 --- a/src/main/java/org/jayield/advs/AdvancerFilter.java +++ b/src/main/java/org/jayield/advs/AdvancerFilter.java @@ -16,33 +16,23 @@ package org.jayield.advs; -import java.util.function.Predicate; - import org.jayield.Advancer; +import org.jayield.Query; +import org.jayield.Traverser; import org.jayield.Yield; +import org.jayield.boxes.BoolBox; + +import java.util.function.Predicate; -public class AdvancerFilter extends AbstractAdvancer { - private final Advancer upstream; +public class AdvancerFilter implements Advancer, Traverser { + private final Query upstream; private final Predicate p; - public AdvancerFilter(Advancer adv, Predicate p) { + public AdvancerFilter(Query adv, Predicate p) { this.upstream = adv; this.p = p; } - /** - * Returns true if it moves successfully. Otherwise returns false - * signaling it has finished. - */ - public boolean move() { - while(upstream.hasNext()) { - curr = upstream.next(); - if(p.test(curr)) - return true; - } - return false; - } - @Override public void traverse(Yield yield) { upstream.traverse(e -> { @@ -50,4 +40,19 @@ public void traverse(Yield yield) { yield.ret(e); }); } + + @Override + public boolean tryAdvance(Yield yield) { + BoolBox found = new BoolBox(); + while(found.isFalse()) { + boolean hasNext = upstream.tryAdvance(item -> { + if(p.test(item)) { + yield.ret(item); + found.set(); + } + }); + if(!hasNext) break; + } + return found.isTrue(); + } } diff --git a/src/main/java/org/jayield/advs/AdvancerFlatMap.java b/src/main/java/org/jayield/advs/AdvancerFlatMap.java index ede1081..741573f 100644 --- a/src/main/java/org/jayield/advs/AdvancerFlatMap.java +++ b/src/main/java/org/jayield/advs/AdvancerFlatMap.java @@ -16,34 +16,22 @@ package org.jayield.advs; -import java.util.function.Function; - import org.jayield.Advancer; import org.jayield.Query; +import org.jayield.Traverser; import org.jayield.Yield; -public class AdvancerFlatMap extends AbstractAdvancer { +import java.util.function.Function; + +public class AdvancerFlatMap implements Advancer, Traverser { private final Query upstream; private final Function> mapper; - Query src; + private Query src; public AdvancerFlatMap(Query query, Function> mapper) { this.upstream = query; this.mapper = mapper; - src = new Query<>(Advancer.empty()); - } - - /** - * Returns true if it moves successfully. Otherwise returns false - * signaling it has finished. - */ - public boolean move() { - while(!src.hasNext()) { - if(!upstream.hasNext()) return false; - src = mapper.apply(upstream.next()); - } - curr = src.next(); - return true; + src = new Query<>(Advancer.empty(), Traverser.empty()); } @Override @@ -52,4 +40,13 @@ public void traverse(Yield yield) { mapper.apply(elem).traverse(yield)); } + + @Override + public boolean tryAdvance(Yield yield) { + while (!src.tryAdvance(yield)) { + if(!upstream.tryAdvance(t -> src = mapper.apply(t))) + return false; + } + return true; + } } diff --git a/src/main/java/org/jayield/advs/AdvancerGenerate.java b/src/main/java/org/jayield/advs/AdvancerGenerate.java index 41e5932..e2e4cf1 100644 --- a/src/main/java/org/jayield/advs/AdvancerGenerate.java +++ b/src/main/java/org/jayield/advs/AdvancerGenerate.java @@ -16,34 +16,29 @@ package org.jayield.advs; -import java.util.NoSuchElementException; -import java.util.function.Supplier; - import org.jayield.Advancer; +import org.jayield.Traverser; import org.jayield.Yield; -public class AdvancerGenerate implements Advancer { +import java.util.function.Supplier; + +public class AdvancerGenerate implements Advancer, Traverser { private final Supplier s; public AdvancerGenerate(Supplier s) { this.s = s; } - @Override - public boolean hasNext() { - return true; - } - - @Override - public U next() { - if(!hasNext()) throw new NoSuchElementException("No more elements available on iteration!"); - return s.get(); - } - @Override public void traverse(Yield yield) { - while (hasNext()) { + while(true) { yield.ret(s.get()); } } + + @Override + public boolean tryAdvance(Yield yield) { + yield.ret(s.get()); + return true; + } } diff --git a/src/main/java/org/jayield/advs/AdvancerIterate.java b/src/main/java/org/jayield/advs/AdvancerIterate.java index b36feaa..39d43ad 100644 --- a/src/main/java/org/jayield/advs/AdvancerIterate.java +++ b/src/main/java/org/jayield/advs/AdvancerIterate.java @@ -16,13 +16,13 @@ package org.jayield.advs; -import java.util.NoSuchElementException; -import java.util.function.UnaryOperator; - import org.jayield.Advancer; +import org.jayield.Traverser; import org.jayield.Yield; -public class AdvancerIterate implements Advancer { +import java.util.function.UnaryOperator; + +public class AdvancerIterate implements Advancer, Traverser { private final UnaryOperator f; private U prev; @@ -32,27 +32,16 @@ public AdvancerIterate(U seed, UnaryOperator f) { } @Override - public boolean hasNext() { - return true; + public void traverse(Yield yield) { + for(U curr = prev; true; curr = f.apply(curr)) + yield.ret(curr); } @Override - public U next() { - if(!hasNext()) throw new NoSuchElementException("No more elements available on iteration!"); + public boolean tryAdvance(Yield yield) { U curr = prev; prev = f.apply(prev); - return curr; - } - - /** - * Continues from the point where tryAdvance or next left the - * internal iteration. - * @param yield - */ - @Override - public void traverse(Yield yield) { - for(U i = prev; true; i = f.apply(i)){ - yield.ret(i); - } + yield.ret(curr); + return true; } } diff --git a/src/main/java/org/jayield/advs/AdvancerLimit.java b/src/main/java/org/jayield/advs/AdvancerLimit.java index db26fd1..c2373df 100644 --- a/src/main/java/org/jayield/advs/AdvancerLimit.java +++ b/src/main/java/org/jayield/advs/AdvancerLimit.java @@ -16,13 +16,12 @@ package org.jayield.advs; -import java.util.NoSuchElementException; - import org.jayield.Advancer; import org.jayield.Query; +import org.jayield.Traverser; import org.jayield.Yield; -public class AdvancerLimit implements Advancer { +public class AdvancerLimit implements Advancer, Traverser { private final Query upstream; private final int n; int count; @@ -34,23 +33,19 @@ public AdvancerLimit(Query upstream, int n) { } @Override - public boolean hasNext() { - return count < n && upstream.hasNext(); - } - - @Override - public T next() { - if(count >= n) throw new NoSuchElementException("Nor more elements available!"); + public boolean tryAdvance(Yield yield) { + if(count >= n) return false; count++; - return upstream.next(); + return upstream.tryAdvance(yield); + } @Override public void traverse(Yield yield) { - upstream.shortCircuit(item -> { - if(count >= n) Yield.bye(); - count++; - yield.ret(item); - }); + if(count >= n) + throw new IllegalStateException("Traverser has already been operated on or closed!"); + while(this.tryAdvance(yield)) { + // Intentionally empty. Action specified on yield statement of tryAdvance(). + } } } diff --git a/src/main/java/org/jayield/advs/AdvancerList.java b/src/main/java/org/jayield/advs/AdvancerList.java index 98d32f5..cc3455e 100644 --- a/src/main/java/org/jayield/advs/AdvancerList.java +++ b/src/main/java/org/jayield/advs/AdvancerList.java @@ -16,13 +16,14 @@ package org.jayield.advs; -import java.util.Iterator; -import java.util.List; - import org.jayield.Advancer; +import org.jayield.Traverser; import org.jayield.Yield; -public class AdvancerList implements Advancer { +import java.util.Iterator; +import java.util.List; + +public class AdvancerList implements Advancer, Traverser { private final List data; private final Iterator current; @@ -32,17 +33,16 @@ public AdvancerList(List data) { } @Override - public U next() { - return current.next(); - } - - @Override - public boolean hasNext() { - return current.hasNext(); + public void traverse(Yield yield) { + if(!current.hasNext()) + throw new IllegalStateException("Traverser has already been operated on or closed!"); + data.forEach(yield::ret); } @Override - public void traverse(Yield yield) { - data.forEach(yield::ret); + public boolean tryAdvance(Yield yield) { + if(!current.hasNext()) return false; + yield.ret(current.next()); + return true; } } diff --git a/src/main/java/org/jayield/advs/AdvancerMap.java b/src/main/java/org/jayield/advs/AdvancerMap.java index 06e3b40..19dec18 100644 --- a/src/main/java/org/jayield/advs/AdvancerMap.java +++ b/src/main/java/org/jayield/advs/AdvancerMap.java @@ -16,33 +16,30 @@ package org.jayield.advs; -import java.util.function.Function; - import org.jayield.Advancer; +import org.jayield.Query; +import org.jayield.Traverser; import org.jayield.Yield; -public class AdvancerMap implements Advancer { +import java.util.function.Function; + +public class AdvancerMap implements Advancer, Traverser { - private final Advancer upstream; + private final Query upstream; private final Function mapper; - public AdvancerMap(Advancer adv, Function mapper) { + public AdvancerMap(Query adv, Function mapper) { this.upstream = adv; this.mapper = mapper; } @Override - public boolean hasNext() { - return upstream.hasNext(); - } - - @Override - public R next() { - return mapper.apply(upstream.next()); + public void traverse(Yield yield) { + upstream.traverse(e -> yield.ret(mapper.apply(e))); } @Override - public void traverse(Yield yield) { - upstream.traverse(e -> yield.ret(mapper.apply(e))); + public boolean tryAdvance(Yield yield) { + return upstream.tryAdvance(item -> yield.ret(mapper.apply(item))); } } diff --git a/src/main/java/org/jayield/advs/AdvancerPeek.java b/src/main/java/org/jayield/advs/AdvancerPeek.java index 07341e8..6a6d4c7 100644 --- a/src/main/java/org/jayield/advs/AdvancerPeek.java +++ b/src/main/java/org/jayield/advs/AdvancerPeek.java @@ -16,35 +16,33 @@ package org.jayield.advs; -import java.util.function.Consumer; - import org.jayield.Advancer; +import org.jayield.Query; +import org.jayield.Traverser; import org.jayield.Yield; -public class AdvancerPeek implements Advancer { - private final Advancer upstream; +import java.util.function.Consumer; + +public class AdvancerPeek implements Advancer, Traverser { + private final Query upstream; private final Consumer action; - public AdvancerPeek(Advancer adv, Consumer action) { + public AdvancerPeek(Query adv, Consumer action) { this.upstream = adv; this.action = action; } @Override - public boolean hasNext() { - return upstream.hasNext(); - } - - @Override - public T next() { - T curr = upstream.next(); - action.accept(curr); - return curr; + public void traverse(Yield yield) { + upstream.traverse(item -> { + action.accept(item); + yield.ret(item); + }); } @Override - public void traverse(Yield yield) { - upstream.traverse(item -> { + public boolean tryAdvance(Yield yield) { + return upstream.tryAdvance(item -> { action.accept(item); yield.ret(item); }); diff --git a/src/main/java/org/jayield/advs/AdvancerSkip.java b/src/main/java/org/jayield/advs/AdvancerSkip.java index 098a4d9..87ff6df 100644 --- a/src/main/java/org/jayield/advs/AdvancerSkip.java +++ b/src/main/java/org/jayield/advs/AdvancerSkip.java @@ -17,30 +17,21 @@ package org.jayield.advs; import org.jayield.Advancer; +import org.jayield.Query; +import org.jayield.Traverser; import org.jayield.Yield; -public class AdvancerSkip implements Advancer { - private final Advancer upstream; +public class AdvancerSkip implements Advancer, Traverser { + private final Query upstream; private final int n; int index; - public AdvancerSkip(Advancer adv, int n) { + public AdvancerSkip(Query adv, int n) { this.upstream = adv; this.n = n; index = 0; } - @Override - public boolean hasNext() { - for (; upstream.hasNext() && index < n; index++) upstream.next(); - return upstream.hasNext(); - } - - @Override - public T next() { - if(!hasNext()) throw new IndexOutOfBoundsException("No such elements on iteration!"); - return upstream.next(); - } /** * Continues from the point where tryAdvance or next left the * internal iteration. @@ -53,4 +44,11 @@ public void traverse(Yield yield) { yield.ret(item); }); } + + @Override + public boolean tryAdvance(Yield yield) { + for (; index < n; index++) + upstream.tryAdvance(item -> {}); + return upstream.tryAdvance(yield); + } } diff --git a/src/main/java/org/jayield/advs/AdvancerStream.java b/src/main/java/org/jayield/advs/AdvancerStream.java index ab2e696..0619cb1 100644 --- a/src/main/java/org/jayield/advs/AdvancerStream.java +++ b/src/main/java/org/jayield/advs/AdvancerStream.java @@ -16,40 +16,28 @@ package org.jayield.advs; -import java.util.Iterator; -import java.util.stream.Stream; - import org.jayield.Advancer; +import org.jayield.Traverser; import org.jayield.Yield; -public class AdvancerStream implements Advancer { - private final Stream upstream; - private Iterator current; - private boolean operated = false; +import java.util.Spliterator; +import java.util.stream.Stream; - public AdvancerStream(Stream data) { - this.upstream = data; - } +public class AdvancerStream implements Advancer, Traverser { + private final Spliterator upstream; - public Iterator current() { - if(operated) return current; - operated = true; - current = upstream.iterator(); - return current; + public AdvancerStream(Stream data) { + this.upstream = data.spliterator(); } - @Override - public U next() { - return current().next(); - } @Override - public boolean hasNext() { - return current().hasNext(); + public void traverse(Yield yield) { + upstream.forEachRemaining(yield::ret); } @Override - public void traverse(Yield yield) { - upstream.forEach(yield::ret); + public boolean tryAdvance(Yield yield) { + return upstream.tryAdvance(yield::ret); } } diff --git a/src/main/java/org/jayield/advs/AdvancerTakeWhile.java b/src/main/java/org/jayield/advs/AdvancerTakeWhile.java index 50516e6..f49a441 100644 --- a/src/main/java/org/jayield/advs/AdvancerTakeWhile.java +++ b/src/main/java/org/jayield/advs/AdvancerTakeWhile.java @@ -16,32 +16,35 @@ package org.jayield.advs; -import java.util.function.Predicate; - +import org.jayield.Advancer; import org.jayield.Query; +import org.jayield.Traverser; import org.jayield.Yield; -public class AdvancerTakeWhile extends AbstractAdvancer { +import java.util.function.Predicate; + +public class AdvancerTakeWhile implements Advancer, Traverser { private final Query upstream; private final Predicate predicate; + private boolean hasNext; public AdvancerTakeWhile(Query upstream, Predicate predicate) { this.upstream = upstream; this.predicate = predicate; + this.hasNext = true; } - /** - * Returns true if it moves successfully. Otherwise returns false - * signaling it has finished. - */ - public boolean move() { - if(upstream.hasNext()) { - curr = upstream.next(); - if(predicate.test(curr)) { - return true; + @Override + public boolean tryAdvance(Yield yield) { + if(!hasNext) return false; // Once predicate is false it finishes the iteration + Yield takeWhile = item -> { + if(predicate.test(item)){ + yield.ret(item); + } else { + hasNext = false; } - } - return false; + }; + return upstream.tryAdvance(takeWhile) && hasNext; } @Override diff --git a/src/main/java/org/jayield/advs/AdvancerThen.java b/src/main/java/org/jayield/advs/AdvancerThen.java deleted file mode 100644 index 6bd0b6d..0000000 --- a/src/main/java/org/jayield/advs/AdvancerThen.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2020, Fernando Miguel Carvalho, mcarvalho@cc.isel.ipl.pt - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jayield.advs; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.function.Function; - -import org.jayield.Advancer; -import org.jayield.Query; -import org.jayield.Traverser; -import org.jayield.Yield; - -public class AdvancerThen implements Advancer { - private Query upstream; - private Function, Traverser> next; - private Iterator curr; - private boolean inMem = false; - - public AdvancerThen(Query upstream, Function, Traverser> next) { - this.upstream = upstream; - this.next = next; - } - - public Iterator curr() { - if(inMem) return curr; - ArrayList mem = new ArrayList<>(); - next.apply(upstream).traverse(mem::add); - inMem = true; - curr = mem.iterator(); - return curr; - } - - @Override - public boolean hasNext() { - return curr().hasNext(); - } - - @Override - public R next() { - return curr().next(); - } - - @Override - public void traverse(Yield yield) { - next.apply(upstream).traverse(yield); - } -} diff --git a/src/main/java/org/jayield/advs/AdvancerZip.java b/src/main/java/org/jayield/advs/AdvancerZip.java index 2008832..e43d542 100644 --- a/src/main/java/org/jayield/advs/AdvancerZip.java +++ b/src/main/java/org/jayield/advs/AdvancerZip.java @@ -16,37 +16,41 @@ package org.jayield.advs; -import java.util.function.BiFunction; - import org.jayield.Advancer; +import org.jayield.Query; +import org.jayield.Traverser; import org.jayield.Yield; +import org.jayield.boxes.BoolBox; + +import java.util.function.BiFunction; -public class AdvancerZip implements Advancer { - private final Advancer upstream; - private final Advancer other; +public class AdvancerZip implements Advancer, Traverser { + private final Query upstream; + private final Query other; private final BiFunction zipper; - public AdvancerZip(Advancer upstream, Advancer other, BiFunction zipper) { + public AdvancerZip(Query upstream, Query other, BiFunction zipper) { this.upstream = upstream; this.other = other; this.zipper = zipper; } @Override - public boolean hasNext() { - return upstream.hasNext() && other.hasNext(); + public boolean tryAdvance(Yield yield) { + BoolBox consumed = new BoolBox(); + upstream.tryAdvance(e1 -> other.tryAdvance(e2 -> { + yield.ret(zipper.apply(e1, e2)); + consumed.set(); + })); + return consumed.isTrue(); } - @Override - public R next() { - return zipper.apply(upstream.next(), other.next()); - } @Override public void traverse(Yield yield) { - upstream.traverse(e -> { - if (!other.hasNext()) return; - yield.ret(zipper.apply(e, other.next())); + upstream.shortCircuit(e1 -> { + if(!other.tryAdvance(e2 -> yield.ret(zipper.apply(e1, e2)))) + Yield.bye(); }); } } diff --git a/src/main/java/org/jayield/boxes/BoolBox.java b/src/main/java/org/jayield/boxes/BoolBox.java index 0552744..8bac56f 100644 --- a/src/main/java/org/jayield/boxes/BoolBox.java +++ b/src/main/java/org/jayield/boxes/BoolBox.java @@ -28,11 +28,17 @@ public BoolBox(boolean value) { } public BoolBox() { + this(false); } public boolean isTrue() { return value; } + + public boolean isFalse() { + return !value; + } + public void set() { value = true; } diff --git a/src/main/java/org/jayield/boxes/Box.java b/src/main/java/org/jayield/boxes/Box.java index d4e7c25..28654f4 100644 --- a/src/main/java/org/jayield/boxes/Box.java +++ b/src/main/java/org/jayield/boxes/Box.java @@ -21,24 +21,32 @@ * created on 06-07-2017 */ public class Box { - private T value; + protected T value; private boolean isPresent; + public Box(T identity) { + this.value = identity; + this.isPresent = true; + } + + public Box() { + } + - public boolean isPresent() { + public final boolean isPresent() { return isPresent; } - public T getValue() { + public final T getValue() { return value; } - public T setValue(T value) { + public final T setValue(T value) { this.value = value; return value; } - public void turnPresent(T e) { + public final void turnPresent(T e) { this.setValue(e); this.isPresent = true; } diff --git a/src/main/java/org/jayield/boxes/DoubleBox.java b/src/main/java/org/jayield/boxes/DoubleBox.java index de0fddb..a2b45a7 100644 --- a/src/main/java/org/jayield/boxes/DoubleBox.java +++ b/src/main/java/org/jayield/boxes/DoubleBox.java @@ -17,7 +17,7 @@ package org.jayield.boxes; public class DoubleBox { - private double value; + protected double value; private boolean isPresent; public DoubleBox() { @@ -30,6 +30,11 @@ public DoubleBox(double value, boolean isPresent) { this.isPresent = isPresent; } + public DoubleBox(double identity) { + this.value = identity; + this.isPresent = true; + } + public double getValue() { return value; } diff --git a/src/main/java/org/jayield/boxes/IntBox.java b/src/main/java/org/jayield/boxes/IntBox.java index 3e5587d..08ce8b7 100644 --- a/src/main/java/org/jayield/boxes/IntBox.java +++ b/src/main/java/org/jayield/boxes/IntBox.java @@ -21,7 +21,7 @@ * created on 06-07-2017 */ public class IntBox { - private int value; + protected int value; private boolean isPresent; public IntBox() { @@ -34,6 +34,10 @@ public IntBox(int value, boolean isPresent) { this.isPresent = isPresent; } + public IntBox(int identity) { + this.value = identity; + } + public int getValue() { return value; } diff --git a/src/main/java/org/jayield/boxes/LongBox.java b/src/main/java/org/jayield/boxes/LongBox.java index 03fb021..d1ea12e 100644 --- a/src/main/java/org/jayield/boxes/LongBox.java +++ b/src/main/java/org/jayield/boxes/LongBox.java @@ -17,7 +17,7 @@ package org.jayield.boxes; public class LongBox { - private long value; + protected long value; private boolean isPresent; public LongBox() { @@ -30,6 +30,10 @@ public LongBox(long value, boolean isPresent) { this.isPresent = isPresent; } + public LongBox(long identity) { + this.value = identity; + } + public long getValue() { return value; } diff --git a/src/main/java/org/jayield/primitives/dbl/DoubleAdvancer.java b/src/main/java/org/jayield/primitives/dbl/DoubleAdvancer.java index f1b559d..ff17b76 100644 --- a/src/main/java/org/jayield/primitives/dbl/DoubleAdvancer.java +++ b/src/main/java/org/jayield/primitives/dbl/DoubleAdvancer.java @@ -1,100 +1,73 @@ package org.jayield.primitives.dbl; -import java.util.NoSuchElementException; -import java.util.function.IntToDoubleFunction; -import java.util.function.LongToDoubleFunction; -import java.util.function.ToDoubleFunction; - import org.jayield.Advancer; +import org.jayield.Yield; import org.jayield.primitives.intgr.IntAdvancer; import org.jayield.primitives.lng.LongAdvancer; +import java.util.function.DoubleToLongFunction; +import java.util.function.IntToDoubleFunction; +import java.util.function.LongToDoubleFunction; +import java.util.function.ToDoubleFunction; + /** * Sequential traverser with both internal and external iteration approach. */ -public interface DoubleAdvancer extends Advancer, DoubleIterator, DoubleTraverser { +public interface DoubleAdvancer extends Advancer { + /** + * Default advance implementation that calls the + * primitive version of it + */ + @Override + default boolean tryAdvance(Yield yield) { + DoubleYield yld = yield::ret; + return this.tryAdvance(yld); + } + /** + * If a remaining element exists, yields that element through + * the given action. + */ + boolean tryAdvance(DoubleYield yield); /** * An DoubleAdvancer object without elements. */ static DoubleAdvancer empty() { - return new DoubleAdvancer() { - @Override - public boolean hasNext() { - return false; - } - - @Override - public double nextDouble() { - throw new NoSuchElementException("No such elements available for iteration!"); - } - - @Override - public void traverse(DoubleYield yield) { - /* Do nothing. Since there are no elements, thus there is nothing to do. */ - } - }; + return action -> false; } - /** - * An DoubleAdvancer object from a generic {@link Advancer} mapped by a {@link ToDoubleFunction}. + * A DoubleAdvancer object from a generic {@link Advancer} mapped by a {@link ToDoubleFunction}. * * @param source * {@link Advancer} with the source elements for this {@code DoubleAdvancer}. * @param mapper - * {@link ToDoubleFunction} that specifies how to map the source elements into double values. + * {@link ToDoubleFunction} that specifies how to map the source elements double values. */ static DoubleAdvancer from(Advancer source, ToDoubleFunction mapper) { - return new DoubleAdvancer() { - @Override - public double nextDouble() { - if (!this.hasNext()) { - throw new NoSuchElementException("No such elements available for iteration!"); - } - return mapper.applyAsDouble(source.next()); - } - - @Override - public boolean hasNext() { - return source.hasNext(); - } - - @Override - public void traverse(DoubleYield yield) { - source.traverse(item -> yield.ret(mapper.applyAsDouble(item))); - } - }; + return yield -> source.tryAdvance(item -> yield.ret(mapper.applyAsDouble(item))); } /** - * An DoubleAdvancer object from a {@link IntAdvancer} mapped by a {@link IntToDoubleFunction}. + * A DoubleAdvancer object from a {@link LongAdvancer} mapped by a {@link LongToDoubleFunction}. * * @param source - * {@link IntAdvancer} with the source elements for this {@code DoubleAdvancer}. + * {@link LongAdvancer} with the source elements for this {@code LongAdvancer}. * @param mapper - * {@link IntToDoubleFunction} that specifies how to map the source elements into int values. + * {@link DoubleToLongFunction} that specifies how to map the source elements into double values. */ - static DoubleAdvancer from(IntAdvancer source, IntToDoubleFunction mapper) { - return from((Advancer) source, mapper::applyAsDouble); + static DoubleAdvancer from(LongAdvancer source, LongToDoubleFunction mapper) { + return from((Advancer) source, mapper::applyAsDouble); } /** - * An DoubleAdvancer object from a {@link LongAdvancer} mapped by a {@link LongToDoubleFunction}. + * A DoubleAdvancer object from a {@link IntAdvancer} mapped by a {@link IntToDoubleFunction}. * * @param source - * {@link LongAdvancer} with the source elements for this {@code DoubleAdvancer}. + * {@link IntAdvancer} with the source elements for this {@code LongAdvancer}. * @param mapper - * {@link LongToDoubleFunction} that specifies how to map the source elements into int values. + * {@link IntToDoubleFunction} that specifies how to map the source elements into double values. */ - static DoubleAdvancer from(LongAdvancer source, LongToDoubleFunction mapper) { - return from((Advancer) source, mapper::applyAsDouble); - } - - @Override - default Double next() { - if (!hasNext()) { - throw new NoSuchElementException("No more elements available on iteration!"); - } - return this.nextDouble(); + static DoubleAdvancer from(IntAdvancer source, IntToDoubleFunction mapper) { + return from((Advancer) source, mapper::applyAsDouble); } } diff --git a/src/main/java/org/jayield/primitives/dbl/DoubleIterator.java b/src/main/java/org/jayield/primitives/dbl/DoubleIterator.java deleted file mode 100644 index 56796a5..0000000 --- a/src/main/java/org/jayield/primitives/dbl/DoubleIterator.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.jayield.primitives.dbl; - -import java.util.Iterator; -import java.util.NoSuchElementException; -import java.util.PrimitiveIterator; - -public interface DoubleIterator extends PrimitiveIterator.OfDouble { - static DoubleIterator from(OfDouble source) { - return new DoubleIterator() { - @Override - public double nextDouble() { - if (!this.hasNext()) { - throw new NoSuchElementException("No such elements available for iteration!"); - } - return source.nextDouble(); - } - - @Override - public boolean hasNext() { - return source.hasNext(); - } - }; - } - - static DoubleIterator from(Iterator iterator) { - return new DoubleIterator() { - @Override - public double nextDouble() { - if (!iterator.hasNext()) { - throw new IndexOutOfBoundsException("No such elements on iteration!"); - } - return iterator.next(); - } - - @Override - public boolean hasNext() { - return iterator.hasNext(); - } - }; - } -} diff --git a/src/main/java/org/jayield/primitives/dbl/DoubleQuery.java b/src/main/java/org/jayield/primitives/dbl/DoubleQuery.java index 3722133..1d1cd2d 100644 --- a/src/main/java/org/jayield/primitives/dbl/DoubleQuery.java +++ b/src/main/java/org/jayield/primitives/dbl/DoubleQuery.java @@ -16,27 +16,6 @@ package org.jayield.primitives.dbl; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.DoubleSummaryStatistics; -import java.util.List; -import java.util.OptionalDouble; -import java.util.Spliterator; -import java.util.Spliterators; -import java.util.function.DoubleBinaryOperator; -import java.util.function.DoubleConsumer; -import java.util.function.DoubleFunction; -import java.util.function.DoublePredicate; -import java.util.function.DoubleSupplier; -import java.util.function.DoubleToIntFunction; -import java.util.function.DoubleToLongFunction; -import java.util.function.DoubleUnaryOperator; -import java.util.function.Function; -import java.util.function.ObjDoubleConsumer; -import java.util.function.Supplier; -import java.util.stream.DoubleStream; -import java.util.stream.StreamSupport; - import org.jayield.Query; import org.jayield.TraversableFinishError; import org.jayield.Yield; @@ -57,12 +36,34 @@ import org.jayield.primitives.dbl.advs.DoubleAdvancerSkip; import org.jayield.primitives.dbl.advs.DoubleAdvancerStream; import org.jayield.primitives.dbl.advs.DoubleAdvancerTakeWhile; -import org.jayield.primitives.dbl.advs.DoubleAdvancerThen; import org.jayield.primitives.dbl.advs.DoubleAdvancerZip; import org.jayield.primitives.intgr.IntAdvancer; import org.jayield.primitives.intgr.IntQuery; +import org.jayield.primitives.intgr.IntTraverser; import org.jayield.primitives.lng.LongAdvancer; import org.jayield.primitives.lng.LongQuery; +import org.jayield.primitives.lng.LongTraverser; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.DoubleSummaryStatistics; +import java.util.List; +import java.util.OptionalDouble; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.function.DoubleBinaryOperator; +import java.util.function.DoubleConsumer; +import java.util.function.DoubleFunction; +import java.util.function.DoublePredicate; +import java.util.function.DoubleSupplier; +import java.util.function.DoubleToIntFunction; +import java.util.function.DoubleToLongFunction; +import java.util.function.DoubleUnaryOperator; +import java.util.function.Function; +import java.util.function.ObjDoubleConsumer; +import java.util.function.Supplier; +import java.util.stream.DoubleStream; +import java.util.stream.StreamSupport; /** * A sequence of primitive double-valued elements supporting sequential @@ -71,9 +72,11 @@ public class DoubleQuery { private final DoubleAdvancer adv; + private final DoubleTraverser trav; - public DoubleQuery(DoubleAdvancer adv) { + public DoubleQuery(DoubleAdvancer adv, DoubleTraverser trav) { this.adv = adv; + this.trav = trav; } /** @@ -81,7 +84,8 @@ public DoubleQuery(DoubleAdvancer adv) { * from the provided {@link DoubleStream} data. */ public static DoubleQuery fromStream(DoubleStream src) { - return new DoubleQuery(new DoubleAdvancerStream(src)); + DoubleAdvancerStream strm = new DoubleAdvancerStream(src); + return new DoubleQuery(strm, strm); } /** @@ -91,7 +95,8 @@ public static DoubleQuery fromStream(DoubleStream src) { * {@code f(f(seed))}, etc. */ public static DoubleQuery iterate(double seed, DoubleUnaryOperator f) { - return new DoubleQuery(new DoubleAdvancerIterate(seed, f)); + DoubleAdvancerIterate iter = new DoubleAdvancerIterate(seed, f); + return new DoubleQuery(iter, iter); } /** @@ -99,7 +104,8 @@ public static DoubleQuery iterate(double seed, DoubleUnaryOperator f) { * where each element is generated by the provided Supplier. */ public static DoubleQuery generate(DoubleSupplier s) { - return new DoubleQuery(new DoubleAdvancerGenerate(s)); + DoubleAdvancerGenerate gen = new DoubleAdvancerGenerate(s); + return new DoubleQuery(gen, gen); } /** @@ -117,7 +123,14 @@ public final void forEach(DoubleYield yield) { * exception is thrown. */ public final void traverse(DoubleYield yield) { - this.adv.traverse(yield); + this.trav.traverse(yield); + } + /** + * If a remaining element exists, yields that element through + * the given action. + */ + public boolean tryAdvance(DoubleYield action) { + return this.adv.tryAdvance(action); } /** @@ -125,7 +138,8 @@ public final void traverse(DoubleYield yield) { * the given predicate. */ public DoubleQuery filter(DoublePredicate p) { - return new DoubleQuery(new DoubleAdvancerFilter(adv, p)); + DoubleAdvancerFilter filter = new DoubleAdvancerFilter(this, p); + return new DoubleQuery(filter, filter); } /** @@ -136,7 +150,8 @@ public DoubleQuery filter(DoublePredicate p) { * DoubleUnaryOperator used to map the elements of this DoubleQuery */ public DoubleQuery map(DoubleUnaryOperator op) { - return new DoubleQuery(new DoubleAdvancerMap(adv, op)); + DoubleAdvancerMap map = new DoubleAdvancerMap(this, op); + return new DoubleQuery(map, map); } /** @@ -147,7 +162,8 @@ public DoubleQuery map(DoubleUnaryOperator op) { * DoubleFunction used to map the elements of this DoubleQuery */ public Query mapToObj(DoubleFunction function) { - return new Query<>(new DoubleAdvancerMapToObj<>(adv, function)); + DoubleAdvancerMapToObj map = new DoubleAdvancerMapToObj<>(this, function); + return new Query<>(map, map); } /** @@ -156,7 +172,8 @@ public Query mapToObj(DoubleFunction function) { * the provided mapping function to each element. */ public DoubleQuery flatMap(DoubleFunction function) { - return new DoubleQuery(new DoubleAdvancerFlatMap(this, function)); + DoubleAdvancerFlatMap map = new DoubleAdvancerFlatMap(this, function); + return new DoubleQuery(map, map); } /** @@ -164,7 +181,8 @@ public DoubleQuery flatMap(DoubleFunction function) { * {@link Object#equals(Object)}) of this query. */ public DoubleQuery distinct() { - return new DoubleQuery(new DoubleAdvancerDistinct(adv)); + DoubleAdvancerDistinct dist = new DoubleAdvancerDistinct(this); + return new DoubleQuery(dist, dist); } /** @@ -176,7 +194,8 @@ public DoubleQuery distinct() { public DoubleQuery sorted() { double[] state = this.toArray(); Arrays.sort(state); - return new DoubleQuery(new DoubleAdvancerArray(state)); + DoubleAdvancerArray arr = new DoubleAdvancerArray(state); + return new DoubleQuery(arr, arr); } /** @@ -206,7 +225,8 @@ public List toList() { * from the resulting {@code DoubleQuery}. */ public DoubleQuery peek(DoubleConsumer action) { - return new DoubleQuery(new DoubleAdvancerPeek(adv, action)); + DoubleAdvancerPeek peek = new DoubleAdvancerPeek(this, action); + return new DoubleQuery(peek, peek); } /** @@ -217,7 +237,8 @@ public DoubleQuery peek(DoubleConsumer action) { * maximum amount of elements to retrieve from this {@code DoubleQuery} */ public DoubleQuery limit(int n) { - return new DoubleQuery(new DoubleAdvancerLimit(this, n)); + DoubleAdvancerLimit lim = new DoubleAdvancerLimit(this, n); + return new DoubleQuery(lim, lim); } /** @@ -228,7 +249,8 @@ public DoubleQuery limit(int n) { * number of elements to discard */ public DoubleQuery skip(int n) { - return new DoubleQuery(new DoubleAdvancerSkip(adv, n)); + DoubleAdvancerSkip skip = new DoubleAdvancerSkip(this, n); + return new DoubleQuery(skip, skip); } /** @@ -236,41 +258,33 @@ public DoubleQuery skip(int n) { * if a reduction can be made, using the provided accumulator. */ public OptionalDouble reduce(DoubleBinaryOperator accumulator) { - if (this.hasNext()) { - return OptionalDouble.of(this.reduce(this.next(), accumulator)); + DoubleBox box = new DoubleBox(); + if(this.tryAdvance(box::setValue)) { + return OptionalDouble.of(this.reduce(box.getValue(), accumulator)); } else { return OptionalDouble.empty(); } } - - /** - * Returns {@code true} if the iteration has more elements. - * (In other words, returns {@code true} if {@link #next} would - * return an element rather than throwing an exception.) - */ - public final boolean hasNext() { - return this.adv.hasNext(); - } - /** * Returns the result of the reduction of the elements of this {@code DoubleQuery}, * using the provided identity value and accumulator. */ public double reduce(double identity, DoubleBinaryOperator accumulator) { - DoubleBox result = new DoubleBox(); - result.setValue(identity); - this.traverse(elem -> result.setValue(accumulator.applyAsDouble(result.getValue(), elem))); - return result.getValue(); - } - - /** - * Returns the next element in the iteration. - */ - public final double next() { - return this.adv.nextDouble(); + class BoxAccumulator extends DoubleBox implements DoubleYield { + public BoxAccumulator(double identity) { + super(identity); + } + @Override + public void ret(double item) { + this.value = accumulator.applyAsDouble(value, item); + } + } + BoxAccumulator box = new BoxAccumulator(identity); + this.traverse(box); + return box.getValue(); } - /** + /** * Returns the lowest double of this {@code DoubleQuery} */ public OptionalDouble min() { @@ -347,7 +361,8 @@ public double sum() { * are the specified values in data parameter. */ public static DoubleQuery of(double... data) { - return new DoubleQuery(new DoubleAdvancerArray(data)); + DoubleAdvancerArray arr = new DoubleAdvancerArray(data); + return new DoubleQuery(arr, arr); } /** @@ -398,7 +413,7 @@ public boolean allMatch(DoublePredicate p) { */ public final void shortCircuit(DoubleYield yield) { try { - this.adv.traverse(yield); + this.trav.traverse(yield); } catch (TraversableFinishError e) { /* Proceed */ } @@ -451,10 +466,7 @@ public OptionalDouble findAny() { */ public OptionalDouble findFirst() { DoubleBox box = new DoubleBox(); - this.shortCircuit(item -> { - box.turnPresent(item); - Yield.bye(); - }); + this.tryAdvance(box::turnPresent); return box.isPresent() ? OptionalDouble.of(box.getValue()) : OptionalDouble.empty(); @@ -477,7 +489,7 @@ public LongQuery asLongQuery() { * @param function DoubleToLongFunction used to map the elements of this DoubleQuery */ public LongQuery mapToLong(DoubleToLongFunction function) { - return new LongQuery(LongAdvancer.from(adv, function)); + return new LongQuery(LongAdvancer.from(adv, function), LongTraverser.from(trav, function)); } /** @@ -497,7 +509,7 @@ public IntQuery asIntQuery() { * @param function DoubleToIntFunction used to map the elements of this DoubleQuery */ public IntQuery mapToInt(DoubleToIntFunction function) { - return new IntQuery(IntAdvancer.from(adv, function)); + return new IntQuery(IntAdvancer.from(adv, function), IntTraverser.from(trav, function)); } /** @@ -505,28 +517,40 @@ public IntQuery mapToInt(DoubleToIntFunction function) { * each boxed to an Double. */ public Query boxed() { - return new Query<>(adv); + return new Query<>(adv, trav); } public DoubleStream toStream() { Spliterator.OfDouble iter = new Spliterators.AbstractDoubleSpliterator(Long.MAX_VALUE, Spliterator.ORDERED) { @Override public boolean tryAdvance(DoubleConsumer action) { - if (!adv.hasNext()) { - return false; - } - action.accept(adv.next()); - return true; + return adv.tryAdvance(action::accept); } @Override public void forEachRemaining(DoubleConsumer action) { - adv.traverse(action::accept); + trav.traverse(action::accept); } }; return StreamSupport.doubleStream(iter, false); } + /** + * The {@code then} operator lets you encapsulate a piece of an operator + * chain into a function. + * That function {@code next} is applied to this {@code DoubleQuery} to produce a new + * {@code DoubleTraverser} object that is encapsulated in the resulting {@code DoubleQuery}. + * On the other hand, the {@code nextAdv} is applied to this query to produce a new + * {@code DoubleAdvancer} object that is encapsulated in the resulting query. + */ + public final DoubleQuery then( + Function nextAdv, + Function next) + { + return new DoubleQuery(nextAdv.apply(this), next.apply(this)); + } + /** * The {@code then} operator lets you encapsulate a piece of an operator * chain into a function. @@ -534,7 +558,10 @@ public void forEachRemaining(DoubleConsumer action) { * {@code DoubleTraverser} object that is encapsulated in the resulting {@code DoubleQuery}. */ public final DoubleQuery then(Function next) { - return new DoubleQuery(new DoubleAdvancerThen(this, next)); + DoubleAdvancer nextAdv = item -> { throw new UnsupportedOperationException( + "Missing tryAdvance() implementation! Use the overloaded then() providing both Advancer and Traverser!"); + }; + return new DoubleQuery(nextAdv, next.apply(this)); } /** @@ -542,7 +569,8 @@ public final DoubleQuery then(Function next) { * this {@code DoubleQuery} that match the given predicate. */ public final DoubleQuery takeWhile(DoublePredicate predicate) { - return new DoubleQuery(new DoubleAdvancerTakeWhile(this, predicate)); + DoubleAdvancerTakeWhile take = new DoubleAdvancerTakeWhile(this, predicate); + return new DoubleQuery(take, take); } /** @@ -551,7 +579,8 @@ public final DoubleQuery takeWhile(DoublePredicate predicate) { * elements of the other {@code Query}. */ public final DoubleQuery concat(DoubleQuery other) { - return new DoubleQuery(new DoubleAdvancerConcat(this, other)); + DoubleAdvancerConcat cat = new DoubleAdvancerConcat(this, other); + return new DoubleQuery(cat, cat); } /** @@ -559,7 +588,8 @@ public final DoubleQuery concat(DoubleQuery other) { * after discarding the first sequence of elements that match the given Predicate. */ public final DoubleQuery dropWhile(DoublePredicate predicate) { - return new DoubleQuery(new DoubleAdvancerDropWhile(this, predicate)); + DoubleAdvancerDropWhile drop = new DoubleAdvancerDropWhile(this, predicate); + return new DoubleQuery(drop, drop); } /** @@ -567,6 +597,7 @@ public final DoubleQuery dropWhile(DoublePredicate predicate) { * sequences, producing a sequence of the results. */ public final DoubleQuery zip(DoubleQuery other, DoubleBinaryOperator zipper) { - return new DoubleQuery(new DoubleAdvancerZip(this.adv, other.adv, zipper)); + DoubleAdvancerZip zip = new DoubleAdvancerZip(this, other, zipper); + return new DoubleQuery(zip, zip); } } diff --git a/src/main/java/org/jayield/primitives/dbl/DoubleTraverser.java b/src/main/java/org/jayield/primitives/dbl/DoubleTraverser.java index 7e8cae2..6d269d9 100644 --- a/src/main/java/org/jayield/primitives/dbl/DoubleTraverser.java +++ b/src/main/java/org/jayield/primitives/dbl/DoubleTraverser.java @@ -18,6 +18,13 @@ import org.jayield.Traverser; import org.jayield.Yield; +import org.jayield.primitives.intgr.IntTraverser; +import org.jayield.primitives.lng.LongTraverser; + +import java.util.function.DoubleToLongFunction; +import java.util.function.IntToDoubleFunction; +import java.util.function.LongToDoubleFunction; +import java.util.function.ToDoubleFunction; /** * Bulk traversal. @@ -42,4 +49,45 @@ default void traverse(Yield yield) { * exception is thrown. */ void traverse(DoubleYield yield); + /** + * An DoubleTraverser object without elements. + */ + static DoubleTraverser empty() { + return action -> {}; + } + /** + * A DoubleTraverser object from a generic {@link Traverser} mapped by a {@link ToDoubleFunction}. + * + * @param source + * {@link Traverser} with the source elements for this {@code DoubleTraverser}. + * @param mapper + * {@link ToDoubleFunction} that specifies how to map the source elements double values. + */ + static DoubleTraverser from(Traverser source, ToDoubleFunction mapper) { + return yield -> source.traverse(item -> yield.ret(mapper.applyAsDouble(item))); + } + + /** + * A DoubleTraverser object from a {@link LongTraverser} mapped by a {@link LongToDoubleFunction}. + * + * @param source + * {@link LongTraverser} with the source elements for this {@code LongTraverser}. + * @param mapper + * {@link DoubleToLongFunction} that specifies how to map the source elements into double values. + */ + static DoubleTraverser from(LongTraverser source, LongToDoubleFunction mapper) { + return from((Traverser) source, mapper::applyAsDouble); + } + + /** + * A DoubleTraverser object from a {@link IntTraverser} mapped by a {@link IntToDoubleFunction}. + * + * @param source + * {@link IntTraverser} with the source elements for this {@code LongTraverser}. + * @param mapper + * {@link IntToDoubleFunction} that specifies how to map the source elements into double values. + */ + static DoubleTraverser from(IntTraverser source, IntToDoubleFunction mapper) { + return from((Traverser) source, mapper::applyAsDouble); + } } diff --git a/src/main/java/org/jayield/primitives/dbl/advs/AbstractDoubleAdvancer.java b/src/main/java/org/jayield/primitives/dbl/advs/AbstractDoubleAdvancer.java deleted file mode 100644 index 154d1d9..0000000 --- a/src/main/java/org/jayield/primitives/dbl/advs/AbstractDoubleAdvancer.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2020, Fernando Miguel Carvalho, mcarvalho@cc.isel.ipl.pt - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jayield.primitives.dbl.advs; - -import org.jayield.advs.AbstractAdvancer; -import org.jayield.primitives.dbl.DoubleAdvancer; - -public abstract class AbstractDoubleAdvancer extends AbstractAdvancer implements DoubleAdvancer { - double currDouble; - - @Override - public final double nextDouble() { - prepareIteration(); - return currDouble; - } - -} diff --git a/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerArray.java b/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerArray.java index 4cc1ab4..445f2f3 100644 --- a/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerArray.java +++ b/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerArray.java @@ -16,12 +16,11 @@ package org.jayield.primitives.dbl.advs; -import java.util.NoSuchElementException; - import org.jayield.primitives.dbl.DoubleAdvancer; +import org.jayield.primitives.dbl.DoubleTraverser; import org.jayield.primitives.dbl.DoubleYield; -public class DoubleAdvancerArray implements DoubleAdvancer { +public class DoubleAdvancerArray implements DoubleAdvancer, DoubleTraverser { private final double[] data; private int current; @@ -30,15 +29,6 @@ public DoubleAdvancerArray(double... data) { this.current = 0; } - - public double nextDouble() { - if (!hasNext()) { - throw new NoSuchElementException("No more elements available on iteration!"); - } - return data[current++]; - } - - @Override public boolean hasNext() { return current < data.length; } @@ -55,4 +45,11 @@ public void traverse(DoubleYield yield) { yield.ret(data[i]); } } + + @Override + public boolean tryAdvance(DoubleYield yield) { + if(!hasNext()) return false; + yield.ret(data[current++]); + return true; + } } diff --git a/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerConcat.java b/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerConcat.java index 947f5a0..528549e 100644 --- a/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerConcat.java +++ b/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerConcat.java @@ -1,12 +1,11 @@ package org.jayield.primitives.dbl.advs; -import java.util.NoSuchElementException; - import org.jayield.primitives.dbl.DoubleAdvancer; import org.jayield.primitives.dbl.DoubleQuery; +import org.jayield.primitives.dbl.DoubleTraverser; import org.jayield.primitives.dbl.DoubleYield; -public class DoubleAdvancerConcat implements DoubleAdvancer { +public class DoubleAdvancerConcat implements DoubleAdvancer, DoubleTraverser { private final DoubleQuery first; private final DoubleQuery second; @@ -15,24 +14,14 @@ public DoubleAdvancerConcat(DoubleQuery first, DoubleQuery second) { this.second = second; } - @Override - public boolean hasNext() { - return first.hasNext() || second.hasNext(); - } - - @Override - public double nextDouble() { - if (first.hasNext()) { - return first.next(); - } else if (second.hasNext()) { - return second.next(); - } - throw new NoSuchElementException("No more elements available on iteration!"); - } - @Override public void traverse(DoubleYield yield) { this.first.traverse(yield); this.second.traverse(yield); } + + @Override + public boolean tryAdvance(DoubleYield yield) { + return first.tryAdvance(yield) || second.tryAdvance(yield); + } } diff --git a/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerDistinct.java b/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerDistinct.java index b7ca5cb..0188697 100644 --- a/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerDistinct.java +++ b/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerDistinct.java @@ -16,33 +16,22 @@ package org.jayield.primitives.dbl.advs; -import java.util.HashSet; - +import org.jayield.boxes.BoolBox; import org.jayield.primitives.dbl.DoubleAdvancer; +import org.jayield.primitives.dbl.DoubleQuery; +import org.jayield.primitives.dbl.DoubleTraverser; import org.jayield.primitives.dbl.DoubleYield; -public class DoubleAdvancerDistinct extends AbstractDoubleAdvancer { +import java.util.HashSet; + +public class DoubleAdvancerDistinct implements DoubleAdvancer, DoubleTraverser { final HashSet mem = new HashSet<>(); - private final DoubleAdvancer upstream; + private final DoubleQuery upstream; - public DoubleAdvancerDistinct(DoubleAdvancer adv) { + public DoubleAdvancerDistinct(DoubleQuery adv) { this.upstream = adv; } - /** - * Returns true if it moves successfully. Otherwise returns false - * signaling it has finished. - */ - public boolean move() { - while (upstream.hasNext()) { - currDouble = upstream.nextDouble(); - if (mem.add(currDouble)) { - return true; - } - } - return false; - } - @Override public void traverse(DoubleYield yield) { upstream.traverse(item -> { @@ -51,4 +40,16 @@ public void traverse(DoubleYield yield) { } }); } + + @Override + public boolean tryAdvance(DoubleYield yield) { + final BoolBox found = new BoolBox(); + while(found.isFalse() && upstream.tryAdvance(item -> { + if(mem.add(item)) { + yield.ret(item); + found.set(); + } + })); + return found.isTrue(); + } } diff --git a/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerDropWhile.java b/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerDropWhile.java index bed5c5b..cde310a 100644 --- a/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerDropWhile.java +++ b/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerDropWhile.java @@ -1,48 +1,52 @@ package org.jayield.primitives.dbl.advs; -import java.util.function.DoublePredicate; - -import org.jayield.boxes.BoolBox; +import org.jayield.primitives.dbl.DoubleAdvancer; import org.jayield.primitives.dbl.DoubleQuery; +import org.jayield.primitives.dbl.DoubleTraverser; import org.jayield.primitives.dbl.DoubleYield; -public class DoubleAdvancerDropWhile extends AbstractDoubleAdvancer { +import java.util.function.DoublePredicate; + +public class DoubleAdvancerDropWhile implements DoubleAdvancer, DoubleTraverser { private final DoubleQuery upstream; private final DoublePredicate predicate; - private final BoolBox dropped; + private boolean dropped; public DoubleAdvancerDropWhile(DoubleQuery upstream, DoublePredicate predicate) { this.upstream = upstream; this.predicate = predicate; - this.dropped = new BoolBox(); + this.dropped = false; } @Override public void traverse(DoubleYield yield) { upstream.traverse(item -> { - if (!dropped.isTrue() && !predicate.test(item)) { - dropped.set(); + if (!dropped && !predicate.test(item)) { + dropped = true; } - if (dropped.isTrue()) { + if (dropped) { yield.ret(item); } }); } @Override - protected boolean move() { - while (!dropped.isTrue() && this.upstream.hasNext()) { - currDouble = upstream.next(); - if (!predicate.test(currDouble)) { - this.dropped.set(); - return true; + public boolean tryAdvance(DoubleYield yield) { + if (dropped) { + return upstream.tryAdvance(yield); + } else { + DoubleYield takeWhile = item -> { + if(!predicate.test(item)){ + dropped = true; + yield.ret(item); + } + }; + while(upstream.tryAdvance(takeWhile) && !dropped) { + // Intentionally empty. Action specified on yield statement of tryAdvance(). } + return dropped; } - if (dropped.isTrue() && upstream.hasNext()) { - currDouble = upstream.next(); - return true; - } - return false; + } } diff --git a/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerFilter.java b/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerFilter.java index 70b778c..db68967 100644 --- a/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerFilter.java +++ b/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerFilter.java @@ -16,34 +16,23 @@ package org.jayield.primitives.dbl.advs; -import java.util.function.DoublePredicate; - +import org.jayield.boxes.BoolBox; import org.jayield.primitives.dbl.DoubleAdvancer; +import org.jayield.primitives.dbl.DoubleQuery; +import org.jayield.primitives.dbl.DoubleTraverser; import org.jayield.primitives.dbl.DoubleYield; -public class DoubleAdvancerFilter extends AbstractDoubleAdvancer { - private final DoubleAdvancer upstream; +import java.util.function.DoublePredicate; + +public class DoubleAdvancerFilter implements DoubleAdvancer, DoubleTraverser { + private final DoubleQuery upstream; private final DoublePredicate p; - public DoubleAdvancerFilter(DoubleAdvancer adv, DoublePredicate p) { + public DoubleAdvancerFilter(DoubleQuery adv, DoublePredicate p) { this.upstream = adv; this.p = p; } - /** - * Returns true if it moves successfully. Otherwise returns false - * signaling it has finished. - */ - public boolean move() { - while (upstream.hasNext()) { - currDouble = upstream.nextDouble(); - if (p.test(currDouble)) { - return true; - } - } - return false; - } - @Override public void traverse(DoubleYield yield) { upstream.traverse(e -> { @@ -52,4 +41,19 @@ public void traverse(DoubleYield yield) { } }); } + + @Override + public boolean tryAdvance(DoubleYield yield) { + BoolBox found = new BoolBox(); + while(found.isFalse()) { + boolean hasNext = upstream.tryAdvance(item -> { + if(p.test(item)) { + yield.ret(item); + found.set(); + } + }); + if(!hasNext) break; + } + return found.isTrue(); + } } diff --git a/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerFlatMap.java b/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerFlatMap.java index 6f43d35..6e2fcbc 100644 --- a/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerFlatMap.java +++ b/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerFlatMap.java @@ -16,13 +16,14 @@ package org.jayield.primitives.dbl.advs; -import java.util.function.DoubleFunction; - import org.jayield.primitives.dbl.DoubleAdvancer; import org.jayield.primitives.dbl.DoubleQuery; +import org.jayield.primitives.dbl.DoubleTraverser; import org.jayield.primitives.dbl.DoubleYield; -public class DoubleAdvancerFlatMap extends AbstractDoubleAdvancer { +import java.util.function.DoubleFunction; + +public class DoubleAdvancerFlatMap implements DoubleAdvancer, DoubleTraverser { private final DoubleQuery upstream; private final DoubleFunction mapper; DoubleQuery src; @@ -30,22 +31,7 @@ public class DoubleAdvancerFlatMap extends AbstractDoubleAdvancer { public DoubleAdvancerFlatMap(DoubleQuery query, DoubleFunction mapper) { this.upstream = query; this.mapper = mapper; - src = new DoubleQuery(DoubleAdvancer.empty()); - } - - /** - * Returns true if it moves successfully. Otherwise returns false - * signaling it has finished. - */ - public boolean move() { - while (!src.hasNext()) { - if (!upstream.hasNext()) { - return false; - } - src = mapper.apply(upstream.next()); - } - currDouble = src.next(); - return true; + src = new DoubleQuery(DoubleAdvancer.empty(), DoubleTraverser.empty()); } @Override @@ -53,4 +39,13 @@ public void traverse(DoubleYield yield) { upstream.traverse(elem -> mapper.apply(elem).traverse(yield)); } + + @Override + public boolean tryAdvance(DoubleYield yield) { + while (!src.tryAdvance(yield)) { + if(!upstream.tryAdvance(t -> src = mapper.apply(t))) + return false; + } + return true; + } } diff --git a/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerGenerate.java b/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerGenerate.java index bff078e..491f126 100644 --- a/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerGenerate.java +++ b/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerGenerate.java @@ -16,13 +16,13 @@ package org.jayield.primitives.dbl.advs; -import java.util.NoSuchElementException; -import java.util.function.DoubleSupplier; - import org.jayield.primitives.dbl.DoubleAdvancer; +import org.jayield.primitives.dbl.DoubleTraverser; import org.jayield.primitives.dbl.DoubleYield; -public class DoubleAdvancerGenerate implements DoubleAdvancer { +import java.util.function.DoubleSupplier; + +public class DoubleAdvancerGenerate implements DoubleAdvancer, DoubleTraverser { private final DoubleSupplier s; public DoubleAdvancerGenerate(DoubleSupplier s) { @@ -31,23 +31,15 @@ public DoubleAdvancerGenerate(DoubleSupplier s) { @Override public void traverse(DoubleYield yield) { - while (hasNext()) { + while (true) { yield.ret(s.getAsDouble()); } } - @Override - public boolean hasNext() { - return true; - } @Override - public double nextDouble() { - if (!hasNext()) { - throw new NoSuchElementException("No more elements available on iteration!"); - } - return s.getAsDouble(); + public boolean tryAdvance(DoubleYield yield) { + yield.ret(s.getAsDouble()); + return true; } - - } diff --git a/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerIterate.java b/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerIterate.java index 28afa9f..01ad1d2 100644 --- a/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerIterate.java +++ b/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerIterate.java @@ -16,13 +16,13 @@ package org.jayield.primitives.dbl.advs; -import java.util.NoSuchElementException; -import java.util.function.DoubleUnaryOperator; - import org.jayield.primitives.dbl.DoubleAdvancer; +import org.jayield.primitives.dbl.DoubleTraverser; import org.jayield.primitives.dbl.DoubleYield; -public class DoubleAdvancerIterate implements DoubleAdvancer { +import java.util.function.DoubleUnaryOperator; + +public class DoubleAdvancerIterate implements DoubleAdvancer, DoubleTraverser { private final DoubleUnaryOperator f; private double prev; @@ -31,21 +31,6 @@ public DoubleAdvancerIterate(double seed, DoubleUnaryOperator f) { this.prev = seed; } - @Override - public double nextDouble() { - if (!hasNext()) { - throw new NoSuchElementException("No more elements available on iteration!"); - } - double curr = prev; - prev = f.applyAsDouble(prev); - return curr; - } - - @Override - public boolean hasNext() { - return true; - } - /** * Continues from the point where tryAdvance or next left the * internal iteration. @@ -58,4 +43,12 @@ public void traverse(DoubleYield yield) { yield.ret(i); } } + + @Override + public boolean tryAdvance(DoubleYield yield) { + double curr = prev; + prev = f.applyAsDouble(prev); + yield.ret(curr); + return true; + } } diff --git a/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerLimit.java b/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerLimit.java index 1fbc1a7..15e88a4 100644 --- a/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerLimit.java +++ b/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerLimit.java @@ -16,14 +16,12 @@ package org.jayield.primitives.dbl.advs; -import java.util.NoSuchElementException; - -import org.jayield.Yield; import org.jayield.primitives.dbl.DoubleAdvancer; import org.jayield.primitives.dbl.DoubleQuery; +import org.jayield.primitives.dbl.DoubleTraverser; import org.jayield.primitives.dbl.DoubleYield; -public class DoubleAdvancerLimit implements DoubleAdvancer { +public class DoubleAdvancerLimit implements DoubleAdvancer, DoubleTraverser { private final DoubleQuery upstream; private final int n; int count; @@ -35,27 +33,18 @@ public DoubleAdvancerLimit(DoubleQuery upstream, int n) { } @Override - public boolean hasNext() { - return count < n && upstream.hasNext(); - } - - @Override - public double nextDouble() { - if (count >= n) { - throw new NoSuchElementException("Nor more elements available!"); + public void traverse(DoubleYield yield) { + if(count >= n) + throw new IllegalStateException("Traverser has already been operated on or closed!"); + while(this.tryAdvance(yield)) { + // Intentionally empty. Action specified on yield statement of tryAdvance(). } - count++; - return upstream.next(); } @Override - public void traverse(DoubleYield yield) { - upstream.shortCircuit(item -> { - if (count >= n) { - Yield.bye(); - } - count++; - yield.ret(item); - }); + public boolean tryAdvance(DoubleYield yield) { + if(count >= n) return false; + count++; + return upstream.tryAdvance(yield); } } diff --git a/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerMap.java b/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerMap.java index c76b387..c82a0ea 100644 --- a/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerMap.java +++ b/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerMap.java @@ -16,33 +16,30 @@ package org.jayield.primitives.dbl.advs; -import java.util.function.DoubleUnaryOperator; - import org.jayield.primitives.dbl.DoubleAdvancer; +import org.jayield.primitives.dbl.DoubleQuery; +import org.jayield.primitives.dbl.DoubleTraverser; import org.jayield.primitives.dbl.DoubleYield; -public class DoubleAdvancerMap implements DoubleAdvancer { +import java.util.function.DoubleUnaryOperator; + +public class DoubleAdvancerMap implements DoubleAdvancer, DoubleTraverser { - private final DoubleAdvancer upstream; + private final DoubleQuery upstream; private final DoubleUnaryOperator mapper; - public DoubleAdvancerMap(DoubleAdvancer adv, DoubleUnaryOperator mapper) { + public DoubleAdvancerMap(DoubleQuery adv, DoubleUnaryOperator mapper) { this.upstream = adv; this.mapper = mapper; } @Override - public boolean hasNext() { - return upstream.hasNext(); - } - - @Override - public double nextDouble() { - return mapper.applyAsDouble(upstream.nextDouble()); + public void traverse(DoubleYield yield) { + upstream.traverse(e -> yield.ret(mapper.applyAsDouble(e))); } @Override - public void traverse(DoubleYield yield) { - upstream.traverse(e -> yield.ret(mapper.applyAsDouble(e))); + public boolean tryAdvance(DoubleYield yield) { + return upstream.tryAdvance(item -> yield.ret(mapper.applyAsDouble(item))); } } diff --git a/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerMapToObj.java b/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerMapToObj.java index b159d40..43335e3 100644 --- a/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerMapToObj.java +++ b/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerMapToObj.java @@ -16,38 +16,30 @@ package org.jayield.primitives.dbl.advs; -import java.util.NoSuchElementException; -import java.util.function.DoubleFunction; - import org.jayield.Advancer; +import org.jayield.Traverser; import org.jayield.Yield; -import org.jayield.primitives.dbl.DoubleAdvancer; +import org.jayield.primitives.dbl.DoubleQuery; + +import java.util.function.DoubleFunction; -public class DoubleAdvancerMapToObj implements Advancer { +public class DoubleAdvancerMapToObj implements Advancer, Traverser { - private final DoubleAdvancer upstream; + private final DoubleQuery upstream; private final DoubleFunction mapper; - public DoubleAdvancerMapToObj(DoubleAdvancer adv, DoubleFunction mapper) { + public DoubleAdvancerMapToObj(DoubleQuery adv, DoubleFunction mapper) { this.upstream = adv; this.mapper = mapper; } @Override - public boolean hasNext() { - return upstream.hasNext(); - } - - @Override - public T next() { - if (!hasNext()) { - throw new NoSuchElementException("No more elements available on iteration!"); - } - return mapper.apply(upstream.nextDouble()); + public void traverse(Yield yield) { + upstream.traverse(e -> yield.ret(mapper.apply(e))); } @Override - public void traverse(Yield yield) { - upstream.traverse(e -> yield.ret(mapper.apply(e))); + public boolean tryAdvance(Yield yield) { + return upstream.tryAdvance(item -> yield.ret(mapper.apply(item))); } } diff --git a/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerPeek.java b/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerPeek.java index 5697772..76ecc8c 100644 --- a/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerPeek.java +++ b/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerPeek.java @@ -16,35 +16,33 @@ package org.jayield.primitives.dbl.advs; -import java.util.function.DoubleConsumer; - import org.jayield.primitives.dbl.DoubleAdvancer; +import org.jayield.primitives.dbl.DoubleQuery; +import org.jayield.primitives.dbl.DoubleTraverser; import org.jayield.primitives.dbl.DoubleYield; -public class DoubleAdvancerPeek implements DoubleAdvancer { - private final DoubleAdvancer upstream; +import java.util.function.DoubleConsumer; + +public class DoubleAdvancerPeek implements DoubleAdvancer, DoubleTraverser { + private final DoubleQuery upstream; private final DoubleConsumer action; - public DoubleAdvancerPeek(DoubleAdvancer adv, DoubleConsumer action) { + public DoubleAdvancerPeek(DoubleQuery adv, DoubleConsumer action) { this.upstream = adv; this.action = action; } @Override - public boolean hasNext() { - return upstream.hasNext(); - } - - @Override - public double nextDouble() { - double curr = upstream.nextDouble(); - action.accept(curr); - return curr; + public void traverse(DoubleYield yield) { + upstream.traverse(item -> { + action.accept(item); + yield.ret(item); + }); } @Override - public void traverse(DoubleYield yield) { - upstream.traverse(item -> { + public boolean tryAdvance(DoubleYield yield) { + return upstream.tryAdvance(item -> { action.accept(item); yield.ret(item); }); diff --git a/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerSkip.java b/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerSkip.java index bdc26de..2fabcea 100644 --- a/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerSkip.java +++ b/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerSkip.java @@ -17,34 +17,21 @@ package org.jayield.primitives.dbl.advs; import org.jayield.primitives.dbl.DoubleAdvancer; +import org.jayield.primitives.dbl.DoubleQuery; +import org.jayield.primitives.dbl.DoubleTraverser; import org.jayield.primitives.dbl.DoubleYield; -public class DoubleAdvancerSkip implements DoubleAdvancer { - private final DoubleAdvancer upstream; +public class DoubleAdvancerSkip implements DoubleAdvancer, DoubleTraverser { + private final DoubleQuery upstream; private final int n; int index; - public DoubleAdvancerSkip(DoubleAdvancer adv, int n) { + public DoubleAdvancerSkip(DoubleQuery adv, int n) { this.upstream = adv; this.n = n; index = 0; } - @Override - public double nextDouble() { - if (!hasNext()) { - throw new IndexOutOfBoundsException("No such elements on iteration!"); - } - return upstream.nextDouble(); - } - - @Override - public boolean hasNext() { - for (; upstream.hasNext() && index < n; index++) - upstream.nextDouble(); - return upstream.hasNext(); - } - /** * Continues from the point where tryAdvance or next left the * internal iteration. @@ -59,4 +46,11 @@ public void traverse(DoubleYield yield) { } }); } + + @Override + public boolean tryAdvance(DoubleYield yield) { + for (; index < n; index++) + upstream.tryAdvance(item -> {}); + return upstream.tryAdvance(yield); + } } diff --git a/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerStream.java b/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerStream.java index 2d2b287..02ccd7f 100644 --- a/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerStream.java +++ b/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerStream.java @@ -16,42 +16,30 @@ package org.jayield.primitives.dbl.advs; -import java.util.stream.DoubleStream; - import org.jayield.primitives.dbl.DoubleAdvancer; -import org.jayield.primitives.dbl.DoubleIterator; +import org.jayield.primitives.dbl.DoubleTraverser; import org.jayield.primitives.dbl.DoubleYield; -public class DoubleAdvancerStream implements DoubleAdvancer { - private final DoubleStream upstream; - private DoubleIterator current; - private boolean operated = false; +import java.util.Spliterator; +import java.util.function.DoubleConsumer; +import java.util.stream.DoubleStream; - public DoubleAdvancerStream(DoubleStream data) { - this.upstream = data; - } +public class DoubleAdvancerStream implements DoubleAdvancer, DoubleTraverser { + private final Spliterator.OfDouble upstream; - @Override - public double nextDouble() { - return current().nextDouble(); - } - - public DoubleIterator current() { - if (operated) { - return current; - } - operated = true; - current = DoubleIterator.from(upstream.iterator()); - return current; + public DoubleAdvancerStream(DoubleStream data) { + this.upstream = data.spliterator(); } @Override - public boolean hasNext() { - return current().hasNext(); + public void traverse(DoubleYield yield) { + DoubleConsumer cons = yield::ret; + upstream.forEachRemaining(cons); } @Override - public void traverse(DoubleYield yield) { - upstream.forEach(yield::ret); + public boolean tryAdvance(DoubleYield yield) { + DoubleConsumer cons = yield::ret; + return upstream.tryAdvance(cons); } } diff --git a/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerTakeWhile.java b/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerTakeWhile.java index 25e27b2..7244ca5 100644 --- a/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerTakeWhile.java +++ b/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerTakeWhile.java @@ -16,33 +16,23 @@ package org.jayield.primitives.dbl.advs; -import java.util.function.DoublePredicate; - import org.jayield.Yield; +import org.jayield.primitives.dbl.DoubleAdvancer; import org.jayield.primitives.dbl.DoubleQuery; +import org.jayield.primitives.dbl.DoubleTraverser; import org.jayield.primitives.dbl.DoubleYield; -public class DoubleAdvancerTakeWhile extends AbstractDoubleAdvancer { +import java.util.function.DoublePredicate; + +public class DoubleAdvancerTakeWhile implements DoubleAdvancer, DoubleTraverser { private final DoubleQuery upstream; private final DoublePredicate predicate; + private boolean hasNext; public DoubleAdvancerTakeWhile(DoubleQuery upstream, DoublePredicate predicate) { this.upstream = upstream; this.predicate = predicate; - } - - /** - * Returns true if it moves successfully. Otherwise returns false - * signaling it has finished. - */ - public boolean move() { - if (upstream.hasNext()) { - currDouble = upstream.next(); - if (predicate.test(currDouble)) { - return true; - } - } - return false; + this.hasNext = true; } @Override @@ -54,4 +44,17 @@ public void traverse(DoubleYield yield) { yield.ret(item); }); } + + @Override + public boolean tryAdvance(DoubleYield yield) { + if(!hasNext) return false; // Once predicate is false it finishes the iteration + DoubleYield takeWhile = item -> { + if(predicate.test(item)){ + yield.ret(item); + } else { + hasNext = false; + } + }; + return upstream.tryAdvance(takeWhile) && hasNext; + } } diff --git a/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerThen.java b/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerThen.java deleted file mode 100644 index 8e35f24..0000000 --- a/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerThen.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2020, Fernando Miguel Carvalho, mcarvalho@cc.isel.ipl.pt - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jayield.primitives.dbl.advs; - -import java.util.ArrayList; -import java.util.function.Function; - -import org.jayield.primitives.dbl.DoubleAdvancer; -import org.jayield.primitives.dbl.DoubleIterator; -import org.jayield.primitives.dbl.DoubleQuery; -import org.jayield.primitives.dbl.DoubleTraverser; -import org.jayield.primitives.dbl.DoubleYield; - -public class DoubleAdvancerThen implements DoubleAdvancer { - private DoubleQuery upstream; - private Function next; - private DoubleIterator curr; - private boolean inMem = false; - - public DoubleAdvancerThen(DoubleQuery upstream, Function next) { - this.upstream = upstream; - this.next = next; - } - - @Override - public boolean hasNext() { - return curr().hasNext(); - } - - public DoubleIterator curr() { - if (inMem) { - return curr; - } - ArrayList mem = new ArrayList<>(); - next.apply(upstream).traverse(mem::add); - inMem = true; - curr = DoubleIterator.from(mem.iterator()); - return curr; - } - - @Override - public double nextDouble() { - return curr().nextDouble(); - } - - @Override - public void traverse(DoubleYield yield) { - next.apply(upstream).traverse(yield); - } -} diff --git a/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerZip.java b/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerZip.java index 9e09c31..c7519dc 100644 --- a/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerZip.java +++ b/src/main/java/org/jayield/primitives/dbl/advs/DoubleAdvancerZip.java @@ -16,37 +16,41 @@ package org.jayield.primitives.dbl.advs; -import java.util.function.DoubleBinaryOperator; - +import org.jayield.Yield; +import org.jayield.boxes.BoolBox; import org.jayield.primitives.dbl.DoubleAdvancer; +import org.jayield.primitives.dbl.DoubleQuery; +import org.jayield.primitives.dbl.DoubleTraverser; import org.jayield.primitives.dbl.DoubleYield; -public class DoubleAdvancerZip implements DoubleAdvancer { - private final DoubleAdvancer upstream; - private final DoubleAdvancer other; +import java.util.function.DoubleBinaryOperator; + +public class DoubleAdvancerZip implements DoubleAdvancer, DoubleTraverser { + private final DoubleQuery upstream; + private final DoubleQuery other; private final DoubleBinaryOperator zipper; - public DoubleAdvancerZip(DoubleAdvancer upstream, DoubleAdvancer other, DoubleBinaryOperator zipper) { + public DoubleAdvancerZip(DoubleQuery upstream, DoubleQuery other, DoubleBinaryOperator zipper) { this.upstream = upstream; this.other = other; this.zipper = zipper; } @Override - public boolean hasNext() { - return upstream.hasNext() && other.hasNext(); - } - - @Override - public double nextDouble() { - return zipper.applyAsDouble(upstream.next(), other.next()); + public void traverse(DoubleYield yield) { + upstream.shortCircuit(e1 -> { + if(!other.tryAdvance(e2 -> yield.ret(zipper.applyAsDouble(e1, e2)))) + Yield.bye(); + }); } @Override - public void traverse(DoubleYield yield) { - upstream.traverse(e -> { - if (!other.hasNext()) return; - yield.ret(zipper.applyAsDouble(e, other.next())); - }); + public boolean tryAdvance(DoubleYield yield) { + BoolBox consumed = new BoolBox(); + upstream.tryAdvance(e1 -> other.tryAdvance(e2 -> { + yield.ret(zipper.applyAsDouble(e1, e2)); + consumed.set(); + })); + return consumed.isTrue(); } } diff --git a/src/main/java/org/jayield/primitives/intgr/IntAdvancer.java b/src/main/java/org/jayield/primitives/intgr/IntAdvancer.java index 596311f..d75cc4f 100644 --- a/src/main/java/org/jayield/primitives/intgr/IntAdvancer.java +++ b/src/main/java/org/jayield/primitives/intgr/IntAdvancer.java @@ -1,39 +1,37 @@ package org.jayield.primitives.intgr; -import java.util.NoSuchElementException; -import java.util.function.DoubleToIntFunction; -import java.util.function.LongToIntFunction; -import java.util.function.ToIntFunction; - import org.jayield.Advancer; +import org.jayield.Yield; import org.jayield.primitives.dbl.DoubleAdvancer; import org.jayield.primitives.lng.LongAdvancer; +import java.util.function.DoubleToIntFunction; +import java.util.function.LongToIntFunction; +import java.util.function.ToIntFunction; + /** * Sequential traverser with both internal and external iteration approach. */ -public interface IntAdvancer extends Advancer, IntIterator, IntTraverser { +public interface IntAdvancer extends Advancer { /** - * An IntAdvancer object without elements. + * If a remaining element exists, yields that element through + * the given action. */ - static IntAdvancer empty() { - return new IntAdvancer() { - @Override - public boolean hasNext() { - return false; - } + boolean tryAdvance(IntYield yield); - @Override - public int nextInt() { - throw new NoSuchElementException("No such elements available for iteration!"); - } + /** + * Default advancer implementation that calls the + * primitive version of it + */ + @Override + default boolean tryAdvance(Yield yield) { + IntYield yld = yield::ret; + return this.tryAdvance(yld); + } - @Override - public void traverse(IntYield yield) { - /* Do nothing. Since there are no elements, thus there is nothing to do. */ - } - }; + static IntAdvancer empty() { + return yield -> false; } /** @@ -45,25 +43,7 @@ public void traverse(IntYield yield) { * {@link ToIntFunction} that specifies how to map the source elements into int values. */ static IntAdvancer from(Advancer source, ToIntFunction mapper) { - return new IntAdvancer() { - @Override - public int nextInt() { - if (!this.hasNext()) { - throw new NoSuchElementException("No such elements available for iteration!"); - } - return mapper.applyAsInt(source.next()); - } - - @Override - public boolean hasNext() { - return source.hasNext(); - } - - @Override - public void traverse(IntYield yield) { - source.traverse(item -> yield.ret(mapper.applyAsInt(item))); - } - }; + return yield -> source.tryAdvance(item -> yield.ret(mapper.applyAsInt(item))); } /** @@ -89,12 +69,4 @@ static IntAdvancer from(DoubleAdvancer source, DoubleToIntFunction mapper) { static IntAdvancer from(LongAdvancer source, LongToIntFunction mapper) { return from((Advancer) source, mapper::applyAsInt); } - - @Override - default Integer next() { - if (!hasNext()) { - throw new NoSuchElementException("No more elements available on iteration!"); - } - return this.nextInt(); - } } diff --git a/src/main/java/org/jayield/primitives/intgr/IntIterator.java b/src/main/java/org/jayield/primitives/intgr/IntIterator.java deleted file mode 100644 index c337fb2..0000000 --- a/src/main/java/org/jayield/primitives/intgr/IntIterator.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.jayield.primitives.intgr; - -import java.util.Iterator; -import java.util.NoSuchElementException; -import java.util.PrimitiveIterator; - -public interface IntIterator extends PrimitiveIterator.OfInt { - static IntIterator from(PrimitiveIterator.OfInt source) { - return new IntIterator() { - @Override - public int nextInt() { - if (!this.hasNext()) { - throw new NoSuchElementException("No such elements available for iteration!"); - } - return source.nextInt(); - } - - @Override - public boolean hasNext() { - return source.hasNext(); - } - }; - } - - static IntIterator from(Iterator iterator) { - return new IntIterator() { - @Override - public int nextInt() { - if (!iterator.hasNext()) { - throw new IndexOutOfBoundsException("No such elements on iteration!"); - } - return iterator.next(); - } - - @Override - public boolean hasNext() { - return iterator.hasNext(); - } - }; - } -} diff --git a/src/main/java/org/jayield/primitives/intgr/IntQuery.java b/src/main/java/org/jayield/primitives/intgr/IntQuery.java index 109add4..410c30a 100644 --- a/src/main/java/org/jayield/primitives/intgr/IntQuery.java +++ b/src/main/java/org/jayield/primitives/intgr/IntQuery.java @@ -16,28 +16,6 @@ package org.jayield.primitives.intgr; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.IntSummaryStatistics; -import java.util.List; -import java.util.OptionalDouble; -import java.util.OptionalInt; -import java.util.Spliterator; -import java.util.Spliterators; -import java.util.function.Function; -import java.util.function.IntBinaryOperator; -import java.util.function.IntConsumer; -import java.util.function.IntFunction; -import java.util.function.IntPredicate; -import java.util.function.IntSupplier; -import java.util.function.IntToDoubleFunction; -import java.util.function.IntToLongFunction; -import java.util.function.IntUnaryOperator; -import java.util.function.ObjIntConsumer; -import java.util.function.Supplier; -import java.util.stream.IntStream; -import java.util.stream.StreamSupport; - import org.jayield.Query; import org.jayield.TraversableFinishError; import org.jayield.Yield; @@ -45,6 +23,7 @@ import org.jayield.boxes.IntBox; import org.jayield.primitives.dbl.DoubleAdvancer; import org.jayield.primitives.dbl.DoubleQuery; +import org.jayield.primitives.dbl.DoubleTraverser; import org.jayield.primitives.intgr.advs.IntAdvancerArray; import org.jayield.primitives.intgr.advs.IntAdvancerConcat; import org.jayield.primitives.intgr.advs.IntAdvancerDistinct; @@ -60,10 +39,32 @@ import org.jayield.primitives.intgr.advs.IntAdvancerSkip; import org.jayield.primitives.intgr.advs.IntAdvancerStream; import org.jayield.primitives.intgr.advs.IntAdvancerTakeWhile; -import org.jayield.primitives.intgr.advs.IntAdvancerThen; import org.jayield.primitives.intgr.advs.IntAdvancerZip; import org.jayield.primitives.lng.LongAdvancer; import org.jayield.primitives.lng.LongQuery; +import org.jayield.primitives.lng.LongTraverser; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.IntSummaryStatistics; +import java.util.List; +import java.util.OptionalDouble; +import java.util.OptionalInt; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.function.Function; +import java.util.function.IntBinaryOperator; +import java.util.function.IntConsumer; +import java.util.function.IntFunction; +import java.util.function.IntPredicate; +import java.util.function.IntSupplier; +import java.util.function.IntToDoubleFunction; +import java.util.function.IntToLongFunction; +import java.util.function.IntUnaryOperator; +import java.util.function.ObjIntConsumer; +import java.util.function.Supplier; +import java.util.stream.IntStream; +import java.util.stream.StreamSupport; /** * A sequence of primitive int-valued elements supporting sequential @@ -72,9 +73,11 @@ public class IntQuery { private final IntAdvancer adv; + private final IntTraverser trav; - public IntQuery(IntAdvancer adv) { + public IntQuery(IntAdvancer adv, IntTraverser trav) { this.adv = adv; + this.trav = trav; } /** @@ -82,7 +85,8 @@ public IntQuery(IntAdvancer adv) { * from the provided {@link IntStream} data. */ public static IntQuery fromStream(IntStream src) { - return new IntQuery(new IntAdvancerStream(src)); + IntAdvancerStream strm = new IntAdvancerStream(src); + return new IntQuery(strm, strm); } /** @@ -92,7 +96,8 @@ public static IntQuery fromStream(IntStream src) { * {@code f(f(seed))}, etc. */ public static IntQuery iterate(int seed, IntUnaryOperator f) { - return new IntQuery(new IntAdvancerIterate(seed, f)); + IntAdvancerIterate iter = new IntAdvancerIterate(seed, f); + return new IntQuery(iter, iter); } /** @@ -100,7 +105,8 @@ public static IntQuery iterate(int seed, IntUnaryOperator f) { * where each element is generated by the provided Supplier. */ public static IntQuery generate(IntSupplier s) { - return new IntQuery(new IntAdvancerGenerate(s)); + IntAdvancerGenerate gen = new IntAdvancerGenerate(s); + return new IntQuery(gen, gen); } /** @@ -118,7 +124,15 @@ public final void forEach(IntYield yield) { * exception is thrown. */ public final void traverse(IntYield yield) { - this.adv.traverse(yield); + this.trav.traverse(yield); + } + + /** + * If a remaining element exists, yields that element through + * the given action. + */ + public boolean tryAdvance(IntYield action) { + return this.adv.tryAdvance(action); } /** @@ -126,7 +140,8 @@ public final void traverse(IntYield yield) { * the given predicate. */ public IntQuery filter(IntPredicate p) { - return new IntQuery(new IntAdvancerFilter(adv, p)); + IntAdvancerFilter filter = new IntAdvancerFilter(this, p); + return new IntQuery(filter, filter); } /** @@ -137,7 +152,8 @@ public IntQuery filter(IntPredicate p) { * IntUnaryOperator used to map the elements of this IntQuery */ public IntQuery map(IntUnaryOperator op) { - return new IntQuery(new IntAdvancerMap(adv, op)); + IntAdvancerMap map = new IntAdvancerMap(this, op); + return new IntQuery(map, map); } /** @@ -148,7 +164,8 @@ public IntQuery map(IntUnaryOperator op) { * IntFunction used to map the elements of this IntQuery */ public Query mapToObj(IntFunction function) { - return new Query<>(new IntAdvancerMapToObj<>(adv, function)); + IntAdvancerMapToObj map = new IntAdvancerMapToObj<>(this, function); + return new Query<>(map, map); } /** @@ -157,7 +174,8 @@ public Query mapToObj(IntFunction function) { * the provided mapping function to each element. */ public IntQuery flatMap(IntFunction function) { - return new IntQuery(new IntAdvancerFlatMap(this, function)); + IntAdvancerFlatMap map = new IntAdvancerFlatMap(this, function); + return new IntQuery(map, map); } /** @@ -165,7 +183,8 @@ public IntQuery flatMap(IntFunction function) { * {@link Object#equals(Object)}) of this query. */ public IntQuery distinct() { - return new IntQuery(new IntAdvancerDistinct(adv)); + IntAdvancerDistinct dis = new IntAdvancerDistinct(this); + return new IntQuery(dis, dis); } /** @@ -177,7 +196,8 @@ public IntQuery distinct() { public IntQuery sorted() { int[] state = this.toArray(); Arrays.sort(state); - return new IntQuery(new IntAdvancerArray(state)); + IntAdvancerArray arr = new IntAdvancerArray(state); + return new IntQuery(arr, arr); } /** @@ -207,7 +227,8 @@ public List toList() { * from the resulting {@code IntQuery}. */ public IntQuery peek(IntConsumer action) { - return new IntQuery(new IntAdvancerPeek(adv, action)); + IntAdvancerPeek peek = new IntAdvancerPeek(this, action); + return new IntQuery(peek, peek); } /** @@ -218,7 +239,8 @@ public IntQuery peek(IntConsumer action) { * maximum amount of elements to retrieve from this {@code IntQuery} */ public IntQuery limit(int n) { - return new IntQuery(new IntAdvancerLimit(this, n)); + IntAdvancerLimit lim = new IntAdvancerLimit(this, n); + return new IntQuery(lim, lim); } /** @@ -229,7 +251,8 @@ public IntQuery limit(int n) { * number of elements to discard */ public IntQuery skip(int n) { - return new IntQuery(new IntAdvancerSkip(adv, n)); + IntAdvancerSkip skip = new IntAdvancerSkip(this, n); + return new IntQuery(skip, skip); } /** @@ -237,38 +260,31 @@ public IntQuery skip(int n) { * if a reduction can be made, using the provided accumulator. */ public OptionalInt reduce(IntBinaryOperator accumulator) { - if (this.hasNext()) { - return OptionalInt.of(this.reduce(this.next(), accumulator)); + IntBox box = new IntBox(); + if(this.tryAdvance(box::setValue)) { + return OptionalInt.of(this.reduce(box.getValue(), accumulator)); } else { return OptionalInt.empty(); } } - /** - * Returns {@code true} if the iteration has more elements. - * (In other words, returns {@code true} if {@link #next} would - * return an element rather than throwing an exception.) - */ - public final boolean hasNext() { - return this.adv.hasNext(); - } - /** * Returns the result of the reduction of the elements of this {@code IntQuery}, * using the provided identity value and accumulator. */ public int reduce(int identity, IntBinaryOperator accumulator) { - IntBox result = new IntBox(); - result.setValue(identity); - this.traverse(elem -> result.setValue(accumulator.applyAsInt(result.getValue(), elem))); - return result.getValue(); - } - - /** - * Returns the next element in the iteration. - */ - public final int next() { - return this.adv.nextInt(); + class BoxAccumulator extends IntBox implements IntYield { + public BoxAccumulator(int identity) { + super(identity); + } + @Override + public void ret(int item) { + this.value = accumulator.applyAsInt(value, item); + } + } + BoxAccumulator box = new BoxAccumulator(identity); + this.traverse(box); + return box.getValue(); } /** @@ -348,7 +364,8 @@ public int sum() { * are the specified values in data parameter. */ public static IntQuery of(int... data) { - return new IntQuery(new IntAdvancerArray(data)); + IntAdvancerArray arr = new IntAdvancerArray(data); + return new IntQuery(arr, arr); } /** @@ -399,7 +416,7 @@ public boolean allMatch(IntPredicate p) { */ public final void shortCircuit(IntYield yield) { try { - this.adv.traverse(yield); + this.trav.traverse(yield); } catch (TraversableFinishError e) { /* Proceed */ } @@ -452,10 +469,7 @@ public OptionalInt findAny() { */ public OptionalInt findFirst() { IntBox box = new IntBox(); - this.shortCircuit(item -> { - box.turnPresent(item); - Yield.bye(); - }); + this.tryAdvance(box::turnPresent); return box.isPresent() ? OptionalInt.of(box.getValue()) : OptionalInt.empty(); @@ -479,7 +493,7 @@ public LongQuery asLongQuery() { * IntToLongFunction used to map the elements of this IntQuery */ public LongQuery mapToLong(IntToLongFunction function) { - return new LongQuery(LongAdvancer.from(adv, function)); + return new LongQuery(LongAdvancer.from(adv, function), LongTraverser.from(trav, function)); } /** @@ -500,7 +514,7 @@ public DoubleQuery asDoubleQuery() { * IntToDoubleFunction used to map the elements of this IntQuery */ public DoubleQuery mapToDouble(IntToDoubleFunction function) { - return new DoubleQuery(DoubleAdvancer.from(adv, function)); + return new DoubleQuery(DoubleAdvancer.from(adv, function), DoubleTraverser.from(trav, function)); } /** @@ -508,28 +522,40 @@ public DoubleQuery mapToDouble(IntToDoubleFunction function) { * each boxed to an Integer. */ public Query boxed() { - return new Query<>(adv); + return new Query<>(adv, trav); } public IntStream toStream() { Spliterator.OfInt iter = new Spliterators.AbstractIntSpliterator(Long.MAX_VALUE, Spliterator.ORDERED) { @Override public boolean tryAdvance(IntConsumer action) { - if (!adv.hasNext()) { - return false; - } - action.accept(adv.next()); - return true; + return adv.tryAdvance(action::accept); } @Override public void forEachRemaining(IntConsumer action) { - adv.traverse(action::accept); + trav.traverse(action::accept); } }; return StreamSupport.intStream(iter, false); } + + /** + * The {@code then} operator lets you encapsulate a piece of an operator + * chain into a function. + * That function {@code next} is applied to this {@code DoubleQuery} to produce a new + * {@code IntTraverser} object that is encapsulated in the resulting {@code DoubleQuery}. + * On the other hand, the {@code nextAdv} is applied to this query to produce a new + * {@code IntAdvancer} object that is encapsulated in the resulting query. + */ + public final IntQuery then( + Function nextAdv, + Function next) + { + return new IntQuery(nextAdv.apply(this), next.apply(this)); + } + /** * The {@code then} operator lets you encapsulate a piece of an operator * chain into a function. @@ -537,7 +563,10 @@ public void forEachRemaining(IntConsumer action) { * {@code IntTraverser} object that is encapsulated in the resulting {@code IntQuery}. */ public final IntQuery then(Function next) { - return new IntQuery(new IntAdvancerThen(this, next)); + IntAdvancer nextAdv = item -> { throw new UnsupportedOperationException( + "Missing tryAdvance() implementation! Use the overloaded then() providing both Advancer and Traverser!"); + }; + return new IntQuery(nextAdv, next.apply(this)); } /** @@ -545,7 +574,8 @@ public final IntQuery then(Function next) { * this {@code IntQuery} that match the given predicate. */ public final IntQuery takeWhile(IntPredicate predicate) { - return new IntQuery(new IntAdvancerTakeWhile(this, predicate)); + IntAdvancerTakeWhile take = new IntAdvancerTakeWhile(this, predicate); + return new IntQuery(take, take); } /** @@ -554,7 +584,8 @@ public final IntQuery takeWhile(IntPredicate predicate) { * elements of the other {@code Query}. */ public final IntQuery concat(IntQuery other) { - return new IntQuery(new IntAdvancerConcat(this, other)); + IntAdvancerConcat cat = new IntAdvancerConcat(this, other); + return new IntQuery(cat, cat); } /** @@ -562,7 +593,8 @@ public final IntQuery concat(IntQuery other) { * after discarding the first sequence of elements that match the given Predicate. */ public final IntQuery dropWhile(IntPredicate predicate) { - return new IntQuery(new IntAdvancerDropWhile(this, predicate)); + IntAdvancerDropWhile drop = new IntAdvancerDropWhile(this, predicate); + return new IntQuery(drop, drop); } /** @@ -570,6 +602,7 @@ public final IntQuery dropWhile(IntPredicate predicate) { * sequences, producing a sequence of the results. */ public final IntQuery zip(IntQuery other, IntBinaryOperator zipper) { - return new IntQuery(new IntAdvancerZip(this.adv, other.adv, zipper)); + IntAdvancerZip zip = new IntAdvancerZip(this, other, zipper); + return new IntQuery(zip, zip); } } diff --git a/src/main/java/org/jayield/primitives/intgr/IntTraverser.java b/src/main/java/org/jayield/primitives/intgr/IntTraverser.java index 64d35a3..8b7d015 100644 --- a/src/main/java/org/jayield/primitives/intgr/IntTraverser.java +++ b/src/main/java/org/jayield/primitives/intgr/IntTraverser.java @@ -18,6 +18,12 @@ import org.jayield.Traverser; import org.jayield.Yield; +import org.jayield.primitives.dbl.DoubleTraverser; +import org.jayield.primitives.lng.LongTraverser; + +import java.util.function.DoubleToIntFunction; +import java.util.function.LongToIntFunction; +import java.util.function.ToIntFunction; /** * Bulk traversal. @@ -26,6 +32,16 @@ * This is a special kind of traversal that disallows individually access. */ public interface IntTraverser extends Traverser { + /** + * Yields elements sequentially in the current thread, + * until all elements have been processed or an + * exception is thrown. + */ + void traverse(IntYield yield); + + static IntTraverser empty() { + return yield -> { }; + } /** * Default traverse implementation that calls the * primitive version of it @@ -35,11 +51,39 @@ default void traverse(Yield yield) { IntYield yld = yield::ret; this.traverse(yld); } + /** + * An IntTraverser object from a generic {@link Traverser} mapped by a {@link ToIntFunction}. + * + * @param source + * {@link Traverser} with the source elements for this {@code IntTraverser}. + * @param mapper + * {@link ToIntFunction} that specifies how to map the source elements into int values. + */ + static IntTraverser from(Traverser source, ToIntFunction mapper) { + return yield -> source.traverse(item -> yield.ret(mapper.applyAsInt(item))); + } /** - * Yields elements sequentially in the current thread, - * until all elements have been processed or an - * exception is thrown. + * An IntTraverser object from a {@link DoubleTraverser} mapped by a {@link DoubleToIntFunction}. + * + * @param source + * {@link DoubleTraverser} with the source elements for this {@code IntTraverser}. + * @param mapper + * {@link DoubleToIntFunction} that specifies how to map the source elements into int values. */ - void traverse(IntYield yield); + static IntTraverser from(DoubleTraverser source, DoubleToIntFunction mapper) { + return from((Traverser) source, mapper::applyAsInt); + } + + /** + * An IntTraverser object from a {@link LongTraverser} mapped by a {@link LongToIntFunction}. + * + * @param source + * {@link LongTraverser} with the source elements for this {@code DoubleTraverser}. + * @param mapper + * {@link LongToIntFunction} that specifies how to map the source elements into int values. + */ + static IntTraverser from(LongTraverser source, LongToIntFunction mapper) { + return from((Traverser) source, mapper::applyAsInt); + } } diff --git a/src/main/java/org/jayield/primitives/intgr/advs/AbstractIntAdvancer.java b/src/main/java/org/jayield/primitives/intgr/advs/AbstractIntAdvancer.java deleted file mode 100644 index 66cfe77..0000000 --- a/src/main/java/org/jayield/primitives/intgr/advs/AbstractIntAdvancer.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2020, Fernando Miguel Carvalho, mcarvalho@cc.isel.ipl.pt - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jayield.primitives.intgr.advs; - -import org.jayield.advs.AbstractAdvancer; -import org.jayield.primitives.intgr.IntAdvancer; - -public abstract class AbstractIntAdvancer extends AbstractAdvancer implements IntAdvancer { - int currInt; - - @Override - public final int nextInt() { - prepareIteration(); - return currInt; - } - -} diff --git a/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerArray.java b/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerArray.java index a622996..0b5d040 100644 --- a/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerArray.java +++ b/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerArray.java @@ -16,12 +16,11 @@ package org.jayield.primitives.intgr.advs; -import java.util.NoSuchElementException; - import org.jayield.primitives.intgr.IntAdvancer; +import org.jayield.primitives.intgr.IntTraverser; import org.jayield.primitives.intgr.IntYield; -public class IntAdvancerArray implements IntAdvancer { +public class IntAdvancerArray implements IntAdvancer, IntTraverser { private final int[] data; private int current; @@ -30,15 +29,6 @@ public IntAdvancerArray(int... data) { this.current = 0; } - - public int nextInt() { - if (!hasNext()) { - throw new NoSuchElementException("No more elements available on iteration!"); - } - return data[current++]; - } - - @Override public boolean hasNext() { return current < data.length; } @@ -55,4 +45,11 @@ public void traverse(IntYield yield) { yield.ret(data[i]); } } + + @Override + public boolean tryAdvance(IntYield yield) { + if(!hasNext()) return false; + yield.ret(data[current++]); + return true; + } } diff --git a/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerConcat.java b/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerConcat.java index 4f5c837..38cdcc5 100644 --- a/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerConcat.java +++ b/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerConcat.java @@ -1,12 +1,11 @@ package org.jayield.primitives.intgr.advs; -import java.util.NoSuchElementException; - import org.jayield.primitives.intgr.IntAdvancer; import org.jayield.primitives.intgr.IntQuery; +import org.jayield.primitives.intgr.IntTraverser; import org.jayield.primitives.intgr.IntYield; -public class IntAdvancerConcat implements IntAdvancer { +public class IntAdvancerConcat implements IntAdvancer, IntTraverser { private final IntQuery first; private final IntQuery second; @@ -15,24 +14,14 @@ public IntAdvancerConcat(IntQuery first, IntQuery second) { this.second = second; } - @Override - public boolean hasNext() { - return first.hasNext() || second.hasNext(); - } - - @Override - public int nextInt() { - if (first.hasNext()) { - return first.next(); - } else if (second.hasNext()) { - return second.next(); - } - throw new NoSuchElementException("No more elements available on iteration!"); - } - @Override public void traverse(IntYield yield) { this.first.traverse(yield); this.second.traverse(yield); } + + @Override + public boolean tryAdvance(IntYield yield) { + return first.tryAdvance(yield) || second.tryAdvance(yield); + } } diff --git a/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerDistinct.java b/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerDistinct.java index d8a84bb..0241ec2 100644 --- a/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerDistinct.java +++ b/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerDistinct.java @@ -16,33 +16,22 @@ package org.jayield.primitives.intgr.advs; -import java.util.HashSet; - +import org.jayield.boxes.BoolBox; import org.jayield.primitives.intgr.IntAdvancer; +import org.jayield.primitives.intgr.IntQuery; +import org.jayield.primitives.intgr.IntTraverser; import org.jayield.primitives.intgr.IntYield; -public class IntAdvancerDistinct extends AbstractIntAdvancer { +import java.util.HashSet; + +public class IntAdvancerDistinct implements IntAdvancer, IntTraverser { final HashSet mem = new HashSet<>(); - private final IntAdvancer upstream; + private final IntQuery upstream; - public IntAdvancerDistinct(IntAdvancer adv) { + public IntAdvancerDistinct(IntQuery adv) { this.upstream = adv; } - /** - * Returns true if it moves successfully. Otherwise returns false - * signaling it has finished. - */ - public boolean move() { - while (upstream.hasNext()) { - currInt = upstream.nextInt(); - if (mem.add(currInt)) { - return true; - } - } - return false; - } - @Override public void traverse(IntYield yield) { upstream.traverse(item -> { @@ -51,4 +40,16 @@ public void traverse(IntYield yield) { } }); } + + @Override + public boolean tryAdvance(IntYield yield) { + final BoolBox found = new BoolBox(); + while(found.isFalse() && upstream.tryAdvance(item -> { + if(mem.add(item)) { + yield.ret(item); + found.set(); + } + })); + return found.isTrue(); + } } diff --git a/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerDropWhile.java b/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerDropWhile.java index 2ac583d..89b20c9 100644 --- a/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerDropWhile.java +++ b/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerDropWhile.java @@ -1,48 +1,52 @@ package org.jayield.primitives.intgr.advs; -import java.util.function.IntPredicate; - -import org.jayield.boxes.BoolBox; +import org.jayield.primitives.intgr.IntAdvancer; import org.jayield.primitives.intgr.IntQuery; +import org.jayield.primitives.intgr.IntTraverser; import org.jayield.primitives.intgr.IntYield; -public class IntAdvancerDropWhile extends AbstractIntAdvancer { +import java.util.function.IntPredicate; + +public class IntAdvancerDropWhile implements IntAdvancer, IntTraverser { private final IntQuery upstream; private final IntPredicate predicate; - private final BoolBox dropped; + private boolean dropped; public IntAdvancerDropWhile(IntQuery upstream, IntPredicate predicate) { this.upstream = upstream; this.predicate = predicate; - this.dropped = new BoolBox(); + this.dropped = false; } @Override public void traverse(IntYield yield) { upstream.traverse(item -> { - if (!dropped.isTrue() && !predicate.test(item)) { - dropped.set(); + if (!dropped && !predicate.test(item)) { + dropped = true; } - if (dropped.isTrue()) { + if (dropped) { yield.ret(item); } }); } @Override - protected boolean move() { - while (!dropped.isTrue() && this.upstream.hasNext()) { - currInt = upstream.next(); - if (!predicate.test(currInt)) { - this.dropped.set(); - return true; + public boolean tryAdvance(IntYield yield) { + if (dropped) { + return upstream.tryAdvance(yield); + } else { + IntYield takeWhile = item -> { + if(!predicate.test(item)){ + dropped = true; + yield.ret(item); + } + }; + while(upstream.tryAdvance(takeWhile) && !dropped) { + // Intentionally empty. Action specified on yield statement of tryAdvance(). } + return dropped; } - if (dropped.isTrue() && upstream.hasNext()) { - currInt = upstream.next(); - return true; - } - return false; + } } diff --git a/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerFilter.java b/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerFilter.java index d4563e0..2c9270e 100644 --- a/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerFilter.java +++ b/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerFilter.java @@ -16,34 +16,23 @@ package org.jayield.primitives.intgr.advs; -import java.util.function.IntPredicate; - +import org.jayield.boxes.BoolBox; import org.jayield.primitives.intgr.IntAdvancer; +import org.jayield.primitives.intgr.IntQuery; +import org.jayield.primitives.intgr.IntTraverser; import org.jayield.primitives.intgr.IntYield; -public class IntAdvancerFilter extends AbstractIntAdvancer { - private final IntAdvancer upstream; +import java.util.function.IntPredicate; + +public class IntAdvancerFilter implements IntAdvancer, IntTraverser { + private final IntQuery upstream; private final IntPredicate p; - public IntAdvancerFilter(IntAdvancer adv, IntPredicate p) { + public IntAdvancerFilter(IntQuery adv, IntPredicate p) { this.upstream = adv; this.p = p; } - /** - * Returns true if it moves successfully. Otherwise returns false - * signaling it has finished. - */ - public boolean move() { - while (upstream.hasNext()) { - currInt = upstream.nextInt(); - if (p.test(currInt)) { - return true; - } - } - return false; - } - @Override public void traverse(IntYield yield) { upstream.traverse(e -> { @@ -52,4 +41,19 @@ public void traverse(IntYield yield) { } }); } + + @Override + public boolean tryAdvance(IntYield yield) { + BoolBox found = new BoolBox(); + while(found.isFalse()) { + boolean hasNext = upstream.tryAdvance(item -> { + if(p.test(item)) { + yield.ret(item); + found.set(); + } + }); + if(!hasNext) break; + } + return found.isTrue(); + } } diff --git a/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerFlatMap.java b/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerFlatMap.java index 04fe2fc..c485c65 100644 --- a/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerFlatMap.java +++ b/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerFlatMap.java @@ -16,13 +16,14 @@ package org.jayield.primitives.intgr.advs; -import java.util.function.IntFunction; - import org.jayield.primitives.intgr.IntAdvancer; import org.jayield.primitives.intgr.IntQuery; +import org.jayield.primitives.intgr.IntTraverser; import org.jayield.primitives.intgr.IntYield; -public class IntAdvancerFlatMap extends AbstractIntAdvancer { +import java.util.function.IntFunction; + +public class IntAdvancerFlatMap implements IntAdvancer, IntTraverser { private final IntQuery upstream; private final IntFunction mapper; IntQuery src; @@ -30,27 +31,20 @@ public class IntAdvancerFlatMap extends AbstractIntAdvancer { public IntAdvancerFlatMap(IntQuery query, IntFunction mapper) { this.upstream = query; this.mapper = mapper; - src = new IntQuery(IntAdvancer.empty()); - } - - /** - * Returns true if it moves successfully. Otherwise returns false - * signaling it has finished. - */ - public boolean move() { - while (!src.hasNext()) { - if (!upstream.hasNext()) { - return false; - } - src = mapper.apply(upstream.next()); - } - currInt = src.next(); - return true; + src = new IntQuery(IntAdvancer.empty(), IntTraverser.empty()); } @Override public void traverse(IntYield yield) { upstream.traverse(elem -> mapper.apply(elem).traverse(yield)); + } + @Override + public boolean tryAdvance(IntYield yield) { + while (!src.tryAdvance(yield)) { + if(!upstream.tryAdvance(t -> src = mapper.apply(t))) + return false; + } + return true; } } diff --git a/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerGenerate.java b/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerGenerate.java index 5a9a61b..2c6fd0c 100644 --- a/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerGenerate.java +++ b/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerGenerate.java @@ -16,13 +16,13 @@ package org.jayield.primitives.intgr.advs; -import java.util.NoSuchElementException; -import java.util.function.IntSupplier; - import org.jayield.primitives.intgr.IntAdvancer; +import org.jayield.primitives.intgr.IntTraverser; import org.jayield.primitives.intgr.IntYield; -public class IntAdvancerGenerate implements IntAdvancer { +import java.util.function.IntSupplier; + +public class IntAdvancerGenerate implements IntAdvancer, IntTraverser { private final IntSupplier s; public IntAdvancerGenerate(IntSupplier s) { @@ -31,23 +31,14 @@ public IntAdvancerGenerate(IntSupplier s) { @Override public void traverse(IntYield yield) { - while (hasNext()) { + while (true) { yield.ret(s.getAsInt()); } } @Override - public boolean hasNext() { + public boolean tryAdvance(IntYield yield) { + yield.ret(s.getAsInt()); return true; } - - @Override - public int nextInt() { - if (!hasNext()) { - throw new NoSuchElementException("No more elements available on iteration!"); - } - return s.getAsInt(); - } - - } diff --git a/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerIterate.java b/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerIterate.java index 0b12245..655d76f 100644 --- a/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerIterate.java +++ b/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerIterate.java @@ -16,13 +16,13 @@ package org.jayield.primitives.intgr.advs; -import java.util.NoSuchElementException; -import java.util.function.IntUnaryOperator; - import org.jayield.primitives.intgr.IntAdvancer; +import org.jayield.primitives.intgr.IntTraverser; import org.jayield.primitives.intgr.IntYield; -public class IntAdvancerIterate implements IntAdvancer { +import java.util.function.IntUnaryOperator; + +public class IntAdvancerIterate implements IntAdvancer, IntTraverser { private final IntUnaryOperator f; private int prev; @@ -31,21 +31,6 @@ public IntAdvancerIterate(int seed, IntUnaryOperator f) { this.prev = seed; } - @Override - public int nextInt() { - if (!hasNext()) { - throw new NoSuchElementException("No more elements available on iteration!"); - } - int curr = prev; - prev = f.applyAsInt(prev); - return curr; - } - - @Override - public boolean hasNext() { - return true; - } - /** * Continues from the point where tryAdvance or next left the * internal iteration. @@ -58,4 +43,12 @@ public void traverse(IntYield yield) { yield.ret(i); } } + + @Override + public boolean tryAdvance(IntYield yield) { + int curr = prev; + prev = f.applyAsInt(prev); + yield.ret(curr); + return true; + } } diff --git a/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerLimit.java b/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerLimit.java index 90ea190..35fb6a9 100644 --- a/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerLimit.java +++ b/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerLimit.java @@ -16,14 +16,12 @@ package org.jayield.primitives.intgr.advs; -import java.util.NoSuchElementException; - -import org.jayield.Yield; import org.jayield.primitives.intgr.IntAdvancer; import org.jayield.primitives.intgr.IntQuery; +import org.jayield.primitives.intgr.IntTraverser; import org.jayield.primitives.intgr.IntYield; -public class IntAdvancerLimit implements IntAdvancer { +public class IntAdvancerLimit implements IntAdvancer, IntTraverser { private final IntQuery upstream; private final int n; int count; @@ -35,27 +33,18 @@ public IntAdvancerLimit(IntQuery upstream, int n) { } @Override - public boolean hasNext() { - return count < n && upstream.hasNext(); - } - - @Override - public int nextInt() { - if (count >= n) { - throw new NoSuchElementException("Nor more elements available!"); + public void traverse(IntYield yield) { + if(count >= n) + throw new IllegalStateException("Traverser has already been operated on or closed!"); + while(this.tryAdvance(yield)) { + // Intentionally empty. Action specified on yield statement of tryAdvance(). } - count++; - return upstream.next(); } @Override - public void traverse(IntYield yield) { - upstream.shortCircuit(item -> { - if (count >= n) { - Yield.bye(); - } - count++; - yield.ret(item); - }); + public boolean tryAdvance(IntYield yield) { + if(count >= n) return false; + count++; + return upstream.tryAdvance(yield); } } diff --git a/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerMap.java b/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerMap.java index 90673be..b5e9f9b 100644 --- a/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerMap.java +++ b/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerMap.java @@ -16,33 +16,30 @@ package org.jayield.primitives.intgr.advs; -import java.util.function.IntUnaryOperator; - import org.jayield.primitives.intgr.IntAdvancer; +import org.jayield.primitives.intgr.IntQuery; +import org.jayield.primitives.intgr.IntTraverser; import org.jayield.primitives.intgr.IntYield; -public class IntAdvancerMap implements IntAdvancer { +import java.util.function.IntUnaryOperator; + +public class IntAdvancerMap implements IntAdvancer, IntTraverser { - private final IntAdvancer upstream; + private final IntQuery upstream; private final IntUnaryOperator mapper; - public IntAdvancerMap(IntAdvancer adv, IntUnaryOperator mapper) { + public IntAdvancerMap(IntQuery adv, IntUnaryOperator mapper) { this.upstream = adv; this.mapper = mapper; } @Override - public boolean hasNext() { - return upstream.hasNext(); - } - - @Override - public int nextInt() { - return mapper.applyAsInt(upstream.nextInt()); + public void traverse(IntYield yield) { + upstream.traverse(e -> yield.ret(mapper.applyAsInt(e))); } @Override - public void traverse(IntYield yield) { - upstream.traverse(e -> yield.ret(mapper.applyAsInt(e))); + public boolean tryAdvance(IntYield yield) { + return upstream.tryAdvance(item -> yield.ret(mapper.applyAsInt(item))); } } diff --git a/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerMapToObj.java b/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerMapToObj.java index 261cc6c..c58eff3 100644 --- a/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerMapToObj.java +++ b/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerMapToObj.java @@ -16,38 +16,30 @@ package org.jayield.primitives.intgr.advs; -import java.util.NoSuchElementException; -import java.util.function.IntFunction; - import org.jayield.Advancer; +import org.jayield.Traverser; import org.jayield.Yield; -import org.jayield.primitives.intgr.IntAdvancer; +import org.jayield.primitives.intgr.IntQuery; + +import java.util.function.IntFunction; -public class IntAdvancerMapToObj implements Advancer { +public class IntAdvancerMapToObj implements Advancer, Traverser { - private final IntAdvancer upstream; + private final IntQuery upstream; private final IntFunction mapper; - public IntAdvancerMapToObj(IntAdvancer adv, IntFunction mapper) { + public IntAdvancerMapToObj(IntQuery adv, IntFunction mapper) { this.upstream = adv; this.mapper = mapper; } @Override - public boolean hasNext() { - return upstream.hasNext(); - } - - @Override - public T next() { - if (!hasNext()) { - throw new NoSuchElementException("No more elements available on iteration!"); - } - return mapper.apply(upstream.nextInt()); + public void traverse(Yield yield) { + upstream.traverse(e -> yield.ret(mapper.apply(e))); } @Override - public void traverse(Yield yield) { - upstream.traverse(e -> yield.ret(mapper.apply(e))); + public boolean tryAdvance(Yield yield) { + return upstream.tryAdvance(item -> yield.ret(mapper.apply(item))); } } diff --git a/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerPeek.java b/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerPeek.java index ee83630..78d1884 100644 --- a/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerPeek.java +++ b/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerPeek.java @@ -16,35 +16,33 @@ package org.jayield.primitives.intgr.advs; -import java.util.function.IntConsumer; - import org.jayield.primitives.intgr.IntAdvancer; +import org.jayield.primitives.intgr.IntQuery; +import org.jayield.primitives.intgr.IntTraverser; import org.jayield.primitives.intgr.IntYield; -public class IntAdvancerPeek implements IntAdvancer { - private final IntAdvancer upstream; +import java.util.function.IntConsumer; + +public class IntAdvancerPeek implements IntAdvancer, IntTraverser { + private final IntQuery upstream; private final IntConsumer action; - public IntAdvancerPeek(IntAdvancer adv, IntConsumer action) { + public IntAdvancerPeek(IntQuery adv, IntConsumer action) { this.upstream = adv; this.action = action; } @Override - public boolean hasNext() { - return upstream.hasNext(); - } - - @Override - public int nextInt() { - int curr = upstream.nextInt(); - action.accept(curr); - return curr; + public void traverse(IntYield yield) { + upstream.traverse(item -> { + action.accept(item); + yield.ret(item); + }); } @Override - public void traverse(IntYield yield) { - upstream.traverse(item -> { + public boolean tryAdvance(IntYield yield) { + return upstream.tryAdvance(item -> { action.accept(item); yield.ret(item); }); diff --git a/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerSkip.java b/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerSkip.java index 8931796..0c85f37 100644 --- a/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerSkip.java +++ b/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerSkip.java @@ -17,34 +17,20 @@ package org.jayield.primitives.intgr.advs; import org.jayield.primitives.intgr.IntAdvancer; +import org.jayield.primitives.intgr.IntQuery; +import org.jayield.primitives.intgr.IntTraverser; import org.jayield.primitives.intgr.IntYield; -public class IntAdvancerSkip implements IntAdvancer { - private final IntAdvancer upstream; +public class IntAdvancerSkip implements IntAdvancer, IntTraverser { + private final IntQuery upstream; private final int n; int index; - public IntAdvancerSkip(IntAdvancer adv, int n) { + public IntAdvancerSkip(IntQuery adv, int n) { this.upstream = adv; this.n = n; index = 0; } - - @Override - public int nextInt() { - if (!hasNext()) { - throw new IndexOutOfBoundsException("No such elements on iteration!"); - } - return upstream.nextInt(); - } - - @Override - public boolean hasNext() { - for (; upstream.hasNext() && index < n; index++) - upstream.nextInt(); - return upstream.hasNext(); - } - /** * Continues from the point where tryAdvance or next left the * internal iteration. @@ -59,4 +45,11 @@ public void traverse(IntYield yield) { } }); } + + @Override + public boolean tryAdvance(IntYield yield) { + for (; index < n; index++) + upstream.tryAdvance(item -> {}); + return upstream.tryAdvance(yield); + } } diff --git a/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerStream.java b/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerStream.java index f464358..18a99ae 100644 --- a/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerStream.java +++ b/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerStream.java @@ -16,42 +16,30 @@ package org.jayield.primitives.intgr.advs; -import java.util.stream.IntStream; - import org.jayield.primitives.intgr.IntAdvancer; -import org.jayield.primitives.intgr.IntIterator; +import org.jayield.primitives.intgr.IntTraverser; import org.jayield.primitives.intgr.IntYield; -public class IntAdvancerStream implements IntAdvancer { - private final IntStream upstream; - private IntIterator current; - private boolean operated = false; +import java.util.Spliterator; +import java.util.function.IntConsumer; +import java.util.stream.IntStream; - public IntAdvancerStream(IntStream data) { - this.upstream = data; - } +public class IntAdvancerStream implements IntAdvancer, IntTraverser { + private final Spliterator.OfInt upstream; - @Override - public int nextInt() { - return current().nextInt(); - } - - public IntIterator current() { - if (operated) { - return current; - } - operated = true; - current = IntIterator.from(upstream.iterator()); - return current; + public IntAdvancerStream(IntStream data) { + this.upstream = data.spliterator(); } @Override - public boolean hasNext() { - return current().hasNext(); + public void traverse(IntYield yield) { + IntConsumer cons = yield::ret; + upstream.forEachRemaining(cons); } @Override - public void traverse(IntYield yield) { - upstream.forEach(yield::ret); + public boolean tryAdvance(IntYield yield) { + IntConsumer cons = yield::ret; + return upstream.tryAdvance(cons); } } diff --git a/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerTakeWhile.java b/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerTakeWhile.java index f5323d4..72a7dea 100644 --- a/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerTakeWhile.java +++ b/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerTakeWhile.java @@ -16,33 +16,23 @@ package org.jayield.primitives.intgr.advs; -import java.util.function.IntPredicate; - import org.jayield.Yield; +import org.jayield.primitives.intgr.IntAdvancer; import org.jayield.primitives.intgr.IntQuery; +import org.jayield.primitives.intgr.IntTraverser; import org.jayield.primitives.intgr.IntYield; -public class IntAdvancerTakeWhile extends AbstractIntAdvancer { +import java.util.function.IntPredicate; + +public class IntAdvancerTakeWhile implements IntAdvancer, IntTraverser { private final IntQuery upstream; private final IntPredicate predicate; + private boolean hasNext; public IntAdvancerTakeWhile(IntQuery upstream, IntPredicate predicate) { this.upstream = upstream; this.predicate = predicate; - } - - /** - * Returns true if it moves successfully. Otherwise returns false - * signaling it has finished. - */ - public boolean move() { - if (upstream.hasNext()) { - currInt = upstream.next(); - if (predicate.test(currInt)) { - return true; - } - } - return false; + this.hasNext = true; } @Override @@ -54,4 +44,17 @@ public void traverse(IntYield yield) { yield.ret(item); }); } + + @Override + public boolean tryAdvance(IntYield yield) { + if(!hasNext) return false; // Once predicate is false it finishes the iteration + IntYield takeWhile = item -> { + if(predicate.test(item)){ + yield.ret(item); + } else { + hasNext = false; + } + }; + return upstream.tryAdvance(takeWhile) && hasNext; + } } diff --git a/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerThen.java b/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerThen.java deleted file mode 100644 index be5b974..0000000 --- a/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerThen.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2020, Fernando Miguel Carvalho, mcarvalho@cc.isel.ipl.pt - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jayield.primitives.intgr.advs; - -import java.util.ArrayList; -import java.util.function.Function; - -import org.jayield.primitives.intgr.IntAdvancer; -import org.jayield.primitives.intgr.IntIterator; -import org.jayield.primitives.intgr.IntQuery; -import org.jayield.primitives.intgr.IntTraverser; -import org.jayield.primitives.intgr.IntYield; - -public class IntAdvancerThen implements IntAdvancer { - private IntQuery upstream; - private Function next; - private IntIterator curr; - private boolean inMem = false; - - public IntAdvancerThen(IntQuery upstream, Function next) { - this.upstream = upstream; - this.next = next; - } - - @Override - public boolean hasNext() { - return curr().hasNext(); - } - - public IntIterator curr() { - if (inMem) { - return curr; - } - ArrayList mem = new ArrayList<>(); - next.apply(upstream).traverse(mem::add); - inMem = true; - curr = IntIterator.from(mem.iterator()); - return curr; - } - - @Override - public int nextInt() { - return curr().nextInt(); - } - - @Override - public void traverse(IntYield yield) { - next.apply(upstream).traverse(yield); - } -} diff --git a/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerZip.java b/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerZip.java index cccc5a3..ad02f8e 100644 --- a/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerZip.java +++ b/src/main/java/org/jayield/primitives/intgr/advs/IntAdvancerZip.java @@ -16,37 +16,40 @@ package org.jayield.primitives.intgr.advs; -import java.util.function.IntBinaryOperator; - +import org.jayield.Yield; +import org.jayield.boxes.BoolBox; import org.jayield.primitives.intgr.IntAdvancer; +import org.jayield.primitives.intgr.IntQuery; +import org.jayield.primitives.intgr.IntTraverser; import org.jayield.primitives.intgr.IntYield; -public class IntAdvancerZip implements IntAdvancer { - private final IntAdvancer upstream; - private final IntAdvancer other; +import java.util.function.IntBinaryOperator; + +public class IntAdvancerZip implements IntAdvancer, IntTraverser { + private final IntQuery upstream; + private final IntQuery other; private final IntBinaryOperator zipper; - public IntAdvancerZip(IntAdvancer upstream, IntAdvancer other, IntBinaryOperator zipper) { + public IntAdvancerZip(IntQuery upstream, IntQuery other, IntBinaryOperator zipper) { this.upstream = upstream; this.other = other; this.zipper = zipper; } - - @Override - public boolean hasNext() { - return upstream.hasNext() && other.hasNext(); - } - @Override - public int nextInt() { - return zipper.applyAsInt(upstream.next(), other.next()); + public void traverse(IntYield yield) { + upstream.shortCircuit(e1 -> { + if(!other.tryAdvance(e2 -> yield.ret(zipper.applyAsInt(e1, e2)))) + Yield.bye(); + }); } @Override - public void traverse(IntYield yield) { - upstream.traverse(e -> { - if (!other.hasNext()) return; - yield.ret(zipper.applyAsInt(e, other.next())); - }); + public boolean tryAdvance(IntYield yield) { + BoolBox consumed = new BoolBox(); + upstream.tryAdvance(e1 -> other.tryAdvance(e2 -> { + yield.ret(zipper.applyAsInt(e1, e2)); + consumed.set(); + })); + return consumed.isTrue(); } } diff --git a/src/main/java/org/jayield/primitives/lng/LongAdvancer.java b/src/main/java/org/jayield/primitives/lng/LongAdvancer.java index 4a9552c..850ae15 100644 --- a/src/main/java/org/jayield/primitives/lng/LongAdvancer.java +++ b/src/main/java/org/jayield/primitives/lng/LongAdvancer.java @@ -1,39 +1,40 @@ package org.jayield.primitives.lng; -import java.util.NoSuchElementException; -import java.util.function.DoubleToLongFunction; -import java.util.function.IntToLongFunction; -import java.util.function.ToLongFunction; - import org.jayield.Advancer; +import org.jayield.Yield; import org.jayield.primitives.dbl.DoubleAdvancer; import org.jayield.primitives.intgr.IntAdvancer; +import java.util.function.DoubleToLongFunction; +import java.util.function.IntToLongFunction; +import java.util.function.ToLongFunction; + /** * Sequential traverser with both longernal and external iteration approach. */ -public interface LongAdvancer extends Advancer, LongIterator, LongTraverser { +public interface LongAdvancer extends Advancer { /** - * An LongAdvancer object without elements. + * If a remaining element exists, yields that element through + * the given action. */ - static LongAdvancer empty() { - return new LongAdvancer() { - @Override - public boolean hasNext() { - return false; - } + boolean tryAdvance(LongYield yield); - @Override - public long nextLong() { - throw new NoSuchElementException("No such elements available for iteration!"); - } + /** + * Default advance implementation that calls the + * primitive version of it + */ + @Override + default boolean tryAdvance(Yield yield) { + LongYield yld = yield::ret; + return this.tryAdvance(yld); + } - @Override - public void traverse(LongYield yield) { - /* Do nothing. Since there are no elements, thus there is nothing to do. */ - } - }; + /** + * An LongAdvancer object without elements. + */ + static LongAdvancer empty() { + return yield -> false; } /** @@ -45,25 +46,7 @@ public void traverse(LongYield yield) { * {@link ToLongFunction} that specifies how to map the source elements longo long values. */ static LongAdvancer from(Advancer source, ToLongFunction mapper) { - return new LongAdvancer() { - @Override - public long nextLong() { - if (!this.hasNext()) { - throw new NoSuchElementException("No such elements available for iteration!"); - } - return mapper.applyAsLong(source.next()); - } - - @Override - public boolean hasNext() { - return source.hasNext(); - } - - @Override - public void traverse(LongYield yield) { - source.traverse(item -> yield.ret(mapper.applyAsLong(item))); - } - }; + return yield -> source.tryAdvance(item -> yield.ret(mapper.applyAsLong(item))); } /** @@ -89,12 +72,4 @@ static LongAdvancer from(DoubleAdvancer source, DoubleToLongFunction mapper) { static LongAdvancer from(IntAdvancer source, IntToLongFunction mapper) { return from((Advancer) source, mapper::applyAsLong); } - - @Override - default Long next() { - if (!hasNext()) { - throw new NoSuchElementException("No more elements available on iteration!"); - } - return this.nextLong(); - } } diff --git a/src/main/java/org/jayield/primitives/lng/LongIterator.java b/src/main/java/org/jayield/primitives/lng/LongIterator.java deleted file mode 100644 index d7b2364..0000000 --- a/src/main/java/org/jayield/primitives/lng/LongIterator.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.jayield.primitives.lng; - -import java.util.Iterator; -import java.util.NoSuchElementException; -import java.util.PrimitiveIterator; - -public interface LongIterator extends PrimitiveIterator.OfLong { - static LongIterator from(OfLong source) { - return new LongIterator() { - @Override - public long nextLong() { - if (!this.hasNext()) { - throw new NoSuchElementException("No such elements available for iteration!"); - } - return source.nextLong(); - } - - @Override - public boolean hasNext() { - return source.hasNext(); - } - }; - } - - static LongIterator from(Iterator iterator) { - return new LongIterator() { - @Override - public long nextLong() { - if (!iterator.hasNext()) { - throw new IndexOutOfBoundsException("No such elements on iteration!"); - } - return iterator.next(); - } - - @Override - public boolean hasNext() { - return iterator.hasNext(); - } - }; - } -} diff --git a/src/main/java/org/jayield/primitives/lng/LongQuery.java b/src/main/java/org/jayield/primitives/lng/LongQuery.java index 0e6545c..55cc56c 100644 --- a/src/main/java/org/jayield/primitives/lng/LongQuery.java +++ b/src/main/java/org/jayield/primitives/lng/LongQuery.java @@ -16,28 +16,6 @@ package org.jayield.primitives.lng; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.LongSummaryStatistics; -import java.util.OptionalDouble; -import java.util.OptionalLong; -import java.util.Spliterator; -import java.util.Spliterators; -import java.util.function.Function; -import java.util.function.LongBinaryOperator; -import java.util.function.LongConsumer; -import java.util.function.LongFunction; -import java.util.function.LongPredicate; -import java.util.function.LongSupplier; -import java.util.function.LongToDoubleFunction; -import java.util.function.LongToIntFunction; -import java.util.function.LongUnaryOperator; -import java.util.function.ObjLongConsumer; -import java.util.function.Supplier; -import java.util.stream.LongStream; -import java.util.stream.StreamSupport; - import org.jayield.Query; import org.jayield.TraversableFinishError; import org.jayield.Yield; @@ -45,8 +23,10 @@ import org.jayield.boxes.LongBox; import org.jayield.primitives.dbl.DoubleAdvancer; import org.jayield.primitives.dbl.DoubleQuery; +import org.jayield.primitives.dbl.DoubleTraverser; import org.jayield.primitives.intgr.IntAdvancer; import org.jayield.primitives.intgr.IntQuery; +import org.jayield.primitives.intgr.IntTraverser; import org.jayield.primitives.lng.advs.LongAdvancerArray; import org.jayield.primitives.lng.advs.LongAdvancerConcat; import org.jayield.primitives.lng.advs.LongAdvancerDistinct; @@ -62,9 +42,30 @@ import org.jayield.primitives.lng.advs.LongAdvancerSkip; import org.jayield.primitives.lng.advs.LongAdvancerStream; import org.jayield.primitives.lng.advs.LongAdvancerTakeWhile; -import org.jayield.primitives.lng.advs.LongAdvancerThen; import org.jayield.primitives.lng.advs.LongAdvancerZip; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.LongSummaryStatistics; +import java.util.OptionalDouble; +import java.util.OptionalLong; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.function.Function; +import java.util.function.LongBinaryOperator; +import java.util.function.LongConsumer; +import java.util.function.LongFunction; +import java.util.function.LongPredicate; +import java.util.function.LongSupplier; +import java.util.function.LongToDoubleFunction; +import java.util.function.LongToIntFunction; +import java.util.function.LongUnaryOperator; +import java.util.function.ObjLongConsumer; +import java.util.function.Supplier; +import java.util.stream.LongStream; +import java.util.stream.StreamSupport; + /** * A sequence of primitive long-valued elements supporting sequential * operations. This is the long primitive specialization of Query. @@ -72,9 +73,11 @@ public class LongQuery { private final LongAdvancer adv; + private final LongTraverser trav; - public LongQuery(LongAdvancer adv) { + public LongQuery(LongAdvancer adv, LongTraverser trav) { this.adv = adv; + this.trav = trav; } /** @@ -82,7 +85,8 @@ public LongQuery(LongAdvancer adv) { * from the provided {@link LongStream} data. */ public static LongQuery fromStream(LongStream src) { - return new LongQuery(new LongAdvancerStream(src)); + LongAdvancerStream strm = new LongAdvancerStream(src); + return new LongQuery(strm, strm); } /** @@ -92,7 +96,8 @@ public static LongQuery fromStream(LongStream src) { * {@code f(f(seed))}, etc. */ public static LongQuery iterate(long seed, LongUnaryOperator f) { - return new LongQuery(new LongAdvancerIterate(seed, f)); + LongAdvancerIterate iter = new LongAdvancerIterate(seed, f); + return new LongQuery(iter, iter); } /** @@ -100,7 +105,8 @@ public static LongQuery iterate(long seed, LongUnaryOperator f) { * where each element is generated by the provided Supplier. */ public static LongQuery generate(LongSupplier s) { - return new LongQuery(new LongAdvancerGenerate(s)); + LongAdvancerGenerate gen = new LongAdvancerGenerate(s); + return new LongQuery(gen, gen); } /** @@ -118,7 +124,15 @@ public final void forEach(LongYield yield) { * exception is thrown. */ public final void traverse(LongYield yield) { - this.adv.traverse(yield); + this.trav.traverse(yield); + } + + /** + * If a remaining element exists, yields that element through + * the given action. + */ + public boolean tryAdvance(LongYield action) { + return this.adv.tryAdvance(action); } /** @@ -126,7 +140,8 @@ public final void traverse(LongYield yield) { * the given predicate. */ public LongQuery filter(LongPredicate p) { - return new LongQuery(new LongAdvancerFilter(adv, p)); + LongAdvancerFilter filter = new LongAdvancerFilter(this, p); + return new LongQuery(filter, filter); } /** @@ -137,7 +152,8 @@ public LongQuery filter(LongPredicate p) { * LongUnaryOperator used to map the elements of this LongQuery */ public LongQuery map(LongUnaryOperator op) { - return new LongQuery(new LongAdvancerMap(adv, op)); + LongAdvancerMap map = new LongAdvancerMap(this, op); + return new LongQuery(map, map); } /** @@ -148,7 +164,8 @@ public LongQuery map(LongUnaryOperator op) { * LongFunction used to map the elements of this LongQuery */ public Query mapToObj(LongFunction function) { - return new Query<>(new LongAdvancerMapToObj<>(adv, function)); + LongAdvancerMapToObj map = new LongAdvancerMapToObj<>(this, function); + return new Query<>(map, map); } /** @@ -157,7 +174,8 @@ public Query mapToObj(LongFunction function) { * the provided mapping function to each element. */ public LongQuery flatMap(LongFunction function) { - return new LongQuery(new LongAdvancerFlatMap(this, function)); + LongAdvancerFlatMap map = new LongAdvancerFlatMap(this, function); + return new LongQuery(map, map); } /** @@ -165,7 +183,8 @@ public LongQuery flatMap(LongFunction function) { * {@link Object#equals(Object)}) of this query. */ public LongQuery distinct() { - return new LongQuery(new LongAdvancerDistinct(adv)); + LongAdvancerDistinct dis = new LongAdvancerDistinct(this); + return new LongQuery(dis, dis); } /** @@ -177,7 +196,8 @@ public LongQuery distinct() { public LongQuery sorted() { long[] state = this.toArray(); Arrays.sort(state); - return new LongQuery(new LongAdvancerArray(state)); + LongAdvancerArray arr = new LongAdvancerArray(state); + return new LongQuery(arr, arr); } /** @@ -207,7 +227,8 @@ public List toList() { * from the resulting {@code LongQuery}. */ public LongQuery peek(LongConsumer action) { - return new LongQuery(new LongAdvancerPeek(adv, action)); + LongAdvancerPeek peek = new LongAdvancerPeek(this, action); + return new LongQuery(peek, peek); } /** @@ -218,7 +239,8 @@ public LongQuery peek(LongConsumer action) { * maximum amount of elements to retrieve from this {@code LongQuery} */ public LongQuery limit(int n) { - return new LongQuery(new LongAdvancerLimit(this, n)); + LongAdvancerLimit lim = new LongAdvancerLimit(this, n); + return new LongQuery(lim, lim); } /** @@ -229,7 +251,8 @@ public LongQuery limit(int n) { * number of elements to discard */ public LongQuery skip(int n) { - return new LongQuery(new LongAdvancerSkip(adv, n)); + LongAdvancerSkip skip = new LongAdvancerSkip(this, n); + return new LongQuery(skip, skip); } /** @@ -237,38 +260,31 @@ public LongQuery skip(int n) { * if a reduction can be made, using the provided accumulator. */ public OptionalLong reduce(LongBinaryOperator accumulator) { - if (this.hasNext()) { - return OptionalLong.of(this.reduce(this.next(), accumulator)); + LongBox box = new LongBox(); + if(this.tryAdvance(box::setValue)) { + return OptionalLong.of(this.reduce(box.getValue(), accumulator)); } else { return OptionalLong.empty(); } } - /** - * Returns {@code true} if the iteration has more elements. - * (In other words, returns {@code true} if {@link #next} would - * return an element rather than throwing an exception.) - */ - public final boolean hasNext() { - return this.adv.hasNext(); - } - /** * Returns the result of the reduction of the elements of this {@code LongQuery}, * using the provided identity value and accumulator. */ public long reduce(long identity, LongBinaryOperator accumulator) { - LongBox result = new LongBox(); - result.setValue(identity); - this.traverse(elem -> result.setValue(accumulator.applyAsLong(result.getValue(), elem))); - return result.getValue(); - } - - /** - * Returns the next element in the iteration. - */ - public final long next() { - return this.adv.nextLong(); + class BoxAccumulator extends LongBox implements LongYield { + public BoxAccumulator(long identity) { + super(identity); + } + @Override + public void ret(long item) { + this.value = accumulator.applyAsLong(value, item); + } + } + BoxAccumulator box = new BoxAccumulator(identity); + this.traverse(box); + return box.getValue(); } /** @@ -348,7 +364,8 @@ public long sum() { * are the specified values in data parameter. */ public static LongQuery of(long... data) { - return new LongQuery(new LongAdvancerArray(data)); + LongAdvancerArray arr = new LongAdvancerArray(data); + return new LongQuery(arr, arr); } /** @@ -399,7 +416,7 @@ public boolean allMatch(LongPredicate p) { */ public final void shortCircuit(LongYield yield) { try { - this.adv.traverse(yield); + this.trav.traverse(yield); } catch (TraversableFinishError e) { /* Proceed */ } @@ -452,10 +469,7 @@ public OptionalLong findAny() { */ public OptionalLong findFirst() { LongBox box = new LongBox(); - this.shortCircuit(item -> { - box.turnPresent(item); - Yield.bye(); - }); + this.tryAdvance(box::turnPresent); return box.isPresent() ? OptionalLong.of(box.getValue()) : OptionalLong.empty(); @@ -479,7 +493,7 @@ public IntQuery asIntQuery() { * LongToIntFunction used to map the elements of this LongQuery */ public IntQuery mapToInt(LongToIntFunction function) { - return new IntQuery(IntAdvancer.from(adv, function)); + return new IntQuery(IntAdvancer.from(adv, function), IntTraverser.from(trav, function)); } /** @@ -500,7 +514,7 @@ public DoubleQuery asDoubleQuery() { * LongToDoubleFunction used to map the elements of this LongQuery */ public DoubleQuery mapToDouble(LongToDoubleFunction function) { - return new DoubleQuery(DoubleAdvancer.from(adv, function)); + return new DoubleQuery(DoubleAdvancer.from(adv, function), DoubleTraverser.from(trav, function)); } /** @@ -508,28 +522,39 @@ public DoubleQuery mapToDouble(LongToDoubleFunction function) { * each boxed to an Long. */ public Query boxed() { - return new Query<>(adv); + return new Query<>(adv, trav); } public LongStream toStream() { Spliterator.OfLong iter = new Spliterators.AbstractLongSpliterator(Long.MAX_VALUE, Spliterator.ORDERED) { @Override public boolean tryAdvance(LongConsumer action) { - if (!adv.hasNext()) { - return false; - } - action.accept(adv.next()); - return true; + return adv.tryAdvance(action::accept); } @Override public void forEachRemaining(LongConsumer action) { - adv.traverse(action::accept); + trav.traverse(action::accept); } }; return StreamSupport.longStream(iter, false); } + /** + * The {@code then} operator lets you encapsulate a piece of an operator + * chain into a function. + * That function {@code next} is applied to this {@code DoubleQuery} to produce a new + * {@code LongTraverser} object that is encapsulated in the resulting {@code DoubleQuery}. + * On the other hand, the {@code nextAdv} is applied to this query to produce a new + * {@code LongAdvancer} object that is encapsulated in the resulting query. + */ + public final LongQuery then( + Function nextAdv, + Function next) + { + return new LongQuery(nextAdv.apply(this), next.apply(this)); + } + /** * The {@code then} operator lets you encapsulate a piece of an operator * chain longo a function. @@ -537,7 +562,10 @@ public void forEachRemaining(LongConsumer action) { * {@code LongTraverser} object that is encapsulated in the resulting {@code LongQuery}. */ public final LongQuery then(Function next) { - return new LongQuery(new LongAdvancerThen(this, next)); + LongAdvancer nextAdv = item -> { throw new UnsupportedOperationException( + "Missing tryAdvance() implementation! Use the overloaded then() providing both Advancer and Traverser!"); + }; + return new LongQuery(nextAdv, next.apply(this)); } /** @@ -545,7 +573,8 @@ public final LongQuery then(Function next) { * this {@code LongQuery} that match the given predicate. */ public final LongQuery takeWhile(LongPredicate predicate) { - return new LongQuery(new LongAdvancerTakeWhile(this, predicate)); + LongAdvancerTakeWhile take = new LongAdvancerTakeWhile(this, predicate); + return new LongQuery(take, take); } /** @@ -554,7 +583,8 @@ public final LongQuery takeWhile(LongPredicate predicate) { * elements of the other {@code Query}. */ public final LongQuery concat(LongQuery other) { - return new LongQuery(new LongAdvancerConcat(this, other)); + LongAdvancerConcat cat = new LongAdvancerConcat(this, other); + return new LongQuery(cat, cat); } /** @@ -562,7 +592,8 @@ public final LongQuery concat(LongQuery other) { * after discarding the first sequence of elements that match the given Predicate. */ public final LongQuery dropWhile(LongPredicate predicate) { - return new LongQuery(new LongAdvancerDropWhile(this, predicate)); + LongAdvancerDropWhile drop = new LongAdvancerDropWhile(this, predicate); + return new LongQuery(drop, drop); } /** @@ -570,6 +601,7 @@ public final LongQuery dropWhile(LongPredicate predicate) { * sequences, producing a sequence of the results. */ public final LongQuery zip(LongQuery other, LongBinaryOperator zipper) { - return new LongQuery(new LongAdvancerZip(this.adv, other.adv, zipper)); + LongAdvancerZip zip = new LongAdvancerZip(this, other, zipper); + return new LongQuery(zip, zip); } } diff --git a/src/main/java/org/jayield/primitives/lng/LongTraverser.java b/src/main/java/org/jayield/primitives/lng/LongTraverser.java index 461bd82..9cc7d55 100644 --- a/src/main/java/org/jayield/primitives/lng/LongTraverser.java +++ b/src/main/java/org/jayield/primitives/lng/LongTraverser.java @@ -18,6 +18,13 @@ import org.jayield.Traverser; import org.jayield.Yield; +import org.jayield.primitives.dbl.DoubleTraverser; +import org.jayield.primitives.intgr.IntAdvancer; +import org.jayield.primitives.intgr.IntTraverser; + +import java.util.function.DoubleToLongFunction; +import java.util.function.IntToLongFunction; +import java.util.function.ToLongFunction; /** * Bulk traversal. @@ -36,10 +43,54 @@ default void traverse(Yield yield) { this.traverse(yld); } + /** + * An LongTraverser object without elements. + */ + static LongTraverser empty() { + return yield -> {}; + } + + /** * Yields elements sequentially in the current thread, * until all elements have been processed or an * exception is thrown. */ void traverse(LongYield yield); + + /** + * An LongTraverser object from a generic {@link Traverser} mapped by a {@link ToLongFunction}. + * + * @param source + * {@link Traverser} with the source elements for this {@code LongTraverser}. + * @param mapper + * {@link ToLongFunction} that specifies how to map the source elements longo long values. + */ + static LongTraverser from(Traverser source, ToLongFunction mapper) { + return yield -> source.traverse(item -> yield.ret(mapper.applyAsLong(item))); + } + + /** + * An LongTraverser object from a {@link DoubleTraverser} mapped by a {@link DoubleToLongFunction}. + * + * @param source + * {@link DoubleTraverser} with the source elements for this {@code LongAdvancer}. + * @param mapper + * {@link DoubleToLongFunction} that specifies how to map the source elements longo long values. + */ + static LongTraverser from(DoubleTraverser source, DoubleToLongFunction mapper) { + return from((Traverser) source, mapper::applyAsLong); + } + + /** + * An LongAdvancer object from a {@link IntTraverser} mapped by a {@link IntToLongFunction}. + * + * @param source + * {@link IntAdvancer} with the source elements for this {@code LongAdvancer}. + * @param mapper + * {@link IntToLongFunction} that specifies how to map the source elements longo long values. + */ + static LongTraverser from(IntTraverser source, IntToLongFunction mapper) { + return from((Traverser) source, mapper::applyAsLong); + } } diff --git a/src/main/java/org/jayield/primitives/lng/advs/AbstractLongAdvancer.java b/src/main/java/org/jayield/primitives/lng/advs/AbstractLongAdvancer.java deleted file mode 100644 index d307b42..0000000 --- a/src/main/java/org/jayield/primitives/lng/advs/AbstractLongAdvancer.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2020, Fernando Miguel Carvalho, mcarvalho@cc.isel.ipl.pt - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jayield.primitives.lng.advs; - -import org.jayield.advs.AbstractAdvancer; -import org.jayield.primitives.lng.LongAdvancer; - -public abstract class AbstractLongAdvancer extends AbstractAdvancer implements LongAdvancer { - long currLong; - - @Override - public final long nextLong() { - prepareIteration(); - return currLong; - } - -} diff --git a/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerArray.java b/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerArray.java index 77bc0fb..2b50bd0 100644 --- a/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerArray.java +++ b/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerArray.java @@ -16,12 +16,11 @@ package org.jayield.primitives.lng.advs; -import java.util.NoSuchElementException; - import org.jayield.primitives.lng.LongAdvancer; +import org.jayield.primitives.lng.LongTraverser; import org.jayield.primitives.lng.LongYield; -public class LongAdvancerArray implements LongAdvancer { +public class LongAdvancerArray implements LongAdvancer, LongTraverser { private final long[] data; private int current; @@ -30,15 +29,6 @@ public LongAdvancerArray(long... data) { this.current = 0; } - - public long nextLong() { - if (!hasNext()) { - throw new NoSuchElementException("No more elements available on iteration!"); - } - return data[current++]; - } - - @Override public boolean hasNext() { return current < data.length; } @@ -55,4 +45,11 @@ public void traverse(LongYield yield) { yield.ret(data[i]); } } + + @Override + public boolean tryAdvance(LongYield yield) { + if(!hasNext()) return false; + yield.ret(data[current++]); + return true; + } } diff --git a/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerConcat.java b/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerConcat.java index 78ddc71..18e04fa 100644 --- a/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerConcat.java +++ b/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerConcat.java @@ -1,12 +1,11 @@ package org.jayield.primitives.lng.advs; -import java.util.NoSuchElementException; - import org.jayield.primitives.lng.LongAdvancer; import org.jayield.primitives.lng.LongQuery; +import org.jayield.primitives.lng.LongTraverser; import org.jayield.primitives.lng.LongYield; -public class LongAdvancerConcat implements LongAdvancer { +public class LongAdvancerConcat implements LongAdvancer, LongTraverser { private final LongQuery first; private final LongQuery second; @@ -15,24 +14,14 @@ public LongAdvancerConcat(LongQuery first, LongQuery second) { this.second = second; } - @Override - public boolean hasNext() { - return first.hasNext() || second.hasNext(); - } - - @Override - public long nextLong() { - if (first.hasNext()) { - return first.next(); - } else if (second.hasNext()) { - return second.next(); - } - throw new NoSuchElementException("No more elements available on iteration!"); - } - @Override public void traverse(LongYield yield) { this.first.traverse(yield); this.second.traverse(yield); } + + @Override + public boolean tryAdvance(LongYield yield) { + return first.tryAdvance(yield) || second.tryAdvance(yield); + } } diff --git a/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerDistinct.java b/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerDistinct.java index 489eeb9..f2821c5 100644 --- a/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerDistinct.java +++ b/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerDistinct.java @@ -16,33 +16,22 @@ package org.jayield.primitives.lng.advs; -import java.util.HashSet; - +import org.jayield.boxes.BoolBox; import org.jayield.primitives.lng.LongAdvancer; +import org.jayield.primitives.lng.LongQuery; +import org.jayield.primitives.lng.LongTraverser; import org.jayield.primitives.lng.LongYield; -public class LongAdvancerDistinct extends AbstractLongAdvancer { +import java.util.HashSet; + +public class LongAdvancerDistinct implements LongAdvancer, LongTraverser { final HashSet mem = new HashSet<>(); - private final LongAdvancer upstream; + private final LongQuery upstream; - public LongAdvancerDistinct(LongAdvancer adv) { + public LongAdvancerDistinct(LongQuery adv) { this.upstream = adv; } - /** - * Returns true if it moves successfully. Otherwise returns false - * signaling it has finished. - */ - public boolean move() { - while (upstream.hasNext()) { - currLong = upstream.nextLong(); - if (mem.add(currLong)) { - return true; - } - } - return false; - } - @Override public void traverse(LongYield yield) { upstream.traverse(item -> { @@ -51,4 +40,16 @@ public void traverse(LongYield yield) { } }); } + + @Override + public boolean tryAdvance(LongYield yield) { + final BoolBox found = new BoolBox(); + while(found.isFalse() && upstream.tryAdvance(item -> { + if(mem.add(item)) { + yield.ret(item); + found.set(); + } + })); + return found.isTrue(); + } } diff --git a/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerDropWhile.java b/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerDropWhile.java index ce34a8f..e0dbcc5 100644 --- a/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerDropWhile.java +++ b/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerDropWhile.java @@ -1,48 +1,51 @@ package org.jayield.primitives.lng.advs; -import java.util.function.LongPredicate; - -import org.jayield.boxes.BoolBox; +import org.jayield.primitives.lng.LongAdvancer; import org.jayield.primitives.lng.LongQuery; +import org.jayield.primitives.lng.LongTraverser; import org.jayield.primitives.lng.LongYield; -public class LongAdvancerDropWhile extends AbstractLongAdvancer { +import java.util.function.LongPredicate; + +public class LongAdvancerDropWhile implements LongAdvancer, LongTraverser { private final LongQuery upstream; private final LongPredicate predicate; - private final BoolBox dropped; + private boolean dropped; public LongAdvancerDropWhile(LongQuery upstream, LongPredicate predicate) { this.upstream = upstream; this.predicate = predicate; - this.dropped = new BoolBox(); + this.dropped = false; } @Override public void traverse(LongYield yield) { upstream.traverse(item -> { - if (!dropped.isTrue() && !predicate.test(item)) { - dropped.set(); + if (!dropped && !predicate.test(item)) { + dropped = true; } - if (dropped.isTrue()) { + if (dropped) { yield.ret(item); } }); } @Override - protected boolean move() { - while (!dropped.isTrue() && this.upstream.hasNext()) { - currLong = upstream.next(); - if (!predicate.test(currLong)) { - this.dropped.set(); - return true; + public boolean tryAdvance(LongYield yield) { + if (dropped) { + return upstream.tryAdvance(yield); + } else { + LongYield takeWhile = item -> { + if(!predicate.test(item)){ + dropped = true; + yield.ret(item); + } + }; + while(upstream.tryAdvance(takeWhile) && !dropped) { + // Intentionally empty. Action specified on yield statement of tryAdvance(). } + return dropped; } - if (dropped.isTrue() && upstream.hasNext()) { - currLong = upstream.next(); - return true; - } - return false; } } diff --git a/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerFilter.java b/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerFilter.java index e8ef808..79cd38e 100644 --- a/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerFilter.java +++ b/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerFilter.java @@ -16,34 +16,23 @@ package org.jayield.primitives.lng.advs; -import java.util.function.LongPredicate; - +import org.jayield.boxes.BoolBox; import org.jayield.primitives.lng.LongAdvancer; +import org.jayield.primitives.lng.LongQuery; +import org.jayield.primitives.lng.LongTraverser; import org.jayield.primitives.lng.LongYield; -public class LongAdvancerFilter extends AbstractLongAdvancer { - private final LongAdvancer upstream; +import java.util.function.LongPredicate; + +public class LongAdvancerFilter implements LongAdvancer, LongTraverser { + private final LongQuery upstream; private final LongPredicate p; - public LongAdvancerFilter(LongAdvancer adv, LongPredicate p) { + public LongAdvancerFilter(LongQuery adv, LongPredicate p) { this.upstream = adv; this.p = p; } - /** - * Returns true if it moves successfully. Otherwise returns false - * signaling it has finished. - */ - public boolean move() { - while (upstream.hasNext()) { - currLong = upstream.nextLong(); - if (p.test(currLong)) { - return true; - } - } - return false; - } - @Override public void traverse(LongYield yield) { upstream.traverse(e -> { @@ -52,4 +41,19 @@ public void traverse(LongYield yield) { } }); } + + @Override + public boolean tryAdvance(LongYield yield) { + BoolBox found = new BoolBox(); + while(found.isFalse()) { + boolean hasNext = upstream.tryAdvance(item -> { + if(p.test(item)) { + yield.ret(item); + found.set(); + } + }); + if(!hasNext) break; + } + return found.isTrue(); + } } diff --git a/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerFlatMap.java b/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerFlatMap.java index c36dde9..f620a18 100644 --- a/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerFlatMap.java +++ b/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerFlatMap.java @@ -16,13 +16,14 @@ package org.jayield.primitives.lng.advs; -import java.util.function.LongFunction; - import org.jayield.primitives.lng.LongAdvancer; import org.jayield.primitives.lng.LongQuery; +import org.jayield.primitives.lng.LongTraverser; import org.jayield.primitives.lng.LongYield; -public class LongAdvancerFlatMap extends AbstractLongAdvancer { +import java.util.function.LongFunction; + +public class LongAdvancerFlatMap implements LongAdvancer, LongTraverser { private final LongQuery upstream; private final LongFunction mapper; LongQuery src; @@ -30,22 +31,7 @@ public class LongAdvancerFlatMap extends AbstractLongAdvancer { public LongAdvancerFlatMap(LongQuery query, LongFunction mapper) { this.upstream = query; this.mapper = mapper; - src = new LongQuery(LongAdvancer.empty()); - } - - /** - * Returns true if it moves successfully. Otherwise returns false - * signaling it has finished. - */ - public boolean move() { - while (!src.hasNext()) { - if (!upstream.hasNext()) { - return false; - } - src = mapper.apply(upstream.next()); - } - currLong = src.next(); - return true; + src = new LongQuery(LongAdvancer.empty(), LongTraverser.empty()); } @Override @@ -53,4 +39,13 @@ public void traverse(LongYield yield) { upstream.traverse(elem -> mapper.apply(elem).traverse(yield)); } + + @Override + public boolean tryAdvance(LongYield yield) { + while (!src.tryAdvance(yield)) { + if(!upstream.tryAdvance(t -> src = mapper.apply(t))) + return false; + } + return true; + } } diff --git a/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerGenerate.java b/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerGenerate.java index 6e79c58..8c1468f 100644 --- a/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerGenerate.java +++ b/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerGenerate.java @@ -16,13 +16,13 @@ package org.jayield.primitives.lng.advs; -import java.util.NoSuchElementException; -import java.util.function.LongSupplier; - import org.jayield.primitives.lng.LongAdvancer; +import org.jayield.primitives.lng.LongTraverser; import org.jayield.primitives.lng.LongYield; -public class LongAdvancerGenerate implements LongAdvancer { +import java.util.function.LongSupplier; + +public class LongAdvancerGenerate implements LongAdvancer, LongTraverser { private final LongSupplier s; public LongAdvancerGenerate(LongSupplier s) { @@ -31,23 +31,14 @@ public LongAdvancerGenerate(LongSupplier s) { @Override public void traverse(LongYield yield) { - while (hasNext()) { + while (true) { yield.ret(s.getAsLong()); } } @Override - public boolean hasNext() { + public boolean tryAdvance(LongYield yield) { + yield.ret(s.getAsLong()); return true; } - - @Override - public long nextLong() { - if (!hasNext()) { - throw new NoSuchElementException("No more elements available on iteration!"); - } - return s.getAsLong(); - } - - } diff --git a/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerIterate.java b/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerIterate.java index 56462f7..94e0d8d 100644 --- a/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerIterate.java +++ b/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerIterate.java @@ -16,13 +16,13 @@ package org.jayield.primitives.lng.advs; -import java.util.NoSuchElementException; -import java.util.function.LongUnaryOperator; - import org.jayield.primitives.lng.LongAdvancer; +import org.jayield.primitives.lng.LongTraverser; import org.jayield.primitives.lng.LongYield; -public class LongAdvancerIterate implements LongAdvancer { +import java.util.function.LongUnaryOperator; + +public class LongAdvancerIterate implements LongAdvancer, LongTraverser { private final LongUnaryOperator f; private long prev; @@ -31,21 +31,6 @@ public LongAdvancerIterate(long seed, LongUnaryOperator f) { this.prev = seed; } - @Override - public long nextLong() { - if (!hasNext()) { - throw new NoSuchElementException("No more elements available on iteration!"); - } - long curr = prev; - prev = f.applyAsLong(prev); - return curr; - } - - @Override - public boolean hasNext() { - return true; - } - /** * Continues from the polong where tryAdvance or next left the * longernal iteration. @@ -58,4 +43,12 @@ public void traverse(LongYield yield) { yield.ret(i); } } + + @Override + public boolean tryAdvance(LongYield yield) { + long curr = prev; + prev = f.applyAsLong(prev); + yield.ret(curr); + return true; + } } diff --git a/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerLimit.java b/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerLimit.java index 97a0738..154e381 100644 --- a/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerLimit.java +++ b/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerLimit.java @@ -16,14 +16,12 @@ package org.jayield.primitives.lng.advs; -import java.util.NoSuchElementException; - -import org.jayield.Yield; import org.jayield.primitives.lng.LongAdvancer; import org.jayield.primitives.lng.LongQuery; +import org.jayield.primitives.lng.LongTraverser; import org.jayield.primitives.lng.LongYield; -public class LongAdvancerLimit implements LongAdvancer { +public class LongAdvancerLimit implements LongAdvancer, LongTraverser { private final LongQuery upstream; private final int n; int count; @@ -35,27 +33,16 @@ public LongAdvancerLimit(LongQuery upstream, int n) { } @Override - public boolean hasNext() { - return count < n && upstream.hasNext(); + public void traverse(LongYield yield) { + if(count >= n) + throw new IllegalStateException("Traverser has already been operated on or closed!"); + while(this.tryAdvance(yield)) { } } @Override - public long nextLong() { - if (count >= n) { - throw new NoSuchElementException("Nor more elements available!"); - } + public boolean tryAdvance(LongYield yield) { + if(count >= n) return false; count++; - return upstream.next(); - } - - @Override - public void traverse(LongYield yield) { - upstream.shortCircuit(item -> { - if (count >= n) { - Yield.bye(); - } - count++; - yield.ret(item); - }); + return upstream.tryAdvance(yield); } } diff --git a/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerMap.java b/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerMap.java index 8aed7c7..f8f499f 100644 --- a/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerMap.java +++ b/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerMap.java @@ -16,33 +16,30 @@ package org.jayield.primitives.lng.advs; -import java.util.function.LongUnaryOperator; - import org.jayield.primitives.lng.LongAdvancer; +import org.jayield.primitives.lng.LongQuery; +import org.jayield.primitives.lng.LongTraverser; import org.jayield.primitives.lng.LongYield; -public class LongAdvancerMap implements LongAdvancer { +import java.util.function.LongUnaryOperator; + +public class LongAdvancerMap implements LongAdvancer, LongTraverser { - private final LongAdvancer upstream; + private final LongQuery upstream; private final LongUnaryOperator mapper; - public LongAdvancerMap(LongAdvancer adv, LongUnaryOperator mapper) { + public LongAdvancerMap(LongQuery adv, LongUnaryOperator mapper) { this.upstream = adv; this.mapper = mapper; } @Override - public boolean hasNext() { - return upstream.hasNext(); - } - - @Override - public long nextLong() { - return mapper.applyAsLong(upstream.nextLong()); + public void traverse(LongYield yield) { + upstream.traverse(e -> yield.ret(mapper.applyAsLong(e))); } @Override - public void traverse(LongYield yield) { - upstream.traverse(e -> yield.ret(mapper.applyAsLong(e))); + public boolean tryAdvance(LongYield yield) { + return upstream.tryAdvance(item -> yield.ret(mapper.applyAsLong(item))); } } diff --git a/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerMapToObj.java b/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerMapToObj.java index bb46920..228e094 100644 --- a/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerMapToObj.java +++ b/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerMapToObj.java @@ -16,38 +16,30 @@ package org.jayield.primitives.lng.advs; -import java.util.NoSuchElementException; -import java.util.function.LongFunction; - import org.jayield.Advancer; +import org.jayield.Traverser; import org.jayield.Yield; -import org.jayield.primitives.lng.LongAdvancer; +import org.jayield.primitives.lng.LongQuery; + +import java.util.function.LongFunction; -public class LongAdvancerMapToObj implements Advancer { +public class LongAdvancerMapToObj implements Advancer, Traverser { - private final LongAdvancer upstream; + private final LongQuery upstream; private final LongFunction mapper; - public LongAdvancerMapToObj(LongAdvancer adv, LongFunction mapper) { + public LongAdvancerMapToObj(LongQuery adv, LongFunction mapper) { this.upstream = adv; this.mapper = mapper; } @Override - public boolean hasNext() { - return upstream.hasNext(); - } - - @Override - public T next() { - if (!hasNext()) { - throw new NoSuchElementException("No more elements available on iteration!"); - } - return mapper.apply(upstream.nextLong()); + public void traverse(Yield yield) { + upstream.traverse(e -> yield.ret(mapper.apply(e))); } @Override - public void traverse(Yield yield) { - upstream.traverse(e -> yield.ret(mapper.apply(e))); + public boolean tryAdvance(Yield yield) { + return upstream.tryAdvance(item -> yield.ret(mapper.apply(item))); } } diff --git a/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerPeek.java b/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerPeek.java index 853b2ae..f90036e 100644 --- a/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerPeek.java +++ b/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerPeek.java @@ -16,35 +16,33 @@ package org.jayield.primitives.lng.advs; -import java.util.function.LongConsumer; - import org.jayield.primitives.lng.LongAdvancer; +import org.jayield.primitives.lng.LongQuery; +import org.jayield.primitives.lng.LongTraverser; import org.jayield.primitives.lng.LongYield; -public class LongAdvancerPeek implements LongAdvancer { - private final LongAdvancer upstream; +import java.util.function.LongConsumer; + +public class LongAdvancerPeek implements LongAdvancer, LongTraverser { + private final LongQuery upstream; private final LongConsumer action; - public LongAdvancerPeek(LongAdvancer adv, LongConsumer action) { + public LongAdvancerPeek(LongQuery adv, LongConsumer action) { this.upstream = adv; this.action = action; } @Override - public boolean hasNext() { - return upstream.hasNext(); - } - - @Override - public long nextLong() { - long curr = upstream.nextLong(); - action.accept(curr); - return curr; + public void traverse(LongYield yield) { + upstream.traverse(item -> { + action.accept(item); + yield.ret(item); + }); } @Override - public void traverse(LongYield yield) { - upstream.traverse(item -> { + public boolean tryAdvance(LongYield yield) { + return upstream.tryAdvance(item -> { action.accept(item); yield.ret(item); }); diff --git a/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerSkip.java b/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerSkip.java index a352c5c..ecb7539 100644 --- a/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerSkip.java +++ b/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerSkip.java @@ -17,34 +17,21 @@ package org.jayield.primitives.lng.advs; import org.jayield.primitives.lng.LongAdvancer; +import org.jayield.primitives.lng.LongQuery; +import org.jayield.primitives.lng.LongTraverser; import org.jayield.primitives.lng.LongYield; -public class LongAdvancerSkip implements LongAdvancer { - private final LongAdvancer upstream; +public class LongAdvancerSkip implements LongAdvancer, LongTraverser { + private final LongQuery upstream; private final int n; int index; - public LongAdvancerSkip(LongAdvancer adv, int n) { + public LongAdvancerSkip(LongQuery adv, int n) { this.upstream = adv; this.n = n; index = 0; } - @Override - public long nextLong() { - if (!hasNext()) { - throw new IndexOutOfBoundsException("No such elements on iteration!"); - } - return upstream.nextLong(); - } - - @Override - public boolean hasNext() { - for (; upstream.hasNext() && index < n; index++) - upstream.nextLong(); - return upstream.hasNext(); - } - /** * Continues from the polong where tryAdvance or next left the * longernal iteration. @@ -59,4 +46,11 @@ public void traverse(LongYield yield) { } }); } + + @Override + public boolean tryAdvance(LongYield yield) { + for (; index < n; index++) + upstream.tryAdvance(item -> {}); + return upstream.tryAdvance(yield); + } } diff --git a/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerStream.java b/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerStream.java index 975d502..09918cd 100644 --- a/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerStream.java +++ b/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerStream.java @@ -16,42 +16,30 @@ package org.jayield.primitives.lng.advs; -import java.util.stream.LongStream; - import org.jayield.primitives.lng.LongAdvancer; -import org.jayield.primitives.lng.LongIterator; +import org.jayield.primitives.lng.LongTraverser; import org.jayield.primitives.lng.LongYield; -public class LongAdvancerStream implements LongAdvancer { - private final LongStream upstream; - private LongIterator current; - private boolean operated = false; +import java.util.Spliterator; +import java.util.function.LongConsumer; +import java.util.stream.LongStream; - public LongAdvancerStream(LongStream data) { - this.upstream = data; - } +public class LongAdvancerStream implements LongAdvancer, LongTraverser { + private final Spliterator.OfLong upstream; - @Override - public long nextLong() { - return current().nextLong(); - } - - public LongIterator current() { - if (operated) { - return current; - } - operated = true; - current = LongIterator.from(upstream.iterator()); - return current; + public LongAdvancerStream(LongStream data) { + this.upstream = data.spliterator(); } @Override - public boolean hasNext() { - return current().hasNext(); + public void traverse(LongYield yield) { + LongConsumer cons = yield::ret; + upstream.forEachRemaining(cons); } @Override - public void traverse(LongYield yield) { - upstream.forEach(yield::ret); + public boolean tryAdvance(LongYield yield) { + LongConsumer cons = yield::ret; + return upstream.tryAdvance(cons); } } diff --git a/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerTakeWhile.java b/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerTakeWhile.java index fba4096..d0d696d 100644 --- a/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerTakeWhile.java +++ b/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerTakeWhile.java @@ -16,33 +16,23 @@ package org.jayield.primitives.lng.advs; -import java.util.function.LongPredicate; - import org.jayield.Yield; +import org.jayield.primitives.lng.LongAdvancer; import org.jayield.primitives.lng.LongQuery; +import org.jayield.primitives.lng.LongTraverser; import org.jayield.primitives.lng.LongYield; -public class LongAdvancerTakeWhile extends AbstractLongAdvancer { +import java.util.function.LongPredicate; + +public class LongAdvancerTakeWhile implements LongAdvancer, LongTraverser { private final LongQuery upstream; private final LongPredicate predicate; + private boolean hasNext; public LongAdvancerTakeWhile(LongQuery upstream, LongPredicate predicate) { this.upstream = upstream; this.predicate = predicate; - } - - /** - * Returns true if it moves successfully. Otherwise returns false - * signaling it has finished. - */ - public boolean move() { - if (upstream.hasNext()) { - currLong = upstream.next(); - if (predicate.test(currLong)) { - return true; - } - } - return false; + this.hasNext = true; } @Override @@ -54,4 +44,17 @@ public void traverse(LongYield yield) { yield.ret(item); }); } + + @Override + public boolean tryAdvance(LongYield yield) { + if(!hasNext) return false; // Once predicate is false it finishes the iteration + LongYield takeWhile = item -> { + if(predicate.test(item)){ + yield.ret(item); + } else { + hasNext = false; + } + }; + return upstream.tryAdvance(takeWhile) && hasNext; + } } diff --git a/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerThen.java b/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerThen.java deleted file mode 100644 index 04cda9a..0000000 --- a/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerThen.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2020, Fernando Miguel Carvalho, mcarvalho@cc.isel.ipl.pt - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jayield.primitives.lng.advs; - -import java.util.ArrayList; -import java.util.function.Function; - -import org.jayield.primitives.lng.LongAdvancer; -import org.jayield.primitives.lng.LongIterator; -import org.jayield.primitives.lng.LongQuery; -import org.jayield.primitives.lng.LongTraverser; -import org.jayield.primitives.lng.LongYield; - -public class LongAdvancerThen implements LongAdvancer { - private LongQuery upstream; - private Function next; - private LongIterator curr; - private boolean inMem = false; - - public LongAdvancerThen(LongQuery upstream, Function next) { - this.upstream = upstream; - this.next = next; - } - - @Override - public boolean hasNext() { - return curr().hasNext(); - } - - public LongIterator curr() { - if (inMem) { - return curr; - } - ArrayList mem = new ArrayList<>(); - next.apply(upstream).traverse(mem::add); - inMem = true; - curr = LongIterator.from(mem.iterator()); - return curr; - } - - @Override - public long nextLong() { - return curr().nextLong(); - } - - @Override - public void traverse(LongYield yield) { - next.apply(upstream).traverse(yield); - } -} diff --git a/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerZip.java b/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerZip.java index de53688..1f8d7fe 100644 --- a/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerZip.java +++ b/src/main/java/org/jayield/primitives/lng/advs/LongAdvancerZip.java @@ -16,37 +16,41 @@ package org.jayield.primitives.lng.advs; -import java.util.function.LongBinaryOperator; - +import org.jayield.Yield; +import org.jayield.boxes.BoolBox; import org.jayield.primitives.lng.LongAdvancer; +import org.jayield.primitives.lng.LongQuery; +import org.jayield.primitives.lng.LongTraverser; import org.jayield.primitives.lng.LongYield; -public class LongAdvancerZip implements LongAdvancer { - private final LongAdvancer upstream; - private final LongAdvancer other; +import java.util.function.LongBinaryOperator; + +public class LongAdvancerZip implements LongAdvancer, LongTraverser { + private final LongQuery upstream; + private final LongQuery other; private final LongBinaryOperator zipper; - public LongAdvancerZip(LongAdvancer upstream, LongAdvancer other, LongBinaryOperator zipper) { + public LongAdvancerZip(LongQuery upstream, LongQuery other, LongBinaryOperator zipper) { this.upstream = upstream; this.other = other; this.zipper = zipper; } @Override - public boolean hasNext() { - return upstream.hasNext() && other.hasNext(); - } - - @Override - public long nextLong() { - return zipper.applyAsLong(upstream.next(), other.next()); + public void traverse(LongYield yield) { + upstream.shortCircuit(e1 -> { + if(!other.tryAdvance(e2 -> yield.ret(zipper.applyAsLong(e1, e2)))) + Yield.bye(); + }); } @Override - public void traverse(LongYield yield) { - upstream.traverse(e -> { - if (!other.hasNext()) return; - yield.ret(zipper.applyAsLong(e, other.next())); - }); + public boolean tryAdvance(LongYield yield) { + BoolBox consumed = new BoolBox(); + upstream.tryAdvance(e1 -> other.tryAdvance(e2 -> { + yield.ret(zipper.applyAsLong(e1, e2)); + consumed.set(); + })); + return consumed.isTrue(); } } diff --git a/src/test/java/org/jayield/AdvancerTest.java b/src/test/java/org/jayield/AdvancerTest.java index 3b6f5ec..599daca 100644 --- a/src/test/java/org/jayield/AdvancerTest.java +++ b/src/test/java/org/jayield/AdvancerTest.java @@ -1,25 +1,21 @@ package org.jayield; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertThrows; - -import java.util.NoSuchElementException; - import org.jayield.boxes.BoolBox; -import org.jayield.primitives.lng.LongAdvancer; import org.testng.annotations.Test; +import static org.testng.Assert.assertFalse; + public class AdvancerTest { @Test() public void testEmptyNext() { - assertThrows(NoSuchElementException.class, () -> Advancer.empty().next()); + assertFalse(Advancer.empty().tryAdvance(item -> { throw new AssertionError("Should not yield any item!"); })); } @Test() public void testEmptyTraverse() { BoolBox box = new BoolBox(); - Advancer.empty().traverse(i -> box.set()); + Traverser.empty().traverse(i -> box.set()); assertFalse(box.isTrue()); } diff --git a/src/test/java/org/jayield/QueryIterateTest.java b/src/test/java/org/jayield/QueryIterateTest.java index 1b808dd..4a9615f 100644 --- a/src/test/java/org/jayield/QueryIterateTest.java +++ b/src/test/java/org/jayield/QueryIterateTest.java @@ -16,23 +16,21 @@ package org.jayield; -import static java.util.Arrays.asList; -import static org.jayield.Query.of; -import static org.jayield.UserExt.collapse; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; -import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals; +import org.jayield.primitives.dbl.DoubleQuery; +import org.jayield.primitives.intgr.IntQuery; +import org.jayield.primitives.lng.LongQuery; +import org.testng.Assert; +import org.testng.annotations.Test; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import org.jayield.primitives.dbl.DoubleQuery; -import org.jayield.primitives.intgr.IntQuery; -import org.jayield.primitives.lng.LongQuery; -import org.testng.AssertJUnit; -import org.testng.annotations.Test; +import static java.util.Arrays.asList; +import static org.jayield.Query.of; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; /** * These tests aim to evaluate only the execution of hasNext() and next() @@ -47,74 +45,117 @@ public class QueryIterateTest { @Test public void testZip() { - Object[] expected = {"a1", "b2", "c3", "d4", "e5", "f6", "g7"}; + List expected = asList("a1", "b2", "c3", "d4", "e5", "f6", "g7"); Query nrs = Query.of(1, 2, 3, 4, 5, 6, 7, 8, 9); - List actual = new ArrayList<>(); Query pipe = Query .of('a', 'b', 'c', 'd', 'e', 'f', 'g') .zip(nrs, (c, n) -> "" + c + n); - while(pipe.hasNext()) { actual.add(pipe.next()); } - assertEquals(actual.toArray(), expected); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { + } + assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); } @Test public void testMapFilter() { - Object[] expected = {"5", "7", "9"}; + List expected = asList("5", "7", "9"); List arrange = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9); Query nrs = Query.fromList(arrange); Query pipe = nrs .filter(n -> n % 2 != 0) .map(Object::toString) .skip(2); - List actual = new ArrayList<>(); - while(pipe.hasNext()) { actual.add(pipe.next()); } - assertEquals(actual.toArray(), expected); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { + } + assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); + } + + @Test(expectedExceptions = { UnsupportedOperationException.class }) + public void testBulkMapFilterOddFail() { + List arrange = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9); + Query nrs = Query.fromList(arrange); + Query pipe = nrs + .filter(n -> n%2 != 0) + .map(Object::toString) + .then(prev -> yield -> { throw new AssertionError("This traverse should not be invoked for this pipeline!"); }); + pipe.tryAdvance(item -> {}); } @Test public void testBulkMapFilterOdd() { Object[] expected = {"3", "7"}; List arrange = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9); - Query nrs = Query.fromList(arrange); List actual = new ArrayList<>(); + Query nrs = Query.fromList(arrange); Query pipe = nrs .filter(n -> n%2 != 0) .map(Object::toString) - .then(prev -> yield -> { - final boolean[] isOdd = {false}; - prev.traverse(item -> { - if(isOdd[0]) yield.ret(item); - isOdd[0] = !isOdd[0]; - }); - }); - while(pipe.hasNext()) { actual.add(pipe.next()); } + .then( + UserExt::oddAdv, + prev -> yield -> { throw new AssertionError("This traverse should not be invoked for this pipeline!"); } + ); + while(pipe.tryAdvance(actual::add)) { } assertEquals(actual.toArray(), expected); } + + @Test(expectedExceptions = { UnsupportedOperationException.class }) + public void testMapCollapseFail() { + Integer[] arrange = {7, 7, 8, 9, 9, 11, 11, 7}; + Query pipe = Query + .of(arrange) + .then( + prev -> yield -> { throw new AssertionError("This traverse should not be invoked for this pipeline!"); } + ); + pipe.tryAdvance(item -> {}); + } + @Test public void testMapCollapse() { - Object[] expected= {7, 8, 9, 11, 7}; + List expected= asList(7, 8, 9, 11, 7); Integer[] arrange = {7, 7, 8, 9, 9, 11, 11, 7}; - List actual = new ArrayList<>(); Query pipe = Query .of(arrange) - .then(n -> collapse(n)); - while(pipe.hasNext()) { actual.add(pipe.next()); } - assertEquals(actual.toArray(), expected); + .then( + UserExt::collapseAdv, + prev -> yield -> { throw new AssertionError("This traverse should not be invoked for this pipeline!"); } + ); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { + } + assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); } @Test public void testFlatMap() { - Object[] expected = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + List expected = asList(1, 2, 3, 4, 5, 6, 7, 8, 9); Integer[] arrange = {2, 5, 8}; - List actual = new ArrayList<>(); Query pipe = Query .of(arrange) .flatMap(nr -> Query.of(nr - 1, nr, nr + 1)); - while(pipe.hasNext()) { actual.add(pipe.next()); } - assertEquals(actual.toArray(), expected); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { + } + assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); } @Test @@ -124,9 +165,10 @@ public void testDistinctCount() { Query pipe = Query .of(arrange) .distinct(); - int total = 0; - while(pipe.hasNext()) { pipe.next(); total++; } - assertEquals(10, total); + int [] count = {0}; + while (pipe.tryAdvance(ignore -> count[0]++)) { + } + assertEquals(count[0], 10); } @Test @@ -134,9 +176,10 @@ public void testIterateLimitLast() { Query pipe = Query .iterate(1, n -> n + 2) .limit(7); - int actual = 0; - while(pipe.hasNext()) { actual = pipe.next(); } - assertEquals(13, actual); + int [] last = {-1}; + while (pipe.tryAdvance(item -> last[0] = item)) { + } + assertEquals(last[0], 13); } @@ -146,9 +189,10 @@ public void testPeekCount() { List actual = new ArrayList<>(); Query pipe = Query.of(arrange) .peek(item -> actual.add(item * 2)); - int count = 0; - while(pipe.hasNext()) { pipe.next(); count++; } - assertEquals(count, 3); + int [] count = {0}; + while (pipe.tryAdvance(ignore -> count[0]++)) { + } + assertEquals(count[0], 3); assertEquals(actual.size(), 3); assertTrue(actual.containsAll(asList(2,4,6))); } @@ -161,9 +205,10 @@ public void testTakeWhileCount() { Query pipe = Query.of(arrange) .takeWhile(item -> helper.indexOf(item) % 2 == 0) .peek(actual::add); - int count = 0; - while(pipe.hasNext()) { pipe.next(); count++; } - assertEquals(count, 1); + int [] count = {0}; + while (pipe.tryAdvance(ignore -> count[0]++)) { + } + assertEquals(count[0], 1); assertEquals(actual.size(), 1); assertFalse(actual.containsAll(asList("a", "x", "v"))); assertEquals(actual.get(0), "a"); @@ -175,89 +220,105 @@ public void testGenerateLimitLast() { int expected = 9; Query pipe = Query .generate(() -> 2 + n[0]++) - .limit(7); - int actual = 0; - while(pipe.hasNext()) { actual = pipe.next(); } - assertEquals(actual, expected); + .takeWhile(nr -> nr < 10); + int [] last = {-1}; + while (pipe.tryAdvance(item -> last[0] = item)) { + } + assertEquals(last[0], expected); } @Test public void testConcat() { String[] input1 = new String[]{"a", "b"}; String[] input2 = new String[]{"c", "d"}; - String[] expected = new String[]{"a", "b", "c", "d"}; + List expected = asList("a", "b", "c", "d"); Query pipe = Query.of(input1).concat(Query.of(input2)); List actual = new ArrayList<>(); - while(pipe.hasNext()) { actual.add(pipe.next()); } - assertEquals(actual.toArray(String[]::new), expected); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { + } + assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); } @Test public void testSorted() { String[] input = new String[]{"b", "d", "a", "c"}; - String[] expected = new String[]{"a", "b", "c", "d"}; + List expected = asList("a", "b", "c", "d"); Query pipe = Query.of(input).sorted(String::compareTo); List actual = new ArrayList<>(); - while(pipe.hasNext()) { actual.add(pipe.next()); } - assertEquals(actual.toArray(String[]::new), expected); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { + } + assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); } @Test public void testDropWhile() { String delimiter = "c"; String[] input = new String[]{"a", "b", delimiter, "d", "e"}; - String[] expected = new String[]{delimiter, "d", "e"}; + List expected = asList(delimiter, "d", "e"); Query pipe = Query.of(input).dropWhile(s -> !delimiter.equals(s)); List actual = new ArrayList<>(); - while(pipe.hasNext()) { actual.add(pipe.next()); } - assertEquals(actual.toArray(String[]::new), expected); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { + } + assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); } @Test public void testMapToInt() { - int[] expected = {1, 2, 3}; + List expected = asList(1, 2, 3); String[] arrange = {"1", "2", "3"}; - int[] actual = new int[expected.length]; IntQuery pipe = of(arrange) .mapToInt(Integer::valueOf); - int index = 0; - while (pipe.hasNext()) { - AssertJUnit.assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - AssertJUnit.assertEquals(expected.length, index); - assertArrayEquals(expected, actual); + assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); } @Test public void testMapToLong() { - long[] expected = {1, 2, 3}; + List expected = asList(1L, 2L, 3L); String[] arrange = {"1", "2", "3"}; - long[] actual = new long[expected.length]; LongQuery pipe = of(arrange) .mapToLong(Long::valueOf); - int index = 0; - while (pipe.hasNext()) { - AssertJUnit.assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - AssertJUnit.assertEquals(expected.length, index); - assertArrayEquals(expected, actual); + assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); } @Test public void testMapToDouble() { - double[] expected = {1, 2, 3}; + List expected = asList(1d, 2d, 3d); String[] arrange = {"1", "2", "3"}; - double[] actual = new double[expected.length]; DoubleQuery pipe = of(arrange) .mapToDouble(Double::valueOf); - int index = 0; - while (pipe.hasNext()) { - AssertJUnit.assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - AssertJUnit.assertEquals(expected.length, index); - assertArrayEquals(expected, actual, 0); + assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); } } diff --git a/src/test/java/org/jayield/QueryToStreamTest.java b/src/test/java/org/jayield/QueryToStreamTest.java index a520a7d..954f235 100644 --- a/src/test/java/org/jayield/QueryToStreamTest.java +++ b/src/test/java/org/jayield/QueryToStreamTest.java @@ -16,15 +16,15 @@ package org.jayield; -import static org.jayield.Query.fromStream; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; +import org.testng.annotations.Test; import java.util.Iterator; import java.util.Spliterator; import java.util.stream.Stream; -import org.testng.annotations.Test; +import static org.jayield.Query.fromStream; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; /** * @author Miguel Gamboa @@ -36,8 +36,7 @@ public void testFromStream() { Integer[] src = {1, 2, 3, 4, 5, 6, 7, 8, 9}; Iterator expected = Stream.of(src).iterator(); Query nrs = fromStream(Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9)); - while(nrs.hasNext()) { - assertEquals(nrs.next(), expected.next()); + while(nrs.tryAdvance(item -> assertEquals(item, expected.next()))) { } assertFalse(expected.hasNext()); } diff --git a/src/test/java/org/jayield/QueryTraverseTest.java b/src/test/java/org/jayield/QueryTraverseTest.java index bfdffb1..13701a7 100644 --- a/src/test/java/org/jayield/QueryTraverseTest.java +++ b/src/test/java/org/jayield/QueryTraverseTest.java @@ -16,14 +16,7 @@ package org.jayield; -import static java.util.Arrays.asList; -import static org.jayield.Query.fromStream; -import static org.jayield.Query.iterate; -import static org.jayield.Query.of; -import static org.jayield.UserExt.collapse; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; +import org.testng.annotations.Test; import java.util.ArrayList; import java.util.Arrays; @@ -32,7 +25,14 @@ import java.util.Optional; import java.util.stream.Stream; -import org.testng.annotations.Test; +import static java.util.Arrays.asList; +import static org.jayield.Query.fromList; +import static org.jayield.Query.fromStream; +import static org.jayield.Query.iterate; +import static org.jayield.Query.of; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; /** * These tests aim to evaluate only the execution of traverse() @@ -90,13 +90,7 @@ public void testBulkMapFilterOdd() { Object[] actual = nrs .filter(n -> n%2 != 0) .map(Object::toString) - .then(prev -> yield -> { - final boolean[] isOdd = {false}; - prev.traverse(item -> { - if(isOdd[0]) yield.ret(item); - isOdd[0] = !isOdd[0]; - }); - }) + .then(UserExt::oddTrav) .toArray(); assertEquals(actual, expected); } @@ -106,7 +100,7 @@ public void testBulkMapCollapse() { Integer[] expected= {7, 8, 9, 11, 7}; Integer[] arrange = {7, 7, 8, 9, 9, 11, 11, 7}; Object[] actual = of(arrange) - .then(n -> collapse(n)) + .then(UserExt::collapseTrav) .toArray(); assertEquals(actual, expected); } @@ -119,13 +113,7 @@ public void testBulkMapFilterOddAndAnyMatch() { boolean actual = nrs .filter(n -> n%2 != 0) .map(Object::toString) - .then(prev -> (yield) -> { - final boolean[] isOdd = {false}; - prev.traverse(item -> { - if(isOdd[0]) yield.ret(item); - isOdd[0] = !isOdd[0]; - }); - }) + .then(UserExt::oddTrav) .anyMatch(n -> n.equals("7")); assertTrue(actual); @@ -134,15 +122,15 @@ public void testBulkMapFilterOddAndAnyMatch() { public void testAllMatchForAllElements() { Integer[] arrange = {2, 4, 6, 8, 10, 12}; boolean actual = of(arrange).allMatch(nr -> nr % 2 == 0); - assertEquals(true, actual); + assertEquals(actual, true); } @Test public void testAllMatchFailOnIntruder() { Integer[] arrange = {2, 4, 6, 7, 10, 12}; int[] count = {0}; boolean actual = of(arrange).peek(__ -> count[0]++).allMatch(nr -> nr % 2 == 0); - assertEquals(false, actual); - assertEquals(4, count[0]); + assertEquals(actual, false); + assertEquals(count[0], 4); } @Test public void testBulkFlatMap() { @@ -161,7 +149,7 @@ public void testShortCircuitFlatMap() { .flatMap(nr -> of(nr - 1, nr, nr + 1)) .findFirst() .get(); - assertEquals(1, actual); + assertEquals(actual, 1); } @Test @@ -179,7 +167,7 @@ public void testBulkDistinctCount() { long total = of(arrange) .distinct() .count(); - assertEquals(10, total); + assertEquals(total, 10); } @Test @@ -188,7 +176,7 @@ public void testBulkMax() { String actual = of(arrange) .max(String.CASE_INSENSITIVE_ORDER) .get(); - assertEquals("y", actual); + assertEquals(actual, "y"); } @Test @@ -230,9 +218,17 @@ public void testBulkIterateLimitMax() { .limit(7) .max(Integer::compare) .get(); - assertEquals(13, actual); + assertEquals(actual, 13); } + @Test + public void testBulkIterateTakeWhileMax() { + int actual = iterate(1, n -> n + 2) + .takeWhile(n -> n < 14) + .max(Integer::compare) + .get(); + assertEquals(actual, 13); + } @Test public void testBulkPeekCount() { @@ -272,8 +268,8 @@ public void testForEach() { @Test public void testToSet() { - String[] input = {"a", "x", "v", "d", "g", "x", "j", "x", "y", "r", "y", "w", "y", "a", "e"}; - long actual = of(input).toSet().size(); + List input = asList("a", "x", "v", "d", "g", "x", "j", "x", "y", "r", "y", "w", "y", "a", "e"); + long actual = fromList(input).toSet().size(); assertEquals(actual, 10); } diff --git a/src/test/java/org/jayield/UserExt.java b/src/test/java/org/jayield/UserExt.java index fc35201..09e79f8 100644 --- a/src/test/java/org/jayield/UserExt.java +++ b/src/test/java/org/jayield/UserExt.java @@ -16,12 +16,15 @@ package org.jayield; +import org.jayield.boxes.BoolBox; +import org.jayield.boxes.Box; + /** * @author Miguel Gamboa * created on 06-07-2017 */ public class UserExt { - static Traverser collapse(Query src) { + static Traverser collapseTrav(Query src) { return yield -> { final Object[] prev = {null}; src.traverse(item -> { @@ -30,4 +33,34 @@ static Traverser collapse(Query src) { }); }; } + static Advancer collapseAdv(Query src) { + final Box prev = new Box<>(); + return yield -> { + BoolBox found = new BoolBox(); + while(found.isFalse() && src.tryAdvance(item -> { + if(!item.equals(prev.getValue())) { + found.set(); + prev.setValue(item); + yield.ret(item); + } + })) {} + return found.isTrue(); + }; + } + static Traverser oddTrav(Query src) { + return yield -> { + final boolean[] isOdd = {false}; + src.traverse(item -> { + if(isOdd[0]) yield.ret(item); + isOdd[0] = !isOdd[0]; + }); + }; + } + static Advancer oddAdv(Query src) { + return yield -> { + if(src.tryAdvance(item -> {})) + return src.tryAdvance(yield); + return false; + }; + } } diff --git a/src/test/java/org/jayield/async/AsyncQueryTest.java b/src/test/java/org/jayield/async/AsyncQueryTest.java index b77820c..0cb67d3 100644 --- a/src/test/java/org/jayield/async/AsyncQueryTest.java +++ b/src/test/java/org/jayield/async/AsyncQueryTest.java @@ -17,7 +17,6 @@ package org.jayield.async; import org.jayield.AsyncQuery; -import org.jayield.Query; import org.testng.annotations.Test; import java.util.Arrays; @@ -34,7 +33,7 @@ public class AsyncQueryTest { @Test public void testOfArrayAndBlockingSubscribe() { - Query expected = Query.of("a", "b", "c", "d"); + Iterator expected = Arrays.asList("a", "b", "c", "d").iterator(); AsyncQuery .of("a b c d".split(" ")) .onNext((item, err) -> { @@ -60,7 +59,7 @@ public void testOfIteratorAndBlockingSubscribe() { @Test public void testSkip() { - Query expected = Query.of(4, 5, 6, 7); + Iterator expected = Arrays.asList(4, 5, 6, 7).iterator(); AsyncQuery .fork(1, 2, 3, 4, 5, 6, 7) .skip(3) @@ -74,7 +73,7 @@ public void testSkip() { @Test public void testFilter() { - Query expected = Query.of(1, 3, 5, 7, 9); + Iterator expected = Arrays.asList(1, 3, 5, 7, 9).iterator(); AsyncQuery .fork(1, 2, 3, 4, 5, 6, 7, 8, 9) .filter(n -> n % 2 != 0) @@ -87,7 +86,7 @@ public void testFilter() { } @Test public void testFilterAndMap() { - Query expected = Query.of(3, 3, 5); + Iterator expected = Arrays.asList(3, 3, 5).iterator(); AsyncQuery .fork("abc", "abcd", "ab", "bad", "super", "isel") .map(String::length) @@ -102,8 +101,8 @@ public void testFilterAndMap() { @Test public void testTakeWhile() { - Query expected1 = Query.of(1, 2, 3, 4, 5); - Query expected2 = Query.of(1, 2, 3, 4); + Iterator expected1 = Arrays.asList(1, 2, 3, 4, 5).iterator(); + Iterator expected2 = Arrays.asList(1, 2, 3, 4).iterator(); AsyncQuery .fork(1, 2, 3, 4, 5, 6, 7, 8, 9) .onNext((item, err) -> { @@ -121,7 +120,7 @@ public void testTakeWhile() { } @Test public void testFlatMapConcat() { - Query expected = Query.of(1, 2, 3, 4, 5, 6, 7, 8, 9); + Iterator expected = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9).iterator(); AsyncQuery .fork(2, 5, 8) .flatMapConcat(nr -> AsyncQuery.fork(nr - 1, nr, nr + 1)) diff --git a/src/test/java/org/jayield/primitives/dbl/DoubleAdvancerTest.java b/src/test/java/org/jayield/primitives/dbl/DoubleAdvancerTest.java index 14617be..b081b31 100644 --- a/src/test/java/org/jayield/primitives/dbl/DoubleAdvancerTest.java +++ b/src/test/java/org/jayield/primitives/dbl/DoubleAdvancerTest.java @@ -1,24 +1,21 @@ package org.jayield.primitives.dbl; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertThrows; - -import java.util.NoSuchElementException; - import org.jayield.boxes.BoolBox; import org.testng.annotations.Test; +import static org.testng.Assert.assertFalse; + public class DoubleAdvancerTest { @Test() public void testEmptyNext() { - assertThrows(NoSuchElementException.class, () -> DoubleAdvancer.empty().next()); + assertFalse(DoubleAdvancer.empty().tryAdvance(item -> { throw new AssertionError("Should not yield any item!"); })); } @Test() public void testEmptyTraverse() { BoolBox box = new BoolBox(); - DoubleAdvancer.empty().traverse(i -> box.set()); + DoubleTraverser.empty().traverse(i -> box.set()); assertFalse(box.isTrue()); } diff --git a/src/test/java/org/jayield/primitives/dbl/DoubleQueryIterateTest.java b/src/test/java/org/jayield/primitives/dbl/DoubleQueryIterateTest.java index 7f10f73..257ae45 100644 --- a/src/test/java/org/jayield/primitives/dbl/DoubleQueryIterateTest.java +++ b/src/test/java/org/jayield/primitives/dbl/DoubleQueryIterateTest.java @@ -16,21 +16,23 @@ package org.jayield.primitives.dbl; -import static org.jayield.primitives.dbl.DoubleQuery.of; -import static org.testng.AssertJUnit.assertEquals; -import static org.testng.AssertJUnit.assertTrue; -import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals; - import org.jayield.Query; -import org.jayield.boxes.IntBox; import org.jayield.primitives.intgr.IntQuery; import org.jayield.primitives.lng.LongQuery; +import org.testng.Assert; import org.testng.annotations.Test; +import java.util.ArrayList; +import java.util.List; + +import static java.util.Arrays.asList; +import static org.jayield.primitives.dbl.DoubleQuery.of; +import static org.testng.Assert.assertEquals; + /** - * These tests aim to evaluate only the execution of hasNext() and next() + * These tests aim to evaluate only the execution of tryAdvance() * along the entire pipeline. - * Each operation should forward the computation through the hasNext() and next() + * Each operation should forward the computation through the tryAdvance() * methods of the upstream. * * @author Miguel Gamboa @@ -41,303 +43,313 @@ public class DoubleQueryIterateTest { @Test public void testMapFilter() { - double[] expected = {2, 4, 6}; + List expected = asList(2d, 4d, 6d); double[] source = {1, 1, 1, 2, 3, 4, 5, 6}; DoubleQuery nrs = DoubleQuery.of(source); DoubleQuery pipe = nrs .map(n -> n * 2) .filter(n -> n <= 6) .skip(2); - double[] actual = new double[expected.length]; - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual, 0); + assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); + } + + @Test(expectedExceptions = { UnsupportedOperationException.class }) + public void testBulkMapFilterOddFail() { + List expected = asList(1d, 3d, 5d); + double[] source = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + DoubleQuery nrs = DoubleQuery.of(source); + DoubleQuery pipe = nrs + .filter(n -> n < 7) + .map(n -> n - 1) + .then( + prev -> yield -> { throw new AssertionError("This traverse should not be invoked for this pipeline!"); } + ); + pipe.tryAdvance(item -> {}); } + @Test public void testBulkMapFilterOdd() { - double[] expected = {1, 3, 5}; + List expected = asList(1d, 3d, 5d); double[] source = {1, 2, 3, 4, 5, 6, 7, 8, 9}; DoubleQuery nrs = DoubleQuery.of(source); DoubleQuery pipe = nrs .filter(n -> n < 7) .map(n -> n - 1) - .then(prev -> yield -> { - final boolean[] isOdd = {false}; - prev.traverse(item -> { - if (isOdd[0]) { - yield.ret(item); - } - isOdd[0] = !isOdd[0]; - }); - }); - double[] actual = new double[expected.length]; - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + .then( + UserExt::oddAdv, + prev -> yield -> { throw new AssertionError("This traverse should not be invoked for this pipeline!"); } + ); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual, 0); + assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); + } + + @Test(expectedExceptions = { UnsupportedOperationException.class }) + public void testMapCollapseFail() { + double[] source = {7, 7, 8, 9, 9, 11, 11, 7}; + DoubleQuery pipe = DoubleQuery + .of(source) + .then(prev -> yield -> { throw new AssertionError("This traverse should not be invoked for this pipeline!"); }); + pipe.tryAdvance(item -> {}); } @Test public void testMapCollapse() { - double[] expected = {7, 8, 9, 11, 7}; + List expected = asList(7d, 8d, 9d, 11d, 7d); double[] source = {7, 7, 8, 9, 9, 11, 11, 7}; - double[] actual = new double[expected.length]; DoubleQuery pipe = DoubleQuery .of(source) - .then(UserExt::collapse); - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + .then( + UserExt::collapseAdv, + prev -> yield -> { throw new AssertionError("This traverse should not be invoked for this pipeline!"); } + ); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual, 0); + assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); } @Test public void testFlatMap() { - double[] expected = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + List expected = asList(1d, 2d, 3d, 4d, 5d, 6d, 7d, 8d, 9d); double[] source = {2, 5, 8}; - double[] actual = new double[expected.length]; DoubleQuery pipe = DoubleQuery .of(source) .flatMap(nr -> DoubleQuery.of(nr - 1, nr, nr + 1)); int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual, 0); + assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); } @Test public void testDistinct() { - double[] expected = {7, 8, 9, 11}; + List expected = asList(7d, 8d, 9d, 11d); double[] source = {7, 7, 8, 9, 9, 11, 11, 7}; - double[] actual = new double[expected.length]; DoubleQuery pipe = DoubleQuery .of(source) .distinct(); - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual, 0); + assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); } @Test public void testIterateLimit() { - double[] expected = {1, 3, 5, 7, 9, 11, 13}; - double[] actual = new double[expected.length]; + List expected = asList(1d, 3d, 5d, 7d, 9d, 11d, 13d); DoubleQuery pipe = DoubleQuery .iterate(1, n -> n + 2) .limit(7); - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual, 0); + assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); } @Test public void testPeekCount() { - double[] expected = {2, 4, 6, 8}; + List expected = asList(2d, 4d, 6d, 8d); double[] source = {1, 2, 3, 4}; - double[] actual = new double[expected.length]; - IntBox index = new IntBox(); - index.setValue(0); + ArrayList actual = new ArrayList(); + DoubleQuery pipe = DoubleQuery .of(source) - .peek(item -> { - actual[index.getValue()] = item * 2; - index.setValue(index.getValue() + 1); - }); - int count = 0; - while (pipe.hasNext()) { - pipe.next(); - count++; + .peek(item -> actual.add(item * 2)); + int []count = {0}; + while (pipe.tryAdvance(ignore -> count[0]++)) { } - assertEquals(expected.length, count); - assertEquals(expected.length, index.getValue()); - assertArrayEquals(expected, actual, 0); + assertEquals(expected.size(), count[0]); + assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); } @Test public void testTakeWhileCount() { - double[] expected = {4, 8}; + List expected = asList(4d, 8d); double[] source = {2, 4, 5, 8}; - double[] actual = new double[expected.length]; - IntBox index = new IntBox(); - index.setValue(0); + ArrayList actual = new ArrayList(); DoubleQuery pipe = DoubleQuery .of(source) .takeWhile(i -> i % 2 == 0) - .peek(item -> { - actual[index.getValue()] = item * 2; - index.setValue(index.getValue() + 1); - }); - int count = 0; - while (pipe.hasNext()) { - pipe.next(); - count++; + .peek(item -> actual.add(item * 2)); + int []count = {0}; + while (pipe.tryAdvance(ignore -> count[0]++)) { } - assertEquals(expected.length, count); - assertEquals(expected.length, index.getValue()); - assertArrayEquals(expected, actual, 0); + assertEquals(expected.size(), count[0]); + assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); } @Test public void testGenerateLimitLast() { - double[] expected = {3, 4, 5, 6, 7, 8, 9}; - double[] actual = new double[expected.length]; + List expected = asList(3d, 4d, 5d, 6d, 7d, 8d, 9d); double[] n = new double[]{1}; DoubleQuery pipe = DoubleQuery .generate(() -> 2 + n[0]++) .limit(7); - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual, 0); + assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); } @Test public void testConcat() { - double[] expected = {1, 2, 3, 4}; + List expected = asList(1d, 2d, 3d, 4d); double[] source1 = {1, 2}; double[] source2 = {3, 4}; - double[] actual = new double[expected.length]; DoubleQuery pipe = DoubleQuery.of(source1).concat(DoubleQuery.of(source2)); - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual, 0); + assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); } @Test public void testSorted() { - double[] expected = {7, 8, 9, 11}; + List expected = asList(7d, 8d, 9d, 11d); double[] source = {11, 7, 9, 8}; - double[] actual = new double[expected.length]; DoubleQuery pipe = DoubleQuery .of(source) .sorted(); - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual, 0); + assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); } @Test public void testDropWhile() { - int delimiter = 9; - double[] expected = {delimiter, 11}; + double delimiter = 9; + List expected = asList(delimiter, 11d); double[] source = {8, 7, delimiter, 11}; - double[] actual = new double[expected.length]; DoubleQuery pipe = DoubleQuery .of(source) .dropWhile(i -> delimiter != i); - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual, 0); + assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); } @Test public void testZip() { - double[] expected = {4, 4, 4}; + List expected = asList(4d, 4d, 4d); double[] source1 = {1, 2, 3}; double[] source2 = {3, 2, 1}; - double[] actual = new double[expected.length]; DoubleQuery pipe = of(source1) .zip(of(source2), Double::sum); - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual, 0); + assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); } @Test public void testMapToObj() { - String[] expected = {"4.0", "4.0", "4.0"}; + List expected = asList("4.0", "4.0", "4.0"); double[] source1 = {1, 2, 3}; double[] source2 = {3, 2, 1}; - String[] actual = new String[expected.length]; Query pipe = of(source1) .zip(of(source2), Double::sum) .mapToObj(String::valueOf); - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual); + assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); } @Test public void testMapToInt() { - int[] expected = {7, 8, 9, 11}; + List expected = asList(7, 8, 9, 11); double[] source = {11, 7, 9, 8}; - int[] actual = new int[expected.length]; IntQuery pipe = DoubleQuery .of(source) .sorted() .asIntQuery(); - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual); + assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); } @Test public void testMapToLong() { - long[] expected = {7, 8, 9, 11}; + List expected = asList(7L, 8L, 9L, 11L); double[] source = {11, 7, 9, 8}; - long[] actual = new long[expected.length]; LongQuery pipe = DoubleQuery .of(source) .sorted() .asLongQuery(); - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual); + assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); } } diff --git a/src/test/java/org/jayield/primitives/dbl/DoubleQueryToDoubleStreamTest.java b/src/test/java/org/jayield/primitives/dbl/DoubleQueryToDoubleStreamTest.java index e0a94a0..b61feb2 100644 --- a/src/test/java/org/jayield/primitives/dbl/DoubleQueryToDoubleStreamTest.java +++ b/src/test/java/org/jayield/primitives/dbl/DoubleQueryToDoubleStreamTest.java @@ -16,15 +16,15 @@ package org.jayield.primitives.dbl; -import static org.jayield.primitives.dbl.DoubleQuery.fromStream; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; +import org.testng.annotations.Test; import java.util.PrimitiveIterator; import java.util.Spliterator; import java.util.stream.DoubleStream; -import org.testng.annotations.Test; +import static org.jayield.primitives.dbl.DoubleQuery.fromStream; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; /** * @author Miguel Gamboa @@ -36,8 +36,7 @@ public void testFromStream() { double[] src = {1, 2, 3, 4, 5, 6, 7, 8, 9}; PrimitiveIterator.OfDouble expected = DoubleStream.of(src).iterator(); DoubleQuery nrs = fromStream(DoubleStream.of(src)); - while (nrs.hasNext()) { - assertEquals(nrs.next(), expected.nextDouble()); + while (nrs.tryAdvance(item -> assertEquals(item, expected.nextDouble()))) { } assertFalse(expected.hasNext()); } diff --git a/src/test/java/org/jayield/primitives/dbl/DoubleQueryTraverseTest.java b/src/test/java/org/jayield/primitives/dbl/DoubleQueryTraverseTest.java index 853f0aa..3783899 100644 --- a/src/test/java/org/jayield/primitives/dbl/DoubleQueryTraverseTest.java +++ b/src/test/java/org/jayield/primitives/dbl/DoubleQueryTraverseTest.java @@ -16,6 +16,14 @@ package org.jayield.primitives.dbl; +import org.jayield.boxes.IntBox; +import org.testng.annotations.Test; + +import java.util.DoubleSummaryStatistics; +import java.util.OptionalDouble; +import java.util.PrimitiveIterator; +import java.util.stream.DoubleStream; + import static org.jayield.primitives.dbl.DoubleQuery.fromStream; import static org.jayield.primitives.dbl.DoubleQuery.iterate; import static org.jayield.primitives.dbl.DoubleQuery.of; @@ -24,14 +32,6 @@ import static org.testng.AssertJUnit.assertTrue; import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals; -import java.util.DoubleSummaryStatistics; -import java.util.OptionalDouble; -import java.util.PrimitiveIterator; -import java.util.stream.DoubleStream; - -import org.jayield.boxes.IntBox; -import org.testng.annotations.Test; - /** * These tests aim to evaluate only the execution of traverse() * along the entire pipeline. @@ -117,15 +117,7 @@ public void testBulkMapFilterOddAndAnyMatch() { boolean actual = nrs .filter(n -> n < 7) .map(n -> n - 1) - .then(prev -> yield -> { - final boolean[] isOdd = {false}; - prev.traverse(item -> { - if (isOdd[0]) { - yield.ret(item); - } - isOdd[0] = !isOdd[0]; - }); - }) + .then(UserExt::oddTrav) .anyMatch(n -> n == 5); assertTrue(actual); } @@ -220,6 +212,15 @@ public void testBulkIterateLimitMax() { assertEquals(actual, expected); } + @Test + public void testBulkIterateTakeWhileMax() { + double expected = 13; + double actual = iterate(1, n -> n + 2) + .takeWhile(n -> n < 14) + .max() + .orElseThrow(); + assertEquals(actual, expected); + } @Test public void testBulkPeekCount() { diff --git a/src/test/java/org/jayield/primitives/dbl/UserExt.java b/src/test/java/org/jayield/primitives/dbl/UserExt.java index 10f357d..13d7089 100644 --- a/src/test/java/org/jayield/primitives/dbl/UserExt.java +++ b/src/test/java/org/jayield/primitives/dbl/UserExt.java @@ -15,6 +15,7 @@ */ package org.jayield.primitives.dbl; +import org.jayield.boxes.BoolBox; import org.jayield.boxes.DoubleBox; /** @@ -33,4 +34,38 @@ static DoubleTraverser collapse(DoubleQuery src) { }); }; } + + static DoubleTraverser oddTrav(DoubleQuery src) { + return yield -> { + final boolean[] isOdd = {false}; + src.traverse(item -> { + if (isOdd[0]) { + yield.ret(item); + } + isOdd[0] = !isOdd[0]; + }); + }; + } + static DoubleAdvancer collapseAdv(DoubleQuery src) { + final DoubleBox prev = new DoubleBox(); + return yield -> { + BoolBox found = new BoolBox(); + while(found.isFalse() && src.tryAdvance(item -> { + if(item != prev.getValue()) { + found.set(); + prev.setValue(item); + yield.ret(item); + } + })) {} + return found.isTrue(); + }; + } + + static DoubleAdvancer oddAdv(DoubleQuery src) { + return yield -> { + if(src.tryAdvance(item -> {})) + return src.tryAdvance(yield); + return false; + }; + } } diff --git a/src/test/java/org/jayield/primitives/intgr/IntAdvancerTest.java b/src/test/java/org/jayield/primitives/intgr/IntAdvancerTest.java index 24f895c..e469e21 100644 --- a/src/test/java/org/jayield/primitives/intgr/IntAdvancerTest.java +++ b/src/test/java/org/jayield/primitives/intgr/IntAdvancerTest.java @@ -1,25 +1,21 @@ package org.jayield.primitives.intgr; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertThrows; - -import java.util.NoSuchElementException; - import org.jayield.boxes.BoolBox; -import org.jayield.primitives.dbl.DoubleAdvancer; import org.testng.annotations.Test; +import static org.testng.Assert.assertFalse; + public class IntAdvancerTest { @Test() public void testEmptyNext() { - assertThrows(NoSuchElementException.class, () -> IntAdvancer.empty().next()); + assertFalse(IntAdvancer.empty().tryAdvance(item -> { throw new AssertionError("Should not yield any item!"); })); } @Test() public void testEmptyTraverse() { BoolBox box = new BoolBox(); - IntAdvancer.empty().traverse(i -> box.set()); + IntTraverser.empty().traverse(i -> box.set()); assertFalse(box.isTrue()); } diff --git a/src/test/java/org/jayield/primitives/intgr/IntQueryIterateTest.java b/src/test/java/org/jayield/primitives/intgr/IntQueryIterateTest.java index 49b6a00..c0b27db 100644 --- a/src/test/java/org/jayield/primitives/intgr/IntQueryIterateTest.java +++ b/src/test/java/org/jayield/primitives/intgr/IntQueryIterateTest.java @@ -16,17 +16,21 @@ package org.jayield.primitives.intgr; -import static org.jayield.primitives.intgr.IntQuery.of; -import static org.testng.AssertJUnit.assertEquals; -import static org.testng.AssertJUnit.assertTrue; -import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals; - import org.jayield.Query; import org.jayield.boxes.IntBox; import org.jayield.primitives.dbl.DoubleQuery; import org.jayield.primitives.lng.LongQuery; +import org.testng.Assert; import org.testng.annotations.Test; +import java.util.ArrayList; +import java.util.List; + +import static java.util.Arrays.asList; +import static org.jayield.primitives.intgr.IntQuery.of; +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals; + /** * These tests aim to evaluate only the execution of hasNext() and next() * along the entire pipeline. @@ -41,116 +45,134 @@ public class IntQueryIterateTest { @Test public void testMapFilter() { - int[] expected = {2, 4, 6}; + List expected = asList(2, 4, 6); int[] source = {1, 1, 1, 2, 3, 4, 5, 6}; IntQuery nrs = IntQuery.of(source); IntQuery pipe = nrs .map(n -> n * 2) .filter(n -> n <= 6) .skip(2); - int[] actual = new int[expected.length]; - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual); + Assert.assertEquals(expected.size(), actual.size()); + Assert.assertEquals(expected, actual); } @Test public void testBulkMapFilterOdd() { - int[] expected = {1, 3, 5}; + List expected = asList(1, 3, 5); int[] source = {1, 2, 3, 4, 5, 6, 7, 8, 9}; IntQuery nrs = IntQuery.of(source); IntQuery pipe = nrs .filter(n -> n < 7) .map(n -> n - 1) - .then(prev -> yield -> { - final boolean[] isOdd = {false}; - prev.traverse(item -> { - if (isOdd[0]) { - yield.ret(item); - } - isOdd[0] = !isOdd[0]; - }); - }); - int[] actual = new int[expected.length]; - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + .then( + UserExt::oddAdv, + prev -> yield -> { throw new AssertionError("This traverse should not be invoked for this pipeline!");} + ); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual); + Assert.assertEquals(expected.size(), actual.size()); + Assert.assertEquals(expected, actual); + } + + @Test(expectedExceptions = { UnsupportedOperationException.class }) + public void testBulkMapFilterOddFail() { + int[] source = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + IntQuery nrs = IntQuery.of(source); + IntQuery pipe = nrs + .filter(n -> n < 7) + .map(n -> n - 1) + .then(prev -> yield -> { throw new AssertionError("This traverse should not be invoked for this pipeline!");}); + pipe.tryAdvance(item -> {}); } @Test public void testMapCollapse() { - int[] expected = {7, 8, 9, 11, 7}; + List expected = asList(7, 8, 9, 11, 7); int[] source = {7, 7, 8, 9, 9, 11, 11, 7}; - int[] actual = new int[expected.length]; IntQuery pipe = IntQuery .of(source) - .then(UserExt::collapse); - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + .then( + UserExt::collapseAdv, + prev -> yield -> { throw new AssertionError("This traverse should not be invoked for this pipeline!");} + ); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual); + Assert.assertEquals(expected.size(), actual.size()); + Assert.assertEquals(expected, actual); + } + + @Test(expectedExceptions = { UnsupportedOperationException.class }) + public void testMapCollapseFail() { + int[] source = {7, 7, 8, 9, 9, 11, 11, 7}; + IntQuery pipe = IntQuery + .of(source) + .then(prev -> yield -> { throw new AssertionError("This traverse should not be invoked for this pipeline!");}); + pipe.tryAdvance(item -> {}); } @Test public void testFlatMap() { - int[] expected = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + List expected = asList(1, 2, 3, 4, 5, 6, 7, 8, 9); int[] source = {2, 5, 8}; - int[] actual = new int[expected.length]; IntQuery pipe = IntQuery .of(source) .flatMap(nr -> IntQuery.of(nr - 1, nr, nr + 1)); - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual); + Assert.assertEquals(expected.size(), actual.size()); + Assert.assertEquals(expected, actual); } @Test public void testDistinct() { - int[] expected = {7, 8, 9, 11}; + List expected = asList(7, 8, 9, 11); int[] source = {7, 7, 8, 9, 9, 11, 11, 7}; - int[] actual = new int[expected.length]; IntQuery pipe = IntQuery .of(source) .distinct(); - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual); + Assert.assertEquals(expected.size(), actual.size()); + Assert.assertEquals(expected, actual); } @Test public void testIterateLimit() { - int[] expected = {1, 3, 5, 7, 9, 11, 13}; - int[] actual = new int[expected.length]; + List expected = asList(1, 3, 5, 7, 9, 11, 13); IntQuery pipe = IntQuery .iterate(1, n -> n + 2) .limit(7); - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual); + Assert.assertEquals(expected.size(), actual.size()); + Assert.assertEquals(expected, actual); } @@ -167,12 +189,10 @@ public void testPeekCount() { actual[index.getValue()] = item * 2; index.setValue(index.getValue() + 1); }); - int count = 0; - while (pipe.hasNext()) { - pipe.next(); - count++; + int []count = {0}; + while (pipe.tryAdvance(ignore -> count[0]++)) { } - assertEquals(expected.length, count); + assertEquals(expected.length, count[0]); assertEquals(expected.length, index.getValue()); assertArrayEquals(expected, actual); } @@ -191,152 +211,150 @@ public void testTakeWhileCount() { actual[index.getValue()] = item * 2; index.setValue(index.getValue() + 1); }); - int count = 0; - while (pipe.hasNext()) { - pipe.next(); - count++; + int []count = {0}; + while (pipe.tryAdvance(ignore -> count[0]++)) { } - assertEquals(expected.length, count); + assertEquals(expected.length, count[0]); assertEquals(expected.length, index.getValue()); assertArrayEquals(expected, actual); } @Test public void testGenerateLimitLast() { - int[] expected = {3, 4, 5, 6, 7, 8, 9}; - int[] actual = new int[expected.length]; + List expected = asList(3, 4, 5, 6, 7, 8, 9); int[] n = new int[]{1}; IntQuery pipe = IntQuery .generate(() -> 2 + n[0]++) .limit(7); - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual); + Assert.assertEquals(expected.size(), actual.size()); + Assert.assertEquals(expected, actual); } @Test public void testConcat() { - int[] expected = {1, 2, 3, 4}; + List expected = asList(1, 2, 3, 4); int[] source1 = {1, 2}; int[] source2 = {3, 4}; - int[] actual = new int[expected.length]; IntQuery pipe = IntQuery.of(source1).concat(IntQuery.of(source2)); - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual); + Assert.assertEquals(expected.size(), actual.size()); + Assert.assertEquals(expected, actual); } @Test public void testSorted() { - int[] expected = {7, 8, 9, 11}; + List expected = asList(7, 8, 9, 11); int[] source = {11, 7, 9, 8}; - int[] actual = new int[expected.length]; IntQuery pipe = IntQuery .of(source) .sorted(); - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual); + Assert.assertEquals(expected.size(), actual.size()); + Assert.assertEquals(expected, actual); } @Test public void testDropWhile() { int delimiter = 9; - int[] expected = {delimiter, 11}; + List expected = asList(delimiter, 11); int[] source = {8, 7, delimiter, 11}; - int[] actual = new int[expected.length]; IntQuery pipe = IntQuery .of(source) .dropWhile(i -> delimiter != i); - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual); + Assert.assertEquals(expected.size(), actual.size()); + Assert.assertEquals(expected, actual); } @Test public void testZip() { - int[] expected = {4, 4, 4}; + List expected = asList(4, 4, 4); int[] source1 = {1, 2, 3}; int[] source2 = {3, 2, 1}; - int[] actual = new int[expected.length]; IntQuery pipe = of(source1) .zip(of(source2), Integer::sum); - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual); + Assert.assertEquals(expected.size(), actual.size()); + Assert.assertEquals(expected, actual); } @Test public void testMapToObj() { - String[] expected = {"4", "4", "4"}; + List expected = asList("4", "4", "4"); int[] source1 = {1, 2, 3}; int[] source2 = {3, 2, 1}; - String[] actual = new String[expected.length]; Query pipe = of(source1) .zip(of(source2), Integer::sum) .mapToObj(String::valueOf); - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual); + Assert.assertEquals(expected.size(), actual.size()); + Assert.assertEquals(expected, actual); } @Test public void testMapToDouble() { - double[] expected = {7, 8, 9, 11}; + List expected = asList(7d, 8d, 9d, 11d); int[] source = {11, 7, 9, 8}; - double[] actual = new double[expected.length]; DoubleQuery pipe = IntQuery .of(source) .sorted() .asDoubleQuery(); - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual, 0); + Assert.assertEquals(expected.size(), actual.size()); + Assert.assertEquals(expected, actual); } @Test public void testMapToLong() { - long[] expected = {7, 8, 9, 11}; + List expected = asList(7L, 8L, 9L, 11L); int[] source = {11, 7, 9, 8}; - long[] actual = new long[expected.length]; LongQuery pipe = IntQuery .of(source) .sorted() .asLongQuery(); - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual); + Assert.assertEquals(expected.size(), actual.size()); + Assert.assertEquals(expected, actual); } } diff --git a/src/test/java/org/jayield/primitives/intgr/IntQueryToIntStreamTest.java b/src/test/java/org/jayield/primitives/intgr/IntQueryToIntStreamTest.java index 273f15e..0f02ee7 100644 --- a/src/test/java/org/jayield/primitives/intgr/IntQueryToIntStreamTest.java +++ b/src/test/java/org/jayield/primitives/intgr/IntQueryToIntStreamTest.java @@ -36,8 +36,7 @@ public void testFromStream() { int[] src = {1, 2, 3, 4, 5, 6, 7, 8, 9}; PrimitiveIterator.OfInt expected = IntStream.of(src).iterator(); IntQuery nrs = fromStream(IntStream.of(src)); - while (nrs.hasNext()) { - assertEquals(nrs.next(), expected.nextInt()); + while (nrs.tryAdvance(item -> assertEquals(item, expected.nextInt()))) { } assertFalse(expected.hasNext()); } diff --git a/src/test/java/org/jayield/primitives/intgr/IntQueryTraverseTest.java b/src/test/java/org/jayield/primitives/intgr/IntQueryTraverseTest.java index e2c93da..2a829cf 100644 --- a/src/test/java/org/jayield/primitives/intgr/IntQueryTraverseTest.java +++ b/src/test/java/org/jayield/primitives/intgr/IntQueryTraverseTest.java @@ -16,6 +16,14 @@ package org.jayield.primitives.intgr; +import org.jayield.boxes.IntBox; +import org.testng.annotations.Test; + +import java.util.IntSummaryStatistics; +import java.util.OptionalInt; +import java.util.PrimitiveIterator; +import java.util.stream.IntStream; + import static org.jayield.primitives.intgr.IntQuery.fromStream; import static org.jayield.primitives.intgr.IntQuery.iterate; import static org.jayield.primitives.intgr.IntQuery.of; @@ -24,15 +32,6 @@ import static org.testng.AssertJUnit.assertTrue; import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals; -import java.util.IntSummaryStatistics; -import java.util.OptionalInt; -import java.util.PrimitiveIterator; -import java.util.stream.IntStream; - -import org.jayield.boxes.IntBox; -import org.jayield.primitives.dbl.DoubleQuery; -import org.testng.annotations.Test; - /** * These tests aim to evaluate only the execution of traverse() * along the entire pipeline. @@ -118,15 +117,7 @@ public void testBulkMapFilterOddAndAnyMatch() { boolean actual = nrs .filter(n -> n < 7) .map(n -> n - 1) - .then(prev -> yield -> { - final boolean[] isOdd = {false}; - prev.traverse(item -> { - if (isOdd[0]) { - yield.ret(item); - } - isOdd[0] = !isOdd[0]; - }); - }) + .then(UserExt::oddTrav) .anyMatch(n -> n == 5); assertTrue(actual); } @@ -222,6 +213,15 @@ public void testBulkIterateLimitMax() { assertEquals(actual, expected); } + @Test + public void testBulkIterateTakeWhileMax() { + int expected = 13; + int actual = iterate(1, n -> n + 2) + .takeWhile(n -> n < 14) + .max() + .orElseThrow(); + assertEquals(actual, expected); + } @Test public void testBulkPeekCount() { diff --git a/src/test/java/org/jayield/primitives/intgr/UserExt.java b/src/test/java/org/jayield/primitives/intgr/UserExt.java index 313529e..af4c240 100644 --- a/src/test/java/org/jayield/primitives/intgr/UserExt.java +++ b/src/test/java/org/jayield/primitives/intgr/UserExt.java @@ -16,6 +16,7 @@ package org.jayield.primitives.intgr; +import org.jayield.boxes.BoolBox; import org.jayield.boxes.IntBox; /** @@ -34,4 +35,37 @@ static IntTraverser collapse(IntQuery src) { }); }; } + static IntTraverser oddTrav(IntQuery src) { + return yield -> { + final boolean[] isOdd = {false}; + src.traverse(item -> { + if (isOdd[0]) { + yield.ret(item); + } + isOdd[0] = !isOdd[0]; + }); + }; + } + static IntAdvancer collapseAdv(IntQuery src) { + final IntBox prev = new IntBox(); + return yield -> { + BoolBox found = new BoolBox(); + while(found.isFalse() && src.tryAdvance(item -> { + if(item != prev.getValue()) { + found.set(); + prev.setValue(item); + yield.ret(item); + } + })) {} + return found.isTrue(); + }; + } + + static IntAdvancer oddAdv(IntQuery src) { + return yield -> { + if(src.tryAdvance(item -> {})) + return src.tryAdvance(yield); + return false; + }; + } } diff --git a/src/test/java/org/jayield/primitives/lng/LongAdvancerTest.java b/src/test/java/org/jayield/primitives/lng/LongAdvancerTest.java index bea7199..dca288d 100644 --- a/src/test/java/org/jayield/primitives/lng/LongAdvancerTest.java +++ b/src/test/java/org/jayield/primitives/lng/LongAdvancerTest.java @@ -1,25 +1,21 @@ package org.jayield.primitives.lng; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertThrows; - -import java.util.NoSuchElementException; - import org.jayield.boxes.BoolBox; -import org.jayield.primitives.intgr.IntAdvancer; import org.testng.annotations.Test; +import static org.testng.Assert.assertFalse; + public class LongAdvancerTest { @Test() public void testEmptyNext() { - assertThrows(NoSuchElementException.class, () -> LongAdvancer.empty().next()); + assertFalse(LongAdvancer.empty().tryAdvance(item -> { throw new AssertionError("Should not yield any item!"); })); } @Test() public void testEmptyTraverse() { BoolBox box = new BoolBox(); - LongAdvancer.empty().traverse(i -> box.set()); + LongTraverser.empty().traverse(i -> box.set()); assertFalse(box.isTrue()); } diff --git a/src/test/java/org/jayield/primitives/lng/LongQueryIterateTest.java b/src/test/java/org/jayield/primitives/lng/LongQueryIterateTest.java index 22fd39c..7cf3097 100644 --- a/src/test/java/org/jayield/primitives/lng/LongQueryIterateTest.java +++ b/src/test/java/org/jayield/primitives/lng/LongQueryIterateTest.java @@ -16,17 +16,22 @@ package org.jayield.primitives.lng; -import static org.jayield.primitives.lng.LongQuery.of; -import static org.testng.AssertJUnit.assertEquals; -import static org.testng.AssertJUnit.assertTrue; -import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals; - import org.jayield.Query; import org.jayield.boxes.IntBox; import org.jayield.primitives.dbl.DoubleQuery; import org.jayield.primitives.intgr.IntQuery; +import org.testng.Assert; +import org.testng.AssertJUnit; import org.testng.annotations.Test; +import java.util.ArrayList; +import java.util.List; + +import static java.util.Arrays.asList; +import static org.jayield.primitives.lng.LongQuery.of; +import static org.testng.Assert.assertEquals; +import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals; + /** * These tests aim to evaluate only the execution of hasNext() and next() * along the entire pipeline. @@ -37,120 +42,136 @@ * created on 03-06-2017 */ public class LongQueryIterateTest { - - @Test public void testMapFilter() { - long[] expected = {2, 4, 6}; + List expected = asList(2L, 4L, 6L); long[] source = {1, 1, 1, 2, 3, 4, 5, 6}; LongQuery nrs = LongQuery.of(source); LongQuery pipe = nrs .map(n -> n * 2) .filter(n -> n <= 6) .skip(2); - long[] actual = new long[expected.length]; - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual); + Assert.assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); + } + + @Test(expectedExceptions = { UnsupportedOperationException.class }) + public void testBulkMapFilterOddFail() { + long[] source = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + LongQuery nrs = LongQuery.of(source); + LongQuery pipe = nrs + .filter(n -> n < 7) + .map(n -> n - 1) + .then(prev -> yield -> { throw new AssertionError("This traverse should not be invoked for this pipeline!"); }); + pipe.tryAdvance(item -> {}); } @Test public void testBulkMapFilterOdd() { - long[] expected = {1, 3, 5}; + List expected = asList(1L, 3L, 5L); long[] source = {1, 2, 3, 4, 5, 6, 7, 8, 9}; LongQuery nrs = LongQuery.of(source); LongQuery pipe = nrs .filter(n -> n < 7) .map(n -> n - 1) - .then(prev -> yield -> { - final boolean[] isOdd = {false}; - prev.traverse(item -> { - if (isOdd[0]) { - yield.ret(item); - } - isOdd[0] = !isOdd[0]; - }); - }); - long[] actual = new long[expected.length]; - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + .then( + UserExt::oddAdv, + prev -> yield -> { throw new AssertionError("This traverse should not be invoked for this pipeline!"); } + ); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual); + Assert.assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); } @Test public void testMapCollapse() { - long[] expected = {7, 8, 9, 11, 7}; + List expected = asList(7L, 8L, 9L, 11L, 7L); long[] source = {7, 7, 8, 9, 9, 11, 11, 7}; - long[] actual = new long[expected.length]; LongQuery pipe = LongQuery .of(source) - .then(UserExt::collapse); - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + .then( + UserExt::collapseAdv, + prev -> yield -> { throw new AssertionError("This traverse should not be invoked for this pipeline!");} + ); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual); + Assert.assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); + } + + @Test(expectedExceptions = { UnsupportedOperationException.class }) + public void testMapCollapseFail() { + long[] source = {7, 7, 8, 9, 9, 11, 11, 7}; + LongQuery pipe = LongQuery + .of(source) + .then(prev -> yield -> { throw new AssertionError("This traverse should not be invoked for this pipeline!");}); + pipe.tryAdvance(item -> {}); } @Test public void testFlatMap() { - long[] expected = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + List expected = asList(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L); long[] source = {2, 5, 8}; - long[] actual = new long[expected.length]; LongQuery pipe = LongQuery .of(source) .flatMap(nr -> LongQuery.of(nr - 1, nr, nr + 1)); - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual); + Assert.assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); } @Test public void testDistinct() { - long[] expected = {7, 8, 9, 11}; + List expected = asList(7L, 8L, 9L, 11L); long[] source = {7, 7, 8, 9, 9, 11, 11, 7}; - long[] actual = new long[expected.length]; LongQuery pipe = LongQuery .of(source) .distinct(); - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual); + Assert.assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); } @Test public void testIterateLimit() { - long[] expected = {1, 3, 5, 7, 9, 11, 13}; - long[] actual = new long[expected.length]; + List expected = asList(1L, 3L, 5L, 7L, 9L, 11L, 13L); LongQuery pipe = LongQuery .iterate(1, n -> n + 2) .limit(7); - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual); + Assert.assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); } @@ -167,13 +188,11 @@ public void testPeekCount() { actual[index.getValue()] = item * 2; index.setValue(index.getValue() + 1); }); - int count = 0; - while (pipe.hasNext()) { - pipe.next(); - count++; + int []count = {0}; + while (pipe.tryAdvance(ignore -> count[0]++)) { } - assertEquals(expected.length, count); - assertEquals(expected.length, index.getValue()); + AssertJUnit.assertEquals(expected.length, count[0]); + AssertJUnit.assertEquals(expected.length, index.getValue()); assertArrayEquals(expected, actual); } @@ -191,152 +210,150 @@ public void testTakeWhileCount() { actual[index.getValue()] = item * 2; index.setValue(index.getValue() + 1); }); - int count = 0; - while (pipe.hasNext()) { - pipe.next(); - count++; + int []count = {0}; + while (pipe.tryAdvance(ignore -> count[0]++)) { } - assertEquals(expected.length, count); - assertEquals(expected.length, index.getValue()); + AssertJUnit.assertEquals(expected.length, count[0]); + AssertJUnit.assertEquals(expected.length, index.getValue()); assertArrayEquals(expected, actual); } @Test public void testGenerateLimitLast() { - long[] expected = {3, 4, 5, 6, 7, 8, 9}; - long[] actual = new long[expected.length]; + List expected = asList(3L, 4L, 5L, 6L, 7L, 8L, 9L); long[] n = new long[]{1}; LongQuery pipe = LongQuery .generate(() -> 2 + n[0]++) .limit(7); - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual); + Assert.assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); } @Test public void testConcat() { - long[] expected = {1, 2, 3, 4}; + List expected = asList(1L, 2L, 3L, 4L); long[] source1 = {1, 2}; long[] source2 = {3, 4}; - long[] actual = new long[expected.length]; LongQuery pipe = LongQuery.of(source1).concat(LongQuery.of(source2)); - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual); + Assert.assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); } @Test public void testSorted() { - long[] expected = {7, 8, 9, 11}; + List expected = asList(7L, 8L, 9L, 11L); long[] source = {11, 7, 9, 8}; - long[] actual = new long[expected.length]; LongQuery pipe = LongQuery .of(source) .sorted(); - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual); + Assert.assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); } @Test public void testDropWhile() { - int delimiter = 9; - long[] expected = {delimiter, 11}; + long delimiter = 9; + List expected = asList(delimiter, 11L); long[] source = {8, 7, delimiter, 11}; - long[] actual = new long[expected.length]; LongQuery pipe = LongQuery .of(source) .dropWhile(i -> delimiter != i); - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual); + Assert.assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); } @Test public void testZip() { - long[] expected = {4, 4, 4}; + List expected = asList(4L, 4L, 4L); long[] source1 = {1, 2, 3}; long[] source2 = {3, 2, 1}; - long[] actual = new long[expected.length]; LongQuery pipe = of(source1) .zip(of(source2), Long::sum); - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual); + Assert.assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); } @Test public void testMapToObj() { - String[] expected = {"4", "4", "4"}; + List expected = asList("4", "4", "4"); long[] source1 = {1, 2, 3}; long[] source2 = {3, 2, 1}; - String[] actual = new String[expected.length]; Query pipe = of(source1) .zip(of(source2), Long::sum) .mapToObj(String::valueOf); - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual); + Assert.assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); } @Test public void testMapToDouble() { - double[] expected = {7, 8, 9, 11}; + List expected = asList(7d, 8d, 9d, 11d); long[] source = {11, 7, 9, 8}; - double[] actual = new double[expected.length]; DoubleQuery pipe = LongQuery .of(source) .sorted() .asDoubleQuery(); - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual, 0); + Assert.assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); } @Test public void testMapToInt() { - int[] expected = {7, 8, 9, 11}; + List expected = asList(7, 8, 9, 11); long[] source = {11, 7, 9, 8}; - int[] actual = new int[expected.length]; IntQuery pipe = LongQuery .of(source) .sorted() .asIntQuery(); - int index = 0; - while (pipe.hasNext()) { - assertTrue(index < expected.length); - actual[index++] = pipe.next(); + List actual = new ArrayList<>(); + while (pipe.tryAdvance(item -> { + Assert.assertTrue(actual.size() < expected.size()); + actual.add(item); + })) { } - assertEquals(expected.length, index); - assertArrayEquals(expected, actual); + Assert.assertEquals(expected.size(), actual.size()); + assertEquals(expected, actual); } } diff --git a/src/test/java/org/jayield/primitives/lng/LongQueryToLongStreamTest.java b/src/test/java/org/jayield/primitives/lng/LongQueryToLongStreamTest.java index 5580b1f..b322342 100644 --- a/src/test/java/org/jayield/primitives/lng/LongQueryToLongStreamTest.java +++ b/src/test/java/org/jayield/primitives/lng/LongQueryToLongStreamTest.java @@ -16,15 +16,15 @@ package org.jayield.primitives.lng; -import static org.jayield.primitives.lng.LongQuery.fromStream; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; +import org.testng.annotations.Test; import java.util.PrimitiveIterator; import java.util.Spliterator; import java.util.stream.LongStream; -import org.testng.annotations.Test; +import static org.jayield.primitives.lng.LongQuery.fromStream; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; /** * @author Miguel Gamboa @@ -36,8 +36,7 @@ public void testFromStream() { long[] src = {1, 2, 3, 4, 5, 6, 7, 8, 9}; PrimitiveIterator.OfLong expected = LongStream.of(src).iterator(); LongQuery nrs = fromStream(LongStream.of(src)); - while (nrs.hasNext()) { - assertEquals(nrs.next(), expected.nextLong()); + while (nrs.tryAdvance(item -> assertEquals(item, expected.nextLong()))) { } assertFalse(expected.hasNext()); } diff --git a/src/test/java/org/jayield/primitives/lng/LongQueryTraverseTest.java b/src/test/java/org/jayield/primitives/lng/LongQueryTraverseTest.java index 47e15d4..705ae28 100644 --- a/src/test/java/org/jayield/primitives/lng/LongQueryTraverseTest.java +++ b/src/test/java/org/jayield/primitives/lng/LongQueryTraverseTest.java @@ -16,6 +16,14 @@ package org.jayield.primitives.lng; +import org.jayield.boxes.IntBox; +import org.testng.annotations.Test; + +import java.util.LongSummaryStatistics; +import java.util.OptionalLong; +import java.util.PrimitiveIterator; +import java.util.stream.LongStream; + import static org.jayield.primitives.lng.LongQuery.fromStream; import static org.jayield.primitives.lng.LongQuery.iterate; import static org.jayield.primitives.lng.LongQuery.of; @@ -24,15 +32,6 @@ import static org.testng.AssertJUnit.assertTrue; import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals; -import java.util.LongSummaryStatistics; -import java.util.OptionalLong; -import java.util.PrimitiveIterator; -import java.util.stream.LongStream; - -import org.jayield.boxes.IntBox; -import org.jayield.primitives.intgr.IntQuery; -import org.testng.annotations.Test; - /** * These tests aim to evaluate only the execution of traverse() * along the entire pipeline. @@ -88,15 +87,7 @@ public void testBulkMapFilterOdd() { long[] actual = nrs .filter(n -> n < 7) .map(n -> n - 1) - .then(prev -> yield -> { - final boolean[] isOdd = {false}; - prev.traverse(item -> { - if (isOdd[0]) { - yield.ret(item); - } - isOdd[0] = !isOdd[0]; - }); - }) + .then(UserExt::oddTrav) .toArray(); assertEquals(actual, expected); } @@ -118,15 +109,7 @@ public void testBulkMapFilterOddAndAnyMatch() { boolean actual = nrs .filter(n -> n < 7) .map(n -> n - 1) - .then(prev -> yield -> { - final boolean[] isOdd = {false}; - prev.traverse(item -> { - if (isOdd[0]) { - yield.ret(item); - } - isOdd[0] = !isOdd[0]; - }); - }) + .then(UserExt::oddTrav) .anyMatch(n -> n == 5); assertTrue(actual); } @@ -211,6 +194,16 @@ public void testBulkMinOnEmpty() { assertFalse(of(arrange).min().isPresent()); } + @Test + public void testBulkIterateTakeWhileMax() { + long expected = 13; + long actual = iterate(1, n -> n + 2) + .takeWhile(n -> n < 14) + .max() + .orElseThrow(); + assertEquals(actual, expected); + } + @Test public void testBulkIterateLimitMax() { long expected = 13; diff --git a/src/test/java/org/jayield/primitives/lng/UserExt.java b/src/test/java/org/jayield/primitives/lng/UserExt.java index 0d7046b..579d4e7 100644 --- a/src/test/java/org/jayield/primitives/lng/UserExt.java +++ b/src/test/java/org/jayield/primitives/lng/UserExt.java @@ -16,6 +16,10 @@ package org.jayield.primitives.lng; +import org.jayield.Advancer; +import org.jayield.Query; +import org.jayield.boxes.BoolBox; +import org.jayield.boxes.Box; import org.jayield.boxes.LongBox; /** @@ -34,4 +38,39 @@ static LongTraverser collapse(LongQuery src) { }); }; } + + static LongTraverser oddTrav(LongQuery src) { + return yield -> { + final boolean[] isOdd = {false}; + src.traverse(item -> { + if (isOdd[0]) { + yield.ret(item); + } + isOdd[0] = !isOdd[0]; + }); + }; + } + + static LongAdvancer collapseAdv(LongQuery src) { + final LongBox prev = new LongBox(); + return yield -> { + BoolBox found = new BoolBox(); + while(found.isFalse() && src.tryAdvance(item -> { + if(item != prev.getValue()) { + found.set(); + prev.setValue(item); + yield.ret(item); + } + })) {} + return found.isTrue(); + }; + } + + static LongAdvancer oddAdv(LongQuery src) { + return yield -> { + if(src.tryAdvance(item -> {})) + return src.tryAdvance(yield); + return false; + }; + } }