• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

amaembo / streamex / #686

19 Jul 2026 09:26AM UTC coverage: 99.777% (-0.02%) from 99.794%
#686

push

amaembo
[#286] EntryStream.withoutKeys and withoutValues don't tolerate streams containing null keys and values respectively

4 of 4 new or added lines in 1 file covered. (100.0%)

4 existing lines in 3 files now uncovered.

5814 of 5827 relevant lines covered (99.78%)

1.0 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.5
/src/main/java/one/util/streamex/Internals.java
1
/*
2
 * Copyright 2015, 2024 StreamEx contributors
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
 *     http://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 one.util.streamex;
17

18
import org.jspecify.annotations.NonNull;
19
import org.jspecify.annotations.NullMarked;
20
import org.jspecify.annotations.Nullable;
21

22
import java.util.*;
23
import java.util.Map.Entry;
24
import java.util.function.*;
25
import java.util.stream.Collector;
26
import java.util.stream.Collector.Characteristics;
27

28
/* package */interface Internals {
29
    int INITIAL_SIZE = 128;
30
    Function<int[], Integer> UNBOX_INT = box -> box[0];
1✔
31
    Function<long[], Long> UNBOX_LONG = box -> box[0];
1✔
32
    Function<double[], Double> UNBOX_DOUBLE = box -> box[0];
1✔
33
    Object NONE = new Object();
1✔
34
    Set<Characteristics> NO_CHARACTERISTICS = EnumSet.noneOf(Characteristics.class);
1✔
35
    Set<Characteristics> UNORDERED_CHARACTERISTICS = EnumSet.of(Characteristics.UNORDERED);
1✔
36
    Set<Characteristics> UNORDERED_ID_CHARACTERISTICS = EnumSet.of(Characteristics.UNORDERED,
1✔
37
        Characteristics.IDENTITY_FINISH);
38
    Set<Characteristics> ID_CHARACTERISTICS = EnumSet.of(Characteristics.IDENTITY_FINISH);
1✔
39
    boolean IMMUTABLE_TO_LIST = isImmutableToSetToList();
1✔
40

41
    static boolean isImmutableToSetToList() {
42
        try {
43
            return Boolean.parseBoolean(System.getProperty("streamex.default.immutable", "false"));
1✔
UNCOV
44
        } catch (SecurityException e) {
×
UNCOV
45
            return false;
×
46
        }
47
    }
48

49
    static void checkNonNegative(String name, int value) {
50
        if (value < 0) {
1✔
51
            throw new IllegalArgumentException(name + " must be non-negative: " + value);
1✔
52
        }
53
    }
1✔
54

55
    final class ByteBuffer {
56
        int size = 0;
1✔
57
        byte[] data;
58

59
        ByteBuffer() {
1✔
60
            data = new byte[INITIAL_SIZE];
1✔
61
        }
1✔
62

63
        ByteBuffer(int size) {
1✔
64
            data = new byte[size];
1✔
65
        }
1✔
66

67
        void add(int n) {
68
            if (data.length == size) {
1✔
69
                data = Arrays.copyOf(data, data.length * 2);
1✔
70
            }
71
            data[size++] = (byte) n;
1✔
72
        }
1✔
73

74
        void addUnsafe(int n) {
75
            data[size++] = (byte) n;
1✔
76
        }
1✔
77

78
        void addAll(ByteBuffer buf) {
79
            if (data.length < buf.size + size) {
1✔
80
                data = Arrays.copyOf(data, buf.size + size);
1✔
81
            }
82
            System.arraycopy(buf.data, 0, data, size, buf.size);
1✔
83
            size += buf.size;
1✔
84
        }
1✔
85

86
        byte[] toArray() {
87
            return data.length == size ? data : Arrays.copyOfRange(data, 0, size);
1✔
88
        }
89
    }
90

91
    final class CharBuffer {
92
        int size = 0;
1✔
93
        char[] data;
94

95
        CharBuffer() {
1✔
96
            data = new char[INITIAL_SIZE];
1✔
97
        }
1✔
98

99
        CharBuffer(int size) {
1✔
100
            data = new char[size];
1✔
101
        }
1✔
102

103
        void add(int n) {
104
            if (data.length == size) {
1✔
105
                data = Arrays.copyOf(data, data.length * 2);
1✔
106
            }
107
            data[size++] = (char) n;
1✔
108
        }
1✔
109

110
        void addUnsafe(int n) {
111
            data[size++] = (char) n;
1✔
112
        }
1✔
113

114
        void addAll(CharBuffer buf) {
115
            if (data.length < buf.size + size) {
1✔
116
                data = Arrays.copyOf(data, buf.size + size);
1✔
117
            }
118
            System.arraycopy(buf.data, 0, data, size, buf.size);
1✔
119
            size += buf.size;
1✔
120
        }
1✔
121

122
        char[] toArray() {
123
            return data.length == size ? data : Arrays.copyOfRange(data, 0, size);
1✔
124
        }
125
    }
126

127
    final class ShortBuffer {
128
        int size = 0;
1✔
129
        short[] data;
130

131
        ShortBuffer() {
1✔
132
            data = new short[INITIAL_SIZE];
1✔
133
        }
1✔
134

135
        ShortBuffer(int size) {
1✔
136
            data = new short[size];
1✔
137
        }
1✔
138

139
        void add(int n) {
140
            if (data.length == size) {
1✔
141
                data = Arrays.copyOf(data, data.length * 2);
1✔
142
            }
143
            data[size++] = (short) n;
1✔
144
        }
1✔
145

146
        void addUnsafe(int n) {
147
            data[size++] = (short) n;
1✔
148
        }
1✔
149

150
        void addAll(ShortBuffer buf) {
151
            if (data.length < buf.size + size) {
1✔
152
                data = Arrays.copyOf(data, buf.size + size);
1✔
153
            }
154
            System.arraycopy(buf.data, 0, data, size, buf.size);
1✔
155
            size += buf.size;
1✔
156
        }
1✔
157

158
        short[] toArray() {
159
            return data.length == size ? data : Arrays.copyOfRange(data, 0, size);
1✔
160
        }
161
    }
162

163
    final class FloatBuffer {
164
        int size = 0;
1✔
165
        float[] data;
166

167
        FloatBuffer() {
1✔
168
            data = new float[INITIAL_SIZE];
1✔
169
        }
1✔
170

171
        FloatBuffer(int size) {
1✔
172
            data = new float[size];
1✔
173
        }
1✔
174

175
        void add(double n) {
176
            if (data.length == size) {
1✔
177
                data = Arrays.copyOf(data, data.length * 2);
1✔
178
            }
179
            data[size++] = (float) n;
1✔
180
        }
1✔
181

182
        void addUnsafe(double n) {
183
            data[size++] = (float) n;
1✔
184
        }
1✔
185

186
        void addAll(FloatBuffer buf) {
187
            if (data.length < buf.size + size) {
1✔
188
                data = Arrays.copyOf(data, buf.size + size);
1✔
189
            }
190
            System.arraycopy(buf.data, 0, data, size, buf.size);
1✔
191
            size += buf.size;
1✔
192
        }
1✔
193

194
        float[] toArray() {
195
            return data.length == size ? data : Arrays.copyOfRange(data, 0, size);
1✔
196
        }
197
    }
198

199
    final class IntBuffer {
200
        int size = 0;
1✔
201
        int[] data;
202

203
        IntBuffer() {
1✔
204
            data = new int[INITIAL_SIZE];
1✔
205
        }
1✔
206

207
        IntBuffer(int size) {
1✔
208
            data = new int[size];
1✔
209
        }
1✔
210

211
        void add(int n) {
212
            if (data.length == size) {
1✔
213
                data = Arrays.copyOf(data, data.length * 2);
1✔
214
            }
215
            data[size++] = n;
1✔
216
        }
1✔
217

218
        void addAll(IntBuffer buf) {
219
            if (data.length < buf.size + size) {
1✔
220
                data = Arrays.copyOf(data, buf.size + size);
1✔
221
            }
222
            System.arraycopy(buf.data, 0, data, size, buf.size);
1✔
223
            size += buf.size;
1✔
224
        }
1✔
225
        
226
        IntStreamEx stream() {
227
            return IntStreamEx.of(data, 0, size);
1✔
228
        }
229

230
        int[] toArray() {
231
            return data.length == size ? data : Arrays.copyOfRange(data, 0, size);
1✔
232
        }
233
    }
234

235
    final class LongBuffer {
236
        int size = 0;
1✔
237
        long[] data;
238

239
        LongBuffer() {
1✔
240
            data = new long[INITIAL_SIZE];
1✔
241
        }
1✔
242

243
        LongBuffer(int size) {
1✔
244
            data = new long[size];
1✔
245
        }
1✔
246

247
        void add(long n) {
248
            if (data.length == size) {
1✔
249
                data = Arrays.copyOf(data, data.length * 2);
1✔
250
            }
251
            data[size++] = n;
1✔
252
        }
1✔
253

254
        void addAll(LongBuffer buf) {
255
            if (data.length < buf.size + size) {
1✔
256
                data = Arrays.copyOf(data, buf.size + size);
1✔
257
            }
258
            System.arraycopy(buf.data, 0, data, size, buf.size);
1✔
259
            size += buf.size;
1✔
260
        }
1✔
261

262
        LongStreamEx stream() {
263
            return LongStreamEx.of(data, 0, size);
1✔
264
        }
265

266
        long[] toArray() {
267
            return data.length == size ? data : Arrays.copyOfRange(data, 0, size);
1✔
268
        }
269
    }
270

271
    final class DoubleBuffer {
272
        int size = 0;
1✔
273
        double[] data;
274

275
        DoubleBuffer() {
1✔
276
            data = new double[INITIAL_SIZE];
1✔
277
        }
1✔
278

279
        DoubleBuffer(int size) {
1✔
280
            data = new double[size];
1✔
281
        }
1✔
282

283
        void add(double n) {
284
            if (data.length == size) {
1✔
285
                data = Arrays.copyOf(data, data.length * 2);
1✔
286
            }
287
            data[size++] = n;
1✔
288
        }
1✔
289

290
        void addAll(DoubleBuffer buf) {
291
            if (data.length < buf.size + size) {
1✔
292
                data = Arrays.copyOf(data, buf.size + size);
1✔
293
            }
294
            System.arraycopy(buf.data, 0, data, size, buf.size);
1✔
295
            size += buf.size;
1✔
296
        }
1✔
297

298
        DoubleStreamEx stream() {
299
            return DoubleStreamEx.of(data, 0, size);
1✔
300
        }
301

302
        double[] toArray() {
303
            return data.length == size ? data : Arrays.copyOfRange(data, 0, size);
1✔
304
        }
305
    }
306

307
    @NullMarked
308
    final class BooleanMap<T> extends AbstractMap<Boolean, T> {
309
        T trueValue, falseValue;
310

311
        BooleanMap(T trueValue, T falseValue) {
1✔
312
            this.trueValue = trueValue;
1✔
313
            this.falseValue = falseValue;
1✔
314
        }
1✔
315

316
        @Override
317
        public boolean containsKey(Object key) {
318
            return key instanceof Boolean;
1✔
319
        }
320

321
        @Override
322
        public @Nullable T get(Object key) {
323
            if (Boolean.TRUE.equals(key))
1✔
324
                return trueValue;
1✔
325
            if (Boolean.FALSE.equals(key))
1✔
326
                return falseValue;
1✔
327
            return null;
1✔
328
        }
329

330
        @Override
331
        public Set<Map.Entry<Boolean, T>> entrySet() {
332
            return new AbstractSet<Map.Entry<Boolean, T>>() {
1✔
333
                @Override
334
                public Iterator<Map.Entry<Boolean, T>> iterator() {
335
                    return Arrays.<Map.Entry<Boolean, T>>asList(new SimpleEntry<>(Boolean.TRUE, trueValue),
1✔
336
                        new SimpleEntry<>(Boolean.FALSE, falseValue)).iterator();
1✔
337
                }
338

339
                @Override
340
                public int size() {
341
                    return 2;
1✔
342
                }
343
            };
344
        }
345

346
        @Override
347
        public int size() {
348
            return 2;
1✔
349
        }
350

351
        @SuppressWarnings({ "unchecked", "rawtypes" })
352
        static <A, R> PartialCollector<BooleanMap<A>, Map<Boolean, R>> partialCollector(Collector<?, A, R> downstream) {
353
            Supplier<A> downstreamSupplier = downstream.supplier();
1✔
354
            Supplier<BooleanMap<A>> supplier = () -> new BooleanMap<>(downstreamSupplier.get(), downstreamSupplier
1✔
355
                    .get());
1✔
356
            BinaryOperator<A> downstreamCombiner = downstream.combiner();
1✔
357
            BiConsumer<BooleanMap<A>, BooleanMap<A>> merger = (left, right) -> {
1✔
358
                left.trueValue = downstreamCombiner.apply(left.trueValue, right.trueValue);
1✔
359
                left.falseValue = downstreamCombiner.apply(left.falseValue, right.falseValue);
1✔
360
            };
1✔
361
            if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
1✔
362
                return (PartialCollector) new PartialCollector<>(supplier, merger, Function.identity(),
1✔
363
                        ID_CHARACTERISTICS);
364
            }
365
            Function<A, R> downstreamFinisher = downstream.finisher();
1✔
366
            return new PartialCollector<>(supplier, merger, par -> new BooleanMap<>(downstreamFinisher
1✔
367
                    .apply(par.trueValue), downstreamFinisher.apply(par.falseValue)), NO_CHARACTERISTICS);
1✔
368
        }
369
    }
370

371
    abstract class BaseCollector<T, A, R> implements MergingCollector<T, A, R> {
372
        final Supplier<A> supplier;
373
        final BiConsumer<A, A> merger;
374
        final Function<A, R> finisher;
375
        final Set<Characteristics> characteristics;
376

377
        BaseCollector(Supplier<A> supplier, BiConsumer<A, A> merger, Function<A, R> finisher,
378
                Set<Characteristics> characteristics) {
1✔
379
            this.supplier = supplier;
1✔
380
            this.merger = merger;
1✔
381
            this.finisher = finisher;
1✔
382
            this.characteristics = characteristics;
1✔
383
        }
1✔
384

385
        @Override
386
        public Set<Characteristics> characteristics() {
387
            return characteristics;
1✔
388
        }
389

390
        @Override
391
        public Supplier<A> supplier() {
392
            return supplier;
1✔
393
        }
394

395
        @Override
396
        public Function<A, R> finisher() {
397
            return finisher;
1✔
398
        }
399

400
        @Override
401
        public BiConsumer<A, A> merger() {
402
            return merger;
1✔
403
        }
404
    }
405

406
    @NullMarked
407
    final class PartialCollector<A extends @Nullable Object, R extends @Nullable Object>
408
            extends BaseCollector<Object, A, R> {
409
        PartialCollector(Supplier<A> supplier, BiConsumer<A, A> merger, Function<A, R> finisher,
410
                Set<Characteristics> characteristics) {
411
            super(supplier, merger, finisher, characteristics);
1✔
412
        }
1✔
413

414
        @Override
415
        public BiConsumer<A, Object> accumulator() {
416
            throw new UnsupportedOperationException();
1✔
417
        }
418

419
        IntCollector<A, R> asInt(ObjIntConsumer<A> intAccumulator) {
420
            return new IntCollectorImpl<>(supplier, intAccumulator, merger, finisher, characteristics);
1✔
421
        }
422

423
        LongCollector<A, R> asLong(ObjLongConsumer<A> longAccumulator) {
424
            return new LongCollectorImpl<>(supplier, longAccumulator, merger, finisher, characteristics);
1✔
425
        }
426

427
        DoubleCollector<A, R> asDouble(ObjDoubleConsumer<A> doubleAccumulator) {
428
            return new DoubleCollectorImpl<>(supplier, doubleAccumulator, merger, finisher, characteristics);
1✔
429
        }
430

431
        <T> Collector<T, A, R> asRef(BiConsumer<A, T> accumulator) {
432
            return Collector.of(supplier, accumulator, combiner(), finisher, characteristics
1✔
433
                    .toArray(new Characteristics[0]));
1✔
434
        }
435

436
        <T> Collector<T, A, R> asCancellable(BiConsumer<A, T> accumulator, Predicate<A> finished) {
437
            return new CancellableCollectorImpl<>(supplier, accumulator, combiner(), finisher, finished,
1✔
438
                    characteristics);
439
        }
440

441
        static PartialCollector<int[], Integer> intSum() {
442
            return new PartialCollector<>(() -> new int[1], (box1, box2) -> box1[0] += box2[0], UNBOX_INT,
1✔
443
                    UNORDERED_CHARACTERISTICS);
444
        }
445

446
        static PartialCollector<long[], Long> longSum() {
447
            return new PartialCollector<>(() -> new long[1], (box1, box2) -> box1[0] += box2[0], UNBOX_LONG,
1✔
448
                    UNORDERED_CHARACTERISTICS);
449
        }
450

451
        static PartialCollector<ObjIntBox<BitSet>, boolean[]> booleanArray() {
452
            return new PartialCollector<>(() -> new ObjIntBox<>(new BitSet(), 0), (box1, box2) -> {
1✔
453
                box2.a.stream().forEach(i -> box1.a.set(i + box1.b));
1✔
454
                box1.b = StrictMath.addExact(box1.b, box2.b);
1✔
455
            }, box -> {
1✔
456
                boolean[] res = new boolean[box.b];
1✔
457
                box.a.stream().forEach(i -> res[i] = true);
1✔
458
                return res;
1✔
459
            }, NO_CHARACTERISTICS);
460
        }
461

462
        @SuppressWarnings("unchecked")
463
        static <K, D, A extends @Nullable Object, M extends Map<K, D>> PartialCollector<Map<K, A>, M> grouping(Supplier<M> mapFactory,
464
                Collector<?, A, D> downstream) {
465
            BinaryOperator<A> downstreamMerger = downstream.combiner();
1✔
466
            BiConsumer<Map<K, A>, Map<K, A>> merger = (map1, map2) -> {
1✔
467
                for (Map.Entry<K, A> e : map2.entrySet())
1✔
468
                    map1.merge(e.getKey(), e.getValue(), downstreamMerger);
1✔
469
            };
1✔
470

471
            if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
1✔
472
                return (PartialCollector<Map<K, A>, M>) new PartialCollector<>((Supplier<Map<K, A>>) mapFactory,
1✔
473
                        merger, Function.identity(), ID_CHARACTERISTICS);
1✔
474
            }
475
            Function<A, D> downstreamFinisher = downstream.finisher();
1✔
476
            return new PartialCollector<>((Supplier<Map<K, A>>) mapFactory, merger, map -> {
1✔
477
                map.replaceAll((k, v) -> ((Function<A, A>) downstreamFinisher).apply(v));
1✔
478
                return (M) map;
1✔
479
            }, NO_CHARACTERISTICS);
480
        }
481

482
        static PartialCollector<StringBuilder, String> joining(CharSequence delimiter, @Nullable CharSequence prefix,
483
                @Nullable CharSequence suffix, boolean hasPS) {
484
            BiConsumer<StringBuilder, StringBuilder> merger = (sb1, sb2) -> {
1✔
485
                if (sb2.length() > 0) {
1✔
486
                    if (sb1.length() > 0)
1✔
487
                        sb1.append(delimiter);
1✔
488
                    sb1.append(sb2);
1✔
489
                }
490
            };
1✔
491
            Supplier<StringBuilder> supplier = StringBuilder::new;
1✔
492
            if (hasPS)
1✔
493
                return new PartialCollector<>(supplier, merger, sb -> String.valueOf(prefix) + sb + suffix,
1✔
494
                        NO_CHARACTERISTICS);
495
            return new PartialCollector<>(supplier, merger, StringBuilder::toString, NO_CHARACTERISTICS);
1✔
496
        }
497
    }
498

499
    @NullMarked
500
    final class CancellableCollectorImpl<T, A extends @Nullable Object, R extends @Nullable Object>
501
            extends CancellableCollector<T, A, R> {
502
        private final Supplier<A> supplier;
503
        private final BiConsumer<A, T> accumulator;
504
        private final BinaryOperator<A> combiner;
505
        private final Function<A, R> finisher;
506
        private final Predicate<A> finished;
507
        private final Set<Characteristics> characteristics;
508

509
        CancellableCollectorImpl(Supplier<A> supplier, BiConsumer<A, T> accumulator, BinaryOperator<A> combiner,
510
                                 Function<A, R> finisher, Predicate<A> finished,
511
                                 Set<java.util.stream.Collector.Characteristics> characteristics) {
1✔
512
            this.supplier = supplier;
1✔
513
            this.accumulator = accumulator;
1✔
514
            this.combiner = combiner;
1✔
515
            this.finisher = finisher;
1✔
516
            this.finished = finished;
1✔
517
            this.characteristics = characteristics;
1✔
518
        }
1✔
519

520
        @Override
521
        public Supplier<A> supplier() {
522
            return supplier;
1✔
523
        }
524

525
        @Override
526
        public BiConsumer<A, T> accumulator() {
527
            return accumulator;
1✔
528
        }
529

530
        @Override
531
        public BinaryOperator<A> combiner() {
532
            return combiner;
1✔
533
        }
534

535
        @Override
536
        public Function<A, R> finisher() {
537
            return finisher;
1✔
538
        }
539

540
        @Override
541
        public Set<Characteristics> characteristics() {
542
            return characteristics;
1✔
543
        }
544

545
        @Override
546
        Predicate<A> finished() {
547
            return finished;
1✔
548
        }
549
    }
550

551
    @NullMarked
552
    final class IntCollectorImpl<A extends @Nullable Object, R extends @Nullable Object>
553
            extends BaseCollector<Integer, A, R> implements IntCollector<A, R> {
554
        private final ObjIntConsumer<A> intAccumulator;
555

556
        IntCollectorImpl(Supplier<A> supplier, ObjIntConsumer<A> intAccumulator, BiConsumer<A, A> merger,
557
                         Function<A, R> finisher, Set<Characteristics> characteristics) {
558
            super(supplier, merger, finisher, characteristics);
1✔
559
            this.intAccumulator = intAccumulator;
1✔
560
        }
1✔
561

562
        @Override
563
        public ObjIntConsumer<A> intAccumulator() {
564
            return intAccumulator;
1✔
565
        }
566
    }
567

568
    @NullMarked
569
    final class LongCollectorImpl<A extends @Nullable Object, R extends @Nullable Object>
570
            extends BaseCollector<Long, A, R> implements LongCollector<A, R> {
571
        private final ObjLongConsumer<A> longAccumulator;
572

573
        LongCollectorImpl(Supplier<A> supplier, ObjLongConsumer<A> longAccumulator, BiConsumer<A, A> merger,
574
                          Function<A, R> finisher, Set<Characteristics> characteristics) {
575
            super(supplier, merger, finisher, characteristics);
1✔
576
            this.longAccumulator = longAccumulator;
1✔
577
        }
1✔
578

579
        @Override
580
        public ObjLongConsumer<A> longAccumulator() {
581
            return longAccumulator;
1✔
582
        }
583
    }
584

585
    @NullMarked
586
    final class DoubleCollectorImpl<A extends @Nullable Object, R extends @Nullable Object>
587
            extends BaseCollector<Double, A, R> implements DoubleCollector<A, R> {
588
        private final ObjDoubleConsumer<A> doubleAccumulator;
589

590
        DoubleCollectorImpl(Supplier<A> supplier, ObjDoubleConsumer<A> doubleAccumulator,
591
                            BiConsumer<A, A> merger, Function<A, R> finisher, Set<Characteristics> characteristics) {
592
            super(supplier, merger, finisher, characteristics);
1✔
593
            this.doubleAccumulator = doubleAccumulator;
1✔
594
        }
1✔
595

596
        @Override
597
        public ObjDoubleConsumer<A> doubleAccumulator() {
598
            return doubleAccumulator;
1✔
599
        }
600
    }
601

602
    class Box<A extends @Nullable Object> implements Consumer<A> {
603
        A a;
604
        
605
        Box() {
1✔
606
        }
1✔
607
        
608
        Box(A obj) {
1✔
609
            this.a = obj;
1✔
610
        }
1✔
611

612
        @Override
613
        public void accept(A a) {
614
            this.a = a;
1✔
615
        }
1✔
616

617
        static <A, R> PartialCollector<Box<A>, R> partialCollector(Collector<?, A, R> c) {
618
            Supplier<A> supplier = c.supplier();
1✔
619
            BinaryOperator<A> combiner = c.combiner();
1✔
620
            Function<A, R> finisher = c.finisher();
1✔
621
            return new PartialCollector<>(() -> new Box<>(supplier.get()), (box1, box2) -> box1.a = combiner.apply(
1✔
622
                box1.a, box2.a), box -> finisher.apply(box.a), NO_CHARACTERISTICS);
1✔
623
        }
624

625
        static <A> Optional<@NonNull A> asOptional(@Nullable Box<@Nullable A> box) {
626
            return box == null ? Optional.empty() : Optional.of(box.a);
1✔
627
        }
628
    }
629

630
    /**
631
     * A box of two elements with special equality semantics: only the second element matters for equality.
632
     * 
633
     * @param <A> type of the first element
634
     * @param <B> type of the second element
635
     */
636
    final class PairBox<A extends @Nullable Object, B extends @Nullable Object> extends Box<A> {
637
        B b;
638

639
        PairBox(A a, B b) {
640
            super(a);
1✔
641
            this.b = b;
1✔
642
        }
1✔
643

644
        static <T> PairBox<T, T> single(T a) {
645
            return new PairBox<>(a, a);
1✔
646
        }
647

648
        @Override
649
        public int hashCode() {
650
            return Objects.hashCode(b);
1✔
651
        }
652

653
        @Override
654
        public boolean equals(Object obj) {
655
            return obj instanceof PairBox && Objects.equals(b, ((PairBox<?, ?>) obj).b);
1✔
656
        }
657
    }
658

659
    final class ObjIntBox<A extends @Nullable Object> extends Box<A> implements Entry<Integer, A> {
660
        int b;
661

662
        ObjIntBox(@Nullable A a, int b) {
663
            super(a);
1✔
664
            this.b = b;
1✔
665
        }
1✔
666

667
        @Override
668
        public Integer getKey() {
669
            return b;
1✔
670
        }
671

672
        @Override
673
        public A getValue() {
674
            return a;
1✔
675
        }
676

677
        @Override
678
        public A setValue(A value) {
679
            throw new UnsupportedOperationException();
1✔
680
        }
681

682
        @Override
683
        public int hashCode() {
684
            return Integer.hashCode(b) ^ (a == null ? 0 : a.hashCode());
1✔
685
        }
686

687
        @Override
688
        public boolean equals(Object o) {
689
            if (!(o instanceof Map.Entry))
1✔
690
                return false;
1✔
691
            Map.Entry<?, ?> e = (Map.Entry<?, ?>) o;
1✔
692
            return getKey().equals(e.getKey()) && Objects.equals(a, e.getValue());
1✔
693
        }
694

695
        @Override
696
        public String toString() {
697
            return b + "=" + a;
1✔
698
        }
699
    }
700

701
    final class ObjLongBox<A extends @Nullable Object> extends Box<A> implements Entry<A, Long> {
702
        long b;
703

704
        ObjLongBox(A a, long b) {
705
            super(a);
1✔
706
            this.b = b;
1✔
707
        }
1✔
708

709
        @Override
710
        public A getKey() {
711
            return a;
1✔
712
        }
713

714
        @Override
715
        public Long getValue() {
716
            return b;
1✔
717
        }
718

719
        @Override
720
        public Long setValue(Long value) {
721
            throw new UnsupportedOperationException();
1✔
722
        }
723

724
        @Override
725
        public int hashCode() {
726
            return Long.hashCode(b) ^ (a == null ? 0 : a.hashCode());
1✔
727
        }
728

729
        @Override
730
        public boolean equals(Object o) {
731
            if (!(o instanceof Map.Entry))
1✔
732
                return false;
1✔
733
            Map.Entry<?, ?> e = (Map.Entry<?, ?>) o;
1✔
734
            return getValue().equals(e.getValue()) && Objects.equals(a, e.getKey());
1✔
735
        }
736

737
        @Override
738
        public String toString() {
739
            return a + "=" + b;
1✔
740
        }
741
    }
742

743
    final class ObjDoubleBox<A> extends Box<A> {
744
        double b;
745

746
        ObjDoubleBox(A a, double b) {
747
            super(a);
1✔
748
            this.b = b;
1✔
749
        }
1✔
750
    }
751

752
    final class PrimitiveBox {
1✔
753
        int i;
754
        double d;
755
        long l;
756
        boolean b;
757

758
        OptionalInt asInt() {
759
            return b ? OptionalInt.of(i) : OptionalInt.empty();
1✔
760
        }
761

762
        OptionalLong asLong() {
763
            return b ? OptionalLong.of(l) : OptionalLong.empty();
1✔
764
        }
765

766
        OptionalDouble asDouble() {
767
            return b ? OptionalDouble.of(d) : OptionalDouble.empty();
1✔
768
        }
769

770
        static final BiConsumer<PrimitiveBox, PrimitiveBox> MAX_LONG = (box1, box2) -> {
1✔
771
            if (box2.b && (!box1.b || box1.l < box2.l)) {
1✔
772
                box1.from(box2);
1✔
773
            }
774
        };
1✔
775

776
        static final BiConsumer<PrimitiveBox, PrimitiveBox> MIN_LONG = (box1, box2) -> {
1✔
777
            if (box2.b && (!box1.b || box1.l > box2.l)) {
1✔
778
                box1.from(box2);
1✔
779
            }
780
        };
1✔
781

782
        static final BiConsumer<PrimitiveBox, PrimitiveBox> MAX_INT = (box1, box2) -> {
1✔
783
            if (box2.b && (!box1.b || box1.i < box2.i)) {
1✔
784
                box1.from(box2);
1✔
785
            }
786
        };
1✔
787

788
        static final BiConsumer<PrimitiveBox, PrimitiveBox> MIN_INT = (box1, box2) -> {
1✔
789
            if (box2.b && (!box1.b || box1.i > box2.i)) {
1✔
790
                box1.from(box2);
1✔
791
            }
792
        };
1✔
793

794
        static final BiConsumer<PrimitiveBox, PrimitiveBox> MAX_DOUBLE = (box1, box2) -> {
1✔
795
            if (box2.b && (!box1.b || Double.compare(box1.d, box2.d) < 0)) {
1✔
796
                box1.from(box2);
1✔
797
            }
798
        };
1✔
799

800
        static final BiConsumer<PrimitiveBox, PrimitiveBox> MIN_DOUBLE = (box1, box2) -> {
1✔
801
            if (box2.b && (!box1.b || Double.compare(box1.d, box2.d) > 0)) {
1✔
802
                box1.from(box2);
1✔
803
            }
804
        };
1✔
805

806
        public void from(PrimitiveBox box) {
807
            b = box.b;
1✔
808
            i = box.i;
1✔
809
            d = box.d;
1✔
810
            l = box.l;
1✔
811
        }
1✔
812
    }
813

814
    final class AverageLong {
1✔
815
        long hi, lo, cnt;
816

817
        public void accept(long val) {
818
            cnt++;
1✔
819
            int cmp = Long.compareUnsigned(lo, lo += val);
1✔
820
            if (val > 0) {
1✔
821
                if (cmp > 0)
1✔
822
                    hi++;
1✔
823
            } else if (cmp < 0)
1✔
824
                hi--;
1✔
825
        }
1✔
826

827
        public AverageLong combine(AverageLong other) {
828
            cnt += other.cnt;
1✔
829
            hi += other.hi;
1✔
830
            if (Long.compareUnsigned(lo, lo += other.lo) > 0) {
1✔
831
                hi++;
1✔
832
            }
833
            return this;
1✔
834
        }
835

836
        public OptionalDouble result() {
837
            if (cnt == 0)
1✔
838
                return OptionalDouble.empty();
1✔
839
            return OptionalDouble.of(((double) (hi + (lo < 0 ? 1 : 0)) / cnt) * 0x1.0p64 + ((double) lo) / cnt);
1✔
840
        }
841
    }
842

843
    @SuppressWarnings("serial")
844
    class CancelException extends Error {
845
        CancelException() {
846
            // Calling this constructor makes the Exception construction much
847
            // faster (like 0.3us vs 1.7us)
848
            super(null, null, false, false);
1✔
849
        }
1✔
850
    }
851

852
    @NullMarked
853
    class ArrayCollection extends AbstractCollection<Object> {
854
        private final Object[] arr;
855

856
        ArrayCollection(Object[] arr) {
1✔
857
            this.arr = arr;
1✔
858
        }
1✔
859

860
        @Override
861
        public Iterator<Object> iterator() {
862
            return Arrays.asList(arr).iterator();
1✔
863
        }
864

865
        @Override
866
        public int size() {
867
            return arr.length;
1✔
868
        }
869

870
        @Override
871
        public Object[] toArray() {
872
            // intentional contract violation here:
873
            // this way new ArrayList(new ArrayCollection(arr)) will not copy
874
            // array at all
875
            return arr;
1✔
876
        }
877
    }
878

879
    /**
880
     * A spliterator which may perform tail-stream optimization
881
     *
882
     * @param <T> the type of elements returned by this spliterator
883
     */
884
    interface TailSpliterator<T> extends Spliterator<T> {
885
        /**
886
         * Either advances by one element feeding it to consumer and returns
887
         * this or returns tail spliterator (this spliterator becomes invalid
888
         * and tail must be used instead) or returns null if traversal finished.
889
         * 
890
         * @param action to feed the next element into
891
         * @return tail spliterator, this or null
892
         */
893
        Spliterator<T> tryAdvanceOrTail(Consumer<? super T> action);
894

895
        /**
896
         * Traverses this spliterator and returns null if traversal is completed
897
         * or tail spliterator if it must be used for further traversal.
898
         * 
899
         * @param action to feed the elements into
900
         * @return tail spliterator or null (never returns this)
901
         */
902
        Spliterator<T> forEachOrTail(Consumer<? super T> action);
903

904
        static <T> Spliterator<T> tryAdvanceWithTail(Spliterator<T> target, Consumer<? super T> action) {
905
            while (true) {
906
                if (target instanceof TailSpliterator) {
1✔
907
                    Spliterator<T> spltr = ((TailSpliterator<T>) target).tryAdvanceOrTail(action);
1✔
908
                    if (spltr == null || spltr == target)
1✔
909
                        return spltr;
1✔
910
                    target = spltr;
1✔
911
                } else {
1✔
912
                    return target.tryAdvance(action) ? target : null;
1✔
913
                }
914
            }
915
        }
916

917
        static <T> void forEachWithTail(Spliterator<T> target, Consumer<? super T> action) {
918
            while (true) {
919
                if (target instanceof TailSpliterator) {
1✔
920
                    Spliterator<T> spltr = ((TailSpliterator<T>) target).forEachOrTail(action);
1✔
921
                    if (spltr == null)
1✔
922
                        break;
1✔
923
                    target = spltr;
1✔
924
                } else {
1✔
925
                    target.forEachRemaining(action);
1✔
926
                    break;
1✔
927
                }
928
            }
929
        }
1✔
930
    }
931

932
    abstract class CloneableSpliterator<T, S extends CloneableSpliterator<T, ?>> implements Spliterator<T>,
1✔
933
            Cloneable {
934
        @SuppressWarnings("unchecked")
935
        S doClone() {
936
            try {
937
                return (S) this.clone();
1✔
938
            } catch (CloneNotSupportedException e) {
1✔
939
                throw new InternalError();
1✔
940
            }
941
        }
942
    }
943

944
    static ObjIntConsumer<StringBuilder> joinAccumulatorInt(CharSequence delimiter) {
945
        return (sb, i) -> (sb.length() > 0 ? sb.append(delimiter) : sb).append(i);
1✔
946
    }
947

948
    static ObjLongConsumer<StringBuilder> joinAccumulatorLong(CharSequence delimiter) {
949
        return (sb, i) -> (sb.length() > 0 ? sb.append(delimiter) : sb).append(i);
1✔
950
    }
951

952
    static ObjDoubleConsumer<StringBuilder> joinAccumulatorDouble(CharSequence delimiter) {
953
        return (sb, i) -> (sb.length() > 0 ? sb.append(delimiter) : sb).append(i);
1✔
954
    }
955

956
    static <T> BinaryOperator<T> selectFirst() {
957
        return (u, v) -> u;
1✔
958
    }
959

960
    static <T> Predicate<T> alwaysTrue() {
961
        return t -> true;
1✔
962
    }
963
    
964
    static int checkLength(int a, int b) {
965
        if (a != b)
1✔
966
            throw new IllegalArgumentException("Length differs: " + a + " != " + b);
1✔
967
        return a;
1✔
968
    }
969

970
    static void rangeCheck(int arrayLength, int startInclusive, int endExclusive) {
971
        if (startInclusive > endExclusive) {
1✔
972
            throw new ArrayIndexOutOfBoundsException("startInclusive(" + startInclusive + ") > endExclusive("
1✔
973
                + endExclusive + ")");
974
        }
975
        if (startInclusive < 0) {
1✔
976
            throw new ArrayIndexOutOfBoundsException(startInclusive);
1✔
977
        }
978
        if (endExclusive > arrayLength) {
1✔
979
            throw new ArrayIndexOutOfBoundsException(endExclusive);
1✔
980
        }
981
    }
1✔
982

983
    static <A> Predicate<A> finished(Collector<?, A, ?> collector) {
984
        if (collector instanceof CancellableCollector)
1✔
985
            return ((CancellableCollector<?, A, ?>) collector).finished();
1✔
986
        return null;
1✔
987
    }
988

989
    @SuppressWarnings("unchecked")
990
    static <T> T none() {
991
        return (T) NONE;
1✔
992
    }
993

994
    static <T> int drainTo(T[] array, Spliterator<T> spliterator) {
995
        Box<T> box = new Box<>();
1✔
996
        int index = 0;
1✔
997
        while (index < array.length && spliterator.tryAdvance(box)) {
1✔
998
            array[index++] = box.a;
1✔
999
        }
1000
        return index;
1✔
1001
    }
1002

1003
    static int intSize(Spliterator<?> spliterator) {
1004
        long size = spliterator.getExactSizeIfKnown();
1✔
1005
        if (size < -1) {
1✔
1006
            throw new IllegalArgumentException("Spliterator violates its contract: getExactSizeIfKnown() = " + size);
1✔
1007
        }
1008
        if (size > Integer.MAX_VALUE) {
1✔
1009
            throw new OutOfMemoryError("Stream size exceeds Integer.MAX_VALUE: " + size);
1✔
1010
        }
1011
        return (int) size;
1✔
1012
    }
1013
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc