|
1 | 1 | package org.usvm.memory |
2 | 2 |
|
| 3 | +import kotlinx.collections.immutable.PersistentMap |
3 | 4 | import kotlinx.collections.immutable.persistentMapOf |
4 | | -import kotlinx.collections.immutable.toPersistentMap |
5 | 5 | import org.usvm.UBoolExpr |
6 | 6 | import org.usvm.UComposer |
7 | 7 | import org.usvm.UExpr |
@@ -317,44 +317,52 @@ data class UTreeUpdates<Key, Reg : Region<Reg>, Sort : USort>( |
317 | 317 | guardBuilder: GuardBuilder, |
318 | 318 | composer: UComposer<*, *>?, |
319 | 319 | ): UTreeUpdates<Key, Reg, Sort> { |
320 | | - var restRecordsAreIrrelevant = false |
321 | | - val symbolicSubtreesStack = |
322 | | - mutableListOf<Pair<Reg, Pair<UUpdateNode<Key, Sort>, RegionTree<Reg, UUpdateNode<Key, Sort>>>>>() |
323 | | - |
324 | | - fun traverseTreeWhilePredicateSatisfied(tree: RegionTree<Reg, UUpdateNode<Key, Sort>>) { |
| 320 | + // returns fully symbolic tree entries after splitting |
| 321 | + fun traverseTreeWhilePredicateSatisfied( |
| 322 | + tree: RegionTree<Reg, UUpdateNode<Key, Sort>>, |
| 323 | + ): List<Pair<Reg, Pair<UUpdateNode<Key, Sort>, RegionTree<Reg, UUpdateNode<Key, Sort>>>>> { |
| 324 | + val symbolicEntries = |
| 325 | + mutableListOf<Pair<Reg, Pair<UUpdateNode<Key, Sort>, RegionTree<Reg, UUpdateNode<Key, Sort>>>>>() |
325 | 326 | // process nodes of the same level from newest to oldest |
326 | | - for ((reg, entry) in tree.entries.toList().reversed()) { |
| 327 | + for ((reg, entry) in tree.entries.toList().asReversed()) { |
327 | 328 | val (node, subtree) = entry |
328 | 329 | val splitUpdate = node.split(key, predicate, matchingWrites, guardBuilder, composer) |
329 | | - // range nodes are considered to belong to invariant tree since they can contain concretes |
330 | | - if (splitUpdate === null || node is URangedUpdateNode<*, *, Key, Sort>) { |
331 | | - traverseTreeWhilePredicateSatisfied(subtree) |
332 | | - if (restRecordsAreIrrelevant) break |
333 | | - } else { |
334 | | - // since [splitWrite] preserves invariant that records satisfying predicate are always |
335 | | - // at the top of the tree we can just add rest branch to splitTreeEntries |
336 | | - symbolicSubtreesStack += reg to entry |
| 330 | + when (splitUpdate) { |
| 331 | + null -> { |
| 332 | + val restSymbolicTree = traverseTreeWhilePredicateSatisfied(subtree) |
| 333 | + symbolicEntries += restSymbolicTree |
| 334 | + } |
| 335 | + // range nodes are considered to belong to concrete subtree since they can contain concretes |
| 336 | + is URangedUpdateNode<*, *, Key, Sort> -> { |
| 337 | + val restSymbolicEntries = traverseTreeWhilePredicateSatisfied(subtree) |
| 338 | + val restTree = RegionTree(restSymbolicEntries.asReversed().toPersistentMap()) |
| 339 | + symbolicEntries.add(reg to (splitUpdate to restTree)) |
| 340 | + } |
| 341 | + |
| 342 | + else -> { |
| 343 | + // since [splitWrite] preserves invariant that records satisfying predicate are always |
| 344 | + // at the top of the tree we can just add rest branch to splitTreeEntries |
| 345 | + symbolicEntries.add(reg to entry) |
| 346 | + } |
337 | 347 | } |
338 | 348 |
|
339 | | - if (guardBuilder.isFalse) { |
340 | | - restRecordsAreIrrelevant = true |
341 | | - break |
342 | | - } |
| 349 | + if (guardBuilder.isFalse) break |
343 | 350 | } |
| 351 | + |
| 352 | + return symbolicEntries |
344 | 353 | } |
345 | 354 |
|
346 | | - traverseTreeWhilePredicateSatisfied(updates) |
| 355 | + val symbolicEntries = traverseTreeWhilePredicateSatisfied(updates) |
347 | 356 |
|
348 | | - val splitTreeEntries = |
349 | | - mutableMapOf<Reg, Pair<UUpdateNode<Key, Sort>, RegionTree<Reg, UUpdateNode<Key, Sort>>>>() |
| 357 | + return this.copy(updates = RegionTree(symbolicEntries.asReversed().toPersistentMap())) |
| 358 | + } |
350 | 359 |
|
351 | | - // reconstruct region tree, including all updates unsatisfying `predicate(update.value(key))` in the same order |
352 | | - while (symbolicSubtreesStack.isNotEmpty()) { |
353 | | - val (reg, entry) = symbolicSubtreesStack.removeLast() |
354 | | - splitTreeEntries[reg] = entry |
| 360 | + private fun <K, V> List<Pair<K, V>>.toPersistentMap(): PersistentMap<K, V> { |
| 361 | + val builder = persistentMapOf<K, V>().builder() |
| 362 | + for ((reg, tree) in this) { |
| 363 | + builder[reg] = tree |
355 | 364 | } |
356 | | - |
357 | | - return this.copy(updates = RegionTree(splitTreeEntries.toPersistentMap())) |
| 365 | + return builder.build() |
358 | 366 | } |
359 | 367 |
|
360 | 368 | override fun splitWrite( |
|
0 commit comments