aboutsummaryrefslogtreecommitdiffstats
path: root/store/src/main/java/org/eclipse/viatra/solver/data/map/internal/ImmutableNode.java
diff options
context:
space:
mode:
Diffstat (limited to 'store/src/main/java/org/eclipse/viatra/solver/data/map/internal/ImmutableNode.java')
-rw-r--r--store/src/main/java/org/eclipse/viatra/solver/data/map/internal/ImmutableNode.java255
1 files changed, 127 insertions, 128 deletions
diff --git a/store/src/main/java/org/eclipse/viatra/solver/data/map/internal/ImmutableNode.java b/store/src/main/java/org/eclipse/viatra/solver/data/map/internal/ImmutableNode.java
index 04a9b19a..b507763f 100644
--- a/store/src/main/java/org/eclipse/viatra/solver/data/map/internal/ImmutableNode.java
+++ b/store/src/main/java/org/eclipse/viatra/solver/data/map/internal/ImmutableNode.java
@@ -15,15 +15,16 @@ public class ImmutableNode<K, V> extends Node<K, V> {
15 */ 15 */
16 final int nodeMap; 16 final int nodeMap;
17 /** 17 /**
18 * Stores Keys, Values, and subnodes. Structure: (K,V)*,NODE; NODES are stored backwards. 18 * Stores Keys, Values, and subnodes. Structure: (K,V)*,NODE; NODES are stored
19 * backwards.
19 */ 20 */
20 final Object[] content; 21 final Object[] content;
21 22
22 /** 23 /**
23 * Hash code derived from immutable hash code 24 * Hash code derived from immutable hash code
24 */ 25 */
25 final int precalculatedHash; 26 final int precalculatedHash;
26 27
27 private ImmutableNode(int dataMap, int nodeMap, Object[] content, int precalculatedHash) { 28 private ImmutableNode(int dataMap, int nodeMap, Object[] content, int precalculatedHash) {
28 super(); 29 super();
29 this.dataMap = dataMap; 30 this.dataMap = dataMap;
@@ -41,83 +42,87 @@ public class ImmutableNode<K, V> extends Node<K, V> {
41 * available. 42 * available.
42 * @return an immutable version of the input node. 43 * @return an immutable version of the input node.
43 */ 44 */
44 @SuppressWarnings("unchecked") 45 static <K, V> ImmutableNode<K, V> constructImmutable(MutableNode<K, V> node,
45 static <K,V> ImmutableNode<K,V> constructImmutable(MutableNode<K,V> node, Map<Node<K, V>, ImmutableNode<K, V>> cache) { 46 Map<Node<K, V>, ImmutableNode<K, V>> cache) {
46 // 1. try to return from cache 47 // 1. try to return from cache
47 if(cache != null) { 48 if (cache != null) {
48 ImmutableNode<K, V> cachedResult = cache.get(node); 49 ImmutableNode<K, V> cachedResult = cache.get(node);
49 if(cachedResult != null) { 50 if (cachedResult != null) {
50 // 1.1 Already cached, return from cache. 51 // 1.1 Already cached, return from cache.
51 return cachedResult; 52 return cachedResult;
52 } 53 }
53 } 54 }
54 55
55 // 2. otherwise construct a new ImmutableNode 56 // 2. otherwise construct a new ImmutableNode
56 int size = 0; 57 int size = 0;
57 for(int i = 0; i<node.content.length; i++) { 58 for (int i = 0; i < node.content.length; i++) {
58 if(node.content[i]!=null) { 59 if (node.content[i] != null) {
59 size++; 60 size++;
60 } 61 }
61 } 62 }
62 63
63 int datas = 0; 64 int datas = 0;
64 int nodes = 0; 65 int nodes = 0;
65 int resultDataMap = 0; 66 int resultDataMap = 0;
66 int resultNodeMap = 0; 67 int resultNodeMap = 0;
67 final Object[] resultContent = new Object[size]; 68 final Object[] resultContent = new Object[size];
68 int bitposition = 1; 69 int bitposition = 1;
69 for(int i = 0; i<FACTOR; i++) { 70 for (int i = 0; i < FACTOR; i++) {
70 Object key = node.content[i*2]; 71 Object key = node.content[i * 2];
71 if(key != null) { 72 if (key != null) {
72 resultDataMap |= bitposition; 73 resultDataMap |= bitposition;
73 resultContent[datas*2] = key; 74 resultContent[datas * 2] = key;
74 resultContent[datas*2+1] = node.content[i*2+1]; 75 resultContent[datas * 2 + 1] = node.content[i * 2 + 1];
75 datas++; 76 datas++;
76 } else { 77 } else {
77 Node<K,V> subnode = (Node<K, V>) node.content[i*2+1]; 78 @SuppressWarnings("unchecked")
78 if(subnode != null) { 79 var subnode = (Node<K, V>) node.content[i * 2 + 1];
80 if (subnode != null) {
79 ImmutableNode<K, V> immutableSubnode = subnode.toImmutable(cache); 81 ImmutableNode<K, V> immutableSubnode = subnode.toImmutable(cache);
80 resultNodeMap |=bitposition; 82 resultNodeMap |= bitposition;
81 resultContent[size-1-nodes] = immutableSubnode; 83 resultContent[size - 1 - nodes] = immutableSubnode;
82 nodes++; 84 nodes++;
83 } 85 }
84 } 86 }
85 bitposition<<=1; 87 bitposition <<= 1;
86 } 88 }
87 final int resultHash = node.hashCode(); 89 final int resultHash = node.hashCode();
88 ImmutableNode<K,V> newImmutable = new ImmutableNode<>(resultDataMap, resultNodeMap, resultContent, resultHash); 90 var newImmutable = new ImmutableNode<K, V>(resultDataMap, resultNodeMap, resultContent, resultHash);
89 91
90 // 3. save new immutable. 92 // 3. save new immutable.
91 if(cache != null) { 93 if (cache != null) {
92 cache.put(newImmutable, newImmutable); 94 cache.put(newImmutable, newImmutable);
93 } 95 }
94 return newImmutable; 96 return newImmutable;
95 } 97 }
96 98
97 private int index(int bitmap, int bitpos) { 99 private int index(int bitmap, int bitpos) {
98 return Integer.bitCount(bitmap & (bitpos-1)); 100 return Integer.bitCount(bitmap & (bitpos - 1));
99 } 101 }
100 102
101 @SuppressWarnings("unchecked")
102 @Override 103 @Override
103 public V getValue(K key, ContinousHashProvider<? super K> hashProvider, V defaultValue, int hash, int depth) { 104 public V getValue(K key, ContinousHashProvider<? super K> hashProvider, V defaultValue, int hash, int depth) {
104 int selectedHashFragment = hashFragment(hash,shiftDepth(depth)); 105 int selectedHashFragment = hashFragment(hash, shiftDepth(depth));
105 int bitposition = 1 << selectedHashFragment; 106 int bitposition = 1 << selectedHashFragment;
106 // If the key is stored as a data 107 // If the key is stored as a data
107 if((dataMap & bitposition) != 0) { 108 if ((dataMap & bitposition) != 0) {
108 int keyIndex = 2*index(dataMap, bitposition); 109 int keyIndex = 2 * index(dataMap, bitposition);
110 @SuppressWarnings("unchecked")
109 K keyCandidate = (K) content[keyIndex]; 111 K keyCandidate = (K) content[keyIndex];
110 if(keyCandidate.equals(key)) { 112 if (keyCandidate.equals(key)) {
111 return (V) content[keyIndex+1]; 113 @SuppressWarnings("unchecked")
114 V value = (V) content[keyIndex + 1];
115 return value;
112 } else { 116 } else {
113 return defaultValue; 117 return defaultValue;
114 } 118 }
115 } 119 }
116 // the key is stored as a node 120 // the key is stored as a node
117 else if((nodeMap & bitposition) != 0) { 121 else if ((nodeMap & bitposition) != 0) {
118 int keyIndex = content.length-1-index(nodeMap, bitposition); 122 int keyIndex = content.length - 1 - index(nodeMap, bitposition);
119 ImmutableNode<K,V> subNode = (ImmutableNode<K,V>) content[keyIndex]; 123 @SuppressWarnings("unchecked")
120 int newDepth = depth+1; 124 var subNode = (ImmutableNode<K, V>) content[keyIndex];
125 int newDepth = depth + 1;
121 int newHash = newHash(hashProvider, key, hash, newDepth); 126 int newHash = newHash(hashProvider, key, hash, newDepth);
122 return subNode.getValue(key, hashProvider, defaultValue, newHash, newDepth); 127 return subNode.getValue(key, hashProvider, defaultValue, newHash, newDepth);
123 } 128 }
@@ -126,21 +131,22 @@ public class ImmutableNode<K, V> extends Node<K, V> {
126 return defaultValue; 131 return defaultValue;
127 } 132 }
128 } 133 }
129 134
130 @SuppressWarnings("unchecked")
131 @Override 135 @Override
132 public Node<K,V> putValue(K key, V value, OldValueBox<V> oldValue, ContinousHashProvider<? super K> hashProvider, V defaultValue, int hash, int depth) { 136 public Node<K, V> putValue(K key, V value, OldValueBox<V> oldValue, ContinousHashProvider<? super K> hashProvider,
133 int selectedHashFragment = hashFragment(hash,shiftDepth(depth)); 137 V defaultValue, int hash, int depth) {
138 int selectedHashFragment = hashFragment(hash, shiftDepth(depth));
134 int bitposition = 1 << selectedHashFragment; 139 int bitposition = 1 << selectedHashFragment;
135 if((dataMap & bitposition) != 0) { 140 if ((dataMap & bitposition) != 0) {
136 int keyIndex = 2*index(dataMap, bitposition); 141 int keyIndex = 2 * index(dataMap, bitposition);
142 @SuppressWarnings("unchecked")
137 K keyCandidate = (K) content[keyIndex]; 143 K keyCandidate = (K) content[keyIndex];
138 if(keyCandidate.equals(key)) { 144 if (keyCandidate.equals(key)) {
139 if(value == defaultValue) { 145 if (value == defaultValue) {
140 // delete 146 // delete
141 MutableNode<K, V> mutable = this.toMutable(); 147 MutableNode<K, V> mutable = this.toMutable();
142 return mutable.removeEntry(selectedHashFragment,oldValue); 148 return mutable.removeEntry(selectedHashFragment, oldValue);
143 } else if(value == content[keyIndex+1]) { 149 } else if (value == content[keyIndex + 1]) {
144 // dont change 150 // dont change
145 oldValue.setOldValue(value); 151 oldValue.setOldValue(value);
146 return this; 152 return this;
@@ -150,7 +156,7 @@ public class ImmutableNode<K, V> extends Node<K, V> {
150 return mutable.updateValue(value, oldValue, selectedHashFragment); 156 return mutable.updateValue(value, oldValue, selectedHashFragment);
151 } 157 }
152 } else { 158 } else {
153 if(value == defaultValue) { 159 if (value == defaultValue) {
154 // dont change 160 // dont change
155 oldValue.setOldValue(defaultValue); 161 oldValue.setOldValue(defaultValue);
156 return this; 162 return this;
@@ -160,19 +166,19 @@ public class ImmutableNode<K, V> extends Node<K, V> {
160 return mutable.putValue(key, value, oldValue, hashProvider, defaultValue, hash, depth); 166 return mutable.putValue(key, value, oldValue, hashProvider, defaultValue, hash, depth);
161 } 167 }
162 } 168 }
163 } else if((nodeMap & bitposition)!=0) { 169 } else if ((nodeMap & bitposition) != 0) {
164 170 int keyIndex = content.length - 1 - index(nodeMap, bitposition);
165 int keyIndex = content.length-1-index(nodeMap, bitposition); 171 @SuppressWarnings("unchecked")
166 ImmutableNode<K,V> subNode = (ImmutableNode<K,V>) content[keyIndex]; 172 var subNode = (ImmutableNode<K, V>) content[keyIndex];
167 int newDepth = depth+1; 173 int newDepth = depth + 1;
168 int newHash = newHash(hashProvider, key, hash, newDepth); 174 int newHash = newHash(hashProvider, key, hash, newDepth);
169 Node<K,V> newsubNode = subNode.putValue(key, value, oldValue, hashProvider, defaultValue, newHash, newDepth); 175 var newsubNode = subNode.putValue(key, value, oldValue, hashProvider, defaultValue, newHash, newDepth);
170 176
171 if(subNode == newsubNode) { 177 if (subNode == newsubNode) {
172 // nothing changed 178 // nothing changed
173 return this; 179 return this;
174 } else { 180 } else {
175 MutableNode<K, V> mutable = toMutable(); 181 MutableNode<K, V> mutable = toMutable();
176 return mutable.updateWithSubNode(selectedHashFragment, newsubNode, value.equals(defaultValue)); 182 return mutable.updateWithSubNode(selectedHashFragment, newsubNode, value.equals(defaultValue));
177 } 183 }
178 } else { 184 } else {
@@ -181,59 +187,56 @@ public class ImmutableNode<K, V> extends Node<K, V> {
181 return mutable.putValue(key, value, oldValue, hashProvider, defaultValue, hash, depth); 187 return mutable.putValue(key, value, oldValue, hashProvider, defaultValue, hash, depth);
182 } 188 }
183 } 189 }
184 190
185
186 @SuppressWarnings("unchecked")
187 @Override 191 @Override
188 public long getSize() { 192 public long getSize() {
189 int result = Integer.bitCount(this.dataMap); 193 int result = Integer.bitCount(this.dataMap);
190 for(int subnodeIndex = 0; subnodeIndex < Integer.bitCount(this.nodeMap); subnodeIndex++) { 194 for (int subnodeIndex = 0; subnodeIndex < Integer.bitCount(this.nodeMap); subnodeIndex++) {
191 ImmutableNode<K,V> subnode = 195 @SuppressWarnings("unchecked")
192 (ImmutableNode<K, V>) this.content[this.content.length-1-subnodeIndex]; 196 var subnode = (ImmutableNode<K, V>) this.content[this.content.length - 1 - subnodeIndex];
193 result += subnode.getSize(); 197 result += subnode.getSize();
194 } 198 }
195 return result; 199 return result;
196 } 200 }
197 201
198 @Override 202 @Override
199 protected MutableNode<K,V> toMutable() { 203 protected MutableNode<K, V> toMutable() {
200 return new MutableNode<>(this); 204 return new MutableNode<>(this);
201 } 205 }
202 206
203 @Override 207 @Override
204 public ImmutableNode<K, V> toImmutable( 208 public ImmutableNode<K, V> toImmutable(Map<Node<K, V>, ImmutableNode<K, V>> cache) {
205 Map<Node<K, V>, ImmutableNode<K, V>> cache) {
206 return this; 209 return this;
207 } 210 }
208 211
209 @Override 212 @Override
210 protected MutableNode<K, V> isMutable() { 213 protected MutableNode<K, V> isMutable() {
211 return null; 214 return null;
212 } 215 }
213 216
214 @SuppressWarnings("unchecked") 217 @SuppressWarnings("unchecked")
215 @Override 218 @Override
216 boolean moveToNext(MapCursor<K, V> cursor) { 219 boolean moveToNext(MapCursor<K, V> cursor) {
217 // 1. try to move to data 220 // 1. try to move to data
218 int datas = Integer.bitCount(this.dataMap); 221 int datas = Integer.bitCount(this.dataMap);
219 if(cursor.dataIndex != MapCursor.INDEX_FINISH) { 222 if (cursor.dataIndex != MapCursor.INDEX_FINISH) {
220 int newDataIndex = cursor.dataIndex + 1; 223 int newDataIndex = cursor.dataIndex + 1;
221 if(newDataIndex < datas) { 224 if (newDataIndex < datas) {
222 cursor.dataIndex = newDataIndex; 225 cursor.dataIndex = newDataIndex;
223 cursor.key = (K) this.content[newDataIndex*2]; 226 cursor.key = (K) this.content[newDataIndex * 2];
224 cursor.value = (V) this.content[newDataIndex*2+1]; 227 cursor.value = (V) this.content[newDataIndex * 2 + 1];
225 return true; 228 return true;
226 } else { 229 } else {
227 cursor.dataIndex = MapCursor.INDEX_FINISH; 230 cursor.dataIndex = MapCursor.INDEX_FINISH;
228 } 231 }
229 } 232 }
230 233
231 // 2. look inside the subnodes 234 // 2. look inside the subnodes
232 int nodes = Integer.bitCount(this.nodeMap); 235 int nodes = Integer.bitCount(this.nodeMap);
233 int newNodeIndex = cursor.nodeIndexStack.peek() + 1; 236 int newNodeIndex = cursor.nodeIndexStack.peek() + 1;
234 if(newNodeIndex < nodes) { 237 if (newNodeIndex < nodes) {
235 // 2.1 found next subnode, move down to the subnode 238 // 2.1 found next subnode, move down to the subnode
236 Node<K, V> subnode = (Node<K, V>) this.content[this.content.length-1-newNodeIndex]; 239 Node<K, V> subnode = (Node<K, V>) this.content[this.content.length - 1 - newNodeIndex];
237 cursor.dataIndex = MapCursor.INDEX_START; 240 cursor.dataIndex = MapCursor.INDEX_START;
238 cursor.nodeIndexStack.pop(); 241 cursor.nodeIndexStack.pop();
239 cursor.nodeIndexStack.push(newNodeIndex); 242 cursor.nodeIndexStack.push(newNodeIndex);
@@ -244,7 +247,7 @@ public class ImmutableNode<K, V> extends Node<K, V> {
244 // 3. no subnode found, move up 247 // 3. no subnode found, move up
245 cursor.nodeStack.pop(); 248 cursor.nodeStack.pop();
246 cursor.nodeIndexStack.pop(); 249 cursor.nodeIndexStack.pop();
247 if(!cursor.nodeStack.isEmpty()) { 250 if (!cursor.nodeStack.isEmpty()) {
248 Node<K, V> supernode = cursor.nodeStack.peek(); 251 Node<K, V> supernode = cursor.nodeStack.peek();
249 return supernode.moveToNext(cursor); 252 return supernode.moveToNext(cursor);
250 } else { 253 } else {
@@ -254,69 +257,69 @@ public class ImmutableNode<K, V> extends Node<K, V> {
254 } 257 }
255 } 258 }
256 } 259 }
257 260
258 @Override 261 @Override
259 public void prettyPrint(StringBuilder builder, int depth, int code) { 262 public void prettyPrint(StringBuilder builder, int depth, int code) {
260 for(int i = 0; i<depth; i++) { 263 for (int i = 0; i < depth; i++) {
261 builder.append("\t"); 264 builder.append("\t");
262 } 265 }
263 if(code>=0) { 266 if (code >= 0) {
264 builder.append(code); 267 builder.append(code);
265 builder.append(":"); 268 builder.append(":");
266 } 269 }
267 builder.append("Immutable("); 270 builder.append("Immutable(");
268 boolean hadContent = false; 271 boolean hadContent = false;
269 int dataMask = 1; 272 int dataMask = 1;
270 for(int i = 0; i<FACTOR; i++) { 273 for (int i = 0; i < FACTOR; i++) {
271 if((dataMask & dataMap) != 0) { 274 if ((dataMask & dataMap) != 0) {
272 if(hadContent) { 275 if (hadContent) {
273 builder.append(","); 276 builder.append(",");
274 } 277 }
275 builder.append(i); 278 builder.append(i);
276 builder.append(":["); 279 builder.append(":[");
277 builder.append(content[2*index(dataMap, dataMask)].toString()); 280 builder.append(content[2 * index(dataMap, dataMask)].toString());
278 builder.append("]->["); 281 builder.append("]->[");
279 builder.append(content[2*index(dataMap, dataMask)+1].toString()); 282 builder.append(content[2 * index(dataMap, dataMask) + 1].toString());
280 builder.append("]"); 283 builder.append("]");
281 hadContent = true; 284 hadContent = true;
282 } 285 }
283 dataMask<<=1; 286 dataMask <<= 1;
284 } 287 }
285 builder.append(")"); 288 builder.append(")");
286 int nodeMask = 1; 289 int nodeMask = 1;
287 for(int i = 0; i<FACTOR; i++) { 290 for (int i = 0; i < FACTOR; i++) {
288 if((nodeMask & nodeMap)!=0) { 291 if ((nodeMask & nodeMap) != 0) {
289 @SuppressWarnings("unchecked") 292 @SuppressWarnings("unchecked")
290 Node<K,V> subNode = (Node<K, V>) content[content.length-1-index(nodeMap, nodeMask)]; 293 Node<K, V> subNode = (Node<K, V>) content[content.length - 1 - index(nodeMap, nodeMask)];
291 builder.append("\n"); 294 builder.append("\n");
292 subNode.prettyPrint(builder, depth+1, i); 295 subNode.prettyPrint(builder, depth + 1, i);
293 } 296 }
294 nodeMask<<=1; 297 nodeMask <<= 1;
295 } 298 }
296 } 299 }
297 300
298 @SuppressWarnings("unchecked")
299 @Override 301 @Override
300 public void checkIntegrity(ContinousHashProvider<? super K> hashProvider, V defaultValue, int depth) { 302 public void checkIntegrity(ContinousHashProvider<? super K> hashProvider, V defaultValue, int depth) {
301 if(depth>0) { 303 if (depth > 0) {
302 boolean orphaned = Integer.bitCount(dataMap) == 1 && nodeMap == 0; 304 boolean orphaned = Integer.bitCount(dataMap) == 1 && nodeMap == 0;
303 if(orphaned) { 305 if (orphaned) {
304 throw new IllegalStateException("Orphaned node! " + dataMap + ": " + content[0]); 306 throw new IllegalStateException("Orphaned node! " + dataMap + ": " + content[0]);
305 } 307 }
306 } 308 }
307 // check the place of data 309 // check the place of data
308 310
309 // check subnodes 311 // check subnodes
310 for(int i = 0; i<Integer.bitCount(nodeMap); i++) { 312 for (int i = 0; i < Integer.bitCount(nodeMap); i++) {
311 Node<K,V> subnode = (Node<K, V>) this.content[this.content.length-1-i]; 313 @SuppressWarnings("unchecked")
312 if(! (subnode instanceof ImmutableNode<?,?>)) { 314 var subnode = (Node<K, V>) this.content[this.content.length - 1 - i];
315 if (!(subnode instanceof ImmutableNode<?, ?>)) {
313 throw new IllegalStateException("Immutable node contains mutable subnodes!"); 316 throw new IllegalStateException("Immutable node contains mutable subnodes!");
314 } else { 317 } else {
315 subnode.checkIntegrity(hashProvider, defaultValue, depth+1); 318 subnode.checkIntegrity(hashProvider, defaultValue, depth + 1);
316 } 319 }
317 } 320 }
318 } 321 }
319 322
320 @Override 323 @Override
321 public int hashCode() { 324 public int hashCode() {
322 return this.precalculatedHash; 325 return this.precalculatedHash;
@@ -328,43 +331,39 @@ public class ImmutableNode<K, V> extends Node<K, V> {
328 return true; 331 return true;
329 if (obj == null) 332 if (obj == null)
330 return false; 333 return false;
331 if (obj instanceof ImmutableNode<?,?>) { 334 if (obj instanceof ImmutableNode<?, ?> other) {
332 ImmutableNode<?,?> other = (ImmutableNode<?,?>) obj; 335 return precalculatedHash == other.precalculatedHash && dataMap == other.dataMap && nodeMap == other.nodeMap
333 if (precalculatedHash != other.precalculatedHash || dataMap != other.dataMap || nodeMap != other.nodeMap || !Arrays.deepEquals(content, other.content)) 336 && Arrays.deepEquals(content, other.content);
334 return false; 337 } else if (obj instanceof MutableNode<?, ?> mutableObj) {
335 else return true; 338 return ImmutableNode.compareImmutableMutable(this, mutableObj);
336 } else if(obj instanceof MutableNode<?,?>) {
337 return ImmutableNode.compareImmutableMutable(this, (MutableNode<?, ?>) obj);
338 } else { 339 } else {
339 return false; 340 return false;
340 } 341 }
341 } 342 }
342 public static boolean compareImmutableMutable( 343
343 ImmutableNode<?, ?> immutable, 344 public static boolean compareImmutableMutable(ImmutableNode<?, ?> immutable, MutableNode<?, ?> mutable) {
344 MutableNode<?, ?> mutable)
345 {
346 int datas = 0; 345 int datas = 0;
347 int nodes = 0; 346 int nodes = 0;
348 final int immutableLength = immutable.content.length; 347 final int immutableLength = immutable.content.length;
349 for(int i = 0; i<FACTOR; i++) { 348 for (int i = 0; i < FACTOR; i++) {
350 Object key = mutable.content[i*2]; 349 Object key = mutable.content[i * 2];
351 // For each key candidate 350 // For each key candidate
352 if(key != null) { 351 if (key != null) {
353 // Check whether a new Key-Value pair can fit into the immutable container 352 // Check whether a new Key-Value pair can fit into the immutable container
354 if(datas*2+nodes+2 <= immutableLength) { 353 if (datas * 2 + nodes + 2 <= immutableLength) {
355 if( !immutable.content[datas*2].equals(key) || 354 if (!immutable.content[datas * 2].equals(key)
356 !immutable.content[datas*2+1].equals(mutable.content[i*2+1])) 355 || !immutable.content[datas * 2 + 1].equals(mutable.content[i * 2 + 1])) {
357 {
358 return false; 356 return false;
359 } 357 }
360 } else return false; 358 } else
359 return false;
361 datas++; 360 datas++;
362 } else { 361 } else {
363 Node<?,?> mutableSubnode = (Node<?, ?>) mutable.content[i*2+1]; 362 var mutableSubnode = (Node<?, ?>) mutable.content[i * 2 + 1];
364 if(mutableSubnode != null) { 363 if (mutableSubnode != null) {
365 if(datas*2+nodes+1 <= immutableLength) { 364 if (datas * 2 + nodes + 1 <= immutableLength) {
366 Object immutableSubnode = immutable.content[immutableLength-1-nodes]; 365 Object immutableSubnode = immutable.content[immutableLength - 1 - nodes];
367 if(!mutableSubnode.equals(immutableSubnode)) { 366 if (!mutableSubnode.equals(immutableSubnode)) {
368 return false; 367 return false;
369 } 368 }
370 nodes++; 369 nodes++;