Skip to content

Commit 92abb70

Browse files
Abdukodiri KurbonzodaAbduqodiri Qurbonzoda
authored andcommitted
Implement PersistentHashMap keys/values/entries
1 parent fa980d9 commit 92abb70

File tree

7 files changed

+374
-133
lines changed

7 files changed

+374
-133
lines changed

kotlinx-collections-immutable/src/main/kotlin/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMap.kt

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -24,47 +24,33 @@ internal const val PUT_KEY_VALUE = 2
2424
internal class ModificationWrapper(var value: Int = NO_MODIFICATION)
2525

2626

27-
internal class PersistentHashMap<K, out V>(private val node: TrieNode<K, V>,
27+
internal class PersistentHashMap<K, V>(val node: TrieNode<K, V>,
2828
override val size: Int): AbstractMap<K, V>(), PersistentMap<K, V> {
2929

3030
override val keys: ImmutableSet<K>
3131
get() {
32-
val iterator = PersistentHashMapIterator(node)
33-
val keys = mutableSetOf<K>()
34-
while (iterator.hasNext()) {
35-
keys.add(iterator.nextKey())
36-
}
37-
return keys.toImmutableSet()
32+
return PersistentHashMapKeys(this)
3833
}
3934

4035
override val values: ImmutableCollection<V>
4136
get() {
42-
val iterator = PersistentHashMapIterator(node)
43-
val values = mutableListOf<V>()
44-
while (iterator.hasNext()) {
45-
values.add(iterator.nextValue())
46-
}
47-
return values.toImmutableList()
37+
return PersistentHashMapValues(this)
4838
}
4939

50-
override val entries: ImmutableSet<Map.Entry<K, V>> get() = _entries ?: createEntries().apply { _entries = this }
51-
52-
private var _entries: ImmutableSet<Map.Entry<K, V>>? = null
40+
override val entries: ImmutableSet<Map.Entry<K, V>>
41+
get() {
42+
return createEntries()
43+
}
5344

5445
private fun createEntries(): ImmutableSet<Map.Entry<K, V>> {
55-
val iterator = PersistentHashMapIterator(node)
56-
val entries = mutableSetOf<Map.Entry<K, V>>()
57-
while (iterator.hasNext()) {
58-
entries.add(iterator.nextEntry())
59-
}
60-
return entries.toImmutableSet()
46+
return PersistentHashMapEntries(this)
6147
}
6248

63-
64-
6549
// TODO: compiler bug: this bridge should be generated automatically
6650
@PublishedApi
67-
internal fun getEntries(): Set<Map.Entry<K, V>> = _entries ?: createEntries().apply { _entries = this }
51+
internal fun getEntries(): Set<Map.Entry<K, V>> {
52+
return createEntries()
53+
}
6854

6955
override fun containsKey(key: K): Boolean {
7056
val keyHash = key?.hashCode() ?: NULL_HASH_CODE

kotlinx-collections-immutable/src/main/kotlin/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBuilder.kt

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import kotlinx.collections.immutable.PersistentMap
2020

2121
internal class Marker
2222

23-
internal class PersistentHashMapBuilder<K, V>(private var node: TrieNode<K, V>,
23+
internal class PersistentHashMapBuilder<K, V>(internal var node: TrieNode<K, V>,
2424
override var size: Int) : PersistentMap.Builder<K, V>, AbstractMutableMap<K, V>() {
2525
internal var marker = Marker()
2626

@@ -31,33 +31,17 @@ internal class PersistentHashMapBuilder<K, V>(private var node: TrieNode<K, V>,
3131

3232
override val entries: MutableSet<MutableMap.MutableEntry<K, V>>
3333
get() {
34-
val iterator = PersistentHashMapIterator(node)
35-
val entries = mutableSetOf<MutableMap.MutableEntry<K, V>>()
36-
while (iterator.hasNext()) {
37-
val entry = iterator.nextEntry().toMutable()
38-
entries.add(entry)
39-
}
40-
return entries
34+
return PersistentHashMapBuilderEntries(this)
4135
}
4236

4337
override val keys: MutableSet<K>
4438
get() {
45-
val iterator = PersistentHashMapIterator(node)
46-
val keys = mutableSetOf<K>()
47-
while (iterator.hasNext()) {
48-
keys.add(iterator.nextKey())
49-
}
50-
return keys
39+
return PersistentHashMapBuilderKeys(this)
5140
}
5241

5342
override val values: MutableCollection<V>
5443
get() {
55-
val iterator = PersistentHashMapIterator(node)
56-
val values = mutableListOf<V>()
57-
while (iterator.hasNext()) {
58-
values.add(iterator.nextValue())
59-
}
60-
return values
44+
return PersistentHashMapBuilderValues(this)
6145
}
6246

6347
override fun containsKey(key: K): Boolean {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/*
2+
* Copyright 2016-2018 JetBrains s.r.o.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package kotlinx.collections.immutable.implementations.immutableMap
18+
19+
20+
internal class TrieNodeMutableEntriesIterator<K, V>(private val builder: PersistentHashMapBuilder<K, V>)
21+
: TrieNodeBaseIterator<K, V, MutableMap.MutableEntry<K, V>>() {
22+
23+
override fun next(): MutableMap.MutableEntry<K, V> {
24+
assert(hasNextKey())
25+
index += 2
26+
return MutableMapEntry(builder, buffer[index - 2] as K, buffer[index - 1] as V)
27+
}
28+
}
29+
30+
private class MutableMapEntry<K, V>(private val builder: PersistentHashMapBuilder<K, V>,
31+
override val key: K,
32+
override val value: V) : MutableMap.MutableEntry<K, V> {
33+
override fun setValue(newValue: V): V {
34+
builder[key] = newValue
35+
return value
36+
}
37+
}
38+
39+
40+
internal abstract class PersistentHashMapBuilderBaseIterator<K, V, T>(private val builder: PersistentHashMapBuilder<K, V>,
41+
path: Array<TrieNodeBaseIterator<K, V, T>>)
42+
: MutableIterator<T>, PersistentHashMapBaseIterator<K, V, T>(builder.node, path) {
43+
44+
private var lastKey: K? = null
45+
private var nextWasInvoked = false
46+
47+
override fun next(): T {
48+
lastKey = currentKey()
49+
nextWasInvoked = true
50+
return super.next()
51+
}
52+
53+
override fun remove() {
54+
if (!nextWasInvoked) {
55+
throw NoSuchElementException()
56+
}
57+
if (hasNext()) {
58+
val currentKey = currentKey()
59+
60+
builder.remove(lastKey)
61+
resetPath(currentKey?.hashCode() ?: NULL_HASH_CODE, builder.node, currentKey, 0)
62+
} else {
63+
builder.remove(lastKey)
64+
}
65+
66+
lastKey = null
67+
nextWasInvoked = false
68+
}
69+
70+
private fun resetPath(keyHash: Int, node: TrieNode<*, *>, key: K, pathIndex: Int) {
71+
val shift = pathIndex * LOG_MAX_BRANCHING_FACTOR
72+
val keyPosition = 1 shl ((keyHash shr shift) and MAX_BRANCHING_FACTOR_MINUS_ONE)
73+
74+
if (node.hasDataAt(keyPosition)) { // key is directly in buffer
75+
val keyIndex = node.keyDataIndex(keyPosition)
76+
77+
assert(node.keyAtIndex(keyIndex) == key)
78+
79+
path[pathIndex].reset(node.buffer, 2 * Integer.bitCount(node.dataMap), keyIndex)
80+
return
81+
}
82+
83+
assert(node.hasNodeAt(keyPosition)) // key is in node
84+
85+
val nodeIndex = node.keyNodeIndex(keyPosition)
86+
val targetNode = node.nodeAtIndex(nodeIndex)
87+
if (shift == MAX_SHIFT) { // collision
88+
path[pathIndex].reset(node.buffer, node.buffer.size, 0)
89+
while (path[pathIndex].currentKey() != key) {
90+
path[pathIndex].moveToNextKey()
91+
}
92+
} else {
93+
path[pathIndex].reset(node.buffer, 2 * Integer.bitCount(node.dataMap), nodeIndex)
94+
resetPath(keyHash, targetNode, key, pathIndex + 1)
95+
}
96+
}
97+
}
98+
99+
internal class PersistentHashMapBuilderEntriesIterator<K, V>(builder: PersistentHashMapBuilder<K, V>)
100+
: PersistentHashMapBuilderBaseIterator<K, V, MutableMap.MutableEntry<K, V>>(builder, Array(TRIE_MAX_HEIGHT + 1) { TrieNodeMutableEntriesIterator<K, V>(builder) })
101+
102+
internal class PersistentHashMapBuilderKeysIterator<K, V>(builder: PersistentHashMapBuilder<K, V>)
103+
: PersistentHashMapBuilderBaseIterator<K, V, K>(builder, Array(TRIE_MAX_HEIGHT + 1) { TrieNodeKeysIterator<K, V>() })
104+
105+
internal class PersistentHashMapBuilderValuesIterator<K, V>(builder: PersistentHashMapBuilder<K, V>)
106+
: PersistentHashMapBuilderBaseIterator<K, V, V>(builder, Array(TRIE_MAX_HEIGHT + 1) { TrieNodeValuesIterator<K, V>() })
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
* Copyright 2016-2018 JetBrains s.r.o.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package kotlinx.collections.immutable.implementations.immutableMap
18+
19+
internal class PersistentHashMapBuilderEntries<K, V>(private val builder: PersistentHashMapBuilder<K, V>)
20+
: MutableSet<MutableMap.MutableEntry<K, V>>, AbstractMutableSet<MutableMap.MutableEntry<K, V>>() {
21+
override fun add(element: MutableMap.MutableEntry<K, V>): Boolean {
22+
throw UnsupportedOperationException()
23+
}
24+
25+
override fun clear() {
26+
builder.clear()
27+
}
28+
29+
override fun iterator(): MutableIterator<MutableMap.MutableEntry<K, V>> {
30+
return PersistentHashMapBuilderEntriesIterator(builder)
31+
}
32+
33+
override fun remove(element: MutableMap.MutableEntry<K, V>): Boolean {
34+
return builder.remove(element.key, element.value)
35+
}
36+
37+
override val size: Int
38+
get() = builder.size
39+
40+
override fun contains(element: MutableMap.MutableEntry<K, V>): Boolean {
41+
return builder[element.key]?.let { candidate -> candidate == element.value }
42+
?: (element.value == null && builder.containsKey(element.key))
43+
}
44+
}
45+
46+
internal class PersistentHashMapBuilderKeys<K, V>(private val builder: PersistentHashMapBuilder<K, V>) : MutableSet<K>, AbstractMutableSet<K>() {
47+
override fun add(element: K): Boolean {
48+
throw UnsupportedOperationException()
49+
}
50+
51+
override fun clear() {
52+
builder.clear()
53+
}
54+
55+
override fun iterator(): MutableIterator<K> {
56+
return PersistentHashMapBuilderKeysIterator(builder)
57+
}
58+
59+
override fun remove(element: K): Boolean {
60+
if (builder.containsKey(element)) {
61+
builder.remove(element)
62+
return true
63+
}
64+
return false
65+
}
66+
67+
override val size: Int
68+
get() = builder.size
69+
70+
override fun contains(element: K): Boolean {
71+
return builder.containsKey(element)
72+
}
73+
}
74+
75+
internal class PersistentHashMapBuilderValues<K, V>(private val builder: PersistentHashMapBuilder<K, V>) : MutableCollection<V>, AbstractMutableCollection<V>() {
76+
override val size: Int
77+
get() = builder.size
78+
79+
override fun contains(element: V): Boolean {
80+
return builder.containsValue(element)
81+
}
82+
83+
override fun add(element: V): Boolean {
84+
throw UnsupportedOperationException()
85+
}
86+
87+
override fun clear() {
88+
builder.clear()
89+
}
90+
91+
override fun iterator(): MutableIterator<V> {
92+
return PersistentHashMapBuilderValuesIterator(builder)
93+
}
94+
}

0 commit comments

Comments
 (0)