diff options
Diffstat (limited to 'Solvers/VIATRA-Solver/org.eclipse.viatra.solver.data/src/org/eclipse/viatra/solver/data/map/internal/MapDiffCursor.java')
-rw-r--r-- | Solvers/VIATRA-Solver/org.eclipse.viatra.solver.data/src/org/eclipse/viatra/solver/data/map/internal/MapDiffCursor.java | 136 |
1 files changed, 96 insertions, 40 deletions
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.solver.data/src/org/eclipse/viatra/solver/data/map/internal/MapDiffCursor.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.solver.data/src/org/eclipse/viatra/solver/data/map/internal/MapDiffCursor.java index 5c911bb4..8d7cda14 100644 --- a/Solvers/VIATRA-Solver/org.eclipse.viatra.solver.data/src/org/eclipse/viatra/solver/data/map/internal/MapDiffCursor.java +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.solver.data/src/org/eclipse/viatra/solver/data/map/internal/MapDiffCursor.java | |||
@@ -4,6 +4,7 @@ import java.util.List; | |||
4 | import java.util.stream.Collectors; | 4 | import java.util.stream.Collectors; |
5 | import java.util.stream.Stream; | 5 | import java.util.stream.Stream; |
6 | 6 | ||
7 | 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.Cursor; |
8 | import org.eclipse.viatra.solver.data.map.DiffCursor; | 9 | import org.eclipse.viatra.solver.data.map.DiffCursor; |
9 | import org.eclipse.viatra.solver.data.map.VersionedMap; | 10 | import org.eclipse.viatra.solver.data.map.VersionedMap; |
@@ -17,43 +18,52 @@ public class MapDiffCursor<KEY,VALUE> implements DiffCursor<KEY, VALUE>, Cursor< | |||
17 | /** | 18 | /** |
18 | * Default value representing missing elements. | 19 | * Default value representing missing elements. |
19 | */ | 20 | */ |
20 | VALUE defaultValue; | 21 | private VALUE defaultValue; |
21 | MapCursor<KEY,VALUE> cursor1; | 22 | private MapCursor<KEY,VALUE> cursor1; |
22 | MapCursor<KEY,VALUE> cursor2; | 23 | private MapCursor<KEY,VALUE> cursor2; |
24 | private ContinousHashProvider<? super KEY> hashProvider; | ||
23 | 25 | ||
24 | // Values | 26 | // Values |
25 | KEY key; | 27 | private KEY key; |
26 | VALUE value1; | 28 | private VALUE fromValue; |
27 | VALUE value2; | 29 | private VALUE toValue; |
28 | 30 | ||
29 | // State | 31 | // State |
30 | /** | 32 | /** |
31 | * Positive number if cursor 1 is behind, negative number if cursor 2 is behind, and 0 if they are at the same position. | 33 | * Positive number if cursor 1 is behind, negative number if cursor 2 is behind, and 0 if they are at the same position. |
32 | */ | 34 | */ |
33 | int cursorRelation; | 35 | private int cursorRelation; |
36 | /** | ||
37 | * Denotes a state when two cursors are in the same position, but they contain different keys. | ||
38 | * Possible values: | ||
39 | * <ul> | ||
40 | * <li>0: not stuck</li> | ||
41 | * <li>1: hashClash, next it should return the key of cursor 1.</li> | ||
42 | * <li>2: hashClash, next it should return the key of cursor 2.</li> | ||
43 | * </ul> | ||
44 | */ | ||
45 | private int hashClash=0; | ||
34 | 46 | ||
35 | public MapDiffCursor(VALUE defaultValue, Cursor<KEY, VALUE> cursor1, Cursor<KEY, VALUE> cursor2) { | 47 | public MapDiffCursor(ContinousHashProvider<? super KEY> hashProvider, VALUE defaultValue, Cursor<KEY, VALUE> cursor1, Cursor<KEY, VALUE> cursor2) { |
36 | super(); | 48 | super(); |
49 | this.hashProvider = hashProvider; | ||
37 | this.defaultValue = defaultValue; | 50 | this.defaultValue = defaultValue; |
38 | this.cursor1 = (MapCursor<KEY, VALUE>) cursor1; | 51 | this.cursor1 = (MapCursor<KEY, VALUE>) cursor1; |
39 | this.cursor2 = (MapCursor<KEY, VALUE>) cursor2; | 52 | this.cursor2 = (MapCursor<KEY, VALUE>) cursor2; |
40 | |||
41 | this.updateState(); | ||
42 | this.moveToConsistentState(); | ||
43 | } | 53 | } |
44 | 54 | ||
45 | public KEY getKey() { | 55 | public KEY getKey() { |
46 | return key; | 56 | return key; |
47 | } | 57 | } |
48 | public VALUE getValue1() { | 58 | public VALUE getFromValue() { |
49 | return value1; | 59 | return fromValue; |
50 | } | 60 | } |
51 | public VALUE getValue2() { | 61 | public VALUE getToValue() { |
52 | return value2; | 62 | return toValue; |
53 | } | 63 | } |
54 | @Override | 64 | @Override |
55 | public VALUE getValue() { | 65 | public VALUE getValue() { |
56 | return this.value2; | 66 | return getToValue(); |
57 | } | 67 | } |
58 | public boolean isTerminated() { | 68 | public boolean isTerminated() { |
59 | return cursor1.isTerminated() && cursor2.isTerminated(); | 69 | return cursor1.isTerminated() && cursor2.isTerminated(); |
@@ -71,33 +81,72 @@ public class MapDiffCursor<KEY,VALUE> implements DiffCursor<KEY, VALUE>, Cursor< | |||
71 | } | 81 | } |
72 | 82 | ||
73 | protected void updateState() { | 83 | protected void updateState() { |
74 | this.cursorRelation = MapCursor.compare(cursor1, cursor2); | 84 | if(!isTerminated()) { |
75 | if(cursorRelation > 0 || cursor2.isTerminated()) { | 85 | this.cursorRelation = MapCursor.compare(cursor1, cursor2); |
76 | this.key = cursor1.getKey(); | 86 | if(cursorRelation > 0 || cursor2.isTerminated()) { |
77 | this.value1 = cursor1.getValue(); | 87 | this.key = cursor1.getKey(); |
78 | this.value2 = defaultValue; | 88 | this.fromValue = cursor1.getValue(); |
79 | } else if(cursorRelation < 0|| cursor1.isTerminated()){ | 89 | this.toValue = defaultValue; |
80 | this.key = cursor2.getKey(); | 90 | } else if(cursorRelation < 0 || cursor1.isTerminated()){ |
81 | this.value1 = defaultValue; | 91 | this.key = cursor2.getKey(); |
82 | this.value2 = cursor1.getValue(); | 92 | this.fromValue = defaultValue; |
83 | } else { | 93 | this.toValue = cursor1.getValue(); |
84 | // cursor1 = cursor2 | 94 | } else { |
85 | if(!cursor1.getKey().equals(cursor2.getKey())) { | 95 | // cursor1 = cursor2 |
86 | throw new IllegalStateException( | 96 | if(cursor1.getKey().equals(cursor2.getKey())) { |
87 | "Cursor comarison tells that they are in the same state, but keys are different. " + cursor1.getKey() + " - " + cursor2.getKey()); | 97 | this.key = cursor1.getKey(); |
98 | this.fromValue = cursor1.getValue(); | ||
99 | this.toValue = defaultValue; | ||
100 | } else { | ||
101 | resolveHashClash1(); | ||
102 | } | ||
88 | } | 103 | } |
89 | this.key = cursor1.getKey(); | ||
90 | this.value1 = cursor1.getValue(); | ||
91 | this.value2 = defaultValue; | ||
92 | } | 104 | } |
93 | } | 105 | } |
106 | protected void resolveHashClash1() { | ||
107 | int compareResult = this.hashProvider.compare(cursor1.key, cursor2.key); | ||
108 | if(compareResult<0) { | ||
109 | this.hashClash = 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 = 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 | protected boolean isInHashClash() { | ||
125 | return this.hashClash != 0; | ||
126 | } | ||
127 | protected void resolveHashClash2() { | ||
128 | if(hashClash == 1) { | ||
129 | this.hashClash = 0; | ||
130 | this.cursorRelation = 0; | ||
131 | this.key = cursor1.key; | ||
132 | this.fromValue = cursor1.value; | ||
133 | this.toValue = defaultValue; | ||
134 | } else if(hashClash == 2) { | ||
135 | this.hashClash = 0; | ||
136 | this.cursorRelation = 0; | ||
137 | this.key = cursor2.key; | ||
138 | this.fromValue = defaultValue; | ||
139 | this.toValue = cursor2.value; | ||
140 | } else throw new IllegalArgumentException("Inconsistent compare result for diffcursor"); | ||
141 | } | ||
142 | |||
94 | 143 | ||
95 | protected boolean differentValues() { | 144 | protected boolean sameValues() { |
96 | return this.value1 != this.value2; | 145 | return this.fromValue == this.toValue; |
97 | } | 146 | } |
98 | protected boolean moveOne() { | 147 | protected boolean moveOne() { |
99 | if(isTerminated()) { | 148 | if(isTerminated()) { |
100 | throw new IllegalStateException("DiffCursor tries to move when terminated!"); | 149 | return false; |
101 | } | 150 | } |
102 | if(this.cursorRelation > 0 || cursor2.isTerminated()) { | 151 | if(this.cursorRelation > 0 || cursor2.isTerminated()) { |
103 | return cursor1.move(); | 152 | return cursor1.move(); |
@@ -129,10 +178,11 @@ public class MapDiffCursor<KEY,VALUE> implements DiffCursor<KEY, VALUE>, Cursor< | |||
129 | lastResult = skipNode(); | 178 | lastResult = skipNode(); |
130 | changed = true; | 179 | changed = true; |
131 | } | 180 | } |
132 | if(differentValues()) { | 181 | if(sameValues()) { |
133 | lastResult = moveOne(); | 182 | lastResult = moveOne(); |
134 | changed = true; | 183 | changed = true; |
135 | } | 184 | } |
185 | updateState(); | ||
136 | } while(changed && !isTerminated()); | 186 | } while(changed && !isTerminated()); |
137 | return lastResult; | 187 | return lastResult; |
138 | } else { | 188 | } else { |
@@ -142,11 +192,17 @@ public class MapDiffCursor<KEY,VALUE> implements DiffCursor<KEY, VALUE>, Cursor< | |||
142 | 192 | ||
143 | public boolean move() { | 193 | public boolean move() { |
144 | if(!isTerminated()) { | 194 | if(!isTerminated()) { |
145 | if(moveOne()) { | 195 | if(isInHashClash()) { |
146 | return moveToConsistentState(); | 196 | this.resolveHashClash2(); |
197 | return true; | ||
147 | } else { | 198 | } else { |
148 | return false; | 199 | if(moveOne()) { |
200 | return moveToConsistentState(); | ||
201 | } else { | ||
202 | return false; | ||
203 | } | ||
149 | } | 204 | } |
205 | |||
150 | } else return false; | 206 | } else return false; |
151 | } | 207 | } |
152 | } | 208 | } |