• 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

99.31
/src/main/java/one/util/streamex/TreeSpliterator.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.AbstractMap;
19
import java.util.ArrayList;
20
import java.util.Collections;
21
import java.util.List;
22
import java.util.Map.Entry;
23
import java.util.Spliterator;
24
import java.util.function.BiFunction;
25
import java.util.function.Consumer;
26
import java.util.function.Function;
27
import java.util.stream.Stream;
28

29
import static one.util.streamex.Internals.CloneableSpliterator;
30
import static one.util.streamex.Internals.ObjIntBox;
31
import static one.util.streamex.Internals.PairBox;
32

33
/**
34
 * @author Tagir Valeev
35
 *
36
 */
37
/* package */ abstract class TreeSpliterator<T, U> extends CloneableSpliterator<U, TreeSpliterator<T, U>> 
38
        implements Consumer<T>, AutoCloseable, Runnable {
39
    private static final int MAX_RECURSION_DEPTH = Integer.getInteger("one.util.streamex.tree.recursiondepth", 128);
1✔
40
    T cur;
41
    List<PairBox<Spliterator<T>, Stream<T>>> spliterators;
42
    private Runnable closeHandler = null;
1✔
43
    long size = Long.MAX_VALUE;
1✔
44

45
    TreeSpliterator(T root) {
1✔
46
        this.cur = root;
1✔
47
    }
1✔
48
    
49
    boolean advance() {
50
        List<PairBox<Spliterator<T>, Stream<T>>> spltrs = spliterators;
1✔
51
        if (spltrs == null) {
1✔
52
            spliterators = new ArrayList<>();
1✔
53
            return true;
1✔
54
        }
55
        for (int lastIdx = spltrs.size() - 1; lastIdx >= 0; lastIdx--) {
1✔
56
            PairBox<Spliterator<T>, Stream<T>> pair = spltrs.get(lastIdx);
1✔
57
            Spliterator<T> spltr = pair.a;
1✔
58
            if (spltr.tryAdvance(this)) {
1✔
59
                return true;
1✔
60
            }
61
            if (pair.b != null)
1✔
62
                pair.b.close();
1✔
63
            spltrs.remove(lastIdx);
1✔
64
        }
65
        return false;
1✔
66
    }
67

68
    boolean append(Stream<T> stream) {
69
        if (stream != null) {
1✔
70
            spliterators.add(new PairBox<>(stream.spliterator(), stream));
1✔
71
        }
72
        return true;
1✔
73
    }
74
    
75
    abstract Stream<T> getStart();
76
    
77
    abstract U getStartElement();
78

79
    @Override
80
    public Spliterator<U> trySplit() {
81
        if (spliterators == null) {
1✔
82
            spliterators = new ArrayList<>();
1✔
83
            Stream<T> stream = getStart();
1✔
84
            if (stream != null) {
1✔
85
                spliterators.add(new PairBox<>(stream.parallel().spliterator(), null));
1✔
86
                closeHandler = stream::close;
1✔
87
            }
88
            return new ConstSpliterator.OfRef<>(getStartElement(), 1, true);
1✔
89
        }
90
        int size = spliterators.size();
1✔
91
        if (size != 1) {
1✔
92
            return null;
1✔
93
        }
94
        Spliterator<T> prefix = spliterators.get(0).a.trySplit();
1✔
95
        if (prefix == null)
1✔
96
            return null;
1✔
97
        TreeSpliterator<T, U> clone = doClone();
1✔
98
        clone.size /= 2;
1✔
99
        this.size -= clone.size;
1✔
100
        clone.spliterators = new ArrayList<>();
1✔
101
        clone.spliterators.add(new PairBox<>(prefix, null));
1✔
102
        closeHandler = StreamContext.compose(closeHandler, clone);
1✔
103
        return clone;
1✔
104
    }
105
    
106
    @Override
107
    public long estimateSize() {
108
        return size;
1✔
109
    }
110

111
    @Override
112
    public int characteristics() {
113
        return ORDERED;
1✔
114
    }
115

116
    @Override
117
    public void accept(T t) {
118
        cur = t;
1✔
119
    }
1✔
120
    
121
    @Override
122
    public void run() {
123
        close();
1✔
124
    }
1✔
125
    
126
    @Override
127
    public void close() {
128
        if (spliterators != null) {
1✔
129
            Throwable t = null;
1✔
130
            for (int i = spliterators.size() - 1; i >= 0; i--) {
1✔
131
                try {
132
                    Stream<T> stream = spliterators.get(i).b;
1✔
133
                    if (stream != null)
1✔
134
                        stream.close();
1✔
135
                } catch (Error | RuntimeException e) {
1✔
136
                    if (t == null)
1✔
137
                        t = e;
1✔
138
                    else
139
                        t.addSuppressed(e);
1✔
140
                }
1✔
141
            }
142
            if (closeHandler != null) {
1✔
143
                try {
144
                    closeHandler.run();
1✔
145
                } catch (Error | RuntimeException e) {
1✔
146
                    if (t == null)
1✔
147
                        t = e;
1✔
148
                    else
149
                        t.addSuppressed(e);
×
150
                }
1✔
151
            }
152
            if (t instanceof RuntimeException)
1✔
153
                throw (RuntimeException) t;
1✔
154
            if (t instanceof Error)
1✔
155
                throw (Error) t;
1✔
156
        }
157
    }
1✔
158
    
159
    static class Acceptor<T> implements Consumer<T> {
160
        private final Consumer<? super T> action;
161
        private final Function<T, Stream<T>> mapper;
162
        private int depth;
163
        
164
        public Acceptor(Consumer<? super T> action, Function<T, Stream<T>> mapper) {
1✔
165
            this.action = action;
1✔
166
            this.mapper = mapper;
1✔
167
        }
1✔
168
    
169
        @Override
170
        public void accept(T t) {
171
            if (depth > MAX_RECURSION_DEPTH) {
1✔
172
                try (TreeSpliterator<T, T> spliterator = new Plain<>(t, mapper)) {
1✔
173
                    do { // nothing
174
                    } while (spliterator.tryAdvance(action));
1✔
175
                }
176
                return;
1✔
177
            }
178
            action.accept(t);
1✔
179
            depth++;
1✔
180
            try (Stream<T> stream = mapper.apply(t)) {
1✔
181
                if (stream != null) {
1✔
182
                    stream.spliterator().forEachRemaining(this);
1✔
183
                }
184
            } finally {
185
                depth--;
1✔
186
            }
187
        }
1✔
188
    }
189

190
    static class Plain<T> extends TreeSpliterator<T, T> {
191
        private final Function<T, Stream<T>> mapper;
192

193
        Plain(T root, Function<T, Stream<T>> mapper) {
194
            super(root);
1✔
195
            this.mapper = mapper;
1✔
196
        }
1✔
197

198
        @Override
199
        public boolean tryAdvance(Consumer<? super T> action) {
200
            if (!advance())
1✔
201
                return false;
1✔
202
            T e = this.cur;
1✔
203
            action.accept(e);
1✔
204
            return append(mapper.apply(e));
1✔
205
        }
206
    
207
        @Override
208
        public void forEachRemaining(Consumer<? super T> action) {
209
            Acceptor<T> acceptor = new Acceptor<>(action, mapper);
1✔
210
            if (spliterators != null) {
1✔
211
                for (int i = spliterators.size() - 1; i >= 0; i--) {
1✔
212
                    PairBox<Spliterator<T>, Stream<T>> pair = spliterators.get(i);
1✔
213
                    pair.a.forEachRemaining(acceptor);
1✔
214
                    if (pair.b != null)
1✔
215
                        pair.b.close();
1✔
216
                }
217
            } else {
218
                spliterators = Collections.emptyList();
1✔
219
                acceptor.accept(cur);
1✔
220
            }
221
        }
1✔
222

223
        @Override
224
        Stream<T> getStart() {
225
            return mapper.apply(cur);
1✔
226
        }
227

228
        @Override
229
        T getStartElement() {
230
            return cur;
1✔
231
        }
232
    }
233
    
234
    static class DepthAcceptor<T> implements Consumer<T> {
235
        private final Consumer<? super Entry<Integer, T>> action;
236
        private final BiFunction<Integer, T, Stream<T>> mapper;
237
        private Integer depth;
238
        
239
        public DepthAcceptor(Consumer<? super Entry<Integer, T>> action, BiFunction<Integer, T, Stream<T>> mapper, Integer depth) {
1✔
240
            this.action = action;
1✔
241
            this.mapper = mapper;
1✔
242
            this.depth = depth;
1✔
243
        }
1✔
244
    
245
        @Override
246
        public void accept(T t) {
247
            if (depth > MAX_RECURSION_DEPTH) {
1✔
248
                try (TreeSpliterator<T, Entry<Integer, T>> spliterator = new Depth<>(t, mapper, depth)) {
1✔
249
                    do { // nothing
250
                    } while (spliterator.tryAdvance(action));
1✔
251
                }
252
                return;
1✔
253
            }
254
            action.accept(new AbstractMap.SimpleImmutableEntry<>(depth, t));
1✔
255
            try (Stream<T> stream = mapper.apply(depth, t)) {
1✔
256
                if (stream != null) {
1✔
257
                    depth++;
1✔
258
                    stream.spliterator().forEachRemaining(this);
1✔
259
                    depth--;
1✔
260
                }
261
            }
262
        }
1✔
263
    }
264

265
    static class Depth<T> extends TreeSpliterator<T, Entry<Integer, T>> {
266
        private final BiFunction<Integer, T, Stream<T>> mapper;
267
        private final int initialDepth;
268

269
        Depth(T root, BiFunction<Integer, T, Stream<T>> mapper, int depth) {
270
            super(root);
1✔
271
            this.mapper = mapper;
1✔
272
            initialDepth = depth;
1✔
273
        }
1✔
274

275
        @Override
276
        public boolean tryAdvance(Consumer<? super Entry<Integer, T>> action) {
277
            if (!advance())
1✔
278
                return false;
1✔
279
            T e = this.cur;
1✔
280
            int depth = initialDepth + spliterators.size();
1✔
281
            action.accept(new ObjIntBox<>(e, depth));
1✔
282
            return append(mapper.apply(depth, e));
1✔
283
        }
284

285
        @Override
286
        public void forEachRemaining(Consumer<? super Entry<Integer, T>> action) {
287
            DepthAcceptor<T> acceptor = new DepthAcceptor<>(action, mapper, initialDepth);
1✔
288
            if (spliterators != null) {
1✔
289
                for (int i = spliterators.size() - 1; i >= 0; i--) {
1✔
290
                    PairBox<Spliterator<T>, Stream<T>> pair = spliterators.get(i);
1✔
291
                    acceptor.depth = i + 1;
1✔
292
                    pair.a.forEachRemaining(acceptor);
1✔
293
                    if (pair.b != null)
1✔
294
                        pair.b.close();
1✔
295
                }
296
            } else {
297
                spliterators = Collections.emptyList();
1✔
298
                acceptor.accept(cur);
1✔
299
            }
300
        }
1✔
301

302
        @Override
303
        Stream<T> getStart() {
304
            return mapper.apply(0, cur);
1✔
305
        }
306

307
        @Override
308
        Entry<Integer, T> getStartElement() {
309
            return new ObjIntBox<>(cur, 0);
1✔
310
        }
311
    }
312
}
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