-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Currently it is quite expensive to do operations like this: ``` set2 = map1.keys intersect set1 ``` This is because the `keys` property on `TreapMap` is an `ImmuableSet`, not a `TreapSet`, so the intersection operation must convert it to a `TreapSet` first, using the generic `Set`->`TreapSet` conversion, which is rather expensive. This is a shame, because a `TreapMap<K, V>` of course is already structured the same way as a `TreapSet<K>`, so the conversion to `TreapSet` should be very cheap. This PR redefines the `keys` property as a `TreapSet`, and defines efficient implementations of this. Depending on usage, we can sometimes avoid the conversion to `TreapSet` altogether; if not, we can do the conversion as a straightforward projection of the existing `TreapMap` structure, avoiding most of the overhead of the generic conversion. We also add `single` and `singleOrNull` methods to `TreapMap`, which are useful in their own right, and can be used to avoid the conversion to `TreapSet` in some cases.
- Loading branch information
Showing
10 changed files
with
122 additions
and
30 deletions.
There are no files selected for viewing
59 changes: 59 additions & 0 deletions
59
collect/src/main/kotlin/com/certora/collect/AbstractKeySet.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package com.certora.collect | ||
|
||
/** | ||
Presents the keys of a [TreapMap] as a [TreapSet]. | ||
The idea here is that a `TreapMap<K, *>` is stored with the same Treap structure as a `TreapSet<K>`, so we can very | ||
quickly create the corresponding `TreapSet<K>` when needed, in O(n) time (as opposed to the naive O(n*log(n)) | ||
method). | ||
We lazily initialize the set, so that we don't create it until we need it. For many operations, we can avoid | ||
creating the set entirely, and just use the map directly. However, many operations, e.g. [addAll]/[union] and | ||
[retainAll/intersect], are much more efficient when we have a [TreapSet], so we create it when needed. | ||
*/ | ||
internal abstract class AbstractKeySet<@Treapable K, S : TreapSet<K>> : TreapSet<K> { | ||
/** | ||
The map whose keys we are presenting as a set. We prefer to use the map directly when possible, so we don't | ||
need to create the set. | ||
*/ | ||
abstract val map: AbstractTreapMap<K, *, *> | ||
/** | ||
The set of keys. This is a lazy property so that we don't create the set until we need it. | ||
*/ | ||
abstract val keys: Lazy<S> | ||
|
||
@Suppress("Treapability") | ||
override fun hashCode() = keys.value.hashCode() | ||
override fun equals(other: Any?) = keys.value.equals(other) | ||
override fun toString() = keys.value.toString() | ||
|
||
override val size get() = map.size | ||
override fun isEmpty() = map.isEmpty() | ||
override fun clear() = treapSetOf<K>() | ||
|
||
override operator fun contains(element: K) = map.containsKey(element) | ||
override operator fun iterator() = map.entrySequence().map { it.key }.iterator() | ||
|
||
override fun add(element: K) = keys.value.add(element) | ||
override fun addAll(elements: Collection<K>) = keys.value.addAll(elements) | ||
override fun remove(element: K) = keys.value.remove(element) | ||
override fun removeAll(elements: Collection<K>) = keys.value.removeAll(elements) | ||
override fun removeAll(predicate: (K) -> Boolean) = keys.value.removeAll(predicate) | ||
override fun retainAll(elements: Collection<K>) = keys.value.retainAll(elements) | ||
|
||
override fun single() = map.single().key | ||
override fun singleOrNull() = map.singleOrNull()?.key | ||
override fun arbitraryOrNull() = map.arbitraryOrNull()?.key | ||
|
||
override fun containsAny(elements: Iterable<K>) = keys.value.containsAny(elements) | ||
override fun containsAny(predicate: (K) -> Boolean) = (this as Iterable<K>).any(predicate) | ||
override fun containsAll(elements: Collection<K>) = keys.value.containsAll(elements) | ||
override fun findEqual(element: K) = keys.value.findEqual(element) | ||
|
||
override fun forEachElement(action: (K) -> Unit) = map.forEachEntry { action(it.key) } | ||
|
||
override fun <R : Any> mapReduce(map: (K) -> R, reduce: (R, R) -> R) = | ||
this.map.mapReduce({ k, _ -> map(k) }, reduce) | ||
override fun <R : Any> parallelMapReduce(map: (K) -> R, reduce: (R, R) -> R, parallelThresholdLog2: Int) = | ||
this.map.parallelMapReduce({ k, _ -> map(k) }, reduce, parallelThresholdLog2) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters