aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/store/src/main/java/tools/refinery/store/model/internal/BaseIndexer.java
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/store/src/main/java/tools/refinery/store/model/internal/BaseIndexer.java')
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/internal/BaseIndexer.java102
1 files changed, 102 insertions, 0 deletions
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/BaseIndexer.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/BaseIndexer.java
new file mode 100644
index 00000000..3d7f59d7
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/BaseIndexer.java
@@ -0,0 +1,102 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.model.internal;
7
8import org.eclipse.collections.api.factory.Maps;
9import org.eclipse.collections.api.factory.primitive.IntObjectMaps;
10import org.eclipse.collections.api.map.MutableMap;
11import org.eclipse.collections.api.map.primitive.MutableIntObjectMap;
12import tools.refinery.store.map.*;
13import tools.refinery.store.tuple.Tuple;
14
15import java.util.Set;
16
17class BaseIndexer<T> {
18 private final MutableIntObjectMap<MutableMap<Tuple, T>>[] maps;
19 private final VersionedMap<Tuple, T> versionedMap;
20
21 public BaseIndexer(int arity, VersionedMap<Tuple, T> map) {
22 if (arity < 2) {
23 throw new IllegalArgumentException("Only arity >= 2 symbols need to be indexed");
24 }
25 // There is no way in Java to create a generic array in a checked way.
26 @SuppressWarnings({"unchecked", "squid:S1905"})
27 var uncheckedMaps = (MutableIntObjectMap<MutableMap<Tuple, T>>[]) new MutableIntObjectMap[arity];
28 maps = uncheckedMaps;
29 for (int i = 0; i < arity; i++) {
30 maps[i] = IntObjectMaps.mutable.empty();
31 }
32 this.versionedMap = map;
33 if (map != null) {
34 var cursor = map.getAll();
35 while (cursor.move()) {
36 put(cursor.getKey(), cursor.getValue());
37 }
38 }
39 }
40
41 public void put(Tuple key, T value) {
42 for (int i = 0; i < maps.length; i++) {
43 var map = maps[i];
44 int element = key.get(i);
45 var adjacentTuples = map.getIfAbsentPut(element, Maps.mutable::empty);
46 adjacentTuples.put(key, value);
47 }
48 }
49
50 public void remove(Tuple key) {
51 for (int i = 0; i < maps.length; i++) {
52 var map = maps[i];
53 int element = key.get(i);
54 var adjacentTuples = map.get(element);
55 if (adjacentTuples == null) {
56 continue;
57 }
58 adjacentTuples.remove(key);
59 if (adjacentTuples.isEmpty()) {
60 map.remove(element);
61 }
62 }
63 }
64
65 private MutableMap<Tuple, T> getAdjacentMap(int slot, int node) {
66 if (slot < 0 || slot >= maps.length) {
67 throw new IllegalArgumentException("Invalid index: " + slot);
68 }
69 var map = maps[slot];
70 return map.get(node);
71 }
72
73 public int getAdjacentSize(int slot, int node) {
74 var adjacentTuples = getAdjacentMap(slot, node);
75 if (adjacentTuples == null) {
76 return 0;
77 }
78 return adjacentTuples.size();
79 }
80
81 public Cursor<Tuple, T> getAdjacent(int slot, int node) {
82 var adjacentTuples = getAdjacentMap(slot, node);
83 if (adjacentTuples == null) {
84 return Cursors.empty();
85 }
86 return new IndexCursor<>(adjacentTuples, versionedMap);
87 }
88
89 private static class IndexCursor<T> extends IteratorBasedCursor<Tuple, T> {
90 private final Set<AnyVersionedMap> dependingMaps;
91
92 public IndexCursor(MutableMap<Tuple, T> map, VersionedMap<Tuple, T> versionedMap) {
93 super(map.entrySet().iterator());
94 dependingMaps = versionedMap == null ? Set.of() : Set.of(versionedMap);
95 }
96
97 @Override
98 public Set<AnyVersionedMap> getDependingMaps() {
99 return dependingMaps;
100 }
101 }
102}