BatchingSpliterator.java

1
/*
2
 * Copyright 2014-2026 Grzegorz Piwowarek, https://4comprehension.com/
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 * https://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
package com.pivovarit.collectors;
17
18
import java.util.ArrayList;
19
import java.util.List;
20
import java.util.Objects;
21
import java.util.Spliterator;
22
import java.util.function.Consumer;
23
import java.util.function.Function;
24
import java.util.stream.Stream;
25
26
import static java.util.stream.Stream.empty;
27
import static java.util.stream.Stream.of;
28
import static java.util.stream.StreamSupport.stream;
29
30
/**
31
 * @author Grzegorz Piwowarek
32
 */
33
final class BatchingSpliterator<T> implements Spliterator<List<T>> {
34
35
    private final List<T> source;
36
37
    private int chunks;
38
    private int chunkSize;
39
    private int consumed;
40
41
    BatchingSpliterator(List<T> list, int batches) {
42
        Objects.requireNonNull(list, "list can't be null");
43 2 1. <init> : changed conditional boundary → KILLED
2. <init> : negated conditional → KILLED
        if (batches < 1) {
44
            throw new IllegalArgumentException("batches can't be lower than one");
45
        }
46
        source = list;
47 1 1. <init> : negated conditional → KILLED
        chunks = list.isEmpty() ? 0 : Math.min(batches, list.size());
48 1 1. <init> : Replaced double division with multiplication → KILLED
        chunkSize = (int) Math.ceil(((double) source.size()) / batches);
49
    }
50
51
    static <T> Stream<List<T>> partitioned(List<T> list, int numberOfParts) {
52
        int size = list.size();
53
54 1 1. partitioned : negated conditional → KILLED
        if (size == 0) {
55
            return empty();
56 1 1. partitioned : negated conditional → KILLED
        } else if (numberOfParts == 1) {
57 1 1. partitioned : replaced return value with Stream.empty for com/pivovarit/collectors/BatchingSpliterator::partitioned → KILLED
            return of(list);
58 2 1. partitioned : changed conditional boundary → SURVIVED
2. partitioned : negated conditional → KILLED
        } else if (size <= numberOfParts) {
59 1 1. partitioned : replaced return value with Stream.empty for com/pivovarit/collectors/BatchingSpliterator::partitioned → KILLED
            return asSingletonListStream(list);
60
        } else {
61 1 1. partitioned : replaced return value with Stream.empty for com/pivovarit/collectors/BatchingSpliterator::partitioned → KILLED
            return stream(new BatchingSpliterator<>(list, numberOfParts), false);
62
        }
63
    }
64
65
    private static <T> Stream<List<T>> asSingletonListStream(List<T> list) {
66
        Stream.Builder<List<T>> acc = Stream.builder();
67
        for (T t : list) {
68
            acc.add(List.of(t));
69
        }
70 1 1. asSingletonListStream : replaced return value with Stream.empty for com/pivovarit/collectors/BatchingSpliterator::asSingletonListStream → KILLED
        return acc.build();
71
    }
72
73
    static <T, R> Function<List<T>, List<R>> batching(Function<? super T, ? extends R> mapper) {
74 1 1. batching : replaced return value with null for com/pivovarit/collectors/BatchingSpliterator::batching → KILLED
        return batch -> {
75
            List<R> list = new ArrayList<>(batch.size());
76
            for (T t : batch) {
77
                list.add(mapper.apply(t));
78
            }
79 1 1. lambda$batching$0 : replaced return value with Collections.emptyList for com/pivovarit/collectors/BatchingSpliterator::lambda$batching$0 → KILLED
            return list;
80
        };
81
    }
82
83
    @Override
84
    public boolean tryAdvance(Consumer<? super List<T>> action) {
85 3 1. tryAdvance : changed conditional boundary → SURVIVED
2. tryAdvance : negated conditional → KILLED
3. tryAdvance : negated conditional → KILLED
        if (consumed < source.size() && chunks != 0) {
86 1 1. tryAdvance : Replaced integer addition with subtraction → KILLED
            int end = Math.min(source.size(), consumed + chunkSize);
87
            List<T> batch = source.subList(consumed, end);
88 1 1. tryAdvance : Replaced integer addition with subtraction → KILLED
            consumed += batch.size();
89 3 1. tryAdvance : changed conditional boundary → SURVIVED
2. tryAdvance : negated conditional → KILLED
3. tryAdvance : Replaced integer subtraction with addition → KILLED
            if (--chunks > 0) {
90 2 1. tryAdvance : Replaced integer subtraction with addition → KILLED
2. tryAdvance : Replaced double division with multiplication → KILLED
                chunkSize = (int) Math.ceil(((double) (source.size() - consumed)) / chunks);
91
            }
92 1 1. tryAdvance : removed call to java/util/function/Consumer::accept → KILLED
            action.accept(batch);
93 1 1. tryAdvance : replaced boolean return with false for com/pivovarit/collectors/BatchingSpliterator::tryAdvance → KILLED
            return true;
94
        } else {
95 1 1. tryAdvance : replaced boolean return with true for com/pivovarit/collectors/BatchingSpliterator::tryAdvance → TIMED_OUT
            return false;
96
        }
97
    }
98
99
    @Override
100
    public Spliterator<List<T>> trySplit() {
101 1 1. trySplit : Replaced integer subtraction with addition → KILLED
        int remaining = source.size() - consumed;
102 4 1. trySplit : changed conditional boundary → SURVIVED
2. trySplit : changed conditional boundary → SURVIVED
3. trySplit : negated conditional → KILLED
4. trySplit : negated conditional → KILLED
        if (remaining <= chunkSize || chunks <= 1) {
103
            return null;
104
        }
105
106 1 1. trySplit : Replaced integer division with multiplication → KILLED
        int midChunks = chunks / 2;
107 1 1. trySplit : Replaced integer division with multiplication → KILLED
        int floor = remaining / chunks;
108 1 1. trySplit : Replaced integer modulus with multiplication → KILLED
        int larger = remaining % chunks;
109 5 1. trySplit : Replaced integer addition with subtraction → KILLED
2. trySplit : Replaced integer addition with subtraction → KILLED
3. trySplit : Replaced integer subtraction with addition → KILLED
4. trySplit : Replaced integer multiplication with division → KILLED
5. trySplit : Replaced integer multiplication with division → KILLED
        int midSize = Math.min(midChunks, larger) * (floor + 1) + Math.max(0, midChunks - larger) * floor;
110
111 1 1. trySplit : Replaced integer addition with subtraction → KILLED
        var subList = source.subList(consumed, consumed + midSize);
112
        var split = new BatchingSpliterator<>(subList, midChunks);
113
114 1 1. trySplit : Replaced integer addition with subtraction → KILLED
        consumed += midSize;
115 1 1. trySplit : Replaced integer subtraction with addition → KILLED
        chunks -= midChunks;
116 2 1. trySplit : Replaced double division with multiplication → KILLED
2. trySplit : Replaced integer subtraction with addition → KILLED
        chunkSize = (int) Math.ceil(((double) (source.size() - consumed)) / chunks);
117
118 1 1. trySplit : replaced return value with null for com/pivovarit/collectors/BatchingSpliterator::trySplit → KILLED
        return split;
119
    }
120
121
    @Override
122
    public long estimateSize() {
123 1 1. estimateSize : replaced long return with 0 for com/pivovarit/collectors/BatchingSpliterator::estimateSize → KILLED
        return chunks;
124
    }
125
126
    @Override
127
    public int characteristics() {
128 1 1. characteristics : replaced int return with 0 for com/pivovarit/collectors/BatchingSpliterator::characteristics → KILLED
        return IMMUTABLE | ORDERED | SIZED;
129
    }
130
}

Mutations

43

1.1
Location : <init>
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[nested-class:EstimateSizeTests]/[method:shouldReturnOneForSingleBatch()]
changed conditional boundary → KILLED

2.2
Location : <init>
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[nested-class:EstimateSizeTests]/[method:shouldReturnOneForSingleBatch()]
negated conditional → KILLED

47

1.1
Location : <init>
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[nested-class:EstimateSizeTests]/[method:shouldReturnOneForSingleBatch()]
negated conditional → KILLED

48

1.1
Location : <init>
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[nested-class:EstimateSizeTests]/[method:shouldAdjustCorrectlyAfterTrySplit()]
Replaced double division with multiplication → KILLED

54

1.1
Location : partitioned
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[method:shouldReturnSameListWhenBatchesIsOne()]
negated conditional → KILLED

56

1.1
Location : partitioned
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[method:shouldReportCorrectSizeWhenMultipleBatches()]
negated conditional → KILLED

57

1.1
Location : partitioned
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[method:shouldReturnSameListWhenBatchesIsOne()]
replaced return value with Stream.empty for com/pivovarit/collectors/BatchingSpliterator::partitioned → KILLED

58

1.1
Location : partitioned
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[method:shouldReportCorrectSizeWhenMultipleBatches()]
negated conditional → KILLED

2.2
Location : partitioned
Killed by : none
changed conditional boundary → SURVIVED
Covering tests

59

1.1
Location : partitioned
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[method:shouldPartitionToSingletonsWhenSizeLessThanBatches()]
replaced return value with Stream.empty for com/pivovarit/collectors/BatchingSpliterator::partitioned → KILLED

61

1.1
Location : partitioned
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[method:shouldReportCorrectSizeWhenMultipleBatches()]
replaced return value with Stream.empty for com/pivovarit/collectors/BatchingSpliterator::partitioned → KILLED

70

1.1
Location : asSingletonListStream
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[method:shouldPartitionToSingletonsWhenSizeLessThanBatches()]
replaced return value with Stream.empty for com/pivovarit/collectors/BatchingSpliterator::asSingletonListStream → KILLED

74

1.1
Location : batching
Killed by : com.pivovarit.collectors.test.BasicProcessingTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.test.BasicProcessingTest]/[test-factory:shouldProcessAllElementsInOrder()]/[dynamic-test:#33]
replaced return value with null for com/pivovarit/collectors/BatchingSpliterator::batching → KILLED

79

1.1
Location : lambda$batching$0
Killed by : com.pivovarit.collectors.test.BasicProcessingTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.test.BasicProcessingTest]/[test-factory:shouldProcessAllElementsInOrder()]/[dynamic-test:#33]
replaced return value with Collections.emptyList for com/pivovarit/collectors/BatchingSpliterator::lambda$batching$0 → KILLED

85

1.1
Location : tryAdvance
Killed by : none
changed conditional boundary → SURVIVED
Covering tests

2.2
Location : tryAdvance
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[nested-class:EstimateSizeTests]/[method:shouldReturnZeroAfterAllConsumed()]
negated conditional → KILLED

3.3
Location : tryAdvance
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[nested-class:EstimateSizeTests]/[method:shouldReturnZeroAfterAllConsumed()]
negated conditional → KILLED

86

1.1
Location : tryAdvance
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[nested-class:EstimateSizeTests]/[method:shouldReturnZeroAfterAllConsumed()]
Replaced integer addition with subtraction → KILLED

88

1.1
Location : tryAdvance
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[nested-class:EstimateSizeTests]/[method:shouldReturnZeroAfterAllConsumed()]
Replaced integer addition with subtraction → KILLED

89

1.1
Location : tryAdvance
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[method:shouldNotExceedBoundsOnLargeChunkRecomputation()]
negated conditional → KILLED

2.2
Location : tryAdvance
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[nested-class:EstimateSizeTests]/[method:shouldReturnZeroAfterAllConsumed()]
Replaced integer subtraction with addition → KILLED

3.3
Location : tryAdvance
Killed by : none
changed conditional boundary → SURVIVED
Covering tests

90

1.1
Location : tryAdvance
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[method:shouldNotExceedBoundsForUnevenSplit()]
Replaced integer subtraction with addition → KILLED

2.2
Location : tryAdvance
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[method:shouldNotExceedBoundsForUnevenSplit()]
Replaced double division with multiplication → KILLED

92

1.1
Location : tryAdvance
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[method:shouldHandleSingleElementList()]
removed call to java/util/function/Consumer::accept → KILLED

93

1.1
Location : tryAdvance
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[nested-class:EstimateSizeTests]/[method:shouldReturnZeroAfterAllConsumed()]
replaced boolean return with false for com/pivovarit/collectors/BatchingSpliterator::tryAdvance → KILLED

95

1.1
Location : tryAdvance
Killed by : none
replaced boolean return with true for com/pivovarit/collectors/BatchingSpliterator::tryAdvance → TIMED_OUT

101

1.1
Location : trySplit
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[nested-class:EstimateSizeTests]/[method:shouldHonourSizedContractAcrossPartialAdvanceAndSplitCombinations()]
Replaced integer subtraction with addition → KILLED

102

1.1
Location : trySplit
Killed by : none
changed conditional boundary → SURVIVED
Covering tests

2.2
Location : trySplit
Killed by : none
changed conditional boundary → SURVIVED Covering tests

3.3
Location : trySplit
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[nested-class:EstimateSizeTests]/[method:shouldAdjustCorrectlyAfterTrySplit()]
negated conditional → KILLED

4.4
Location : trySplit
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[nested-class:EstimateSizeTests]/[method:shouldAdjustCorrectlyAfterTrySplit()]
negated conditional → KILLED

106

1.1
Location : trySplit
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[nested-class:EstimateSizeTests]/[method:shouldAdjustCorrectlyAfterTrySplit()]
Replaced integer division with multiplication → KILLED

107

1.1
Location : trySplit
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[nested-class:EstimateSizeTests]/[method:shouldAdjustCorrectlyAfterTrySplit()]
Replaced integer division with multiplication → KILLED

108

1.1
Location : trySplit
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[nested-class:EstimateSizeTests]/[method:shouldNotOvercountRemainderAfterUnevenTrySplit()]
Replaced integer modulus with multiplication → KILLED

109

1.1
Location : trySplit
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[nested-class:EstimateSizeTests]/[method:shouldHonourSizedContractAcrossPartialAdvanceAndSplitCombinations()]
Replaced integer addition with subtraction → KILLED

2.2
Location : trySplit
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[nested-class:EstimateSizeTests]/[method:shouldAdjustCorrectlyAfterTrySplit()]
Replaced integer addition with subtraction → KILLED

3.3
Location : trySplit
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[nested-class:EstimateSizeTests]/[method:shouldNotOvercountRemainderAfterUnevenTrySplit()]
Replaced integer subtraction with addition → KILLED

4.4
Location : trySplit
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[nested-class:EstimateSizeTests]/[method:shouldHonourSizedContractAcrossPartialAdvanceAndSplitCombinations()]
Replaced integer multiplication with division → KILLED

5.5
Location : trySplit
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[method:shouldSplitAndProcessIndependently()]
Replaced integer multiplication with division → KILLED

111

1.1
Location : trySplit
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[nested-class:EstimateSizeTests]/[method:shouldAdjustCorrectlyAfterTrySplit()]
Replaced integer addition with subtraction → KILLED

114

1.1
Location : trySplit
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[nested-class:EstimateSizeTests]/[method:shouldNotOvercountRemainderAfterUnevenTrySplit()]
Replaced integer addition with subtraction → KILLED

115

1.1
Location : trySplit
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[nested-class:EstimateSizeTests]/[method:shouldAdjustCorrectlyAfterTrySplit()]
Replaced integer subtraction with addition → KILLED

116

1.1
Location : trySplit
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[nested-class:EstimateSizeTests]/[method:shouldNotOvercountRemainderAfterUnevenTrySplit()]
Replaced double division with multiplication → KILLED

2.2
Location : trySplit
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[nested-class:EstimateSizeTests]/[method:shouldNotOvercountRemainderAfterUnevenTrySplit()]
Replaced integer subtraction with addition → KILLED

118

1.1
Location : trySplit
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[nested-class:EstimateSizeTests]/[method:shouldAdjustCorrectlyAfterTrySplit()]
replaced return value with null for com/pivovarit/collectors/BatchingSpliterator::trySplit → KILLED

123

1.1
Location : estimateSize
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[nested-class:EstimateSizeTests]/[method:shouldReturnOneForSingleBatch()]
replaced long return with 0 for com/pivovarit/collectors/BatchingSpliterator::estimateSize → KILLED

128

1.1
Location : characteristics
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[method:shouldReportOrderedSizedAndSubSized()]
replaced int return with 0 for com/pivovarit/collectors/BatchingSpliterator::characteristics → KILLED

Active mutators

Tests examined


Report generated by PIT 1.30.0 support