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

amaembo / streamex / #667

02 Sep 2023 01:21PM UTC coverage: 99.462% (-0.2%) from 99.619%
#667

push

amaembo
One more test for Limiter

5733 of 5764 relevant lines covered (99.46%)

0.99 hits per line

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

98.73
/src/main/java/one/util/streamex/WithFirstSpliterator.java
1
/*
2
 * Copyright 2015, 2019 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.concurrent.locks.ReentrantLock;
20
import java.util.function.BiFunction;
21
import java.util.function.Consumer;
22

23
import one.util.streamex.Internals.CloneableSpliterator;
24

25
/**
26
 * @author Tagir Valeev
27
 */
28
/* package */final class WithFirstSpliterator<T, R> extends CloneableSpliterator<R, WithFirstSpliterator<T, R>> implements Consumer<T> {
29
    private static final int STATE_NONE = 0;
30
    private static final int STATE_FIRST_READ = 1;
31
    private static final int STATE_INIT = 2;
32
    private static final int STATE_EMPTY = 3;
33

34
    private ReentrantLock lock;
35
    private Spliterator<T> source;
36
    private WithFirstSpliterator<T, R> prefix;
37
    private volatile T first;
38
    private volatile int state = STATE_NONE;
1✔
39
    private final BiFunction<? super T, ? super T, ? extends R> mapper;
40
    private Consumer<? super R> action;
41
    
42
    WithFirstSpliterator(Spliterator<T> source, BiFunction<? super T, ? super T, ? extends R> mapper) {
1✔
43
        this.source = source;
1✔
44
        this.mapper = mapper;
1✔
45
    }
1✔
46
    
47
    private void acquire() {
48
        if (lock != null && state == STATE_NONE) {
1✔
49
            lock.lock();
1✔
50
        }
51
    }
1✔
52
    
53
    private void release() {
54
        if (lock != null && lock.isHeldByCurrentThread()) {
1✔
55
            lock.unlock();
1✔
56
        }
57
    }
1✔
58

59
    @Override
60
    public boolean tryAdvance(Consumer<? super R> action) {
61
        if (state == STATE_NONE) {
1✔
62
            acquire();
1✔
63
            try {
64
                doInit();
1✔
65
            } finally {
66
                release();
1✔
67
            }
68
        }
69
        if (state == STATE_FIRST_READ) {
1✔
70
            state = STATE_INIT;
1✔
71
            action.accept(mapper.apply(first, first));
1✔
72
            return true;
1✔
73
        }
74
        if (state != STATE_INIT)
1✔
75
            return false;
1✔
76
        this.action = action;
1✔
77
        boolean hasNext = source.tryAdvance(this);
1✔
78
        this.action = null;
1✔
79
        return hasNext;
1✔
80
    }
81

82
    private void doInit() {
83
        int prefixState = state;
1✔
84
        if (prefixState != STATE_NONE)
1✔
85
            return;
1✔
86
        if (prefix != null) {
1✔
87
            prefix.doInit();
1✔
88
            prefixState = prefix.state;
1✔
89
        }
90
        if (prefixState == STATE_FIRST_READ || prefixState == STATE_INIT) {
1✔
91
            first = prefix.first;
1✔
92
            state = STATE_INIT;
1✔
93
            return;
1✔
94
        }
95
        state = source.tryAdvance(x -> first = x) ? STATE_FIRST_READ : STATE_EMPTY;
1✔
96
    }
1✔
97

98
    @Override
99
    public void forEachRemaining(Consumer<? super R> action) {
100
        acquire();
1✔
101
        int myState = state;
1✔
102
        this.action = action;
1✔
103
        if (myState == STATE_FIRST_READ || myState == STATE_INIT) {
1✔
104
            release();
1✔
105
            if (myState == STATE_FIRST_READ) {
1✔
106
                state = STATE_INIT;
1✔
107
                accept(first);
1✔
108
            }
109
            source.forEachRemaining(this);
1✔
110
            this.action = null;
1✔
111
            return;
1✔
112
        }
113
        try {
114
            Consumer<T> init = x -> {
1✔
115
                if (state == STATE_NONE) {
1✔
116
                    if (prefix != null) {
1✔
117
                        prefix.doInit();
1✔
118
                    }
119
                    this.first = (prefix == null || prefix.state == STATE_EMPTY) ? x : prefix.first;
1✔
120
                    state = STATE_INIT;
1✔
121
                }
122
                release();
1✔
123
            };
1✔
124
            source.forEachRemaining(init.andThen(this));
1✔
125
            this.action = null;
1✔
126
        } finally {
127
            release();
1✔
128
        }
129
    }
1✔
130

131
    @Override
132
    public Spliterator<R> trySplit() {
133
        if (state != STATE_NONE)
1✔
134
            return null;
1✔
135
        Spliterator<T> prefix;
136
        if (lock == null)
1✔
137
            lock = new ReentrantLock();
1✔
138
        acquire();
1✔
139
        try {
140
            if (state != STATE_NONE)
1✔
141
                return null;
×
142
            prefix = source.trySplit();
1✔
143
            if (prefix == null)
1✔
144
                return null;
1✔
145
            WithFirstSpliterator<T, R> result = doClone();
1✔
146
            result.source = prefix;
1✔
147
            return this.prefix = result;
1✔
148
        } finally {
149
            release();
1✔
150
        }
151
    }
152

153
    @Override
154
    public long estimateSize() {
155
        return source.estimateSize();
1✔
156
    }
157

158
    @Override
159
    public int characteristics() {
160
        return NONNULL
1✔
161
            | (source.characteristics() & (DISTINCT | IMMUTABLE | CONCURRENT | ORDERED | (lock == null ? SIZED : 0)));
1✔
162
    }
163

164
    @Override
165
    public void accept(T x) {
166
        action.accept(mapper.apply(first, x));
1✔
167
    }
1✔
168
}
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