diff options
Diffstat (limited to 'store/src/main/java/org/eclipse/viatra/solver/data/map/internal/MapDiffCursor.java')
-rw-r--r-- | store/src/main/java/org/eclipse/viatra/solver/data/map/internal/MapDiffCursor.java | 221 |
1 files changed, 0 insertions, 221 deletions
diff --git a/store/src/main/java/org/eclipse/viatra/solver/data/map/internal/MapDiffCursor.java b/store/src/main/java/org/eclipse/viatra/solver/data/map/internal/MapDiffCursor.java deleted file mode 100644 index 35d20539..00000000 --- a/store/src/main/java/org/eclipse/viatra/solver/data/map/internal/MapDiffCursor.java +++ /dev/null | |||
@@ -1,221 +0,0 @@ | |||
1 | package org.eclipse.viatra.solver.data.map.internal; | ||
2 | |||
3 | import java.util.List; | ||
4 | import java.util.stream.Stream; | ||
5 | |||
6 | import org.eclipse.viatra.solver.data.map.ContinousHashProvider; | ||
7 | import org.eclipse.viatra.solver.data.map.Cursor; | ||
8 | import org.eclipse.viatra.solver.data.map.DiffCursor; | ||
9 | import org.eclipse.viatra.solver.data.map.VersionedMap; | ||
10 | |||
11 | /** | ||
12 | * A cursor representing the difference between two states of a map. | ||
13 | * | ||
14 | * @author Oszkar Semerath | ||
15 | * | ||
16 | */ | ||
17 | public class MapDiffCursor<K, V> implements DiffCursor<K, V>, Cursor<K, V> { | ||
18 | /** | ||
19 | * Default value representing missing elements. | ||
20 | */ | ||
21 | private V defaultValue; | ||
22 | private MapCursor<K, V> cursor1; | ||
23 | private MapCursor<K, V> cursor2; | ||
24 | private ContinousHashProvider<? super K> hashProvider; | ||
25 | |||
26 | // Values | ||
27 | private K key; | ||
28 | private V fromValue; | ||
29 | private V toValue; | ||
30 | |||
31 | // State | ||
32 | /** | ||
33 | * Positive number if cursor 1 is behind, negative number if cursor 2 is behind, | ||
34 | * and 0 if they are at the same position. | ||
35 | */ | ||
36 | private int cursorRelation; | ||
37 | private HashClash hashClash = HashClash.NONE; | ||
38 | |||
39 | public MapDiffCursor(ContinousHashProvider<? super K> hashProvider, V defaultValue, Cursor<K, V> cursor1, | ||
40 | Cursor<K, V> cursor2) { | ||
41 | super(); | ||
42 | this.hashProvider = hashProvider; | ||
43 | this.defaultValue = defaultValue; | ||
44 | this.cursor1 = (MapCursor<K, V>) cursor1; | ||
45 | this.cursor2 = (MapCursor<K, V>) cursor2; | ||
46 | } | ||
47 | |||
48 | @Override | ||
49 | public K getKey() { | ||
50 | return key; | ||
51 | } | ||
52 | |||
53 | @Override | ||
54 | public V getFromValue() { | ||
55 | return fromValue; | ||
56 | } | ||
57 | |||
58 | @Override | ||
59 | public V getToValue() { | ||
60 | return toValue; | ||
61 | } | ||
62 | |||
63 | @Override | ||
64 | public V getValue() { | ||
65 | return getToValue(); | ||
66 | } | ||
67 | |||
68 | public boolean isTerminated() { | ||
69 | return cursor1.isTerminated() && cursor2.isTerminated(); | ||
70 | } | ||
71 | |||
72 | @Override | ||
73 | public boolean isDirty() { | ||
74 | return this.cursor1.isDirty() || this.cursor2.isDirty(); | ||
75 | } | ||
76 | |||
77 | @Override | ||
78 | public List<VersionedMap<?, ?>> getDependingMaps() { | ||
79 | return Stream.concat(cursor1.getDependingMaps().stream(), cursor2.getDependingMaps().stream()).toList(); | ||
80 | } | ||
81 | |||
82 | protected void updateState() { | ||
83 | if (!isTerminated()) { | ||
84 | this.cursorRelation = MapCursor.compare(cursor1, cursor2); | ||
85 | if (cursorRelation > 0 || cursor2.isTerminated()) { | ||
86 | this.key = cursor1.getKey(); | ||
87 | this.fromValue = cursor1.getValue(); | ||
88 | this.toValue = defaultValue; | ||
89 | } else if (cursorRelation < 0 || cursor1.isTerminated()) { | ||
90 | this.key = cursor2.getKey(); | ||
91 | this.fromValue = defaultValue; | ||
92 | this.toValue = cursor1.getValue(); | ||
93 | } else { | ||
94 | // cursor1 = cursor2 | ||
95 | if (cursor1.getKey().equals(cursor2.getKey())) { | ||
96 | this.key = cursor1.getKey(); | ||
97 | this.fromValue = cursor1.getValue(); | ||
98 | this.toValue = defaultValue; | ||
99 | } else { | ||
100 | resolveHashClashWithFirstEntry(); | ||
101 | } | ||
102 | } | ||
103 | } | ||
104 | } | ||
105 | |||
106 | protected void resolveHashClashWithFirstEntry() { | ||
107 | int compareResult = this.hashProvider.compare(cursor1.key, cursor2.key); | ||
108 | if (compareResult < 0) { | ||
109 | this.hashClash = HashClash.STUCK_CURSOR_2; | ||
110 | this.cursorRelation = 0; | ||
111 | this.key = cursor1.key; | ||
112 | this.fromValue = cursor1.value; | ||
113 | this.toValue = defaultValue; | ||
114 | } else if (compareResult > 0) { | ||
115 | this.hashClash = HashClash.STUCK_CURSOR_1; | ||
116 | this.cursorRelation = 0; | ||
117 | this.key = cursor2.key; | ||
118 | this.fromValue = defaultValue; | ||
119 | this.toValue = cursor2.value; | ||
120 | } else { | ||
121 | throw new IllegalArgumentException("Inconsistent compare result for diffcursor"); | ||
122 | } | ||
123 | } | ||
124 | |||
125 | protected boolean isInHashClash() { | ||
126 | return this.hashClash != HashClash.NONE; | ||
127 | } | ||
128 | |||
129 | protected void resolveHashClashWithSecondEntry() { | ||
130 | switch (this.hashClash) { | ||
131 | case STUCK_CURSOR_1: | ||
132 | this.hashClash = HashClash.NONE; | ||
133 | this.cursorRelation = 0; | ||
134 | this.key = cursor1.key; | ||
135 | this.fromValue = cursor1.value; | ||
136 | this.toValue = defaultValue; | ||
137 | break; | ||
138 | case STUCK_CURSOR_2: | ||
139 | this.hashClash = HashClash.NONE; | ||
140 | this.cursorRelation = 0; | ||
141 | this.key = cursor2.key; | ||
142 | this.fromValue = defaultValue; | ||
143 | this.toValue = cursor2.value; | ||
144 | break; | ||
145 | default: | ||
146 | throw new IllegalArgumentException("Inconsistent compare result for diffcursor"); | ||
147 | } | ||
148 | } | ||
149 | |||
150 | protected boolean sameValues() { | ||
151 | if (this.fromValue == null) { | ||
152 | return this.toValue == null; | ||
153 | } else { | ||
154 | return this.fromValue.equals(this.toValue); | ||
155 | } | ||
156 | } | ||
157 | |||
158 | protected boolean moveOne() { | ||
159 | if (isTerminated()) { | ||
160 | return false; | ||
161 | } | ||
162 | if (this.cursorRelation > 0 || cursor2.isTerminated()) { | ||
163 | return cursor1.move(); | ||
164 | } else if (this.cursorRelation < 0 || cursor1.isTerminated()) { | ||
165 | return cursor2.move(); | ||
166 | } else { | ||
167 | boolean moved1 = cursor1.move(); | ||
168 | boolean moved2 = cursor2.move(); | ||
169 | return moved1 && moved2; | ||
170 | } | ||
171 | } | ||
172 | |||
173 | private boolean skipNode() { | ||
174 | if (isTerminated()) { | ||
175 | throw new IllegalStateException("DiffCursor tries to skip when terminated!"); | ||
176 | } | ||
177 | boolean update1 = cursor1.skipCurrentNode(); | ||
178 | boolean update2 = cursor2.skipCurrentNode(); | ||
179 | updateState(); | ||
180 | return update1 && update2; | ||
181 | } | ||
182 | |||
183 | protected boolean moveToConsistentState() { | ||
184 | if (!isTerminated()) { | ||
185 | boolean changed; | ||
186 | boolean lastResult = true; | ||
187 | do { | ||
188 | changed = false; | ||
189 | if (MapCursor.sameSubnode(cursor1, cursor2)) { | ||
190 | lastResult = skipNode(); | ||
191 | changed = true; | ||
192 | } | ||
193 | if (sameValues()) { | ||
194 | lastResult = moveOne(); | ||
195 | changed = true; | ||
196 | } | ||
197 | updateState(); | ||
198 | } while (changed && !isTerminated()); | ||
199 | return lastResult; | ||
200 | } else { | ||
201 | return false; | ||
202 | } | ||
203 | } | ||
204 | |||
205 | public boolean move() { | ||
206 | if (!isTerminated()) { | ||
207 | if (isInHashClash()) { | ||
208 | this.resolveHashClashWithSecondEntry(); | ||
209 | return true; | ||
210 | } else { | ||
211 | if (moveOne()) { | ||
212 | return moveToConsistentState(); | ||
213 | } else { | ||
214 | return false; | ||
215 | } | ||
216 | } | ||
217 | |||
218 | } else | ||
219 | return false; | ||
220 | } | ||
221 | } | ||