From 4f6274b01b9cdaf408b92ef672a3aa70920d7f09 Mon Sep 17 00:00:00 2001 From: Vladimir Sitnikov Date: Wed, 14 Dec 2022 12:11:58 +0300 Subject: [PATCH] Replace Stream API with for loop in ShrinkingDistance with for loops It makes the stacktraces shorter and easier to reason. See https://github.com/jlink/jqwik/issues/431 --- .../java/net/jqwik/api/ShrinkingDistance.java | 67 ++++++++++++++++--- 1 file changed, 56 insertions(+), 11 deletions(-) diff --git a/api/src/main/java/net/jqwik/api/ShrinkingDistance.java b/api/src/main/java/net/jqwik/api/ShrinkingDistance.java index 3b995aef3..24ff16e5f 100644 --- a/api/src/main/java/net/jqwik/api/ShrinkingDistance.java +++ b/api/src/main/java/net/jqwik/api/ShrinkingDistance.java @@ -4,6 +4,7 @@ import java.util.stream.*; import org.apiguardian.api.*; +import org.jetbrains.annotations.*; import static org.apiguardian.api.API.Status.*; @@ -13,6 +14,8 @@ public class ShrinkingDistance implements Comparable { @API(status = MAINTAINED, since = "1.2.0") public static final ShrinkingDistance MAX = ShrinkingDistance.of(Long.MAX_VALUE); + private static final ShrinkingDistance MIN = ShrinkingDistance.of(0); + private final long[] distances; @API(status = MAINTAINED, since = "1.0") @@ -22,20 +25,44 @@ public static ShrinkingDistance of(long... distances) { @API(status = MAINTAINED, since = "1.0") public static ShrinkingDistance forCollection(Collection> elements) { - ShrinkingDistance sumDistanceOfElements = elements - .stream() - .map(Shrinkable::distance) - .reduce(ShrinkingDistance.of(0), ShrinkingDistance::plus); + if (elements.isEmpty()) { + return MIN; + } - return ShrinkingDistance.of(elements.size()).append(sumDistanceOfElements); + long[] data = null; + for (Shrinkable element : elements) { + long[] next = element.distance().distances; + if (data == null) { + data = Arrays.copyOf(next, next.length); + continue; + } + data = sumUpArrays(data, data, next); + + } + return new ShrinkingDistance(concatArrays(new long[]{elements.size()}, data)); } @API(status = MAINTAINED, since = "1.0") public static ShrinkingDistance combine(List> shrinkables) { - return shrinkables - .stream() - .map(Shrinkable::distance) - .reduce(new ShrinkingDistance(new long[0]), ShrinkingDistance::append); + if (shrinkables.isEmpty()) { + return MIN; + } + // Compute the total size of the required array + List distances = new ArrayList<>(shrinkables.size()); + int totalLength = 0; + for (Shrinkable shrinkable : shrinkables) { + long[] next = shrinkable.distance().distances; + totalLength += next.length; + distances.add(next); + } + // Append all the arrays together + long[] data = new long[totalLength]; + int index = 0; + for (long[] distance : distances) { + System.arraycopy(distance, 0, data, index, distance.length); + index += distance.length; + } + return new ShrinkingDistance(data); } private ShrinkingDistance(long[] distances) { @@ -98,7 +125,7 @@ private int compareDimension(ShrinkingDistance other, int i) { return Long.compare(left, right); } - private long at(long[] array, int i) { + private static long at(long[] array, int i) { return array.length > i ? array[i] : 0; } @@ -120,13 +147,31 @@ private long[] sumUpArrays(long[] left, long[] right) { return sum; } + private static long[] sumUpArrays(long @Nullable [] sum, long[] left, long[] right) { + if (sum == null || sum.length < left.length || sum.length < right.length) { + sum = new long[Math.max(left.length, right.length)]; + } + for (int i = 0; i < sum.length; i++) { + sum[i] = saturatedAdd(at(left, i), at(right, i)); + } + return sum; + } + + private static long saturatedAdd(long a, long b) { + long sum = a + b; + if (((a ^ sum) & (b ^ sum)) < 0) { + return Long.MAX_VALUE; + } + return sum; + } + @API(status = INTERNAL) public ShrinkingDistance append(ShrinkingDistance other) { long[] appendedDistances = concatArrays(distances, other.distances); return new ShrinkingDistance(appendedDistances); } - private long[] concatArrays(long[] left, long[] right) { + private static long[] concatArrays(long[] left, long[] right) { long[] concatenated = Arrays.copyOf(left, left.length + right.length); System.arraycopy(right, 0, concatenated, left.length, right.length); return concatenated;