diff options
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.java | 102 |
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 | */ | ||
6 | package tools.refinery.store.model.internal; | ||
7 | |||
8 | import org.eclipse.collections.api.factory.Maps; | ||
9 | import org.eclipse.collections.api.factory.primitive.IntObjectMaps; | ||
10 | import org.eclipse.collections.api.map.MutableMap; | ||
11 | import org.eclipse.collections.api.map.primitive.MutableIntObjectMap; | ||
12 | import tools.refinery.store.map.*; | ||
13 | import tools.refinery.store.tuple.Tuple; | ||
14 | |||
15 | import java.util.Set; | ||
16 | |||
17 | class 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 | } | ||