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
    private int maxChunks;
37
38
    private int chunks;
39
    private int chunkSize;
40
    private int consumed;
41
42
    BatchingSpliterator(List<T> list, int batches) {
43
        Objects.requireNonNull(list, "list can't be null");
44 2 1. <init> : changed conditional boundary → KILLED
2. <init> : negated conditional → KILLED
        if (batches < 1) {
45
            throw new IllegalArgumentException("batches can't be lower than one");
46
        }
47
        source = list;
48 1 1. <init> : negated conditional → KILLED
        chunks = list.isEmpty() ? 0 : batches;
49
        maxChunks = Math.min(list.size(), batches);
50 1 1. <init> : Replaced double division with multiplication → KILLED
        chunkSize = (int) Math.ceil(((double) source.size()) / batches);
51
    }
52
53
    static <T> Stream<List<T>> partitioned(List<T> list, int numberOfParts) {
54
        int size = list.size();
55
56 1 1. partitioned : negated conditional → KILLED
        if (size == 0) {
57
            return empty();
58 1 1. partitioned : negated conditional → KILLED
        } else if (numberOfParts == 1) {
59 1 1. partitioned : replaced return value with Stream.empty for com/pivovarit/collectors/BatchingSpliterator::partitioned → KILLED
            return of(list);
60 2 1. partitioned : changed conditional boundary → SURVIVED
2. partitioned : negated conditional → KILLED
        } else if (size <= numberOfParts) {
61 1 1. partitioned : replaced return value with Stream.empty for com/pivovarit/collectors/BatchingSpliterator::partitioned → KILLED
            return asSingletonListStream(list);
62
        } else {
63 1 1. partitioned : replaced return value with Stream.empty for com/pivovarit/collectors/BatchingSpliterator::partitioned → KILLED
            return stream(new BatchingSpliterator<>(list, numberOfParts), false);
64
        }
65
    }
66
67
    private static <T> Stream<List<T>> asSingletonListStream(List<T> list) {
68
        Stream.Builder<List<T>> acc = Stream.builder();
69
        for (T t : list) {
70
            acc.add(List.of(t));
71
        }
72 1 1. asSingletonListStream : replaced return value with Stream.empty for com/pivovarit/collectors/BatchingSpliterator::asSingletonListStream → KILLED
        return acc.build();
73
    }
74
75
    static <T, R> Function<List<T>, List<R>> batching(Function<? super T, R> mapper) {
76 1 1. batching : replaced return value with null for com/pivovarit/collectors/BatchingSpliterator::batching → KILLED
        return batch -> {
77
            List<R> list = new ArrayList<>(batch.size());
78
            for (T t : batch) {
79
                list.add(mapper.apply(t));
80
            }
81 1 1. lambda$batching$0 : replaced return value with Collections.emptyList for com/pivovarit/collectors/BatchingSpliterator::lambda$batching$0 → KILLED
            return list;
82
        };
83
    }
84
85
    @Override
86
    public boolean tryAdvance(Consumer<? super List<T>> action) {
87 3 1. tryAdvance : changed conditional boundary → KILLED
2. tryAdvance : negated conditional → KILLED
3. tryAdvance : negated conditional → KILLED
        if (consumed < source.size() && chunks != 0) {
88 1 1. tryAdvance : Replaced integer addition with subtraction → KILLED
            int end = Math.min(source.size(), consumed + chunkSize);
89
            List<T> batch = source.subList(consumed, end);
90 1 1. tryAdvance : Replaced integer addition with subtraction → KILLED
            consumed += batch.size();
91 3 1. tryAdvance : Replaced integer subtraction with addition → KILLED
2. tryAdvance : Replaced double division with multiplication → KILLED
3. tryAdvance : Replaced integer subtraction with addition → KILLED
            chunkSize = (int) Math.ceil(((double) (source.size() - consumed)) / --chunks);
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 → SURVIVED
        int remaining = source.size() - consumed;
102 4 1. trySplit : changed conditional boundary → SURVIVED
2. trySplit : changed conditional boundary → KILLED
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 multiplication with division → KILLED
        int midSize = midChunks * chunkSize;
108
109 1 1. trySplit : Replaced integer addition with subtraction → KILLED
        var subList = source.subList(consumed, consumed + midSize);
110
        var split = new BatchingSpliterator<>(subList, midChunks);
111
112 1 1. trySplit : Replaced integer addition with subtraction → KILLED
        consumed += midSize;
113 1 1. trySplit : Replaced integer subtraction with addition → KILLED
        chunks -= midChunks;
114 1 1. trySplit : Replaced integer subtraction with addition → SURVIVED
        maxChunks -= midChunks;
115 2 1. trySplit : Replaced integer subtraction with addition → KILLED
2. trySplit : Replaced double division with multiplication → KILLED
        chunkSize = (int) Math.ceil(((double) (source.size() - consumed)) / chunks);
116
117 1 1. trySplit : replaced return value with null for com/pivovarit/collectors/BatchingSpliterator::trySplit → KILLED
        return split;
118
    }
119
120
    @Override
121
    public long estimateSize() {
122 2 1. estimateSize : replaced long return with 0 for com/pivovarit/collectors/BatchingSpliterator::estimateSize → KILLED
2. estimateSize : negated conditional → KILLED
        return chunks == 0
123
          ? 0
124 2 1. estimateSize : Replaced integer subtraction with addition → KILLED
2. estimateSize : Replaced double division with multiplication → KILLED
          : Math.max(1, (int) Math.ceil((double) (source.size() - consumed) / chunkSize));
125
    }
126
127
    @Override
128
    public int characteristics() {
129 1 1. characteristics : replaced int return with 0 for com/pivovarit/collectors/BatchingSpliterator::characteristics → KILLED
        return IMMUTABLE | ORDERED | SIZED | SUBSIZED;
130
    }
131
}

Mutations

44

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]/[method:shouldReturnEmptyIfZeroParts()]
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:shouldReturnZeroForEmptyList()]
negated conditional → KILLED

50

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

56

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

58

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

59

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

60

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

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

61

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

63

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

72

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

76

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

81

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

87

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

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

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

90

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

91

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

3.3
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

92

1.1
Location : tryAdvance
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[method:shouldHandleExactDivisibility()]
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 : none
Replaced integer subtraction with addition → SURVIVED
Covering tests

102

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

2.2
Location : trySplit
Killed by : com.pivovarit.collectors.BatchingSpliteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.BatchingSpliteratorTest]/[method:shouldHandleSingleElementList()]
changed conditional boundary → KILLED

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]/[method:shouldSplitAndProcessIndependently()]
Replaced integer multiplication with division → KILLED

109

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

112

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

113

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

114

1.1
Location : trySplit
Killed by : none
Replaced integer subtraction with addition → SURVIVED
Covering tests

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

2.2
Location : trySplit
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

117

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

122

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

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

124

1.1
Location : estimateSize
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

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

129

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.22.0