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

amaembo / streamex / #673

29 Nov 2023 08:51AM UTC coverage: 99.69%. Remained the same
#673

push

web-flow
Merge pull request #274 from Kivanval/fix/desc

Correcting a comment in StreamEx.java

5787 of 5805 relevant lines covered (99.69%)

1.0 hits per line

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

99.6
/src/main/java/one/util/streamex/PairSpliterator.java
1
/*
2
 * Copyright 2015, 2023 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 java.util.Spliterator;
19
import java.util.function.BiConsumer;
20
import java.util.function.BiFunction;
21
import java.util.function.Consumer;
22
import java.util.function.DoubleBinaryOperator;
23
import java.util.function.DoubleConsumer;
24
import java.util.function.DoubleUnaryOperator;
25
import java.util.function.Function;
26
import java.util.function.IntBinaryOperator;
27
import java.util.function.IntConsumer;
28
import java.util.function.IntUnaryOperator;
29
import java.util.function.LongBinaryOperator;
30
import java.util.function.LongConsumer;
31
import java.util.function.LongUnaryOperator;
32

33
import static one.util.streamex.Internals.CloneableSpliterator;
34
import static one.util.streamex.Internals.NONE;
35
import static one.util.streamex.Internals.TailSpliterator;
36
import static one.util.streamex.Internals.none;
37

38
/**
39
 * @author Tagir Valeev
40
 */
41
/* package */abstract class PairSpliterator<T, S extends Spliterator<T>, R, SS extends PairSpliterator<T, S, R, SS>>
42
        extends CloneableSpliterator<R, SS> {
43
    static final int MODE_PAIRS = 0;
44
    static final int MODE_MAP_FIRST = 1;
45
    static final int MODE_MAP_LAST = 2;
46
    static final int MODE_MAP_FIRST_OR_ELSE = 3;
47
    static final int MODE_MAP_LAST_OR_ELSE = 4;
48
    
49
    static final Sink<?> EMPTY = new Sink<>(null);
1✔
50
    // Common lock for all the derived spliterators
51
    final Object lock = new Object();
1✔
52
    final int mode;
53
    S source;
54
    @SuppressWarnings("unchecked")
1✔
55
    Sink<T> left = (Sink<T>) EMPTY;
56
    @SuppressWarnings("unchecked")
1✔
57
    Sink<T> right = (Sink<T>) EMPTY;
58

59
    static final class Sink<T> {
60
        Sink<T> other;
61
        private T payload = none();
1✔
62
        private final Object lock;
63

64
        Sink(Object lock) {
1✔
65
            this.lock = lock;
1✔
66
        }
1✔
67

68
        boolean push(T payload, BiConsumer<T, T> fn, boolean isLeft) {
69
            if (lock == null)
1✔
70
                return false;
1✔
71
            T otherPayload;
72
            synchronized (lock) {
1✔
73
                Sink<T> that = other;
1✔
74
                if (that == null)
1✔
75
                    return false;
1✔
76
                otherPayload = that.payload;
1✔
77
                if (otherPayload == NONE) {
1✔
78
                    this.payload = payload;
1✔
79
                    return false;
1✔
80
                }
81
                other = null;
1✔
82
                that.clear();
1✔
83
            }
1✔
84
            if (isLeft)
1✔
85
                fn.accept(payload, otherPayload);
1✔
86
            else
87
                fn.accept(otherPayload, payload);
1✔
88
            return true;
1✔
89
        }
90

91
        boolean connect(Sink<T> right, BiConsumer<T, T> fn) {
92
            if (lock == null)
1✔
93
                return false;
1✔
94
            T a, b;
95
            synchronized (lock) {
1✔
96
                Sink<T> leftLeft = this.other;
1✔
97
                Sink<T> rightRight = right.other;
1✔
98
                if (leftLeft == null || rightRight == null) {
1✔
99
                    if (rightRight != null)
1✔
100
                        rightRight.clear();
×
101
                    if (leftLeft != null)
1✔
102
                        leftLeft.clear();
1✔
103
                    return false;
1✔
104
                }
105
                rightRight.other = leftLeft;
1✔
106
                leftLeft.other = rightRight;
1✔
107
                if (leftLeft.payload == NONE || rightRight.payload == NONE)
1✔
108
                    return false;
1✔
109
                a = leftLeft.payload;
1✔
110
                b = rightRight.payload;
1✔
111
                leftLeft.clear();
1✔
112
                rightRight.clear();
1✔
113
            }
1✔
114
            fn.accept(a, b);
1✔
115
            return true;
1✔
116
        }
117

118
        void clear() {
119
            other = null;
1✔
120
            payload = none();
1✔
121
        }
1✔
122
    }
123

124
    PairSpliterator(S source, int mode, T headTail) {
1✔
125
        this.source = source;
1✔
126
        this.mode = mode;
1✔
127
        if (mode != MODE_PAIRS) {
1✔
128
            Sink<T> sink = new Sink<>(this.lock);
1✔
129
            Sink<T> other = new Sink<>(this.lock);
1✔
130
            sink.other = other;
1✔
131
            other.other = sink;
1✔
132
            other.push(headTail, null, true);
1✔
133
            if (mode == MODE_MAP_FIRST || mode == MODE_MAP_FIRST_OR_ELSE)
1✔
134
                this.left = sink;
1✔
135
            else
136
                this.right = sink;
1✔
137
        }
138
    }
1✔
139
    
140
    @Override
141
    public long estimateSize() {
142
        long size = source.estimateSize();
1✔
143
        if (size == Long.MAX_VALUE || size == 0)
1✔
144
            return size;
1✔
145
        return size - 1;
1✔
146
    }
147

148
    @Override
149
    public int characteristics() {
150
        return source.characteristics()
1✔
151
            & ((left == EMPTY && right == EMPTY ? SIZED : 0) | CONCURRENT | IMMUTABLE | ORDERED);
1✔
152
    }
153

154
    @SuppressWarnings("unchecked")
155
    @Override
156
    public SS trySplit() {
157
        S prefixSource = (S) source.trySplit();
1✔
158
        if (prefixSource == null)
1✔
159
            return null;
1✔
160
        SS clone = doClone();
1✔
161
        Sink<T> left = new Sink<>(lock);
1✔
162
        Sink<T> right = new Sink<>(lock);
1✔
163
        clone.source = prefixSource;
1✔
164
        clone.right = right.other = left;
1✔
165
        this.left = left.other = right;
1✔
166
        return clone;
1✔
167
    }
168

169
    void finish(BiConsumer<T, T> fn, T cur) {
170
        Sink<T> r = right, l = left;
1✔
171
        right = left = null;
1✔
172
        if (l != null) {
1✔
173
            l.connect(r, fn);
1✔
174
        } else if (r != null) {
1✔
175
            r.push(cur, fn, true);
1✔
176
        }
177
    }
1✔
178

179
    static class PSOfRef<T, R> extends PairSpliterator<T, Spliterator<T>, R, PSOfRef<T, R>> implements
180
            Consumer<T>, TailSpliterator<R> {
181
        private static final Object HEAD_TAIL = new Object();
1✔
182

183
        private final BiFunction<? super T, ? super T, ? extends R> mapper;
184
        private T cur;
185

186
        PSOfRef(BiFunction<? super T, ? super T, ? extends R> mapper, Spliterator<T> source) {
187
            super(source, MODE_PAIRS, null);
1✔
188
            this.mapper = mapper;
1✔
189
        }
1✔
190

191
        // Must be called only if T == R
192
        @SuppressWarnings("unchecked")
193
        PSOfRef(Function<? super T, ? extends R> mapper, Spliterator<T> source, boolean first) {
194
            super(source, first ? MODE_MAP_FIRST : MODE_MAP_LAST, (T) HEAD_TAIL);
1✔
195
            BiFunction<? super T, ? super T, ?> m = first ?
1✔
196
                    ((a, b) -> a == HEAD_TAIL ? mapper.apply(b) : (T) b) :
1✔
197
                    ((a, b) -> b == HEAD_TAIL ? mapper.apply(a) : (T) a);
1✔
198
            this.mapper = (BiFunction<? super T, ? super T, ? extends R>) m;
1✔
199
        }
1✔
200

201
        @SuppressWarnings("unchecked")
202
        PSOfRef(Function<? super T, ? extends R> boundMapper, Function<? super T, ? extends R> elseMapper, Spliterator<T> source, boolean first) {
203
            super(source, first ? MODE_MAP_FIRST_OR_ELSE : MODE_MAP_LAST_OR_ELSE, (T) HEAD_TAIL);
1✔
204
            this.mapper = first ? 
1✔
205
                ((a, b) -> a == HEAD_TAIL ? boundMapper.apply(b) : elseMapper.apply(b)) :
1✔
206
                ((a, b) -> b == HEAD_TAIL ? boundMapper.apply(a) : elseMapper.apply(a));
1✔
207
        }
1✔
208

209
        @Override
210
        public void accept(T t) {
211
            cur = t;
1✔
212
        }
1✔
213

214
        private BiConsumer<T, T> fn(Consumer<? super R> action) {
215
            return (a, b) -> action.accept(mapper.apply(a, b));
1✔
216
        }
217

218
        @Override
219
        public boolean tryAdvance(Consumer<? super R> action) {
220
            Sink<T> l = left, r = right;
1✔
221
            if (l != null) {
1✔
222
                left = null;
1✔
223
                if (!source.tryAdvance(this)) {
1✔
224
                    right = null;
1✔
225
                    return l.connect(r, fn(action));
1✔
226
                }
227
                if (l.push(cur, fn(action), false))
1✔
228
                    return true;
1✔
229
            }
230
            T prev = cur;
1✔
231
            if (!source.tryAdvance(this)) {
1✔
232
                right = null;
1✔
233
                return r != null && r.push(prev, fn(action), true);
1✔
234
            }
235
            action.accept(mapper.apply(prev, cur));
1✔
236
            return true;
1✔
237
        }
238

239
        @Override
240
        public void forEachRemaining(Consumer<? super R> action) {
241
            BiConsumer<T, T> fn = fn(action);
1✔
242
            source.forEachRemaining(next -> {
1✔
243
                if (left != null) {
1✔
244
                    left.push(cur = next, fn, false);
1✔
245
                    left = null;
1✔
246
                } else {
247
                    action.accept(mapper.apply(cur, cur = next));
1✔
248
                }
249
            });
1✔
250
            finish(fn, cur);
1✔
251
        }
1✔
252

253
        @Override
254
        public Spliterator<R> tryAdvanceOrTail(Consumer<? super R> action) {
255
            if (mode != MODE_MAP_FIRST || right != EMPTY) {
1✔
256
                return tryAdvance(action) ? this : null;
1✔
257
            }
258
            if (left != null) {
1✔
259
                Sink<T> l = left;
1✔
260
                left = null;
1✔
261
                source = TailSpliterator.tryAdvanceWithTail(source, this);
1✔
262
                if (source == null) {
1✔
263
                    right = null;
1✔
264
                    return null;
1✔
265
                }
266
                if (l.push(cur, fn(action), false))
1✔
267
                    return this;
1✔
268
            }
269
            @SuppressWarnings("unchecked")
270
            Spliterator<R> s = (Spliterator<R>) source;
1✔
271
            source = null;
1✔
272
            return s;
1✔
273
        }
274
        
275
        @Override
276
        public Spliterator<R> forEachOrTail(Consumer<? super R> action) {
277
            if (mode != MODE_MAP_FIRST || right != EMPTY) {
1✔
278
                forEachRemaining(action);
1✔
279
                return null;
1✔
280
            }
281
            while (true) {
282
                Spliterator<R> tail = tryAdvanceOrTail(action);
1✔
283
                if (tail != this)
1✔
284
                    return tail;
1✔
285
            }
1✔
286
        }
287
    }
288

289
    static final class PSOfInt extends PairSpliterator<Integer, Spliterator.OfInt, Integer, PSOfInt> implements
290
            Spliterator.OfInt, IntConsumer {
291
        private final IntBinaryOperator mapper;
292
        private final IntUnaryOperator unaryMapper;
293
        private int cur;
294

295
        PSOfInt(IntBinaryOperator mapper, IntUnaryOperator unaryMapper, Spliterator.OfInt source, int mode) {
296
            super(source, mode, null);
1✔
297
            this.mapper = mapper;
1✔
298
            this.unaryMapper = unaryMapper;
1✔
299
        }
1✔
300
        
301
        @Override
302
        public void accept(int t) {
303
            cur = t;
1✔
304
        }
1✔
305

306
        private BiConsumer<Integer, Integer> fn(IntConsumer action) {
307
            switch (mode) {
1✔
308
            case MODE_MAP_FIRST:
309
                return (a, b) -> action.accept(a == null ? unaryMapper.applyAsInt(b) : b);
1✔
310
            case MODE_MAP_LAST:
311
                return (a, b) -> action.accept(b == null ? unaryMapper.applyAsInt(a) : a);
1✔
312
            default:
313
                return (a, b) -> action.accept(mapper.applyAsInt(a, b));
1✔
314
            }
315
        }
316

317
        @Override
318
        public boolean tryAdvance(IntConsumer action) {
319
            Sink<Integer> l = left, r = right;
1✔
320
            if (l != null) {
1✔
321
                left = null;
1✔
322
                if (!source.tryAdvance(this)) {
1✔
323
                    right = null;
1✔
324
                    return l.connect(r, fn(action));
1✔
325
                }
326
                if (l.push(cur, fn(action), false))
1✔
327
                    return true;
1✔
328
            }
329
            int prev = cur;
1✔
330
            if (!source.tryAdvance(this)) {
1✔
331
                right = null;
1✔
332
                return r != null && r.push(prev, fn(action), true);
1✔
333
            }
334
            action.accept(mapper.applyAsInt(prev, cur));
1✔
335
            return true;
1✔
336
        }
337

338
        @Override
339
        public void forEachRemaining(IntConsumer action) {
340
            BiConsumer<Integer, Integer> fn = fn(action);
1✔
341
            source.forEachRemaining((int next) -> {
1✔
342
                if (left != null) {
1✔
343
                    left.push(cur = next, fn, false);
1✔
344
                    left = null;
1✔
345
                } else {
346
                    action.accept(mapper.applyAsInt(cur, cur = next));
1✔
347
                }
348
            });
1✔
349
            finish(fn, cur);
1✔
350
        }
1✔
351
    }
352

353
    static final class PSOfLong extends PairSpliterator<Long, Spliterator.OfLong, Long, PSOfLong> implements
354
            Spliterator.OfLong, LongConsumer {
355
        private final LongBinaryOperator mapper;
356
        private final LongUnaryOperator unaryMapper;
357
        private long cur;
358

359
        PSOfLong(LongBinaryOperator mapper, LongUnaryOperator unaryMapper, Spliterator.OfLong source, int mode) {
360
            super(source, mode, null);
1✔
361
            this.mapper = mapper;
1✔
362
            this.unaryMapper = unaryMapper;
1✔
363
        }
1✔
364

365
        @Override
366
        public void accept(long t) {
367
            cur = t;
1✔
368
        }
1✔
369

370
        private BiConsumer<Long, Long> fn(LongConsumer action) {
371
            switch (mode) {
1✔
372
            case MODE_MAP_FIRST:
373
                return (a, b) -> action.accept(a == null ? unaryMapper.applyAsLong(b) : b);
1✔
374
            case MODE_MAP_LAST:
375
                return (a, b) -> action.accept(b == null ? unaryMapper.applyAsLong(a) : a);
1✔
376
            default:
377
                return (a, b) -> action.accept(mapper.applyAsLong(a, b));
1✔
378
            }
379
        }
380

381
        @Override
382
        public boolean tryAdvance(LongConsumer action) {
383
            Sink<Long> l = left, r = right;
1✔
384
            if (l != null) {
1✔
385
                left = null;
1✔
386
                if (!source.tryAdvance(this)) {
1✔
387
                    right = null;
1✔
388
                    return l.connect(r, fn(action));
1✔
389
                }
390
                if (l.push(cur, fn(action), false))
1✔
391
                    return true;
1✔
392
            }
393
            long prev = cur;
1✔
394
            if (!source.tryAdvance(this)) {
1✔
395
                right = null;
1✔
396
                return r != null && r.push(prev, fn(action), true);
1✔
397
            }
398
            action.accept(mapper.applyAsLong(prev, cur));
1✔
399
            return true;
1✔
400
        }
401

402
        @Override
403
        public void forEachRemaining(LongConsumer action) {
404
            BiConsumer<Long, Long> fn = fn(action);
1✔
405
            source.forEachRemaining((long next) -> {
1✔
406
                if (left != null) {
1✔
407
                    left.push(cur = next, fn, false);
1✔
408
                    left = null;
1✔
409
                } else {
410
                    action.accept(mapper.applyAsLong(cur, cur = next));
1✔
411
                }
412
            });
1✔
413
            finish(fn, cur);
1✔
414
        }
1✔
415
    }
416

417
    static final class PSOfDouble extends PairSpliterator<Double, Spliterator.OfDouble, Double, PSOfDouble> implements
418
            Spliterator.OfDouble, DoubleConsumer {
419
        private final DoubleBinaryOperator mapper;
420
        private final DoubleUnaryOperator unaryMapper;
421
        private double cur;
422

423
        PSOfDouble(DoubleBinaryOperator mapper, DoubleUnaryOperator unaryMapper, Spliterator.OfDouble source, int mode) {
424
            super(source, mode, null);
1✔
425
            this.mapper = mapper;
1✔
426
            this.unaryMapper = unaryMapper;
1✔
427
        }
1✔
428

429
        @Override
430
        public void accept(double t) {
431
            cur = t;
1✔
432
        }
1✔
433

434
        private BiConsumer<Double, Double> fn(DoubleConsumer action) {
435
            switch (mode) {
1✔
436
            case MODE_MAP_FIRST:
437
                return (a, b) -> action.accept(a == null ? unaryMapper.applyAsDouble(b) : b);
1✔
438
            case MODE_MAP_LAST:
439
                return (a, b) -> action.accept(b == null ? unaryMapper.applyAsDouble(a) : a);
1✔
440
            default:
441
                return (a, b) -> action.accept(mapper.applyAsDouble(a, b));
1✔
442
            }
443
        }
444

445
        @Override
446
        public boolean tryAdvance(DoubleConsumer action) {
447
            Sink<Double> l = left, r = right;
1✔
448
            if (l != null) {
1✔
449
                left = null;
1✔
450
                if (!source.tryAdvance(this)) {
1✔
451
                    right = null;
1✔
452
                    return l.connect(r, fn(action));
1✔
453
                }
454
                if (l.push(cur, fn(action), false))
1✔
455
                    return true;
1✔
456
            }
457
            double prev = cur;
1✔
458
            if (!source.tryAdvance(this)) {
1✔
459
                right = null;
1✔
460
                return r != null && r.push(prev, fn(action), true);
1✔
461
            }
462
            action.accept(mapper.applyAsDouble(prev, cur));
1✔
463
            return true;
1✔
464
        }
465

466
        @Override
467
        public void forEachRemaining(DoubleConsumer action) {
468
            BiConsumer<Double, Double> fn = fn(action);
1✔
469
            source.forEachRemaining((double next) -> {
1✔
470
                if (left != null) {
1✔
471
                    left.push(cur = next, fn, false);
1✔
472
                    left = null;
1✔
473
                } else {
474
                    action.accept(mapper.applyAsDouble(cur, cur = next));
1✔
475
                }
476
            });
1✔
477
            finish(fn, cur);
1✔
478
        }
1✔
479
    }
480
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc