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

amaembo / streamex / #677

02 Nov 2024 08:50AM UTC coverage: 99.673%. Remained the same
#677

push

amaembo
Optimize imports

5786 of 5805 relevant lines covered (99.67%)

1.0 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, 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 java.util.*;
19
import java.util.Map.Entry;
20
import java.util.function.BiFunction;
21
import java.util.function.Consumer;
22
import java.util.function.Function;
23
import java.util.stream.Stream;
24

25
import static one.util.streamex.Internals.*;
26

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

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

62
    boolean append(Stream<T> stream) {
63
        if (stream != null) {
1✔
64
            spliterators.add(new PairBox<>(stream.spliterator(), stream));
1✔
65
        }
66
        return true;
1✔
67
    }
68
    
69
    abstract Stream<T> getStart();
70
    
71
    abstract U getStartElement();
72

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

105
    @Override
106
    public int characteristics() {
107
        return ORDERED;
1✔
108
    }
109

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

184
    static class Plain<T> extends TreeSpliterator<T, T> {
185
        private final Function<T, Stream<T>> mapper;
186

187
        Plain(T root, Function<T, Stream<T>> mapper) {
188
            super(root);
1✔
189
            this.mapper = mapper;
1✔
190
        }
1✔
191

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

217
        @Override
218
        Stream<T> getStart() {
219
            return mapper.apply(cur);
1✔
220
        }
221

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

259
    static class Depth<T> extends TreeSpliterator<T, Entry<Integer, T>> {
260
        private final BiFunction<Integer, T, Stream<T>> mapper;
261
        private final int initialDepth;
262

263
        Depth(T root, BiFunction<Integer, T, Stream<T>> mapper, int depth) {
264
            super(root);
1✔
265
            this.mapper = mapper;
1✔
266
            initialDepth = depth;
1✔
267
        }
1✔
268

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

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

296
        @Override
297
        Stream<T> getStart() {
298
            return mapper.apply(0, cur);
1✔
299
        }
300

301
        @Override
302
        Entry<Integer, T> getStartElement() {
303
            return new ObjIntBox<>(cur, 0);
1✔
304
        }
305
    }
306
}
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