Skip to content

Commit 4b67bef

Browse files
author
Abduqodiri Qurbonzoda
committed
Support null key and fail-fast iterators in OrderedMap and Builder
1 parent f3834c8 commit 4b67bef

File tree

4 files changed

+93
-61
lines changed

4 files changed

+93
-61
lines changed

kotlinx-collections-immutable/src/main/kotlin/kotlinx/collections/immutable/implementations/persistentOrderedMap/PersistentOrderedMap.kt

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,24 @@ import kotlinx.collections.immutable.PersistentMap
2222
import kotlinx.collections.immutable.implementations.immutableMap.PersistentHashMap
2323
import kotlinx.collections.immutable.mutate
2424

25-
internal class LinkedValue<out K, out V>(val value: V, val previous: K?, val next: K?)
25+
internal object EndOfLink
26+
27+
internal class LinkedValue<V>(val value: V, val previous: Any?, val next: Any?) {
28+
constructor(value: V) : this(value, EndOfLink, EndOfLink)
29+
30+
fun withValue(newValue: V) = LinkedValue(newValue, previous, next)
31+
fun withPrevious(newPrevious: Any?) = LinkedValue(value, newPrevious, next)
32+
fun withNext(newNext: Any?) = LinkedValue(value, previous, newNext)
33+
34+
fun putNextLink(value: V, previous: Any?): LinkedValue<V> {
35+
// assert(next === EndOfLink)
36+
return LinkedValue(value, previous, EndOfLink)
37+
}
38+
}
2639

2740
internal class PersistentOrderedMap<K, V>(internal val firstKey: K?,
2841
internal val lastKey: K?,
29-
internal val map: PersistentHashMap<K, LinkedValue<K, V>>): AbstractMap<K, V>(), PersistentMap<K, V> {
42+
internal val map: PersistentHashMap<K, LinkedValue<V>>): AbstractMap<K, V>(), PersistentMap<K, V> {
3043

3144
override val size: Int
3245
get() = map.size
@@ -70,36 +83,37 @@ internal class PersistentOrderedMap<K, V>(internal val firstKey: K?,
7083
if (links.value == value) {
7184
return this
7285
}
73-
val newMap = map.put(key, LinkedValue(value, links.previous, links.next))
86+
val newMap = map.put(key, links.withValue(value))
7487
return PersistentOrderedMap(firstKey, lastKey, newMap)
7588
}
7689
if (isEmpty()) {
77-
val newMap = map.put(key, LinkedValue<K, V>(value, null, null))
90+
val newMap = map.put(key, LinkedValue(value))
7891
return PersistentOrderedMap(key, key, newMap)
7992
}
80-
val oldLinks = map[lastKey]!!
81-
assert(oldLinks.next == null)
82-
val newLinks = LinkedValue(oldLinks.value, oldLinks.previous, key)
83-
val newMap = map.put(lastKey as K, newLinks).put(key, LinkedValue(value, lastKey, null))
93+
val lastLink = map[lastKey]!!
94+
// assert(lastLink.next === EndOfLink)
95+
val newMap = map
96+
.put(lastKey as K, lastLink.withNext(key))
97+
.put(key, lastLink.putNextLink(value, lastKey))
8498
return PersistentOrderedMap(firstKey, key, newMap)
8599
}
86100

87101
override fun remove(key: K): PersistentOrderedMap<K, V> {
88102
val links = map[key] ?: return this
89103

90104
var newMap = map.remove(key)
91-
if (key != firstKey) {
105+
if (links.previous !== EndOfLink) {
92106
val previousLinks = newMap[links.previous]!!
93-
assert(previousLinks.next == key)
94-
newMap = newMap.put(links.previous as K, LinkedValue(previousLinks.value, previousLinks.previous, links.next))
107+
// assert(previousLinks.next == key)
108+
newMap = newMap.put(links.previous as K, previousLinks.withNext(links.next))
95109
}
96-
if (key != lastKey) {
110+
if (links.next !== EndOfLink) {
97111
val nextLinks = newMap[links.next]!!
98-
assert(nextLinks.previous == key)
99-
newMap = newMap.put(links.next as K, LinkedValue(nextLinks.value, links.previous, nextLinks.next))
112+
// assert(nextLinks.previous == key)
113+
newMap = newMap.put(links.next as K, nextLinks.withPrevious(links.previous))
100114
}
101-
val newFirstKey = if (key == firstKey) links.next else firstKey
102-
val newLastKey = if (key == lastKey) links.previous else lastKey
115+
val newFirstKey = if (links.previous === EndOfLink) links.next as? K else firstKey
116+
val newLastKey = if (links.next === EndOfLink) links.previous as? K else lastKey
103117
return PersistentOrderedMap(newFirstKey, newLastKey, newMap)
104118
}
105119

kotlinx-collections-immutable/src/main/kotlin/kotlinx/collections/immutable/implementations/persistentOrderedMap/PersistentOrderedMapBuilder.kt

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -64,44 +64,45 @@ internal class PersistentOrderedMapBuilder<K, V>(private var map: PersistentOrde
6464
override fun put(key: K, value: @UnsafeVariance V): V? {
6565
val links = mapBuilder[key]
6666
if (links != null) {
67-
if (links.value == value) {
67+
if (links.value === value) {
6868
return value
6969
}
70-
mapBuilder[key] = LinkedValue(value, links.previous, links.next)
70+
mapBuilder[key] = links.withValue(value)
7171
return links.value
7272
}
7373

7474
if (isEmpty()) { // isEmpty
7575
firstKey = key
7676
lastKey = key
77-
mapBuilder[key] = LinkedValue<K, V>(value, null, null)
77+
mapBuilder[key] = LinkedValue(value)
7878
return null
7979
}
80-
val oldLinks = mapBuilder[lastKey]!!
81-
assert(oldLinks.next == null)
82-
val newLinks = LinkedValue(oldLinks.value, oldLinks.previous, key)
80+
val lastLink = mapBuilder[lastKey]!!
81+
assert(lastLink.next == EndOfLink)
8382

84-
mapBuilder[lastKey as K] = newLinks
85-
mapBuilder[key] = LinkedValue(value, lastKey, null)
83+
mapBuilder[lastKey as K] = lastLink.withNext(key)
84+
mapBuilder[key] = lastLink.putNextLink(value, lastKey)
8685
lastKey = key
8786
return null
8887
}
8988

9089
override fun remove(key: K): V? {
9190
val links = mapBuilder.remove(key) ?: return null
9291

93-
if (links.previous != null) {
92+
if (links.previous !== EndOfLink) {
9493
val previousLinks = mapBuilder[links.previous]!!
95-
assert(previousLinks.next == key)
96-
mapBuilder[links.previous] = LinkedValue(previousLinks.value, previousLinks.previous, links.next)
94+
// assert(previousLinks.next == key)
95+
mapBuilder[links.previous as K] = previousLinks.withNext(links.next)
96+
} else {
97+
firstKey = links.next as? K
9798
}
98-
if (links.next != null) {
99+
if (links.next !== EndOfLink) {
99100
val nextLinks = mapBuilder[links.next]!!
100-
assert(nextLinks.previous == key)
101-
mapBuilder[links.next] = LinkedValue(nextLinks.value, links.previous, nextLinks.next)
101+
// assert(nextLinks.previous == key)
102+
mapBuilder[links.next as K] = nextLinks.withPrevious(links.previous)
103+
} else {
104+
lastKey = links.previous as? K
102105
}
103-
firstKey = if (key == firstKey) links.next else firstKey
104-
lastKey = if (key == lastKey) links.previous else lastKey
105106
return links.value
106107
}
107108

kotlinx-collections-immutable/src/main/kotlin/kotlinx/collections/immutable/implementations/persistentOrderedMap/PersistentOrderedMapBuilderContentIterators.kt

Lines changed: 41 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -18,80 +18,97 @@ package kotlinx.collections.immutable.implementations.persistentOrderedMap
1818

1919
import kotlinx.collections.immutable.implementations.immutableMap.MapEntry
2020

21-
internal open class PersistentOrderedMapBuilderLinksIterator<K, V>(internal var nextKey: K?,
22-
internal val map: MutableMap<K, LinkedValue<K, V>>) : MutableIterator<LinkedValue<K, V>> {
23-
internal var lastProcessedKey: K? = null
21+
internal open class PersistentOrderedMapBuilderLinksIterator<K, V>(
22+
private var nextKey: K?,
23+
internal val builder: PersistentOrderedMapBuilder<K, V>
24+
) : MutableIterator<LinkedValue<V>> {
25+
26+
internal var lastIteratedKey: K? = null
2427
private var nextWasInvoked = false
28+
private var expectedModCount = builder.mapBuilder.modCount
2529
internal var index = 0
2630

2731
override fun hasNext(): Boolean {
28-
return index < map.size
32+
return index < builder.size
2933
}
3034

31-
override fun next(): LinkedValue<K, V> {
32-
if (!hasNext()) {
33-
throw NoSuchElementException()
34-
}
35-
lastProcessedKey = nextKey
35+
override fun next(): LinkedValue<V> {
36+
checkForComodification()
37+
checkHasNext()
38+
lastIteratedKey = nextKey
3639
nextWasInvoked = true
3740
index++
38-
val result = map[nextKey as K]!!
39-
nextKey = result.next
41+
val result = builder.mapBuilder[nextKey]!!
42+
nextKey = result.next as? K
4043
return result
4144
}
4245

4346
override fun remove() {
44-
if (!nextWasInvoked) {
45-
throw NoSuchElementException()
46-
}
47-
map.remove(lastProcessedKey)
48-
lastProcessedKey = null
47+
checkNextWasInvoked()
48+
builder.remove(lastIteratedKey)
49+
lastIteratedKey = null
4950
nextWasInvoked = false
51+
expectedModCount = builder.mapBuilder.modCount
5052
index--
5153
}
54+
55+
private fun checkHasNext() {
56+
if (!hasNext())
57+
throw NoSuchElementException()
58+
}
59+
60+
private fun checkNextWasInvoked() {
61+
if (!nextWasInvoked)
62+
throw IllegalStateException()
63+
}
64+
65+
private fun checkForComodification() {
66+
if (builder.mapBuilder.modCount != expectedModCount)
67+
throw ConcurrentModificationException()
68+
}
5269
}
5370

5471
internal class PersistentOrderedMapBuilderEntriesIterator<K, V>(map: PersistentOrderedMapBuilder<K, V>): MutableIterator<MutableMap.MutableEntry<K, V>> {
55-
private val internal = PersistentOrderedMapBuilderLinksIterator(map.firstKey, map.mapBuilder)
72+
private val internal = PersistentOrderedMapBuilderLinksIterator(map.firstKey, map)
5673

5774
override fun hasNext(): Boolean {
5875
return internal.hasNext()
5976
}
6077

6178
override fun next(): MutableMap.MutableEntry<K, V> {
6279
val links = internal.next()
63-
return MutableMapEntry(internal.map, internal.lastProcessedKey as K, links)
80+
return MutableMapEntry(internal.builder.mapBuilder, internal.lastIteratedKey as K, links)
6481
}
6582

6683
override fun remove() {
6784
internal.remove()
6885
}
6986
}
7087

71-
private class MutableMapEntry<K, V>(private val mutableMap: MutableMap<K, LinkedValue<K, V>>,
88+
private class MutableMapEntry<K, V>(private val mutableMap: MutableMap<K, LinkedValue<V>>,
7289
key: K,
73-
private var links: LinkedValue<K, V>) : MapEntry<K, V>(key, links.value), MutableMap.MutableEntry<K, V> {
90+
private var links: LinkedValue<V>) : MapEntry<K, V>(key, links.value), MutableMap.MutableEntry<K, V> {
7491
override val value: V
7592
get() = links.value
7693

7794
override fun setValue(newValue: V): V {
7895
val result = links.value
79-
links = LinkedValue(newValue, links.previous, links.next)
96+
links = links.withValue(newValue)
8097
mutableMap[key] = links
8198
return result
8299
}
83100
}
84101

85102
internal class PersistentOrderedMapBuilderKeysIterator<out K, out V>(map: PersistentOrderedMapBuilder<K, V>): MutableIterator<K> {
86-
private val internal = PersistentOrderedMapBuilderLinksIterator(map.firstKey, map.mapBuilder)
103+
private val internal = PersistentOrderedMapBuilderLinksIterator(map.firstKey, map)
87104

88105
override fun hasNext(): Boolean {
89106
return internal.hasNext()
90107
}
91108

92109
override fun next(): K {
93110
internal.next()
94-
return internal.lastProcessedKey as K
111+
return internal.lastIteratedKey as K
95112
}
96113

97114
override fun remove() {
@@ -100,7 +117,7 @@ internal class PersistentOrderedMapBuilderKeysIterator<out K, out V>(map: Persis
100117
}
101118

102119
internal class PersistentOrderedMapBuilderValuesIterator<out K, out V>(map: PersistentOrderedMapBuilder<K, V>): MutableIterator<V> {
103-
private val internal = PersistentOrderedMapBuilderLinksIterator(map.firstKey, map.mapBuilder)
120+
private val internal = PersistentOrderedMapBuilderLinksIterator(map.firstKey, map)
104121

105122
override fun hasNext(): Boolean {
106123
return internal.hasNext()

kotlinx-collections-immutable/src/main/kotlin/kotlinx/collections/immutable/implementations/persistentOrderedMap/PersistentOrderedMapContentIterators.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,21 @@ package kotlinx.collections.immutable.implementations.persistentOrderedMap
1818

1919
import kotlinx.collections.immutable.implementations.immutableMap.MapEntry
2020

21-
internal open class PersistentOrderedMapLinksIterator<K, out V>(internal var nextKey: K?,
22-
internal val map: Map<K, LinkedValue<K, V>>) : Iterator<LinkedValue<K, V>> {
21+
internal open class PersistentOrderedMapLinksIterator<K, V>(internal var nextKey: K?,
22+
internal val map: Map<K, LinkedValue<V>>) : Iterator<LinkedValue<V>> {
2323
internal var index = 0
2424

2525
override fun hasNext(): Boolean {
2626
return index < map.size
2727
}
2828

29-
override fun next(): LinkedValue<K, V> {
29+
override fun next(): LinkedValue<V> {
3030
if (!hasNext()) {
3131
throw NoSuchElementException()
3232
}
33-
val result = map[nextKey as K]!!
33+
val result = map[nextKey]!!
3434
index++
35-
nextKey = result.next
35+
nextKey = result.next as? K
3636
return result
3737
}
3838

0 commit comments

Comments
 (0)