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

gephi / graphstore / #504

03 Oct 2025 01:24PM UTC coverage: 91.042% (+0.2%) from 90.873%
#504

push

web-flow
Add Spliterator on NodesQuadTree (#243)

* Change default config for block size and default dict size

* Replace LinkedHashSet with arrays and implement spliterator

* Add multi-node edge iterator

* Refactoring to remove duplicate getNodes methods in quadtree

* Add edge iteration support in quadtree

* Add global quad tree edge iterator option

* Refactor to configure edge inout iterator locking and test all edges in quadtree spliterator

* Formatting

* Git ignore

* Non approximate support for global iterator and bugfix

* Add additional tests

* Quadtree versioning

* Tweak boundaries

* Documentation

* Update src/main/java/org/gephi/graph/impl/NodesQuadTree.java

Remove distinct from spliterator as edges can be returned twice

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Fix locking function name clash in view decorator

* Fix toArray

* Reduce memory overhead of quad node array init

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

535 of 615 new or added lines in 10 files covered. (86.99%)

1 existing line in 1 file now uncovered.

11576 of 12715 relevant lines covered (91.04%)

0.91 hits per line

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

76.54
/src/main/java/org/gephi/graph/impl/GraphViewDecorator.java
1
/*
2
 * Copyright 2012-2013 Gephi Consortium
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5
 * use this file except in compliance with the License. You may obtain a copy of
6
 * 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, WITHOUT
12
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
 * License for the specific language governing permissions and limitations under
14
 * the License.
15
 */
16
package org.gephi.graph.impl;
17

18
import java.util.Collection;
19
import java.util.Iterator;
20
import java.util.Set;
21
import java.util.Spliterator;
22
import java.util.ConcurrentModificationException;
23
import java.util.function.Consumer;
24
import org.gephi.graph.api.DirectedSubgraph;
25
import org.gephi.graph.api.Edge;
26
import org.gephi.graph.api.EdgeIterable;
27
import org.gephi.graph.api.Graph;
28
import org.gephi.graph.api.GraphModel;
29
import org.gephi.graph.api.GraphView;
30
import org.gephi.graph.api.Interval;
31
import org.gephi.graph.api.Node;
32
import org.gephi.graph.api.NodeIterable;
33
import org.gephi.graph.api.Rect2D;
34
import org.gephi.graph.api.SpatialIndex;
35
import org.gephi.graph.api.Subgraph;
36
import org.gephi.graph.api.UndirectedSubgraph;
37

38
public class GraphViewDecorator implements DirectedSubgraph, UndirectedSubgraph, SpatialIndex {
39

40
    protected final boolean undirected;
41
    protected final GraphViewImpl view;
42
    protected final GraphStore graphStore;
43

44
    public GraphViewDecorator(GraphStore graphStore, GraphViewImpl view, boolean undirected) {
1✔
45
        this.graphStore = graphStore;
1✔
46
        this.view = view;
1✔
47
        this.undirected = undirected;
1✔
48
    }
1✔
49

50
    @Override
51
    public Edge getEdge(Node node1, Node node2) {
52
        graphStore.autoReadLock();
1✔
53
        try {
54
            EdgeImpl edge = graphStore.edgeStore.get(node1, node2, undirected);
1✔
55
            if (edge != null && view.containsEdge(edge)) {
1✔
56
                return edge;
1✔
57
            }
58
            return null;
1✔
59
        } finally {
60
            graphStore.autoReadUnlock();
1✔
61
        }
62
    }
63

64
    @Override
65
    public EdgeIterable getEdges(Node node1, Node node2) {
66
        return new EdgeIterableWrapper(
×
67
                () -> new EdgeViewIterator(graphStore.edgeStore.getAll(node1, node2, undirected)),
×
68
                graphStore.getAutoLock());
×
69
    }
70

71
    @Override
72
    public Edge getEdge(Node node1, Node node2, int type) {
73
        graphStore.autoReadLock();
1✔
74
        try {
75
            EdgeImpl edge = graphStore.edgeStore.get(node1, node2, type, undirected);
1✔
76
            if (edge != null && view.containsEdge(edge)) {
1✔
77
                return edge;
1✔
78
            }
79
            return null;
1✔
80
        } finally {
81
            graphStore.autoReadUnlock();
1✔
82
        }
83
    }
84

85
    @Override
86
    public EdgeIterable getEdges(Node node1, Node node2, int type) {
87
        return new EdgeIterableWrapper(
×
88
                () -> new EdgeViewIterator(graphStore.edgeStore.getAll(node1, node2, type, undirected)),
×
89
                graphStore.getAutoLock());
×
90
    }
91

92
    @Override
93
    public Edge getMutualEdge(Edge e) {
94
        graphStore.autoReadLock();
1✔
95
        try {
96
            EdgeImpl edge = graphStore.edgeStore.getMutualEdge(e);
1✔
97
            if (edge != null && view.containsEdge(edge)) {
1✔
98
                return edge;
1✔
99
            }
100
            return null;
1✔
101
        } finally {
102
            graphStore.autoReadUnlock();
1✔
103
        }
104
    }
105

106
    @Override
107
    public NodeIterable getPredecessors(Node node) {
108
        checkValidInViewNodeObject(node);
1✔
109
        return new NodeIterableWrapper(() -> new NeighborsIterator((NodeImpl) node,
1✔
110
                new EdgeViewIterator(graphStore.edgeStore.edgeInIterator(node))), graphStore.getAutoLock());
1✔
111
    }
112

113
    @Override
114
    public NodeIterable getPredecessors(Node node, int type) {
115
        checkValidInViewNodeObject(node);
1✔
116
        return new NodeIterableWrapper(
1✔
117
                () -> new NeighborsIterator((NodeImpl) node,
1✔
118
                        new EdgeViewIterator(graphStore.edgeStore.edgeInIterator(node, type))),
1✔
119
                graphStore.getAutoLock());
1✔
120
    }
121

122
    @Override
123
    public NodeIterable getSuccessors(Node node) {
124
        checkValidInViewNodeObject(node);
1✔
125
        return new NodeIterableWrapper(() -> new NeighborsIterator((NodeImpl) node,
1✔
126
                new EdgeViewIterator(graphStore.edgeStore.edgeOutIterator(node))), graphStore.getAutoLock());
1✔
127
    }
128

129
    @Override
130
    public NodeIterable getSuccessors(Node node, int type) {
131
        checkValidInViewNodeObject(node);
1✔
132
        return new NodeIterableWrapper(
1✔
133
                () -> new NeighborsIterator((NodeImpl) node,
1✔
134
                        new EdgeViewIterator(graphStore.edgeStore.edgeOutIterator(node, type))),
1✔
135
                graphStore.getAutoLock());
1✔
136
    }
137

138
    @Override
139
    public EdgeIterable getInEdges(Node node) {
140
        checkValidInViewNodeObject(node);
1✔
141
        return new EdgeIterableWrapper(() -> new EdgeViewIterator(graphStore.edgeStore.edgeInIterator(node)),
1✔
142
                graphStore.getAutoLock());
1✔
143
    }
144

145
    @Override
146
    public EdgeIterable getInEdges(Node node, int type) {
147
        checkValidInViewNodeObject(node);
1✔
148
        return new EdgeIterableWrapper(() -> new EdgeViewIterator(graphStore.edgeStore.edgeInIterator(node, type)),
1✔
149
                graphStore.getAutoLock());
1✔
150
    }
151

152
    @Override
153
    public EdgeIterable getOutEdges(Node node) {
154
        checkValidInViewNodeObject(node);
1✔
155
        return new EdgeIterableWrapper(() -> new EdgeViewIterator(graphStore.edgeStore.edgeOutIterator(node)),
1✔
156
                graphStore.getAutoLock());
1✔
157
    }
158

159
    @Override
160
    public EdgeIterable getOutEdges(Node node, int type) {
161
        checkValidInViewNodeObject(node);
1✔
162
        return new EdgeIterableWrapper(() -> new EdgeViewIterator(graphStore.edgeStore.edgeOutIterator(node, type)),
1✔
163
                graphStore.getAutoLock());
1✔
164
    }
165

166
    @Override
167
    public boolean isAdjacent(Node source, Node target) {
168
        checkValidInViewNodeObject(source);
1✔
169
        checkValidInViewNodeObject(target);
1✔
170
        graphStore.autoReadLock();
1✔
171
        try {
172
            EdgeImpl edge = graphStore.edgeStore.get(source, target, undirected);
1✔
173
            return edge != null && view.containsEdge(edge);
1✔
174
        } finally {
175
            graphStore.autoReadUnlock();
1✔
176
        }
177
    }
178

179
    @Override
180
    public boolean isAdjacent(Node source, Node target, int type) {
181
        checkValidInViewNodeObject(source);
1✔
182
        checkValidInViewNodeObject(target);
1✔
183
        graphStore.autoReadLock();
1✔
184
        try {
185
            EdgeImpl edge = graphStore.edgeStore.get(source, target, type, undirected);
1✔
186
            return edge != null && view.containsEdge(edge);
1✔
187
        } finally {
188
            graphStore.autoReadUnlock();
1✔
189
        }
190
    }
191

192
    @Override
193
    public boolean addEdge(Edge edge) {
194
        checkValidEdgeObject(edge);
1✔
195
        graphStore.autoWriteLock();
1✔
196
        try {
197
            return view.addEdge(edge);
1✔
198
        } finally {
199
            graphStore.autoWriteUnlock();
1✔
200
        }
201

202
    }
203

204
    @Override
205
    public boolean addNode(Node node) {
206
        checkValidNodeObject(node);
1✔
207
        graphStore.autoWriteLock();
1✔
208
        try {
209
            return view.addNode(node);
1✔
210
        } finally {
211
            graphStore.autoWriteUnlock();
1✔
212
        }
213
    }
214

215
    @Override
216
    public boolean addAllEdges(Collection<? extends Edge> edges) {
217
        graphStore.autoWriteLock();
1✔
218
        try {
219
            return view.addAllEdges(edges);
1✔
220
        } finally {
221
            graphStore.autoWriteUnlock();
1✔
222
        }
223
    }
224

225
    @Override
226
    public boolean addAllNodes(Collection<? extends Node> nodes) {
227
        graphStore.autoWriteLock();
1✔
228
        try {
229
            return view.addAllNodes(nodes);
1✔
230
        } finally {
231
            graphStore.autoWriteUnlock();
1✔
232
        }
233
    }
234

235
    @Override
236
    public boolean removeEdge(Edge edge) {
237
        checkValidEdgeObject(edge);
1✔
238
        graphStore.autoWriteLock();
1✔
239
        try {
240
            return view.removeEdge(edge);
1✔
241
        } finally {
242
            graphStore.autoWriteUnlock();
1✔
243
        }
244
    }
245

246
    @Override
247
    public boolean removeNode(Node node) {
248
        checkValidNodeObject(node);
1✔
249
        graphStore.autoWriteLock();
1✔
250
        try {
251
            return view.removeNode(node);
1✔
252
        } finally {
253
            graphStore.autoWriteUnlock();
1✔
254
        }
255
    }
256

257
    @Override
258
    public boolean removeAllEdges(Collection<? extends Edge> edges) {
259
        graphStore.autoWriteLock();
1✔
260
        try {
261
            return view.removeEdgeAll(edges);
1✔
262
        } finally {
263
            graphStore.autoWriteUnlock();
1✔
264
        }
265
    }
266

267
    @Override
268
    public boolean removeAllNodes(Collection<? extends Node> nodes) {
269
        graphStore.autoWriteLock();
1✔
270
        try {
271
            return view.removeNodeAll(nodes);
1✔
272
        } finally {
273
            graphStore.autoWriteUnlock();
1✔
274
        }
275
    }
276

277
    @Override
278
    public boolean retainNodes(Collection<? extends Node> nodes) {
279
        graphStore.autoWriteLock();
1✔
280
        try {
281
            return view.retainNodes(nodes);
1✔
282
        } finally {
283
            graphStore.autoWriteUnlock();
1✔
284
        }
285
    }
286

287
    @Override
288
    public boolean retainEdges(Collection<? extends Edge> edges) {
289
        graphStore.autoWriteLock();
1✔
290
        try {
291
            return view.retainEdges(edges);
1✔
292
        } finally {
293
            graphStore.autoWriteUnlock();
1✔
294
        }
295
    }
296

297
    @Override
298
    public boolean contains(Node node) {
299
        checkValidNodeObject(node);
1✔
300
        graphStore.autoReadLock();
1✔
301
        try {
302
            return view.containsNode(node);
1✔
303
        } finally {
304
            graphStore.autoReadUnlock();
1✔
305
        }
306
    }
307

308
    @Override
309
    public boolean contains(Edge edge) {
310
        checkValidEdgeObject(edge);
1✔
311
        graphStore.autoReadLock();
1✔
312
        try {
313
            return view.containsEdge((EdgeImpl) edge);
1✔
314
        } finally {
315
            graphStore.autoReadUnlock();
1✔
316
        }
317
    }
318

319
    @Override
320
    public Node getNode(Object id) {
321
        graphStore.autoReadLock();
1✔
322
        try {
323
            NodeImpl node = graphStore.getNode(id);
1✔
324
            if (node != null && view.containsNode(node)) {
1✔
325
                return node;
1✔
326
            }
327
            return null;
1✔
328
        } finally {
329
            graphStore.autoReadUnlock();
1✔
330
        }
331
    }
332

333
    @Override
334
    public Node getNodeByStoreId(int id) {
335
        graphStore.autoReadLock();
×
336
        try {
337
            NodeImpl node = graphStore.getNodeByStoreId(id);
×
338
            if (node != null && view.containsNode(node)) {
×
339
                return node;
×
340
            }
341
            return null;
×
342
        } finally {
343
            graphStore.autoReadUnlock();
×
344
        }
345
    }
346

347
    @Override
348
    public boolean hasNode(final Object id) {
349
        return getNode(id) != null;
1✔
350
    }
351

352
    @Override
353
    public Edge getEdge(Object id) {
354
        graphStore.autoReadLock();
1✔
355
        try {
356
            EdgeImpl edge = graphStore.getEdge(id);
1✔
357
            if (edge != null && view.containsEdge(edge)) {
1✔
358
                return edge;
1✔
359
            }
360
            return null;
1✔
361
        } finally {
362
            graphStore.autoReadUnlock();
1✔
363
        }
364
    }
365

366
    @Override
367
    public Edge getEdgeByStoreId(int id) {
368
        graphStore.autoReadLock();
×
369
        try {
370
            EdgeImpl edge = graphStore.getEdgeByStoreId(id);
×
371
            if (edge != null && view.containsEdge(edge)) {
×
372
                return edge;
×
373
            }
374
            return null;
×
375
        } finally {
376
            graphStore.autoReadUnlock();
×
377
        }
378
    }
379

380
    @Override
381
    public boolean hasEdge(final Object id) {
382
        return getEdge(id) != null;
1✔
383
    }
384

385
    @Override
386
    public NodeIterable getNodes() {
387
        return new NodeIterableWrapper(() -> new NodeViewIterator(graphStore.nodeStore.iterator()),
1✔
388
                NodeViewSpliterator::new, graphStore.getAutoLock());
1✔
389
    }
390

391
    @Override
392
    public EdgeIterable getEdges() {
393
        if (undirected) {
1✔
394
            return new EdgeIterableWrapper(() -> new UndirectedEdgeViewIterator(graphStore.edgeStore.iterator()),
1✔
395
                    () -> graphStore.edgeStore
1✔
396
                            .newFilteredSizedSpliterator(e -> view.containsEdge(e) && !isUndirectedToIgnore(e), view
1✔
397
                                    .getUndirectedEdgeCount()),
1✔
398
                    graphStore.getAutoLock());
1✔
399
        } else {
400
            return new EdgeIterableWrapper(() -> new EdgeViewIterator(graphStore.edgeStore.iterator()),
1✔
401
                    () -> graphStore.edgeStore.newFilteredSizedSpliterator(view::containsEdge, view.getEdgeCount()),
1✔
402
                    graphStore.getAutoLock());
1✔
403
        }
404
    }
405

406
    @Override
407
    public EdgeIterable getEdges(int type) {
408
        if (undirected) {
×
409
            return new EdgeIterableWrapper(
×
410
                    () -> new UndirectedEdgeViewIterator(graphStore.edgeStore.iteratorType(type, undirected)),
×
411
                    () -> graphStore.edgeStore.newFilteredSizedSpliterator(e -> e.getType() == type && view
×
412
                            .containsEdge(e) && !isUndirectedToIgnore(e), view.getUndirectedEdgeCount(type)),
×
413
                    graphStore.getAutoLock());
×
414
        } else {
415
            return new EdgeIterableWrapper(
×
416
                    () -> new EdgeViewIterator(graphStore.edgeStore.iteratorType(type, undirected)),
×
417
                    () -> graphStore.edgeStore
×
418
                            .newFilteredSizedSpliterator(e -> e.getType() == type && view.containsEdge(e), view
×
419
                                    .getEdgeCount(type)),
×
420
                    graphStore.getAutoLock());
×
421
        }
422
    }
423

424
    @Override
425
    public EdgeIterable getSelfLoops() {
426
        return new EdgeIterableWrapper(() -> new EdgeViewIterator(graphStore.edgeStore.iteratorSelfLoop()),
1✔
427
                () -> graphStore.edgeStore.newFilteredSpliterator(e -> e.isSelfLoop() && view.containsEdge(e)),
1✔
428
                graphStore.getAutoLock());
1✔
429
    }
430

431
    @Override
432
    public NodeIterable getNeighbors(Node node) {
433
        checkValidInViewNodeObject(node);
1✔
434
        return new NodeIterableWrapper(
1✔
435
                () -> new NeighborsIterator((NodeImpl) node,
1✔
436
                        new UndirectedEdgeViewIterator(graphStore.edgeStore.edgeIterator(node, true))),
1✔
437
                graphStore.getAutoLock());
1✔
438
    }
439

440
    @Override
441
    public NodeIterable getNeighbors(Node node, int type) {
442
        checkValidInViewNodeObject(node);
1✔
443
        return new NodeIterableWrapper(
1✔
444
                () -> new NeighborsIterator((NodeImpl) node,
1✔
445
                        new UndirectedEdgeViewIterator(graphStore.edgeStore.edgeIterator(node, type))),
1✔
446
                graphStore.getAutoLock());
1✔
447
    }
448

449
    @Override
450
    public EdgeIterable getEdges(Node node) {
451
        checkValidInViewNodeObject(node);
1✔
452
        if (undirected) {
1✔
453
            return new EdgeIterableWrapper(
1✔
454
                    () -> new UndirectedEdgeViewIterator(graphStore.edgeStore.edgeIterator(node, true)),
1✔
455
                    graphStore.getAutoLock());
1✔
456
        } else {
457
            return new EdgeIterableWrapper(() -> new EdgeViewIterator(graphStore.edgeStore.edgeIterator(node, true)),
1✔
458
                    graphStore.getAutoLock());
1✔
459
        }
460
    }
461

462
    @Override
463
    public EdgeIterable getEdges(Node node, int type) {
464
        checkValidInViewNodeObject(node);
1✔
465
        if (undirected) {
1✔
466
            return new EdgeIterableWrapper(
1✔
467
                    () -> new UndirectedEdgeViewIterator(graphStore.edgeStore.edgeIterator(node, type)),
1✔
468
                    graphStore.getAutoLock());
1✔
469
        } else {
470
            return new EdgeIterableWrapper(() -> new EdgeViewIterator(graphStore.edgeStore.edgeIterator(node, type)),
1✔
471
                    graphStore.getAutoLock());
1✔
472
        }
473
    }
474

475
    @Override
476
    public int getNodeCount() {
477
        return view.getNodeCount();
1✔
478
    }
479

480
    @Override
481
    public int getEdgeCount() {
482
        if (undirected) {
1✔
483
            return view.getUndirectedEdgeCount();
1✔
484
        } else {
485
            return view.getEdgeCount();
1✔
486
        }
487
    }
488

489
    @Override
490
    public int getEdgeCount(int type) {
491
        if (undirected) {
1✔
492
            return view.getUndirectedEdgeCount(type);
1✔
493
        } else {
494
            return view.getEdgeCount(type);
1✔
495
        }
496
    }
497

498
    @Override
499
    public Node getOpposite(Node node, Edge edge) {
500
        checkValidInViewNodeObject(node);
1✔
501
        checkValidInViewEdgeObject(edge);
1✔
502

503
        return graphStore.getOpposite(node, edge);
1✔
504
    }
505

506
    @Override
507
    public int getDegree(Node node) {
508
        if (undirected) {
1✔
509
            int count = 0;
1✔
510
            EdgeStore.EdgeInOutIterator itr = graphStore.edgeStore.edgeIterator(node, true);
1✔
511
            while (itr.hasNext()) {
1✔
512
                EdgeImpl edge = itr.next();
1✔
513
                if (view.containsEdge(edge) && !isUndirectedToIgnore(edge)) {
1✔
514
                    count++;
1✔
515
                    if (edge.isSelfLoop()) {
1✔
516
                        count++;
1✔
517
                    }
518
                }
519
            }
1✔
520
            return count;
1✔
521
        } else {
522
            int count = 0;
1✔
523
            EdgeStore.EdgeInOutIterator itr = graphStore.edgeStore.edgeIterator(node, true);
1✔
524
            while (itr.hasNext()) {
1✔
525
                EdgeImpl edge = itr.next();
1✔
526
                if (view.containsEdge(edge)) {
1✔
527
                    count++;
1✔
528
                    if (edge.isSelfLoop()) {
1✔
529
                        count++;
1✔
530
                    }
531
                }
532
            }
1✔
533
            return count;
1✔
534
        }
535
    }
536

537
    @Override
538
    public int getInDegree(Node node) {
539
        int count = 0;
1✔
540
        EdgeStore.EdgeInIterator itr = graphStore.edgeStore.edgeInIterator(node);
1✔
541
        while (itr.hasNext()) {
1✔
542
            if (view.containsEdge(itr.next())) {
1✔
543
                count++;
1✔
544
            }
545
        }
546
        return count;
1✔
547
    }
548

549
    @Override
550
    public int getOutDegree(Node node) {
551
        int count = 0;
1✔
552
        EdgeStore.EdgeOutIterator itr = graphStore.edgeStore.edgeOutIterator(node);
1✔
553
        while (itr.hasNext()) {
1✔
554
            if (view.containsEdge(itr.next())) {
1✔
555
                count++;
1✔
556
            }
557
        }
558
        return count;
1✔
559
    }
560

561
    @Override
562
    public boolean isSelfLoop(Edge edge) {
563
        return edge.isSelfLoop();
1✔
564
    }
565

566
    @Override
567
    public boolean isDirected(Edge edge) {
568
        return edge.isDirected();
1✔
569
    }
570

571
    @Override
572
    public boolean isIncident(Edge edge1, Edge edge2) {
573
        graphStore.autoReadLock();
1✔
574
        try {
575
            checkValidInViewEdgeObject(edge1);
1✔
576
            checkValidInViewEdgeObject(edge2);
1✔
577

578
            return graphStore.edgeStore.isIncident((EdgeImpl) edge1, (EdgeImpl) edge2);
1✔
579
        } finally {
580
            graphStore.autoReadUnlock();
1✔
581
        }
582
    }
583

584
    @Override
585
    public boolean isIncident(final Node node, final Edge edge) {
586
        graphStore.autoReadLock();
1✔
587
        try {
588
            checkValidInViewNodeObject(node);
1✔
589
            checkValidInViewEdgeObject(edge);
1✔
590

591
            return graphStore.edgeStore.isIncident((NodeImpl) node, (EdgeImpl) edge);
1✔
592
        } finally {
593
            graphStore.autoReadUnlock();
1✔
594
        }
595
    }
596

597
    @Override
598
    public void clearEdges(Node node) {
599
        graphStore.autoWriteLock();
1✔
600
        try {
601
            EdgeStore.EdgeInOutIterator itr = graphStore.edgeStore.edgeIterator(node, false);
1✔
602
            while (itr.hasNext()) {
1✔
603
                EdgeImpl edge = itr.next();
1✔
604
                view.removeEdge(edge);
1✔
605
            }
1✔
606
        } finally {
607
            graphStore.autoWriteUnlock();
1✔
608
        }
609
    }
1✔
610

611
    @Override
612
    public void clearEdges(Node node, int type) {
613
        graphStore.autoWriteLock();
1✔
614
        try {
615
            EdgeStore.EdgeTypeInOutIterator itr = graphStore.edgeStore.edgeIterator(node, type);
1✔
616
            while (itr.hasNext()) {
1✔
617
                EdgeImpl edge = itr.next();
1✔
618
                view.removeEdge(edge);
1✔
619
            }
1✔
620
        } finally {
621
            graphStore.autoWriteUnlock();
1✔
622
        }
623
    }
1✔
624

625
    @Override
626
    public void clear() {
627
        view.clear();
1✔
628
    }
1✔
629

630
    @Override
631
    public void clearEdges() {
632
        view.clearEdges();
1✔
633
    }
1✔
634

635
    @Override
636
    public Object getAttribute(String key) {
637
        return view.attributes.getValue(key);
1✔
638
    }
639

640
    @Override
641
    public Object getAttribute(String key, double timestamp) {
642
        return view.attributes.getValue(key, timestamp);
1✔
643
    }
644

645
    @Override
646
    public Object getAttribute(String key, Interval interval) {
647
        return view.attributes.getValue(key, interval);
1✔
648
    }
649

650
    @Override
651
    public Set<String> getAttributeKeys() {
652
        return view.attributes.getKeys();
1✔
653
    }
654

655
    @Override
656
    public void setAttribute(String key, Object value) {
657
        view.attributes.setValue(key, value);
1✔
658
    }
1✔
659

660
    @Override
661
    public void setAttribute(String key, Object value, double timestamp) {
662
        view.attributes.setValue(key, value, timestamp);
1✔
663
    }
1✔
664

665
    @Override
666
    public void setAttribute(String key, Object value, Interval interval) {
667
        view.attributes.setValue(key, value, interval);
1✔
668
    }
1✔
669

670
    @Override
671
    public void removeAttribute(String key) {
672
        view.attributes.removeValue(key);
1✔
673
    }
1✔
674

675
    @Override
676
    public void removeAttribute(String key, double timestamp) {
677
        view.attributes.removeValue(key, timestamp);
1✔
678
    }
1✔
679

680
    @Override
681
    public void removeAttribute(String key, Interval interval) {
682
        view.attributes.removeValue(key, interval);
1✔
683
    }
1✔
684

685
    @Override
686
    public GraphModel getModel() {
687
        return graphStore.graphModel;
×
688
    }
689

690
    @Override
691
    public int getVersion() {
692
        return view.getVersion();
×
693
    }
694

695
    @Override
696
    public boolean isDirected() {
697
        return graphStore.isDirected();
1✔
698
    }
699

700
    @Override
701
    public boolean isUndirected() {
702
        return graphStore.isUndirected();
1✔
703
    }
704

705
    @Override
706
    public boolean isMixed() {
707
        return graphStore.isMixed();
×
708
    }
709

710
    @Override
711
    public void readLock() {
712
        graphStore.lock.readLock();
1✔
713
    }
1✔
714

715
    @Override
716
    public void readUnlock() {
717
        graphStore.lock.readUnlock();
1✔
718
    }
1✔
719

720
    @Override
721
    public void readUnlockAll() {
722
        graphStore.lock.readUnlockAll();
×
723
    }
×
724

725
    @Override
726
    public void writeLock() {
727
        graphStore.lock.writeLock();
1✔
728
    }
1✔
729

730
    @Override
731
    public GraphLockImpl getLock() {
732
        return graphStore.lock;
1✔
733
    }
734

735
    @Override
736
    public void writeUnlock() {
737
        graphStore.lock.writeUnlock();
1✔
738
    }
1✔
739

740
    @Override
741
    public GraphView getView() {
742
        return view;
1✔
743
    }
744

745
    @Override
746
    public void fill() {
747
        graphStore.autoWriteLock();
1✔
748
        try {
749
            view.fill();
1✔
750
        } finally {
751
            graphStore.autoWriteUnlock();
1✔
752
        }
753
    }
1✔
754

755
    @Override
756
    public void union(Subgraph subGraph) {
757
        checkValidViewObject(subGraph.getView());
1✔
758

759
        graphStore.autoWriteLock();
1✔
760
        try {
761
            view.union((GraphViewImpl) subGraph.getView());
1✔
762
        } finally {
763
            graphStore.autoWriteUnlock();
1✔
764
        }
765
    }
1✔
766

767
    @Override
768
    public void intersection(Subgraph subGraph) {
769
        checkValidViewObject(subGraph.getView());
1✔
770

771
        graphStore.autoWriteLock();
1✔
772
        try {
773
            view.intersection((GraphViewImpl) subGraph.getView());
1✔
774
        } finally {
775
            graphStore.autoWriteUnlock();
1✔
776
        }
777
    }
1✔
778

779
    @Override
780
    public void not() {
781
        graphStore.autoWriteLock();
×
782
        try {
783
            view.not();
×
784
        } finally {
785
            graphStore.autoWriteUnlock();
×
786
        }
787
    }
×
788

789
    @Override
790
    public Graph getRootGraph() {
791
        return graphStore;
×
792
    }
793

794
    @Override
795
    public SpatialIndex getSpatialIndex() {
796
        if (graphStore.spatialIndex == null) {
1✔
797
            throw new UnsupportedOperationException("Spatial index is disabled (from Configuration)");
×
798
        }
799
        return this;
1✔
800
    }
801

802
    void checkWriteLock() {
803
        if (graphStore.lock != null) {
×
804
            graphStore.lock.checkHoldWriteLock();
×
805
        }
806
    }
×
807

808
    void checkValidNodeObject(final Node n) {
809
        if (n == null) {
1✔
810
            throw new NullPointerException();
×
811
        }
812
        if (!(n instanceof NodeImpl)) {
1✔
813
            throw new ClassCastException("Object must be a NodeImpl object");
×
814
        }
815
        if (n.getStoreId() == NodeStore.NULL_ID) {
1✔
816
            throw new IllegalArgumentException("Node should belong to a store");
×
817
        }
818
    }
1✔
819

820
    void checkValidInViewNodeObject(final Node n) {
821
        checkValidNodeObject(n);
1✔
822

823
        if (!view.containsNode(n)) {
1✔
824
            throw new RuntimeException("Node doesn't belong to this view");
1✔
825
        }
826
    }
1✔
827

828
    void checkValidEdgeObject(final Edge n) {
829
        if (n == null) {
1✔
830
            throw new NullPointerException();
×
831
        }
832
        if (!(n instanceof EdgeImpl)) {
1✔
833
            throw new ClassCastException("Object must be a EdgeImpl object");
×
834
        }
835
        if (n.getStoreId() == EdgeStore.NULL_ID) {
1✔
836
            throw new IllegalArgumentException("Edge should belong to a store");
×
837
        }
838
    }
1✔
839

840
    void checkValidInViewEdgeObject(final Edge e) {
841
        checkValidEdgeObject(e);
1✔
842

843
        if (!view.containsEdge(e)) {
1✔
844
            throw new RuntimeException("Edge doesn't belong to this view");
×
845
        }
846
    }
1✔
847

848
    void checkValidViewObject(final GraphView view) {
849
        if (view == null) {
1✔
850
            throw new NullPointerException();
×
851
        }
852
        if (!(view instanceof GraphViewImpl)) {
1✔
853
            throw new ClassCastException("Object must be a GraphViewImpl object");
×
854
        }
855
        if (((GraphViewImpl) view).graphStore != graphStore) {
1✔
856
            throw new RuntimeException("The view doesn't belong to this store");
×
857
        }
858
    }
1✔
859

860
    boolean isUndirectedToIgnore(final EdgeImpl edge) {
861
        if (edge.isMutual() && edge.source.storeId < edge.target.storeId) {
1✔
862
            if (view.containsEdge(graphStore.edgeStore.get(edge.target, edge.source, edge.type, false))) {
1✔
863
                return true;
1✔
864
            }
865
        }
866
        return false;
1✔
867
    }
868

869
    @Override
870
    public NodeIterable getNodesInArea(Rect2D rect) {
871
        if (graphStore.spatialIndex == null) {
×
872
            throw new UnsupportedOperationException("Spatial index is disabled (from Configuration)");
×
873
        }
NEW
874
        return graphStore.spatialIndex.getNodesInArea(rect, view::containsNode);
×
875
    }
876

877
    @Override
878
    public NodeIterable getApproximateNodesInArea(Rect2D rect) {
NEW
879
        if (graphStore.spatialIndex == null) {
×
NEW
880
            throw new UnsupportedOperationException("Spatial index is disabled (from Configuration)");
×
881
        }
NEW
882
        return graphStore.spatialIndex.getApproximateNodesInArea(rect, view::containsNode);
×
883
    }
884

885
    @Override
886
    public EdgeIterable getEdgesInArea(Rect2D rect) {
887
        if (graphStore.spatialIndex == null) {
×
888
            throw new UnsupportedOperationException("Spatial index is disabled (from Configuration)");
×
889
        }
NEW
890
        return graphStore.spatialIndex.getEdgesInArea(rect, view::containsEdge);
×
891
    }
892

893
    @Override
894
    public EdgeIterable getApproximateEdgesInArea(Rect2D rect) {
NEW
895
        if (graphStore.spatialIndex == null) {
×
NEW
896
            throw new UnsupportedOperationException("Spatial index is disabled (from Configuration)");
×
897
        }
NEW
898
        return graphStore.spatialIndex.getApproximateEdgesInArea(rect, view::containsEdge);
×
899
    }
900

901
    @Override
902
    public Rect2D getBoundaries() {
903
        if (graphStore.spatialIndex == null) {
1✔
NEW
904
            throw new UnsupportedOperationException("Spatial index is disabled (from Configuration)");
×
905
        }
906
        return graphStore.spatialIndex.getBoundaries(view::containsNode);
1✔
907
    }
908

909
    @Override
910
    public void spatialIndexReadLock() {
NEW
911
        if (graphStore.spatialIndex == null) {
×
NEW
912
            throw new UnsupportedOperationException("Spatial index is disabled (from Configuration)");
×
913
        }
NEW
914
        graphStore.spatialIndex.spatialIndexReadLock();
×
NEW
915
    }
×
916

917
    @Override
918
    public void spatialIndexReadUnlock() {
NEW
919
        if (graphStore.spatialIndex == null) {
×
NEW
920
            throw new UnsupportedOperationException("Spatial index is disabled (from Configuration)");
×
921
        }
NEW
922
        graphStore.spatialIndex.spatialIndexReadUnlock();
×
UNCOV
923
    }
×
924

925
    private final class NodeViewSpliterator implements Spliterator<Node> {
926

927
        private final int endBlockExclusive;
928
        private int blockIndex;
929
        private int indexInBlock;
930
        private NodeImpl[] currentArray;
931
        private int currentLength;
932
        private final int expectedVersion;
933
        private int totalSize;
934
        private int consumed;
935

936
        NodeViewSpliterator() {
937
            this(0, graphStore.nodeStore.blocksCount);
1✔
938
        }
1✔
939

940
        NodeViewSpliterator(int startBlock, int endBlockExclusive) {
1✔
941
            this.blockIndex = startBlock;
1✔
942
            this.endBlockExclusive = endBlockExclusive;
1✔
943
            this.expectedVersion = graphStore.version != null ? graphStore.version.getNodeVersion() : 0;
1✔
944
            this.consumed = 0;
1✔
945

946
            // Use the view's node count for exact sizing
947
            // Use the total store size for the root spliterator (covering all blocks)
948
            if (startBlock == 0 && endBlockExclusive == graphStore.nodeStore.blocksCount) {
1✔
949
                this.totalSize = view.getNodeCount();
1✔
950
            } else {
951
                // For split spliterators, compute proportionally
952
                this.totalSize = computeSizeEstimate(startBlock, endBlockExclusive);
×
953
            }
954

955
            if (startBlock < endBlockExclusive) {
1✔
956
                NodeStore.NodeBlock b = graphStore.nodeStore.blocks[startBlock];
1✔
957
                currentArray = b.backingArray;
1✔
958
                currentLength = b.nodeLength;
1✔
959
                indexInBlock = 0;
1✔
960
            } else {
1✔
961
                currentArray = null;
×
962
                currentLength = 0;
×
963
                indexInBlock = 0;
×
964
            }
965
        }
1✔
966

967
        private void advanceBlock() {
968
            blockIndex++;
1✔
969
            if (blockIndex < endBlockExclusive) {
1✔
970
                NodeStore.NodeBlock b = graphStore.nodeStore.blocks[blockIndex];
×
971
                currentArray = b.backingArray;
×
972
                currentLength = b.nodeLength;
×
973
                indexInBlock = 0;
×
974
            } else {
×
975
                currentArray = null;
1✔
976
                currentLength = 0;
1✔
977
                indexInBlock = 0;
1✔
978
            }
979
        }
1✔
980

981
        private void checkForComodification() {
982
            if (graphStore.version != null && expectedVersion != graphStore.version.getNodeVersion()) {
1✔
983
                throw new ConcurrentModificationException();
×
984
            }
985
        }
1✔
986

987
        private int computeSizeEstimate(int start, int end) {
988
            int sum = 0;
×
989
            for (int i = start; i < end; i++) {
×
990
                NodeStore.NodeBlock b = graphStore.nodeStore.blocks[i];
×
991
                if (b != null) {
×
992
                    // Exact count: nodeLength minus garbageLength
993
                    sum += (b.nodeLength - b.garbageLength);
×
994
                }
995
            }
996
            if (sum > 0) {
×
997
                // Scale by view ratio to estimate number of nodes in view
998
                double viewRatio = (double) view.getNodeCount() / graphStore.nodeStore.size;
×
999
                sum = (int) Math.round(sum * viewRatio);
×
1000
            }
1001
            return sum;
×
1002
        }
1003

1004
        @Override
1005
        public boolean tryAdvance(Consumer<? super Node> action) {
1006
            checkForComodification();
1✔
1007
            while (currentArray != null) {
1✔
1008
                while (indexInBlock < currentLength) {
1✔
1009
                    NodeImpl n = currentArray[indexInBlock++];
1✔
1010
                    if (n != null && view.containsNode(n)) {
1✔
1011
                        consumed++;
1✔
1012
                        action.accept(n);
1✔
1013
                        return true;
1✔
1014
                    }
1015
                }
1✔
1016
                advanceBlock();
1✔
1017
            }
1018
            return false;
1✔
1019
        }
1020

1021
        @Override
1022
        public Spliterator<Node> trySplit() {
1023
            // Only split at block boundaries to preserve encounter order
1024
            if (indexInBlock != 0) {
1✔
1025
                return null;
×
1026
            }
1027

1028
            int currentPos = blockIndex;
1✔
1029
            int remainingBlocks = endBlockExclusive - currentPos;
1✔
1030

1031
            if (remainingBlocks <= 1) {
1✔
1032
                return null;
1✔
1033
            }
1034

1035
            int mid = currentPos + remainingBlocks / 2;
×
1036

1037
            // Create left half
1038
            NodeViewSpliterator left = new NodeViewSpliterator(currentPos, mid);
×
1039

1040
            // Update this spliterator to become the right half
1041
            blockIndex = mid;
×
1042
            if (mid < endBlockExclusive) {
×
1043
                NodeStore.NodeBlock b = graphStore.nodeStore.blocks[mid];
×
1044
                currentArray = b.backingArray;
×
1045
                currentLength = b.nodeLength;
×
1046
                indexInBlock = 0;
×
1047
            } else {
×
1048
                currentArray = null;
×
1049
                currentLength = 0;
×
1050
                indexInBlock = 0;
×
1051
            }
1052

1053
            // Update this spliterator size
1054
            this.totalSize = Math.max(0, totalSize - left.totalSize);
×
1055

1056
            return left;
×
1057
        }
1058

1059
        @Override
1060
        public long estimateSize() {
1061
            // Use the exact view size minus what we've consumed
1062
            long remaining = totalSize - consumed;
1✔
1063
            return remaining < 0 ? 0 : remaining;
1✔
1064
        }
1065

1066
        @Override
1067
        public int characteristics() {
1068
            // SIZED because we know the exact count from view.getNodeCount()
1069
            // But not SUBSIZED because splits can't guarantee exact size distribution
1070
            return Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.NONNULL | Spliterator.SIZED;
1✔
1071
        }
1072
    }
1073

1074
    protected final class NodeViewIterator implements Iterator<Node> {
1075

1076
        private final Iterator<Node> nodeIterator;
1077
        private NodeImpl pointer;
1078

1079
        public NodeViewIterator(Iterator<Node> nodeIterator) {
1✔
1080
            this.nodeIterator = nodeIterator;
1✔
1081
        }
1✔
1082

1083
        @Override
1084
        public boolean hasNext() {
1085
            pointer = null;
1✔
1086
            while (pointer == null) {
1✔
1087
                if (!nodeIterator.hasNext()) {
1✔
1088
                    return false;
1✔
1089
                }
1090
                pointer = (NodeImpl) nodeIterator.next();
1✔
1091
                if (!view.containsNode(pointer)) {
1✔
1092
                    pointer = null;
1✔
1093
                }
1094
            }
1095
            return true;
1✔
1096
        }
1097

1098
        @Override
1099
        public Node next() {
1100
            return pointer;
1✔
1101
        }
1102

1103
        @Override
1104
        public void remove() {
1105
            checkWriteLock();
×
1106
            removeNode(pointer);
×
1107
        }
×
1108
    }
1109

1110
    protected final class EdgeViewIterator implements Iterator<Edge> {
1111

1112
        private final Iterator<Edge> edgeIterator;
1113
        private EdgeImpl pointer;
1114

1115
        public EdgeViewIterator(Iterator<Edge> edgeIterator) {
1✔
1116
            this.edgeIterator = edgeIterator;
1✔
1117
        }
1✔
1118

1119
        @Override
1120
        public boolean hasNext() {
1121
            pointer = null;
1✔
1122
            while (pointer == null) {
1✔
1123
                if (!edgeIterator.hasNext()) {
1✔
1124
                    return false;
1✔
1125
                }
1126
                pointer = (EdgeImpl) edgeIterator.next();
1✔
1127
                if (!view.containsEdge(pointer)) {
1✔
1128
                    pointer = null;
1✔
1129
                }
1130
            }
1131
            return true;
1✔
1132
        }
1133

1134
        @Override
1135
        public Edge next() {
1136
            return pointer;
1✔
1137
        }
1138

1139
        @Override
1140
        public void remove() {
1141
            checkWriteLock();
×
1142
            removeEdge(pointer);
×
1143
        }
×
1144
    }
1145

1146
    protected final class UndirectedEdgeViewIterator implements Iterator<Edge> {
1147

1148
        protected final Iterator<Edge> itr;
1149
        protected EdgeImpl pointer;
1150

1151
        public UndirectedEdgeViewIterator(Iterator<Edge> itr) {
1✔
1152
            this.itr = itr;
1✔
1153
        }
1✔
1154

1155
        @Override
1156
        public boolean hasNext() {
1157
            pointer = null;
1✔
1158
            while (pointer == null || !view.containsEdge(pointer) || isUndirectedToIgnore(pointer)) {
1✔
1159
                if (!itr.hasNext()) {
1✔
1160
                    return false;
1✔
1161
                }
1162
                pointer = (EdgeImpl) itr.next();
1✔
1163
            }
1164
            return true;
1✔
1165
        }
1166

1167
        @Override
1168
        public EdgeImpl next() {
1169
            return pointer;
1✔
1170
        }
1171

1172
        @Override
1173
        public void remove() {
1174
            itr.remove();
×
1175
        }
×
1176
    }
1177

1178
    protected static class NeighborsIterator implements Iterator<Node> {
1179

1180
        protected final NodeImpl node;
1181
        protected final Iterator<Edge> itr;
1182

1183
        public NeighborsIterator(NodeImpl node, Iterator<Edge> itr) {
1✔
1184
            this.node = node;
1✔
1185
            this.itr = itr;
1✔
1186
        }
1✔
1187

1188
        @Override
1189
        public boolean hasNext() {
1190
            return itr.hasNext();
1✔
1191
        }
1192

1193
        @Override
1194
        public Node next() {
1195
            Edge e = itr.next();
1✔
1196
            return e.getSource() == node ? e.getTarget() : e.getSource();
1✔
1197
        }
1198

1199
        @Override
1200
        public void remove() {
1201
            throw new UnsupportedOperationException("Remove not supported for this iterator");
×
1202
        }
1203
    }
1204
}
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

© 2026 Coveralls, Inc