|
|
@@ -7,15 +7,43 @@ import net.ranides.assira.collection.query.CQueryAbstract;
|
|
|
import net.ranides.assira.collection.query.base.CQAbstractFilter;
|
|
|
|
|
|
import java.util.Iterator;
|
|
|
+import java.util.List;
|
|
|
import java.util.function.Predicate;
|
|
|
import java.util.stream.Stream;
|
|
|
|
|
|
public class BaseSplit {
|
|
|
|
|
|
- public static <T, R> CQuery<R> split(CQueryAbstract<T> that, CQuery.SplitQueryFunction<? super T, R> f) {
|
|
|
- return new CQAbstractFilter<T,R>(that) {
|
|
|
+ // Implementation note:
|
|
|
+ //
|
|
|
+ // We can't use stream#flatMap because derived stream evaluates too much.
|
|
|
+ // more precisely, it applies #map to all elements generated from element:
|
|
|
+ // EXPECTED:
|
|
|
+ // A source: abc def ghi
|
|
|
+ // B flat: a b c | d e f | .
|
|
|
+ // C map: A B C | D . .
|
|
|
+ // d limit(4) A B C | D
|
|
|
+ // UNFORTUNATELY:
|
|
|
+ // A source: abc def ghi
|
|
|
+ // B flat: a b c | d e f | .
|
|
|
+ // C map: A B C | D E F
|
|
|
+ // d limit(4) A B C | D
|
|
|
+ //
|
|
|
+ // So we fall-back to our own iterator implementation, sorry
|
|
|
+ //
|
|
|
+ // Reference:
|
|
|
+ // https://bugs.openjdk.java.net/browse/JDK-8075939
|
|
|
+ // https://stackoverflow.com/questions/29229373/why-filter-after-flatmap-is-not-completely-lazy-in-java-streams
|
|
|
+
|
|
|
+
|
|
|
+ private static final boolean DONT_USE_FLAT_STREAM = true;
|
|
|
+
|
|
|
+ public static <T, R> CQuery<R> flat(CQueryAbstract<T> that, CQuery.SplitQueryFunction<? super T, R> f) {
|
|
|
+ return new CQAbstractSplit<T,R>(that) {
|
|
|
@Override
|
|
|
public Stream<R> stream() {
|
|
|
+ if (DONT_USE_FLAT_STREAM) {
|
|
|
+ return BaseIterable.stream(this);
|
|
|
+ }
|
|
|
return source.stream().flatMap(s -> f.apply(s).stream());
|
|
|
}
|
|
|
|
|
|
@@ -28,13 +56,21 @@ public class BaseSplit {
|
|
|
public boolean whileEach(Predicate<? super R> consumer) {
|
|
|
return source.whileEach(s -> f.apply(s).whileEach(consumer));
|
|
|
}
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<R> list() {
|
|
|
+ return BaseStream.list(this);
|
|
|
+ }
|
|
|
};
|
|
|
}
|
|
|
|
|
|
- public static <T,R> CQuery<R> split(CQueryAbstract<T> that, CQuery.SplitIterableFunction<? super T, R> f) {
|
|
|
- return new CQAbstractFilter<T,R>(that) {
|
|
|
+ public static <T,R> CQuery<R> flat(CQueryAbstract<T> that, CQuery.SplitIterableFunction<? super T, R> f) {
|
|
|
+ return new CQAbstractSplit<T,R>(that) {
|
|
|
@Override
|
|
|
public Stream<R> stream() {
|
|
|
+ if (DONT_USE_FLAT_STREAM) {
|
|
|
+ return BaseIterable.stream(this);
|
|
|
+ }
|
|
|
return source.stream().flatMap(s -> IteratorUtils.stream(f.apply(s).iterator()));
|
|
|
}
|
|
|
|
|
|
@@ -51,10 +87,13 @@ public class BaseSplit {
|
|
|
};
|
|
|
}
|
|
|
|
|
|
- public static <T,R> CQuery<R> split(CQueryAbstract<T> that, CQuery.SplitArrayFunction<? super T, R> f) {
|
|
|
- return new CQAbstractFilter<T,R>(that) {
|
|
|
+ public static <T,R> CQuery<R> flat(CQueryAbstract<T> that, CQuery.SplitArrayFunction<? super T, R> f) {
|
|
|
+ return new CQAbstractSplit<T,R>(that) {
|
|
|
@Override
|
|
|
public Stream<R> stream() {
|
|
|
+ if (DONT_USE_FLAT_STREAM) {
|
|
|
+ return BaseIterable.stream(this);
|
|
|
+ }
|
|
|
return source.stream().flatMap(s -> Stream.of(f.apply(s)));
|
|
|
}
|
|
|
|
|
|
@@ -72,9 +111,12 @@ public class BaseSplit {
|
|
|
}
|
|
|
|
|
|
public static <T> CQuery<T> splitIf(CQueryAbstract<T> that, Predicate<? super T> p, CQuery.SplitQueryFunction<? super T, T> f) {
|
|
|
- return new CQAbstractFilter<T,T>(that) {
|
|
|
+ return new CQAbstractSplit<T,T>(that) {
|
|
|
@Override
|
|
|
public Stream<T> stream() {
|
|
|
+ if (DONT_USE_FLAT_STREAM) {
|
|
|
+ return BaseIterable.stream(this);
|
|
|
+ }
|
|
|
return source.stream().flatMap(s -> p.test(s) ? f.apply(s).stream() : Stream.of(s));
|
|
|
}
|
|
|
|
|
|
@@ -95,9 +137,12 @@ public class BaseSplit {
|
|
|
}
|
|
|
|
|
|
public static <T> CQuery<T> splitIf(CQueryAbstract<T> that, Predicate<? super T> p, CQuery.SplitIterableFunction<? super T, T> f) {
|
|
|
- return new CQAbstractFilter<T,T>(that) {
|
|
|
+ return new CQAbstractSplit<T,T>(that) {
|
|
|
@Override
|
|
|
public Stream<T> stream() {
|
|
|
+ if (DONT_USE_FLAT_STREAM) {
|
|
|
+ return BaseIterable.stream(this);
|
|
|
+ }
|
|
|
return source.stream().flatMap(s -> {
|
|
|
return p.test(s) ? IteratorUtils.stream(f.apply(s).iterator()) : Stream.of(s);
|
|
|
});
|
|
|
@@ -121,9 +166,12 @@ public class BaseSplit {
|
|
|
}
|
|
|
|
|
|
public static <T> CQuery<T> splitIf(CQueryAbstract<T> that, Predicate<? super T> p, CQuery.SplitArrayFunction<? super T, T> f) {
|
|
|
- return new CQAbstractFilter<T,T>(that) {
|
|
|
+ return new CQAbstractSplit<T,T>(that) {
|
|
|
@Override
|
|
|
public Stream<T> stream() {
|
|
|
+ if (DONT_USE_FLAT_STREAM) {
|
|
|
+ return BaseIterable.stream(this);
|
|
|
+ }
|
|
|
return source.stream().flatMap(s -> {
|
|
|
return p.test(s) ? Stream.of(f.apply(s)) : Stream.of(s);
|
|
|
});
|
|
|
@@ -146,4 +194,16 @@ public class BaseSplit {
|
|
|
};
|
|
|
}
|
|
|
|
|
|
+ private static abstract class CQAbstractSplit<T,R> extends CQAbstractFilter<T,R> {
|
|
|
+
|
|
|
+ public CQAbstractSplit(CQueryAbstract<T> source) {
|
|
|
+ super(source);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean hasFastStream() {
|
|
|
+ return !DONT_USE_FLAT_STREAM && source.hasFastStream();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
}
|