-
Notifications
You must be signed in to change notification settings - Fork 47
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: implement IdentityHashMap for the JS target
- Loading branch information
1 parent
75a71f6
commit 4a5fdbc
Showing
10 changed files
with
457 additions
and
11 deletions.
There are no files selected for viewing
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
86 changes: 86 additions & 0 deletions
86
...kotlin-runtime/src/jsMain/kotlin/com/strumenta/antlrkotlin/runtime/IdentityEntriesView.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,86 @@ | ||
// Copyright 2017-present Strumenta and contributors, licensed under Apache 2.0. | ||
// Copyright 2024-present Strumenta and contributors, licensed under BSD 3-Clause. | ||
package com.strumenta.antlrkotlin.runtime | ||
|
||
import js.collections.JsMap | ||
import kotlin.collections.MutableMap.MutableEntry as ME | ||
|
||
internal class IdentityEntriesView<K, V>(private val jsMap: JsMap<K, V>) : AbstractMutableSet<ME<K, V>>() { | ||
override val size: Int | ||
get() = jsMap.size | ||
|
||
override fun isEmpty(): Boolean = | ||
jsMap.size == 0 | ||
|
||
override fun clear(): Unit = | ||
jsMap.clear() | ||
|
||
override fun add(element: ME<K, V>): Boolean = | ||
throw UnsupportedOperationException("Adding is not supported on entries") | ||
|
||
override fun remove(element: ME<K, V>): Boolean { | ||
val (key, value) = element | ||
return remove(key, value) | ||
} | ||
|
||
override fun removeAll(elements: Collection<ME<K, V>>): Boolean { | ||
var removed = false | ||
|
||
for (element in elements) { | ||
removed = remove(element) || removed | ||
} | ||
|
||
return removed | ||
} | ||
|
||
override fun contains(element: ME<K, V>): Boolean { | ||
val k = undefinedToNull(element.key) | ||
return jsMap.has(k) && jsMap[k] === element.value | ||
} | ||
|
||
override fun iterator(): MutableIterator<ME<K, V>> { | ||
val iterator = jsMap.iterator() | ||
return object : MutableIterator<ME<K, V>> { | ||
var lastEntry: IdentityEntriesView<K, V>.IdentityEntry? = null | ||
|
||
override fun hasNext(): Boolean = | ||
iterator.hasNext() | ||
|
||
override fun next(): ME<K, V> { | ||
val (key, value) = iterator.next() | ||
val entry = IdentityEntry(key, value) | ||
lastEntry = entry | ||
return entry | ||
} | ||
|
||
override fun remove() { | ||
val lastEntry = checkNotNull(this.lastEntry) | ||
remove(lastEntry.key, lastEntry.value) | ||
} | ||
} | ||
} | ||
|
||
private fun remove(key: K, value: V): Boolean { | ||
val k = undefinedToNull(key) | ||
|
||
if (jsMap.has(k)) { | ||
// IMPORTANT: notice that we use reference/strict equality | ||
if (jsMap[k] === value) { | ||
return jsMap.delete(k) | ||
} | ||
} | ||
|
||
return false | ||
} | ||
|
||
private inner class IdentityEntry(override val key: K, override var value: V) : ME<K, V> { | ||
override fun setValue(newValue: V): V { | ||
val oldValue = value | ||
check(oldValue === jsMap[key]) | ||
|
||
jsMap[key] = newValue | ||
value = newValue | ||
return oldValue | ||
} | ||
} | ||
} |
78 changes: 78 additions & 0 deletions
78
antlr-kotlin-runtime/src/jsMain/kotlin/com/strumenta/antlrkotlin/runtime/IdentityHashMap.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,78 @@ | ||
// Copyright 2017-present Strumenta and contributors, licensed under Apache 2.0. | ||
// Copyright 2024-present Strumenta and contributors, licensed under BSD 3-Clause. | ||
package com.strumenta.antlrkotlin.runtime | ||
|
||
import js.collections.JsMap | ||
import kotlin.collections.MutableMap.MutableEntry as ME | ||
|
||
public actual class IdentityHashMap<K, V> : MutableMap<K, V> { | ||
private val jsMap = JsMap<K, V>() | ||
|
||
actual override val size: Int | ||
get() = jsMap.size | ||
|
||
actual override val keys: MutableSet<K> | ||
get() = IdentityKeysView(this) | ||
|
||
actual override val values: MutableCollection<V> | ||
get() = IdentityValuesView(this) | ||
|
||
actual override val entries: MutableSet<ME<K, V>> | ||
get() = IdentityEntriesView(jsMap) | ||
|
||
actual override fun isEmpty(): Boolean = | ||
jsMap.size == 0 | ||
|
||
actual override fun clear(): Unit = | ||
jsMap.clear() | ||
|
||
actual override fun get(key: K): V? { | ||
val k = undefinedToNull(key) | ||
return undefinedToNull(jsMap[k]) | ||
} | ||
|
||
actual override fun put(key: K, value: V): V? { | ||
val k = undefinedToNull(key) | ||
val previousValue = jsMap[k] | ||
jsMap[k] = value | ||
return undefinedToNull(previousValue) | ||
} | ||
|
||
actual override fun remove(key: K): V? { | ||
val k = undefinedToNull(key) | ||
val removedValue = jsMap[k] | ||
jsMap.delete(k) | ||
return undefinedToNull(removedValue) | ||
} | ||
|
||
actual override fun putAll(from: Map<out K, V>) { | ||
for ((key, value) in from) { | ||
val k = undefinedToNull(key) | ||
jsMap[k] = value | ||
} | ||
} | ||
|
||
actual override fun containsKey(key: K): Boolean { | ||
val k = undefinedToNull(key) | ||
return jsMap.has(k) | ||
} | ||
|
||
actual override fun containsValue(value: V): Boolean { | ||
for (v in jsMap.values()) { | ||
// IMPORTANT: notice that we use reference/strict equality | ||
if (v === value) { | ||
return true | ||
} | ||
} | ||
|
||
return false | ||
} | ||
|
||
/** | ||
* Same as `remove(key)`, but returns a boolean value. | ||
*/ | ||
internal fun removeBoolean(key: K): Boolean { | ||
val k = undefinedToNull(key) | ||
return jsMap.delete(k) | ||
} | ||
} |
47 changes: 47 additions & 0 deletions
47
antlr-kotlin-runtime/src/jsMain/kotlin/com/strumenta/antlrkotlin/runtime/IdentityKeysView.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,47 @@ | ||
// Copyright 2017-present Strumenta and contributors, licensed under Apache 2.0. | ||
// Copyright 2024-present Strumenta and contributors, licensed under BSD 3-Clause. | ||
package com.strumenta.antlrkotlin.runtime | ||
|
||
internal class IdentityKeysView<K>(private val map: IdentityHashMap<K, *>) : AbstractMutableSet<K>() { | ||
override val size: Int | ||
get() = map.size | ||
|
||
override fun isEmpty(): Boolean = | ||
map.isEmpty() | ||
|
||
override fun clear(): Unit = | ||
map.clear() | ||
|
||
override fun contains(element: K): Boolean = | ||
map.containsKey(element) | ||
|
||
override fun add(element: K): Boolean = | ||
throw UnsupportedOperationException("Adding is not supported on keys") | ||
|
||
override fun remove(element: K): Boolean = | ||
map.removeBoolean(element) | ||
|
||
override fun removeAll(elements: Collection<K>): Boolean { | ||
var removed = false | ||
|
||
for (element in elements) { | ||
removed = remove(element) || removed | ||
} | ||
|
||
return removed | ||
} | ||
|
||
override fun iterator(): MutableIterator<K> { | ||
val entriesIterator = map.entries.iterator() | ||
return object : MutableIterator<K> { | ||
override fun hasNext(): Boolean = | ||
entriesIterator.hasNext() | ||
|
||
override fun next(): K = | ||
entriesIterator.next().key | ||
|
||
override fun remove(): Unit = | ||
entriesIterator.remove() | ||
} | ||
} | ||
} |
58 changes: 58 additions & 0 deletions
58
...-kotlin-runtime/src/jsMain/kotlin/com/strumenta/antlrkotlin/runtime/IdentityValuesView.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,58 @@ | ||
// Copyright 2017-present Strumenta and contributors, licensed under Apache 2.0. | ||
// Copyright 2024-present Strumenta and contributors, licensed under BSD 3-Clause. | ||
package com.strumenta.antlrkotlin.runtime | ||
|
||
internal class IdentityValuesView<V>(private val map: IdentityHashMap<*, V>) : AbstractMutableCollection<V>() { | ||
override val size: Int | ||
get() = map.size | ||
|
||
override fun isEmpty(): Boolean = | ||
map.isEmpty() | ||
|
||
override fun clear(): Unit = | ||
map.clear() | ||
|
||
override fun add(element: V): Boolean = | ||
throw UnsupportedOperationException("Adding is not supported on values") | ||
|
||
override fun remove(element: V): Boolean { | ||
val iterator = iterator() | ||
|
||
while (iterator.hasNext()) { | ||
// IMPORTANT: notice that we use reference/strict equality | ||
if (iterator.next() === element) { | ||
iterator.remove() | ||
return true | ||
} | ||
} | ||
|
||
return false | ||
} | ||
|
||
override fun removeAll(elements: Collection<V>): Boolean { | ||
var removed = false | ||
|
||
for (element in elements) { | ||
removed = remove(element) || removed | ||
} | ||
|
||
return removed | ||
} | ||
|
||
override operator fun contains(element: V): Boolean = | ||
map.containsValue(element) | ||
|
||
override operator fun iterator(): MutableIterator<V> { | ||
val entriesIterator = map.entries.iterator() | ||
return object : MutableIterator<V> { | ||
override fun hasNext(): Boolean = | ||
entriesIterator.hasNext() | ||
|
||
override fun next(): V = | ||
entriesIterator.next().value | ||
|
||
override fun remove(): Unit = | ||
entriesIterator.remove() | ||
} | ||
} | ||
} |
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
Oops, something went wrong.